diff --git a/.github/workflows/Downgrade.yml b/.github/workflows/Downgrade.yml index 32b6234b..f207d1b4 100644 --- a/.github/workflows/Downgrade.yml +++ b/.github/workflows/Downgrade.yml @@ -15,14 +15,14 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - version: ['1'] + version: ['1.10'] steps: - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v1 with: version: ${{ matrix.version }} - uses: cjdoris/julia-downgrade-compat-action@v1 -# if: ${{ matrix.version == '1.6' }} +# if: ${{ matrix.version == '1.10' }} with: skip: Pkg,TOML - uses: julia-actions/julia-buildpkg@v1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc97c85d..1883999f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,39 +15,65 @@ jobs: matrix: test_set: ["basic", "plots", "higher_order", "estimation"] version: ['1.8', '1.9', '1.10'] - os: [ubuntu-latest, macOS-latest, windows-latest] - arch: [x64] + os: [ubuntu-latest, macos-14, windows-latest] + arch: [x64, arm64] exclude: - version: '1.8' - os: macOS-latest + os: ubuntu-latest - version: '1.8' os: windows-latest - version: '1.9' - os: macOS-latest + os: ubuntu-latest - version: '1.9' os: windows-latest + - arch: arm64 + os: ubuntu-latest + - arch: arm64 + os: windows-latest + - arch: x64 + os: macos-14 include: - os: ubuntu-latest prefix: xvfb-run + # - version: '1.10' + # os: macos-14 + # arch: x64 + # test_set: "solver0" + # - version: '1.10' + # os: macos-14 + # arch: x64 + # test_set: "solver1" + # - version: '1.10' + # os: macos-14 + # arch: x64 + # test_set: "solver2" + # - version: '1.10' + # os: macos-14 + # arch: x64 + # test_set: "solver3" - version: '1.10' - os: ubuntu-latest + os: macos-14 arch: x64 test_set: "1st_order_inversion_estimation" - version: '1.10' - os: ubuntu-latest + os: macos-14 arch: x64 test_set: "2nd_order_estimation" - version: '1.10' - os: ubuntu-latest + os: macos-14 arch: x64 test_set: "3rd_order_estimation" + # - version: '1.10' + # os: macOS-latest + # arch: x64 + # test_set: "basic" - version: 'nightly' - os: ubuntu-latest + os: macos-14 arch: x64 test_set: "basic" allow_failure: true - version: '^1.11.0-0' - os: ubuntu-latest + os: macos-14 arch: x64 test_set: "basic" allow_failure: true @@ -57,14 +83,14 @@ jobs: with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} - - name: Set Custom Test Environment Variable + - name: Set Custom Test Environment Variable (Windows) if: matrix.os == 'windows-latest' run: echo "TEST_SET=${{ matrix.test_set }}" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8 - - name: Set Custom Test Environment Variable (Unix) + - name: Set Custom Test Environment Variable (non-Windows) if: matrix.os != 'windows-latest' run: echo "TEST_SET=${{ matrix.test_set }}" >> $GITHUB_ENV - - name: Set JULIA_NUM_THREADS for Julia 1.10 on Ubuntu - if: matrix.version == '1.10' && matrix.os == 'ubuntu-latest' && (matrix.test_set == 'hmc_estimation' || matrix.test_set == 'tempering_estimation' || matrix.test_set == '2nd_order_estimation' || matrix.test_set == '3rd_order_estimation') + - name: Set JULIA_NUM_THREADS for estimation tests + if: matrix.version == '1.10' && (matrix.test_set == 'estimation' || matrix.test_set == 'solver0' || matrix.test_set == 'solver1' || matrix.test_set == 'solver2' || matrix.test_set == 'solver3' || matrix.test_set == '1st_order_inversion_estimation' || matrix.test_set == '2nd_order_estimation' || matrix.test_set == '3rd_order_estimation') run: echo "JULIA_NUM_THREADS=auto" >> $GITHUB_ENV - uses: actions/cache@v4 env: diff --git a/.gitignore b/.gitignore index 4dd24e18..caa5fc61 100644 --- a/.gitignore +++ b/.gitignore @@ -55,4 +55,7 @@ estimation__* .micromamba/ results -octave* \ No newline at end of file +octave* +*.jls +samples* +*samples.csv \ No newline at end of file diff --git a/Project.toml b/Project.toml index 5f19705b..988e579e 100644 --- a/Project.toml +++ b/Project.toml @@ -8,6 +8,7 @@ AbstractDifferentiation = "c29ec348-61ec-40c8-8164-b8c60e9d9f3d" AxisKeys = "94b1ba4f-4ee9-5380-92f1-94cde586c3c5" BlockTriangularForm = "adeb47b7-70bf-415a-bb24-c358563e873a" ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" +Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" DynarePreprocessor_jll = "23afba7c-24e5-5ee2-bc2c-b42e07f0492a" @@ -52,6 +53,7 @@ AxisKeys = "^0.2" BlockTriangularForm = "^0.1" CSV = "^0.10" ChainRulesCore = "^1" +Combinatorics = "^1" DataFrames = "^1" DataStructures = "^0.18" DocStringExtensions = "^0.8, 0.9" diff --git a/benchmark/SW07_estimation.jl b/benchmark/SW07_estimation.jl deleted file mode 100644 index 4287dbfb..00000000 --- a/benchmark/SW07_estimation.jl +++ /dev/null @@ -1,678 +0,0 @@ -using MacroModelling -import Turing -import Turing: NUTS, sample, logpdf, Truncated#, Normal, Beta, Gamma, InverseGamma, -using Random, CSV, DataFrames, Zygote, AxisKeys, MCMCChains -# using ComponentArrays, Optimization, OptimizationNLopt, OptimizationOptimisers -import DynamicPPL: logjoint -import ChainRulesCore: @ignore_derivatives, ignore_derivatives - -@model SW07 begin - a[0] = calfa * rkf[0] + (1 - calfa) * (wf[0]) - - zcapf[0] = (1 / (czcap / (1 - czcap))) * rkf[0] - - rkf[0] = wf[0] + labf[0] - kf[0] - - kf[0] = kpf[-1] + zcapf[0] - - invef[0] = (1 / (1 + cbetabar * cgamma)) * (invef[-1] + cbetabar * cgamma * invef[1] + (1 / (cgamma ^ 2 * csadjcost)) * pkf[0]) + qs[0] - - pkf[0] = - rrf[0] + (1 / ((1 - chabb / cgamma) / (csigma * (1 + chabb / cgamma)))) * b[0] + (crk / (crk + (1 - ctou))) * rkf[1] + ((1 - ctou) / (crk + (1 - ctou))) * pkf[1] - - cf[0] = (chabb / cgamma) / (1 + chabb / cgamma) * cf[-1] + (1 / (1 + chabb / cgamma)) * cf[1] + ((csigma - 1) * cwhlc / (csigma * (1 + chabb / cgamma))) * (labf[0] - labf[1]) - (1 - chabb / cgamma) / (csigma * (1 + chabb / cgamma)) * (rrf[0]) + b[0] - - yf[0] = ccy * cf[0] + ciy * invef[0] + g[0] + crkky * zcapf[0] - - yf[0] = cfc * (calfa * kf[0] + (1 - calfa) * labf[0] + a[0]) - - wf[0] = csigl * labf[0] + (1 / (1 - chabb / cgamma)) * cf[0] - (chabb / cgamma) / (1 - chabb / cgamma) * cf[-1] - - kpf[0] = (1 - cikbar) * kpf[-1] + (cikbar) * invef[0] + (cikbar) * (cgamma ^ 2 * csadjcost) * qs[0] - - mc[0] = calfa * rk[0] + (1 - calfa) * (w[0]) - a[0] - - zcap[0] = (1 / (czcap / (1 - czcap))) * rk[0] - - rk[0] = w[0] + lab[0] - k[0] - - k[0] = kp[-1] + zcap[0] - - inve[0] = (1 / (1 + cbetabar * cgamma)) * (inve[-1] + cbetabar * cgamma * inve[1] + (1 / (cgamma ^ 2 * csadjcost)) * pk[0]) + qs[0] - - pk[0] = - r[0] + pinf[1] + (1 / ((1 - chabb / cgamma) / (csigma * (1 + chabb / cgamma)))) * b[0] + (crk / (crk + (1 - ctou))) * rk[1] + ((1 - ctou) / (crk + (1 - ctou))) * pk[1] - - c[0] = (chabb / cgamma) / (1 + chabb / cgamma) * c[-1] + (1 / (1 + chabb / cgamma)) * c[1] + ((csigma - 1) * cwhlc / (csigma * (1 + chabb / cgamma))) * (lab[0] - lab[1]) - (1 - chabb / cgamma) / (csigma * (1 + chabb / cgamma)) * (r[0] - pinf[1]) + b[0] - - y[0] = ccy * c[0] + ciy * inve[0] + g[0] + crkky * zcap[0] - - y[0] = cfc * (calfa * k[0] + (1 - calfa) * lab[0] + a[0]) - - pinf[0] = (1 / (1 + cbetabar * cgamma * cindp)) * (cbetabar * cgamma * pinf[1] + cindp * pinf[-1] + ((1 - cprobp) * (1 - cbetabar * cgamma * cprobp) / cprobp) / ((cfc - 1) * curvp + 1) * (mc[0])) + spinf[0] - - w[0] = (1 / (1 + cbetabar * cgamma)) * w[-1] + (cbetabar * cgamma / (1 + cbetabar * cgamma)) * w[1] + (cindw / (1 + cbetabar * cgamma)) * pinf[-1] - (1 + cbetabar * cgamma * cindw) / (1 + cbetabar * cgamma) * pinf[0] + (cbetabar * cgamma) / (1 + cbetabar * cgamma) * pinf[1] + (1 - cprobw) * (1 - cbetabar * cgamma * cprobw) / ((1 + cbetabar * cgamma) * cprobw) * (1 / ((clandaw - 1) * curvw + 1)) * (csigl * lab[0] + (1 / (1 - chabb / cgamma)) * c[0] - ((chabb / cgamma) / (1 - chabb / cgamma)) * c[-1] - w[0]) + sw[0] - - r[0] = crpi * (1 - crr) * pinf[0] + cry * (1 - crr) * (y[0] - yf[0]) + crdy * (y[0] - yf[0] - y[-1] + yf[-1]) + crr * r[-1] + ms[0] - - a[0] = crhoa * a[-1] + z_ea * ea[x] - - b[0] = crhob * b[-1] + z_eb * eb[x] - - g[0] = crhog * g[-1] + z_eg * eg[x] + cgy * z_ea * ea[x] - - qs[0] = crhoqs * qs[-1] + z_eqs * eqs[x] - - ms[0] = crhoms * ms[-1] + z_em * em[x] - - spinf[0] = crhopinf * spinf[-1] + epinfma[0] - cmap * epinfma[-1] - - epinfma[0] = z_epinf * epinf[x] - - sw[0] = crhow * sw[-1] + ewma[0] - cmaw * ewma[-1] - - ewma[0] = z_ew * ew[x] - - kp[0] = (1 - cikbar) * kp[-1] + cikbar * inve[0] + cikbar * cgamma ^ 2 * csadjcost * qs[0] - - dy[0] = y[0] - y[-1] + ctrend - - dc[0] = c[0] - c[-1] + ctrend - - dinve[0] = inve[0] - inve[-1] + ctrend - - dw[0] = w[0] - w[-1] + ctrend - - pinfobs[0] = (pinf[0]) + constepinf - - robs[0] = (r[0]) + conster - - labobs[0] = lab[0] + constelab - -end - - -@parameters SW07 begin - ctou=.025 - clandaw=1.5 - cg=0.18 - curvp=10 - curvw=10 - - calfa=.24 - # cgamma=1.004 - # cbeta=.9995 - csigma=1.5 - # cpie=1.005 - cfc=1.5 - cgy=0.51 - - csadjcost= 6.0144 - chabb= 0.6361 - cprobw= 0.8087 - csigl= 1.9423 - cprobp= 0.6 - cindw= 0.3243 - cindp= 0.47 - czcap= 0.2696 - crpi= 1.488 - crr= 0.8762 - cry= 0.0593 - crdy= 0.2347 - - crhoa= 0.9977 - crhob= 0.5799 - crhog= 0.9957 - crhols= 0.9928 - crhoqs= 0.7165 - crhoas=1 - crhoms=0 - crhopinf=0 - crhow=0 - cmap = 0 - cmaw = 0 - - clandap=cfc - cbetabar=cbeta*cgamma^(-csigma) - cr=cpie/(cbeta*cgamma^(-csigma)) - crk=(cbeta^(-1))*(cgamma^csigma) - (1-ctou) - cw = (calfa^calfa*(1-calfa)^(1-calfa)/(clandap*crk^calfa))^(1/(1-calfa)) - cikbar=(1-(1-ctou)/cgamma) - cik=(1-(1-ctou)/cgamma)*cgamma - clk=((1-calfa)/calfa)*(crk/cw) - cky=cfc*(clk)^(calfa-1) - ciy=cik*cky - ccy=1-cg-cik*cky - crkky=crk*cky - cwhlc=(1/clandaw)*(1-calfa)/calfa*crk*cky/ccy - cwly=1-crk*cky - - conster=(cr-1)*100 - # ctrend=(cgamma-1)*100 - ctrend=(1.004-1)*100 - # constepinf=(cpie-1)*100 - constepinf=(1.005-1)*100 - - cpie=1+constepinf/100 - cgamma=1+ctrend/100 - - cbeta=1/(1+constebeta/100) - constebeta = 100 / .9995 - 100 - - constelab=0 - - z_ea = 0.4618 - z_eb = 1.8513 - z_eg = 0.6090 - z_eqs = 0.6017 - z_em = 0.2397 - z_epinf = 0.1455 - z_ew = 0.2089 -end - -# load data -dat = CSV.read("test/data/usmodel.csv", DataFrame) -data = KeyedArray(Array(dat)',Variable = Symbol.(strip.(names(dat))), Time = 1:size(dat)[1]) - -# declare observables -observables = [:dy, :dc, :dinve, :labobs, :pinfobs, :dw, :robs] - -# Subsample from 1966Q1 - 2004Q4 -# subset observables in data -data = data(observables,75:230) - -# functions to map mean and standard deviations to distribution parameters - - - -Turing.@model function SW07_loglikelihood_function(data, m, observables,fixed_parameters) - z_ea ~ Truncated(InverseGamma(0.1, 2.0, μσ = true),0.01,3) - z_eb ~ Truncated(InverseGamma(0.1, 2.0, μσ = true),0.025,5) - z_eg ~ Truncated(InverseGamma(0.1, 2.0, μσ = true),0.01,3) - z_eqs ~ Truncated(InverseGamma(0.1, 2.0, μσ = true),0.01,3) - z_em ~ Truncated(InverseGamma(0.1, 2.0, μσ = true),0.01,3) - z_epinf ~ Truncated(InverseGamma(0.1, 2.0, μσ = true),0.01,3) - z_ew ~ Truncated(InverseGamma(0.1, 2.0, μσ = true),0.01,3) - crhoa ~ Truncated(Beta(0.5, 0.20, μσ = true),.01,.9999) - crhob ~ Truncated(Beta(0.5, 0.20, μσ = true),.01,.9999) - crhog ~ Truncated(Beta(0.5, 0.20, μσ = true),.01,.9999) - crhoqs ~ Truncated(Beta(0.5, 0.20, μσ = true),.01,.9999) - crhoms ~ Truncated(Beta(0.5, 0.20, μσ = true),.01,.9999) - crhopinf~ Truncated(Beta(0.5, 0.20, μσ = true),.01,.9999) - crhow ~ Truncated(Beta(0.5, 0.20, μσ = true),.001,.9999) - cmap ~ Truncated(Beta(0.5, 0.2, μσ = true),0.01,.9999) - cmaw ~ Truncated(Beta(0.5, 0.2, μσ = true),0.01,.9999) - csadjcost~ Truncated(Normal(4,1.5),2,15) - csigma ~ Truncated(Normal(1.50,0.375),0.25,3) - chabb ~ Truncated(Beta(0.7, 0.1, μσ = true),0.001,0.99) - cprobw ~ Truncated(Beta(0.5, 0.1, μσ = true),0.3,0.95) - csigl ~ Truncated(Normal(2,0.75),0.25,10) - cprobp ~ Truncated(Beta(0.5, 0.10, μσ = true),0.5,0.95) - cindw ~ Truncated(Beta(0.5, 0.15, μσ = true),0.01,0.99) - cindp ~ Truncated(Beta(0.5, 0.15, μσ = true),0.01,0.99) - czcap ~ Truncated(Beta(0.5, 0.15, μσ = true),0.01,1) - cfc ~ Truncated(Normal(1.25,0.125),1.0,3) - crpi ~ Truncated(Normal(1.5,0.25),1.0,3) - crr ~ Truncated(Beta(0.75, 0.10, μσ = true),0.5,0.975) - cry ~ Truncated(Normal(0.125,0.05),0.001,0.5) - crdy ~ Truncated(Normal(0.125,0.05),0.001,0.5) - constepinf~ Truncated(Gamma(0.625,0.1, μσ = true),0.1,2.0) - constebeta~ Truncated(Gamma(0.25,0.1, μσ = true),0.01,2.0) - constelab ~ Truncated(Normal(0.0,2.0),-10.0,10.0) - ctrend ~ Truncated(Normal(0.4,0.10),0.1,0.8) - cgy ~ Truncated(Normal(0.5,0.25),0.01,2.0) - calfa ~ Truncated(Normal(0.3,0.05),0.01,1.0) - - ctou, clandaw, cg, curvp, curvw, crhols, crhoas = fixed_parameters - - parameters_combined = [ctou,clandaw,cg,curvp,curvw,calfa,csigma,cfc,cgy,csadjcost,chabb,cprobw,csigl,cprobp,cindw,cindp,czcap,crpi,crr,cry,crdy,crhoa,crhob,crhog,crhols,crhoqs,crhoas,crhoms,crhopinf,crhow,cmap,cmaw,constelab,z_ea,z_eb,z_eg,z_eqs,z_em,z_epinf,z_ew,ctrend,constepinf,constebeta] - - kalman_prob = get_loglikelihood(m, data(observables), parameters_combined) - - # println(kalman_prob) - - Turing.@addlogprob! kalman_prob -end - - -SW07.parameter_values[indexin([:crhoms, :crhopinf, :crhow, :cmap, :cmaw],SW07.parameters)] .= 0.02 - -fixed_parameters = SW07.parameter_values[indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters)] - -SW07_loglikelihood = SW07_loglikelihood_function(data, SW07, observables, fixed_parameters) - - - -n_samples = 1000 - -Turing.setadbackend(:zygote) -samps = Turing.sample(SW07_loglikelihood, NUTS(), n_samples, progress = true)#, init_params = sol) - - -serialize("chain-file.jls", samps) - - - - -# pars = ComponentArray(Float64[SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))]...],Axis(SW07.parameters[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))])) - - -# Mode calculation - -function calculate_posterior_loglikelihoods(parameters, u) - ctou, clandaw, cg, curvp, curvw, crhols, crhoas = @ignore_derivatives SW07.parameter_values[indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters)] - - calfa,csigma,cfc,cgy,csadjcost,chabb,cprobw,csigl,cprobp,cindw,cindp,czcap,crpi,crr,cry,crdy,crhoa,crhob,crhog,crhoqs,crhoms,crhopinf,crhow,cmap,cmaw,constelab,z_ea,z_eb,z_eg,z_eqs,z_em,z_epinf,z_ew,ctrend,constepinf,constebeta = parameters - - parameters_combined = [ctou,clandaw,cg,curvp,curvw,calfa,csigma,cfc,cgy,csadjcost,chabb,cprobw,csigl,cprobp,cindw,cindp,czcap,crpi,crr,cry,crdy,crhoa,crhob,crhog,crhols,crhoqs,crhoas,crhoms,crhopinf,crhow,cmap,cmaw,constelab,z_ea,z_eb,z_eg,z_eqs,z_em,z_epinf,z_ew,ctrend,constepinf,constebeta] - - log_lik = 0 - log_lik -= get_loglikelihood(SW07, data(observables), parameters_combined, filter = :kalman) - log_lik -= logpdf(Truncated(InverseGamma(0.1, 2.0, μσ = true),0.01,3), z_ea) - log_lik -= logpdf(Truncated(InverseGamma(0.1, 2.0, μσ = true),0.025,5), z_eb) - log_lik -= logpdf(Truncated(InverseGamma(0.1, 2.0, μσ = true),0.01,3), z_eg) - log_lik -= logpdf(Truncated(InverseGamma(0.1, 2.0, μσ = true),0.01,3), z_eqs) - log_lik -= logpdf(Truncated(InverseGamma(0.1, 2.0, μσ = true),0.01,3), z_em) - log_lik -= logpdf(Truncated(InverseGamma(0.1, 2.0, μσ = true),0.01,3), z_epinf) - log_lik -= logpdf(Truncated(InverseGamma(0.1, 2.0, μσ = true),0.01,3), z_ew) - log_lik -= logpdf(Truncated(Beta(0.5, 0.20, μσ = true),.01,.9999), crhoa) - log_lik -= logpdf(Truncated(Beta(0.5, 0.20, μσ = true),.01,.9999), crhob) - log_lik -= logpdf(Truncated(Beta(0.5, 0.20, μσ = true),.01,.9999), crhog) - log_lik -= logpdf(Truncated(Beta(0.5, 0.20, μσ = true),.01,.9999), crhoqs) - log_lik -= logpdf(Truncated(Beta(0.5, 0.20, μσ = true),.01,.9999), crhoms) - log_lik -= logpdf(Truncated(Beta(0.5, 0.20, μσ = true),.01,.9999), crhopinf) - log_lik -= logpdf(Truncated(Beta(0.5, 0.20, μσ = true),.001,.9999), crhow) - log_lik -= logpdf(Truncated(Beta(0.5, 0.2, μσ = true),0.01,.9999), cmap) - log_lik -= logpdf(Truncated(Beta(0.5, 0.2, μσ = true),0.01,.9999), cmaw) - log_lik -= logpdf(Truncated(Normal(4,1.5),2,15), csadjcost) - log_lik -= logpdf(Truncated(Normal(1.50,0.375),0.25,3), csigma) - log_lik -= logpdf(Truncated(Beta(0.7, 0.1, μσ = true),0.001,0.99), chabb) - log_lik -= logpdf(Beta(0.5, 0.1, μσ = true), cprobw) - # log_lik -= logpdf(Truncated(Beta(0.5, 0.1, μσ = true),0.3,0.95), cprobw) - log_lik -= logpdf(Truncated(Normal(2,0.75),0.25,10), csigl) - log_lik -= logpdf(Beta(0.5, 0.10, μσ = true), cprobp) - # log_lik -= logpdf(Truncated(Beta(0.5, 0.10, μσ = true),0.5,0.95), cprobp) - log_lik -= logpdf(Truncated(Beta(0.5, 0.15, μσ = true),0.01,0.99), cindw) - log_lik -= logpdf(Truncated(Beta(0.5, 0.15, μσ = true),0.01,0.99), cindp) - log_lik -= logpdf(Truncated(Beta(0.5, 0.15, μσ = true),0.01,1), czcap) - log_lik -= logpdf(Truncated(Normal(1.25,0.125),1.0,3), cfc) - log_lik -= logpdf(Truncated(Normal(1.5,0.25),1.0,3), crpi) - # log_lik -= logpdf(Truncated(Beta(0.75, 0.10, μσ = true),0.5,0.975), crr) - log_lik -= logpdf(Beta(0.75, 0.10, μσ = true), crr) - log_lik -= logpdf(Truncated(Normal(0.125,0.05),0.001,0.5), cry) - log_lik -= logpdf(Truncated(Normal(0.125,0.05),0.001,0.5), crdy) - log_lik -= logpdf(Truncated(Gamma(0.625,0.1, μσ = true),0.1,2.0), constepinf) - log_lik -= logpdf(Truncated(Gamma(0.25,0.1, μσ = true),0.01,2.0), constebeta) - log_lik -= logpdf(Truncated(Normal(0.0,2.0),-10.0,10.0), constelab) - log_lik -= logpdf(Truncated(Normal(0.4,0.10),0.1,0.8), ctrend) - log_lik -= logpdf(Truncated(Normal(0.5,0.25),0.01,2.0), cgy) - log_lik -= logpdf(Truncated(Normal(0.3,0.05),0.01,1.0), calfa) - - return log_lik -end - - -SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))] - -SW07.parameter_values[indexin([:cprobw,:cprobp,:crr],SW07.parameters)] - -SW07.parameter_values[indexin([:crhoms, :crhopinf, :crhow, :cmap, :cmaw],SW07.parameters)] .= 0.02 - -calculate_posterior_loglikelihoods(SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))],[]) - - -using ForwardDiff, BenchmarkTools, FiniteDifferences - - - -@benchmark calculate_posterior_loglikelihoods(SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))],[]) - -@profview for i in 1:100 calculate_posterior_loglikelihoods(SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))],[]) end - - -forw_grad = ForwardDiff.gradient(x -> calculate_posterior_loglikelihoods(x,[]), SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))]) - -reverse_grad = Zygote.gradient(x -> calculate_posterior_loglikelihoods(x,[]), SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))])[1] - -fin_grad = FiniteDifferences.grad(central_fdm(4,1),x -> calculate_posterior_loglikelihoods(x,[]), SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))])[1] - - - - -@benchmark ForwardDiff.gradient(x -> calculate_posterior_loglikelihoods(x,[]), SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))]) - -@benchmark Zygote.gradient(x -> calculate_posterior_loglikelihoods(x,[]), SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))])[1] - -@benchmark FiniteDifferences.grad(central_fdm(4,1),x -> calculate_posterior_loglikelihoods(x,[]), SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))])[1] - - - -@profview ForwardDiff.gradient(x -> calculate_posterior_loglikelihoods(x,[]), SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))]) - -@profview for i in 1:30 Zygote.gradient(x -> calculate_posterior_loglikelihoods(x,[]), SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))])[1] end - -@profview for i in 1:10 FiniteDifferences.grad(central_fdm(4,1),x -> calculate_posterior_loglikelihoods(x,[]), SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))])[1] end - - -𝓂 = SW07 -verbose = true -parameters = nothing -tol = eps() -import LinearAlgebra as ℒ -using ImplicitDifferentiation -import MacroModelling: ℳ - -calculate_covariance_AD(sol; T, subset_indices) = ImplicitFunction(sol->calculate_covariance_forward(sol, T=T, subset_indices = subset_indices), (x,y)->calculate_covariance_conditions(x,y,T=T, subset_indices = subset_indices)) -# calculate_covariance_AD(sol, T = 𝓂.timings, subset_indices = Int64[observables_and_states...]) - - - -function calculate_kalman_filter_loglikelihoods(𝓂::ℳ, data::AbstractArray{Float64}, observables::Vector{Symbol}; parameters = nothing, verbose::Bool = false, tol::Float64 = eps()) - @assert length(observables) == size(data)[1] "Data columns and number of observables are not identical. Make sure the data contains only the selected observables." - @assert length(observables) <= 𝓂.timings.nExo "Cannot estimate model with more observables than exogenous shocks. Have at least as many shocks as observable variables." - - @ignore_derivatives sort!(observables) - - # @ignore_derivatives solve!(𝓂, verbose = verbose) - - if isnothing(parameters) - parameters = 𝓂.parameter_values - else - ub = @ignore_derivatives fill(1e12+rand(),length(𝓂.parameters)) - lb = @ignore_derivatives -ub - - for (i,v) in enumerate(𝓂.bounded_vars) - if v ∈ 𝓂.parameters - @ignore_derivatives lb[i] = 𝓂.lower_bounds[i] - @ignore_derivatives ub[i] = 𝓂.upper_bounds[i] - end - end - - if min(max(parameters,lb),ub) != parameters - return -Inf - end - end - - SS_and_pars, (solution_error, iters) = 𝓂.SS_solve_func(parameters, 𝓂, verbose, false, 𝓂.solver_parameters) - - if solution_error > tol || isnan(solution_error) - return -Inf - end - - NSSS_labels = @ignore_derivatives [sort(union(𝓂.exo_present,𝓂.var))...,𝓂.calibration_equations_parameters...] - - obs_indices = @ignore_derivatives indexin(observables,NSSS_labels) - - data_in_deviations = collect(data(observables)) .- SS_and_pars[obs_indices] - - ∇₁ = calculate_jacobian(parameters, SS_and_pars, 𝓂) |> Matrix - - sol = calculate_first_order_solution(∇₁; T = 𝓂.timings) - - observables_and_states = @ignore_derivatives sort(union(𝓂.timings.past_not_future_and_mixed_idx,indexin(observables,sort(union(𝓂.aux,𝓂.var,𝓂.exo_present))))) - - A = @views sol[observables_and_states,1:𝓂.timings.nPast_not_future_and_mixed] * ℒ.diagm(ones(length(observables_and_states)))[@ignore_derivatives(indexin(𝓂.timings.past_not_future_and_mixed_idx,observables_and_states)),:] - B = @views sol[observables_and_states,𝓂.timings.nPast_not_future_and_mixed+1:end] - - C = @views ℒ.diagm(ones(length(observables_and_states)))[@ignore_derivatives(indexin(sort(indexin(observables,sort(union(𝓂.aux,𝓂.var,𝓂.exo_present)))),observables_and_states)),:] - - 𝐁 = B * B' - - # Gaussian Prior - - calculate_covariance_ = calculate_covariance_AD(sol, T = 𝓂.timings, subset_indices = Int64[observables_and_states...]) - - P = calculate_covariance_(sol) - # P = reshape((ℒ.I - ℒ.kron(A, A)) \ reshape(𝐁, prod(size(A)), 1), size(A)) - u = zeros(length(observables_and_states)) - # u = SS_and_pars[sort(union(𝓂.timings.past_not_future_and_mixed,observables))] |> collect - z = C * u - - loglik = 0.0 - - v = similar(z) - F = C * C' - K = similar(C') - - for t in 1:size(data)[2] - v .= data_in_deviations[:,t] - z - - F .= C * P * C' - - # F = (F + F') / 2 - - # loglik += log(max(eps(),ℒ.det(F))) + v' * ℒ.pinv(F) * v - # K = P * C' * ℒ.pinv(F) - - # loglik += log(max(eps(),ℒ.det(F))) + v' / F * v - Fdet = ℒ.det(F) - - if Fdet < eps() return -Inf end - - loglik += log(Fdet) + v' / F * v - - K .= P * C' / F - - P .= A * (P - K * C * P) * A' + 𝐁 - - u .= A * (u + K * v) - - z .= C * u - end - - return -(loglik + length(data) * log(2 * 3.141592653589793)) / 2 # otherwise conflicts with model parameters assignment -end - - - - -function calculate_kalman_filter_loglikelihoods(𝓂::ℳ, data::AbstractArray{Float64}, observables::Vector{Symbol}; parameters = nothing, verbose::Bool = false, tol::Float64 = eps()) - @assert length(observables) == size(data)[1] "Data columns and number of observables are not identical. Make sure the data contains only the selected observables." - @assert length(observables) <= 𝓂.timings.nExo "Cannot estimate model with more observables than exogenous shocks. Have at least as many shocks as observable variables." - - @ignore_derivatives sort!(observables) - - # @ignore_derivatives solve!(𝓂, verbose = verbose) - - if isnothing(parameters) - parameters = 𝓂.parameter_values - else - ub = @ignore_derivatives fill(1e12+rand(),length(𝓂.parameters)) - lb = @ignore_derivatives -ub - - for (i,v) in enumerate(𝓂.bounded_vars) - if v ∈ 𝓂.parameters - @ignore_derivatives lb[i] = 𝓂.lower_bounds[i] - @ignore_derivatives ub[i] = 𝓂.upper_bounds[i] - end - end - - if min(max(parameters,lb),ub) != parameters - return -Inf - end - end - - SS_and_pars, (solution_error, iters) = 𝓂.SS_solve_func(parameters, 𝓂, verbose, false, 𝓂.solver_parameters) - - if solution_error > tol || isnan(solution_error) - return -Inf - end - - NSSS_labels = @ignore_derivatives [sort(union(𝓂.exo_present,𝓂.var))...,𝓂.calibration_equations_parameters...] - - obs_indices = @ignore_derivatives indexin(observables,NSSS_labels) - - data_in_deviations = collect(data(observables)) .- SS_and_pars[obs_indices] - - ∇₁ = calculate_jacobian(parameters, SS_and_pars, 𝓂) |> Matrix - - sol = calculate_first_order_solution(∇₁; T = 𝓂.timings) - - observables_and_states = @ignore_derivatives sort(union(𝓂.timings.past_not_future_and_mixed_idx,indexin(observables,sort(union(𝓂.aux,𝓂.var,𝓂.exo_present))))) - - A = @views sol[observables_and_states,1:𝓂.timings.nPast_not_future_and_mixed] * ℒ.diagm(ones(length(observables_and_states)))[@ignore_derivatives(indexin(𝓂.timings.past_not_future_and_mixed_idx,observables_and_states)),:] - B = @views sol[observables_and_states,𝓂.timings.nPast_not_future_and_mixed+1:end] - - C = @views ℒ.diagm(ones(length(observables_and_states)))[@ignore_derivatives(indexin(sort(indexin(observables,sort(union(𝓂.aux,𝓂.var,𝓂.exo_present)))),observables_and_states)),:] - - 𝐁 = B * B' - - # Gaussian Prior - - calculate_covariance_ = calculate_covariance_AD(sol, T = 𝓂.timings, subset_indices = Int64[observables_and_states...]) - - P = calculate_covariance_(sol) - # P = reshape((ℒ.I - ℒ.kron(A, A)) \ reshape(𝐁, prod(size(A)), 1), size(A)) - u = zeros(length(observables_and_states)) - # u = SS_and_pars[sort(union(𝓂.timings.past_not_future_and_mixed,observables))] |> collect - z = C * u - - loglik = 0.0 - - for t in 1:size(data)[2] - v = data_in_deviations[:,t] - z - - F = P * C * C' - - # F = (F + F') / 2 - - # loglik += log(max(eps(),ℒ.det(F))) + v' * ℒ.pinv(F) * v - # K = P * C' * ℒ.pinv(F) - - # loglik += log(max(eps(),ℒ.det(F))) + v' / F * v - Fdet = ℒ.det(F) - - if Fdet < eps() return -Inf end - - loglik += log(Fdet) + v' / F * v - - F = RecursiveFactorization.lu!(F) - - K = P * C' / F - - P = A * (P - K * C * P) * A' + 𝐁 - - u = A * (u + K * v) - - z = C * u - end - - return -(loglik + length(data) * log(2 * 3.141592653589793)) / 2 # otherwise conflicts with model parameters assignment -end - - -using BenchmarkTools, Zygote, ForwardDiff -using TriangularSolve, RecursiveFactorization, Octavian - -F = C * P * C' -F = RecursiveFactorization.lu!(F) -C' / F -TriangularSolve.rdiv!(AA, collect(C'), UpperTriangular(F.U)) -BB = similar(AA) -TriangularSolve.ldiv!(AA, LowerTriangular(F.L), AA) -TriangularSolve.rdiv!(BB, AA, (F.L)) -C' / F.U / F.L -F.U / C' * F.L - -F.L \ C' / F.U -ForwardDiff.jacobian(P-> begin F = C * P * C' -F = RecursiveFactorization.lu!(F) -C' / F -end, P) - -@benchmark begin F = C * P * C' - # F = RecursiveFactorization.lu!(F) - C' / F - end - - -N = 100 -A = rand(N,N); B = rand(N,N); C = similar(A); -TriangularSolve.rdiv!(C, A, UpperTriangular(B))* UpperTriangular(B) -A - -A / UpperTriangular(B) - -C - -F -det -using LinearAlgebra, Octavian -@benchmark F .= RecursiveFactorization.lu!(F) -@benchmark FS = lu!(F) -TriangularSolve.rdiv!(AA,C',F) -AA = similar(C') - - -Fdet = ℒ.det(F) - -if Fdet < eps() return -Inf end - -loglik += log(Fdet) + v' / F * v - -K = P * C' / F - -P = A * (P - K * C * P) * A' + 𝐁 - -u = A * (u + K * v) - -z = C * u - - -@benchmark calculate_posterior_loglikelihoods(SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))],[]) - -@benchmark calculate_posterior_loglikelihood(SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))],[]) - -ForwardDiff.gradient(x->calculate_posterior_loglikelihood(x,[]),Float64[SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))]...]) - -@benchmark ForwardDiff.gradient(x->calculate_posterior_loglikelihood(x,[]),Float64[SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))]...]) - -using Profile -@profile for i in 1:3 ForwardDiff.gradient(x->calculate_posterior_loglikelihood(x,[]),Float64[SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))]...]) end - - -import ForwardDiff -@profview ForwardDiff.gradient(x->calculate_posterior_loglikelihood(x,[]),Float64[SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))]...]) - - -import ProfileView, ForwardDiff -ProfileView.@profview ForwardDiff.gradient(x->calculate_posterior_loglikelihood(x,[]),Float64[SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))]...]) - - -Zygote.gradient(x->calculate_posterior_loglikelihood(x,[]),Float64[SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))]...])[1] - -# logpdf(Truncated(Beta(beta_map(0.75,0.10)...),0.5,0.975),.51) -# Zygote.gradient(x->logpdf(Truncated(Beta(beta_map(0.75,0.10)...),0.5,0.975),x),.51) - -# Zygote.gradient(x->logpdf(Truncated(Beta(beta_map(0.5,0.1)...),0.01,0.95),x),.51) - - -@benchmark Zygote.gradient(x->calculate_posterior_loglikelihood(x,[]),Float64[SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))]...])[1] - - -f = OptimizationFunction(calculate_posterior_loglikelihood, Optimization.AutoZygote()) - -prob = OptimizationProblem(f, Float64[SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))]...], []); -sol = solve(prob, Optimisers.Adam(), maxiters = 1000) -sol.minimum - -lbs = [0.01 ,0.025 ,0.01 ,0.01 ,0.01 ,0.01 ,0.01 ,0.01 ,0.01 ,0.01 ,0.01 ,0.01 ,0.01 ,0.001 ,0.01 ,0.01 ,2.0 ,0.25 ,0.001 ,0.05 ,0.25 ,0.05 ,0.01 ,0.01 ,0.01 ,1.0 ,1.0 ,0.05 ,0.001 ,0.001 ,0.1 ,0.01 ,0.0 ,0.1 ,0.01 ,0.01] - -ubs = [3.0, 5.0, 3.0, 3.0, 3.0, 3.0, 3.0, 0.9999, 0.9999, 0.9999, 0.9999, 0.9999, 0.9999, 0.9999, 0.9999, 0.9999, 15.0, 3.0, 0.99, 0.95, 10.0, 0.95, 0.99, 0.99, 1.0, 3.0, 3.0, 0.975, 0.5, 0.5, 2.0, 2.0, 10.0, 0.8, 2.0, 1.0] - -sort_idx = sortperm(indexin([:z_ea,:z_eb,:z_eg,:z_eqs,:z_em,:z_epinf,:z_ew,:crhoa,:crhob,:crhog,:crhoqs,:crhoms,:crhopinf,:crhow,:cmap,:cmaw,:csadjcost,:csigma,:chabb,:cprobw,:csigl,:cprobp,:cindw,:cindp,:czcap,:cfc,:crpi,:crr,:cry,:crdy,:constepinf,:constebeta,:constelab,:ctrend,:cgy,:calfa],SW07.parameters)) - -prob = OptimizationProblem(f, Float64[SW07.parameter_values[setdiff(1:length(SW07.parameters),indexin([:ctou,:clandaw,:cg,:curvp,:curvw,:crhols,:crhoas],SW07.parameters))]...], [], lb = lbs[sort_idx], ub = ubs[sort_idx]); -sol = solve(prob, NLopt.LD_LBFGS(), maxtime = 100) -sol.minimum - -sol = solve(prob, NLopt.LN_SBPLX(), maxtime = 10) -sol.minimum - -# using MAT - -# vars = matread("/Users/thorekockerols/Downloads/sw07/usmodel_mode.mat") - - -# calculate_posterior_loglikelihood(vec(vars["xparam1"]),[]) -# ([a-z_]+),([\d\.\s-]+),([\d\.\s-]+),([\d\.\s-]+),([a-z_]+),([\d\.\s-]+),([\d\.\s-]+); -# logpdf(Truncated($5($5_map($6,$7)...),$3,$4),$1) - diff --git a/benchmark/optim_solver_params.jl b/benchmark/optim_solver_params.jl new file mode 100644 index 00000000..620cb001 --- /dev/null +++ b/benchmark/optim_solver_params.jl @@ -0,0 +1,1209 @@ +import Pkg +# Pkg.activate("/home/cdsw/MacroModelling.jl-ss_solver2/MacroModelling.jl-ss_solver/") +Pkg.add(["Optimization", "OptimizationNLopt", "BlackBoxOptim"])#, "OptimizationMultistartOptimization", "OptimizationMetaheuristics"]) + +using MacroModelling, Optimization, OptimizationNLopt, Optim # , OptimizationMultistartOptimization, OptimizationMetaheuristics +import BlackBoxOptim#, OptimizationEvolutionary + +max_time = 3 * 60^2 +transformation = 1 +algo = "BBO_DE" + +# max_time = Meta.parse(ENV["maxtime"]) # "4" # +# transformation = Meta.parse(ENV["transformation"]) # "4" # +# algo = ENV["algorithm"] # "ESCH" # +# max_time = Meta.parse(ENV["maxtime"]) # "4" # +# transformation = Meta.parse(ENV["transformation"]) # "4" # +# algo = ENV["algorithm"] # "ESCH" # + + +# logic to implement + +# when finding the NSSS the first time: use the system with aux variables as unknowns, parameters and solved vars as unknowns, separate the system into smaller blocks if possible +# do redundant var reduction only if the vars to reduce are not part of nonlinear expressions +# search for optim parameters that solve any of the models with a side condition of having the least necessary iterations +# for estimation use the small system (no aux, pars and solved vars) and again look for optim parameters that solve the system with the least necessary iterations during estimation + + +include("../test/models/RBC_CME_calibration_equations_and_parameter_definitions_lead_lags_numsolve.jl") +# include("../test/models/RBC_CME_calibration_equations_and_parameter_definitions.jl") +include("../models/Backus_Kehoe_Kydland_1992.jl") +include("../models/Baxter_King_1993.jl") +include("../models/Smets_Wouters_2003.jl") +include("../models/GNSS_2010.jl") +include("../models/Ghironi_Melitz_2005.jl") +include("../models/SGU_2003_debt_premium.jl") +# include("../models/NAWM_EAUS_2008.jl") # stands out +include("../models/JQ_2012_RBC.jl") +include("../models/Ireland_2004.jl") +include("../models/Caldara_et_al_2012.jl") +include("../models/Gali_Monacelli_2005_CITR.jl") +include("../models/Gali_2015_chapter_3_nonlinear.jl") +include("../models/Aguiar_Gopinath_2007.jl") +include("../models/Ascari_Sbordone_2014.jl") # stands out +include("../models/FS2000.jl") +include("../models/Smets_Wouters_2007.jl") +include("../models/Smets_Wouters_2007_linear.jl") +# include("../models/RBC_baseline.jl") # no solver block / everything analytical +include("../models/Guerrieri_Iacoviello_2017.jl") # stands out + + + + +function optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time; max_evals = 300000) + prob = OptimizationProblem(evaluate_pars_loglikelihood, parameters, all_models, lb = lbs, ub = ubs) + + opt = Options(verbose = true, parallel_evaluation = false) + + if algo == "ESCH" + sol = solve(prob, NLopt.GN_ESCH(), maxtime = max_time); sol.minimum + pars = deepcopy(sol.u) + elseif algo == "SAMIN" + sol = Optim.optimize(x -> evaluate_pars_loglikelihood(x, all_models), lbs, ubs, parameters, + SAMIN(nt = 10, + ns = 10, + rt = 0.95, + verbosity = 2), + Optim.Options(time_limit = max_time, + # show_trace = true, + iterations = 10000000, + # extended_trace = true, + # show_every = 10000 + )) + pars = Optim.minimizer(sol) + elseif algo == "PS" + sol = Optim.optimize(x -> evaluate_pars_loglikelihood(x, all_models), lbs, ubs, parameters, + ParticleSwarm(lower = lbs, + upper = ubs, + n_particles = 500), + Optim.Options(time_limit = max_time, + show_trace = true, + iterations = 1000000, + extended_trace = true, + show_every = 100 + )) + pars = Optim.minimizer(sol) + elseif algo == "MLSL" + sol = solve(prob, NLopt.G_MLSL_LDS(), local_method = NLopt.LN_BOBYQA(), maxtime = max_time); sol.minimum + pars = deepcopy(sol.u) + # elseif algo == "TikTak" + # sol = solve(prob, MultistartOptimization.TikTak(5000), NLopt.LN_NELDERMEAD(), maxtime = max_time); sol.minimum + # pars = deepcopy(sol.u) + elseif algo == "BBO_SS" + sol = BlackBoxOptim.bboptimize(x -> evaluate_pars_loglikelihood(x, all_models), parameters, + SearchRange = [(lb, ub) for (ub, lb) in zip(ubs, lbs)], + NumDimensions = length(parameters), + MaxTime = max_time, + # PopulationSize = 500, + TraceMode = :verbose, + TraceInterval = 60, + Method = :generating_set_search)# + # Method = :adaptive_de_rand_1_bin_radiuslimited) + + pars = BlackBoxOptim.best_candidate(sol) + elseif algo == "BBO_DXNES" + sol = BlackBoxOptim.bboptimize(x -> evaluate_pars_loglikelihood(x, all_models), parameters, + SearchRange = [(lb, ub) for (ub, lb) in zip(ubs, lbs)], + NumDimensions = length(parameters), + MaxTime = max_time, + # PopulationSize = 500, + TraceMode = :verbose, + TraceInterval = 60, + Method = :dxnes)# + # Method = :adaptive_de_rand_1_bin_radiuslimited) + + pars = BlackBoxOptim.best_candidate(sol) + elseif algo == "BBO_DE" + sol = BlackBoxOptim.bboptimize(x -> evaluate_pars_loglikelihood(x, all_models), parameters, + SearchRange = [(lb, ub) for (ub, lb) in zip(ubs, lbs)], + NumDimensions = length(parameters), + # MaxTime = max_time, # has precedence over max_evals + MaxFuncEvals = max_evals, + PopulationSize = 500, + TraceMode = :verbose, + TraceInterval = 60, + # Method = :generating_set_search)# + Method = :adaptive_de_rand_1_bin_radiuslimited) + + pars = BlackBoxOptim.best_candidate(sol) + elseif algo == "DE" + sol = solve(prob, DE(options = opt), maxtime = max_time); sol.minimum + pars = deepcopy(sol.u) + elseif algo == "SA" # terminates early with not great results + sol = solve(prob, SA(options = opt), maxtime = max_time); sol.minimum + pars = deepcopy(sol.u) + elseif algo == "ECA" + sol = solve(prob, ECA(options = opt), maxtime = max_time); sol.minimum + pars = deepcopy(sol.u) + elseif algo == "MCCGA" # terminates early with not great results + sol = solve(prob, MCCGA(options = opt), maxtime = max_time); sol.minimum + pars = deepcopy(sol.u) + elseif algo == "BRKGA" # terminates early with not great results + sol = solve(prob, BRKGA(options = opt), maxtime = max_time); sol.minimum + pars = deepcopy(sol.u) + elseif algo == "PSO" + sol = solve(prob, PSO(options = opt), maxtime = max_time); sol.minimum + pars = deepcopy(sol.u) + elseif algo == "WOA" + sol = solve(prob, WOA(N = 500, options = opt), maxtime = max_time); sol.minimum + pars = deepcopy(sol.u) + elseif algo == "ABC" + sol = solve(prob, ABC(N = 500, options = opt), maxtime = max_time); sol.minimum + pars = deepcopy(sol.u) + elseif algo == "NOMAD" # terminates early with not great results + sol = solve(prob, NOMADOpt(), maxtime = max_time); sol.minimum + pars = deepcopy(sol.u) + elseif algo == "GA" + sol = solve(prob, Evolutionary.GA(), maxtime = max_time); sol.minimum + pars = deepcopy(sol.u) + end + + println("Parameters: $pars") + + prob = OptimizationProblem(evaluate_pars_loglikelihood, pars, all_models, lb = lbs, ub = ubs) + sol = solve(prob, NLopt.LN_BOBYQA()); sol.minimum + + prob = OptimizationProblem(evaluate_pars_loglikelihood, sol.u, all_models, lb = lbs, ub = ubs) + sol = solve(prob, NLopt.LN_NELDERMEAD()); sol.minimum + + prob = OptimizationProblem(evaluate_pars_loglikelihood, sol.u, all_models, lb = lbs, ub = ubs) + sol = solve(prob, NLopt.LN_SBPLX()); sol.minimum + + prob = OptimizationProblem(evaluate_pars_loglikelihood, sol.u, all_models, lb = lbs, ub = ubs) + sol = solve(prob, NLopt.LN_PRAXIS()); sol.minimum + + println("Parameters after refinement: $(sol.u)") + return sol.u +end + + +function calc_total_runtime(model, par_inputs) + runtime = @elapsed outmodel = try model.SS_solve_func(model.parameter_values, model, false, true, [par_inputs]) catch end + # outmodel = try model.SS_solve_func(model.parameter_values, model, false, true, [par_inputs]) catch end + runtime = outmodel isa Tuple{Vector{Float64}, Tuple{Float64, Int64}} ? + (outmodel[2][1] > 1e-12) || !isfinite(outmodel[2][1]) ? + 10 : + runtime : + 10 + + # if model.model_name == "Smets_Wouters_2007" + # if (abs(outmodel[1][indexin([:ygap], model.var)][1]) > .01) || (outmodel[1][indexin([:y], model.var)][1] < .01) + # runtime = 10 + # end + # end + + return runtime * 1e3 +end + + +maxiters = 250 + +# Function to calculate the posterior log likelihood +function evaluate_pars_loglikelihood(pars, models) + log_lik = 0.0 + + model_runtimes = zeros(length(models)) + + pars[1:2] = sort(pars[1:2], rev = true) + + # Apply prior distributions + # log_lik -= sum(x -> log(x) - x, pars[1:19]) # logpdf of a gamma dist with mean and variance 1 + log_lik -= -sum(pars[1:19]) # logpdf of a gamma dist with mean and variance 1 + log_lik -= -log(5 * sqrt(2 * π)) - (pars[20]^2 / (2 * 5^2)) # logpdf of a normal dist with mean = 0 and + + + # Example solver parameters - this needs to be replaced with actual logic + par_inputs = MacroModelling.solver_parameters(eps(), eps(), maxiters, pars..., transformation, 0.0, 2) + + # Iterate over all models and calculate the total iterations + for (i,model) in enumerate(models) + total_runtimes = calc_total_runtime(model, par_inputs) +# model_runtimes[i] = 1e1 * total_runtimes + model_runtimes[i] = total_runtimes + end + + return Float64(log_lik / 1e3 + sum(model_runtimes)) +end + + + +# optim across multiple models and parameters sets + +function evaluate_multi_pars_loglikelihood(pars, models) + num_starting_points = length(pars) - 19 + + model_runtimes = zeros(length(models), num_starting_points) .+ 1e4 + + pars_mat = zeros(20, num_starting_points) + + pars_mat[1:19,:] .= pars[1:19] + pars_mat[20,:] .= pars[20:end] + + log_lik = 0.0 + + log_lik -= -sum(pars[1:19]) # logpdf of a gamma dist with mean and variance 1 + + for k in 1:num_starting_points + pars_mat[1:2, k] = sort(pars_mat[1:2, k], rev = true) + + # Apply prior distributions + log_lik -= -log(5 * sqrt(2 * π)) - (pars_mat[20, k]^2 / (2 * 5^2)) # logpdf of a normal dist with mean = 0 and + end + + [if length(model.NSSS_solver_cache) > 1 pop!(model.NSSS_solver_cache) end for model in models] + + total_runtime = @elapsed for (i,model) in enumerate(models) + for k in 1:num_starting_points + # Example solver parameters - this needs to be replaced with actual logic + par_inputs = MacroModelling.solver_parameters(eps(), eps(), eps(), maxiters, pars_mat[:, k]..., transformation, 0.0, 2) + + # Iterate over all models and calculate the total iterations + total_runtimes = calc_total_runtime(model, par_inputs) + # model_runtimes[i] = 1e1 * total_runtimes + model_runtimes[i, k] = total_runtimes + + if total_runtimes < 1e4 + break + end + end + end + + [if length(model.NSSS_solver_cache) > 1 pop!(model.NSSS_solver_cache) end for model in models] + + return Float64(log_lik / 1e2 + 1e3 * total_runtime + sum(minimum(model_runtimes, dims = 2))) +end + +n_starting_points = 5 + +parameters = rand(19 + n_starting_points) +parameters[20:end] .-= 1 + +lbs = fill(eps(), length(parameters)) +lbs[20:end] .= -20 + +ubs = fill(100.0,length(parameters)) + + + +all_models = [ + Smets_Wouters_2003, + Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + GNSS_2010, + Ascari_Sbordone_2014, + Smets_Wouters_2003, + Backus_Kehoe_Kydland_1992, + m, + Baxter_King_1993, + Ghironi_Melitz_2005, + SGU_2003_debt_premium, + JQ_2012_RBC, + Ireland_2004, + Caldara_et_al_2012, + Gali_Monacelli_2005_CITR, + Gali_2015_chapter_3_nonlinear, + Aguiar_Gopinath_2007, + FS2000, + Smets_Wouters_2007_linear +]; + +# [if length(model.NSSS_solver_cache) > 1 pop!(model.NSSS_solver_cache) end for model in all_models] + +# all_models[1].NSSS_solver_cache +# pars = [2.9912988764832833, 0.8725, 0.0027, 0.028948770826150612, 8.04, 4.076413176215408, 0.06375413238034794, 0.24284340766769424, 0.5634017580097571, 0.009549630552246828, 0.6342888355132347, 0.5275522227754195, 1.0, 0.06178989216048817, 0.5234277812131813, 0.422, 0.011209254402846185, 0.5047, 0.6020757011698457, 0.7688] + +# evaluate_multi_pars_loglikelihood(pars, all_models) + + + +# models = all_models +# num_starting_points = length(pars) - 19 + +# model_runtimes = zeros(length(models), num_starting_points) .+ 1e4 + +# pars_mat = zeros(20, num_starting_points) + +# pars_mat[1:19,:] .= pars[1:19] +# pars_mat[20,:] .= pars[20:end] + +# log_lik = 0.0 + +# log_lik -= -sum(pars[1:19]) # logpdf of a gamma dist with mean and variance 1 + +# for k in 1:num_starting_points +# pars_mat[1:2, k] = sort(pars_mat[1:2, k], rev = true) + +# # Apply prior distributions +# log_lik -= -log(5 * sqrt(2 * π)) - (pars_mat[20, k]^2 / (2 * 5^2)) # logpdf of a normal dist with mean = 0 and +# end + +# total_runtime = @elapsed for (i,model) in enumerate(models) +# for k in 1:num_starting_points +# # Example solver parameters - this needs to be replaced with actual logic +# par_inputs = MacroModelling.solver_parameters(eps(), eps(), eps(), maxiters, pars_mat[:, k]..., transformation, 0.0, 2) + +# # Iterate over all models and calculate the total iterations +# total_runtimes = calc_total_runtime(model, par_inputs) +# # model_runtimes[i] = 1e1 * total_runtimes +# model_runtimes[i, k] = total_runtimes + +# if total_runtimes < 1e4 +# break +# end +# end +# end + +# model_runtimes + +# using BenchmarkTools + +# @benchmark evaluate_multi_pars_loglikelihood(parameters, all_models) + + +sol = BlackBoxOptim.bboptimize(x -> evaluate_multi_pars_loglikelihood(x, all_models), parameters, + SearchRange = [(lb, ub) for (ub, lb) in zip(ubs, lbs)], + NumDimensions = length(parameters), + MaxFuncEvals = 150000, + PopulationSize = 500, + TraceMode = :verbose, + TraceInterval = 60, + Method = :adaptive_de_rand_1_bin_radiuslimited) + +pars = BlackBoxOptim.best_candidate(sol) + + +println("Parameters: $pars") + +prob = OptimizationProblem(evaluate_multi_pars_loglikelihood, pars, all_models, lb = lbs, ub = ubs) +sol = solve(prob, NLopt.LN_BOBYQA()); sol.minimum + +prob = OptimizationProblem(evaluate_multi_pars_loglikelihood, sol.u, all_models, lb = lbs, ub = ubs) +sol = solve(prob, NLopt.LN_NELDERMEAD()); sol.minimum + +prob = OptimizationProblem(evaluate_multi_pars_loglikelihood, sol.u, all_models, lb = lbs, ub = ubs) +sol = solve(prob, NLopt.LN_SBPLX()); sol.minimum + +prob = OptimizationProblem(evaluate_multi_pars_loglikelihood, sol.u, all_models, lb = lbs, ub = ubs) +sol = solve(prob, NLopt.LN_PRAXIS()); sol.minimum + +println("Parameters after refinement: $(sol.u)") + + +# best if you have fixed parameters but can vary the starting points +parameters = [89.26544495540728, 0.300470076841684, 32.608492240550035, 61.628310990014114, 0.22610409380854896, 3.919570107373496, 35.50795473779334, 37.03271739937227, 62.749088965512996, 70.21693929731778, 74.40398893915436, 3.675790863305796, 89.82730346299283, 80.8421422677031, 85.98114225234478, 26.64171352273762, 18.55068585609554, 90.36787165320399, 2.932047332701063, 26.0419358675045, 69.93130357191069, 10.854564115179858, -12.964333286598562, 1.4740906290561546] + + +sol = Optim.optimize(x -> evaluate_multi_pars_loglikelihood(x, all_models), lbs, ubs, parameters, + SAMIN( + # nt = 10, + # ns = 10, + # rt = 0.95, + verbosity = 2), + Optim.Options(#time_limit = max_time, + # show_trace = true, + iterations = 10000, + # extended_trace = true, + # show_every = 10000 + )) +pars = Optim.minimizer(sol) + +println("Parameters: $pars") + + + +sol2 = Optim.optimize(x -> evaluate_multi_pars_loglikelihood(x, all_models), lbs, ubs, parameters, + SAMIN( + # nt = 10, + # ns = 10, + # rt = 0.95, + verbosity = 2), + Optim.Options(#time_limit = max_time, + # show_trace = true, + iterations = 150000, + # extended_trace = true, + # show_every = 10000 + )) +pars2 = Optim.minimizer(sol2) + +println("Parameters: $pars2") + + +# try WOA +using OptimizationMetaheuristics +prob = OptimizationProblem(evaluate_multi_pars_loglikelihood, parameters, all_models, lb = lbs, ub = ubs) +opt = Options(verbose = true) +sol = solve(prob, WOA(N = 500, options = opt), maxiters = 100000); sol.minimum +pars = deepcopy(sol.u) + + +# check and test +parameters = [ +# 1.3085202378210083, 0.6105549045960956, 0.03852983653587412, 0.08808948562001635, 0.7013754861667181, 0.7197509835511993, 0.0140910151224454, 0.632379435443292, 0.8804360170508678, 8.900794787180901e-5, 0.26078954123808185, 0.012356130300425807, 2.1261322455643277, 0.012242714503695308, 3.847413047615463e-5, 0.03025833174488186, 0.1363582300112309, 1.44308892579897, 0.37248766077122875, 1.108766811279455, + +# 1.3297775271726404, 0.15319852379823493, 0.6699860803856564, 0.6900232265277791, 0.20475425381819404, 2.262685062460725, 2.2699742966136798, 1.2291724039360243, 0.021285654449971443, 1.0340066995030113, 0.8056829713933548, 11.92136102981244, 8.982777633585407, 1.2387705193031366, 2.020240978873358, 0.9772105023172172, 0.8758962165861031, 1.6775999050973718, 0.17285722944375806, 2.3642317805128723, + +# 0.8018861924730344, 0.35239298915976797, 0.2646475929658103, 1.186368814356376, 0.524025988271922, 10.716281966365939, 2.029733636528348, 2.2454645781759983, 0.9512589173571688, 1.2446190885719692, 2.230105642973023, 4.789929974394461, 8.380570181553736, 0.3967470094955483, 4.120697086148709, 0.16607831975540038, 3.1181759287637996, 5.9373761688423015, 0.9912587488183398, 7.914764797861666, + +2.9912988764832833, 0.8725, 0.0027, 0.028948770826150612, 8.04, 4.076413176215408, 0.06375413238034794, 0.24284340766769424, 0.5634017580097571, 0.009549630552246828, 0.6342888355132347, 0.5275522227754195, 1.0, 0.06178989216048817, 0.5234277812131813, 0.422, 0.011209254402846185, 0.5047, 0.6020757011698457, 0.7688, + +# 9.861895121230758, 0.8149503715148578, 0.9678020443929615, 0.18557020181492592, 4.030611919120903, 0.752295946458232, 2.6645217191702217, 0.48862922551351196, 2.691920187300656, 0.1481681514337109, 21.361810615227746, 9.874698215009003, 4.6879339377305325, 1.4175229801847284, 0.9181067256779919, 0.059514897395779566, 1.7242569574632507, 2.5049303237604046, 11.183060736240922, 1.1199048614715326, + +# 15.223285246843304, 0.95517, 38.52678, 43.54497, 0.0008500000000000058, 0.62934, 75.54509549110291, 7.261945059036699, 85.51936289088874, 87.41658873754673, 55.07229950750884, 4.11876, 39.10866, 19.048629999998944, 10.314559999999997, 28.678813991497712, 36.343002891808354, 20.09102186880269, 8.49258045180932, 2.4593900000000004, + +1.9479518608134938, 0.02343520604394183, 5.125002799990568, 0.02387522857907376, 0.2239226474715968, 4.889172213411495, 1.747880258818237, 2.8683242331457, 0.938229356687311, 1.4890887655876235, 1.6261504814901664, 11.26863249187599, 36.05486169712279, 6.091535897587629, 11.73936761697657, 3.189349432626493, 0.21045178305336348, 0.17122196312330415, 13.251662547139363, 5.282429995876679, + +2.3501880185956425, 0.34719465026279933, 0.17940177610230787, 3.3208811288225013e-7, 2.3594279405914094, 0.01744795164958195, 0.3760309936238473, 0.5558583990737875, 0.4552242235443654, 0.00806368022406653, 0.15220396104940526, 0.1989463492329444, 0.2444244510687956, 0.2714545659358831, 0.540719120976854, 0.004678690087611936, 0.7814520924679657, 0.36042250877546034, 0.8677525614007071, 1.000000007280896, + +1.6547113200789028, 0.2888180697750419, 2.6131946125574808, 1.0951585278957863, 0.4032764541534676, 0.22740583391740837, 0.06292806556843489, 0.3063814695233383, 2.18936892936353, 0.08097914377788905, 0.801015608756103, 0.6310333037406995, 2.541128858413585, 1.1584233799831622, 0.19449153292438376, 0.01062818770703848, 0.006105451489346563, 1.7875265604307713, 0.009242344285457445, 1.5580112273980442, + +7.5545497047246535, 0.7240882313900331, 0.026826520249843368, 0.10205911465204487, 0.5956561762004062, 2.1081959797078547, 14.668199530847641, 3.80569870943874, 2.220446049250313e-16, 7.849834643004542, 0.6171679895257539, 17.060417824592612, 28.30288205638385, 2.954162387825047, 18.017706573812315, 1.2105079901981806, 2.3419161784026286, 2.8150807254369727, 3.5005572136867653, 0.7479730479526492, + +42.236595565806624, 12.014745765229392, 0.02203921025452384, 10.201979789860719, 2.1553941367567515, 3.2293988973657584, 18.98556976873586, 1.9765758516959744, 3.023326338882099, 0.8237577165890975, 7.360777287790799, 32.16501424615938, 32.54261688213752, 31.713230025016163, 3.857051987722223, 13.28701330015268, 4.046226705080187, 15.656054606371212, 27.022465242976605, 1.5097432076326989, + +0.018374593136845512, 0.0038499468663194024, 0.018067627240156547, 0.005128997752625631, 1.3857636249255316, 0.4063190895216115, 2.6109739336078506, 9.15361624221388, 4.135315960111046, 8.490912854294038, 2.18937426052877, 9.180611286117626, 51.7961214848368, 0.5448952939846764, 3.1120295202227974, 0.9581635851842967, 0.024597005356203933, 3.5532652135992904, 6.275410304068712, 0.9756811656138908, + +0.4962191951232305, 0.12405479877054953, 0.6695167602982844, 2.1006462351919585e-9, 1.053146766586542, 0.14910773315223777, 0.027116129072231022, 1.256812542554111, 0.1557692851835663, 0.05493586207222183, 0.31919453560163635, 0.07325819085405584, 0.2597000556732767, 0.14821778589797047, 0.012891720477424292, 0.29090329230116474, 0.445491689587889, 0.1685397832608439, 0.02117295897791548, 0.0011754472077501322, + +5.3719596604917825, 1.0629845997885847, 0.15771151885194457, 0.14720197886201114, 0.5935754820726649, 0.6436991724194971, 3.720439601043781, 8.047753721169693, 2.882349026317014, 1.4437880974850783, 2.3067390900986693, 4.620197460427168, 10.511318402228515, 0.06669323243998078, 4.910958483843366, 0.6904243207750654, 0.7943469864736756, 2.4086193062418824, 1.3508461744925238, 1.751335770814352, + +# 1.3398738344541519, 0.35187697402609885, 0.9423918915080955, 0.12873941995734006, 1.2364316363700447, 12.831348413414263, 0.07195388729374519, 0.5336582047882454, 0.7190979615613164, 0.35923760018153417, 0.027519281838197678, 0.23570674787197157, 0.002933984194285578, 0.27195333778365594, 0.11024658432932247, 1.4381762810336909, 0.406128679882458, 0.20626040416709104, 0.10169014504383994, -5.351901133543868e-7, + +4.294035907826813, 2.3347332598422255, 1.4875337056636178, 20.74907132926113, 4.7859315720403615, 6.1297263913535796, 5.872332511263355, 9.459647455599736, 4.569075808027596, 16.76730895449611, 20.259762521296032, 47.59601647655178, 47.985157266888514, 16.01765806147523, 7.751873368928798, 14.845916250683704, 3.559233815238337, 2.747206002686553, 17.76784661990265, 1.881192515028712, + +2.280700601842886, 0.0031625974039871485, 0.9146749481680747, 2.72467107885148, 2.982409316485249, 7.6153887182877895, 32.60301422472388, 5.021154629315351, 2.1078579221645652, 9.191155788503199, 0.4216796538649238, 37.766075894950546, 60.753552950460005, 22.51917943015377, 32.0901748751557, 10.415198072919477, 2.3696254859060844, 4.948347574159594, 2.1030134006293153, 1.44525912242339, + +7.297048793403832, 0.004615358619737044, 0.14800106069823574, 0.42069895836508886, 0.9392423798218741, 0.015544798831901664, 4.497954810530372, 8.358852594112914, 5.3742160977607565, 0.31094581188772913, 0.7858408109182204, 19.225167181040128, 43.78549778722635, 8.577704390472906, 43.77110326774883, 39.790296456122626, 31.5172379725736, 7.008689861906436, 5.643260746602744, 0.8872967209964785, + +8.530598532730615, 2.051681699063373, 6.924289455785735, 0.3544727300751251, 0.0864227300863801, 2.0826443401111407, 15.605609318003374, 2.6784312188740573, 2.694130852304065, 4.499139568059303, 1.6997354284432789, 14.884155927459053, 17.554915222164354, 5.996189373290768, 8.028613935355631, 3.6036903156179316, 0.7865356506932696, 1.581020742008601, 7.323928443120537, 1.2704654330282996, + +41.67156470636132, 4.1615294292873255, 1.7731538958193431, 2.8143797468298404, 5.816672553434534, 13.69961109645873, 9.48462337784073, 5.372800952946997, 2.334576768672413, 4.978435398686042, 1.530970770596612, 40.420562680682984, 45.6996241723041, 18.91855001681407, 9.655624836436182, 4.991722372699691, 16.668868812046295, 6.5821480424719505, 10.052798836648709, 1.0057035856900112, + +1.0242323883590136, 0.5892723157762478, 0.0006988523559835617, 0.009036867721330505, 0.14457591298892497, 1.3282546133453548, 0.7955753778741823, 1.7661485851863441e-6, 2.6206711939142943e-7, 7.052160321659248e-12, 1.06497513443326e-6, 5.118937128189348, 90.94952163302091, 3.1268025435012207e-13, 1.691251847378593, 0.5455751102495228, 0.1201767636895742, 0.0007802908980930664, 0.011310267585075185, 1.0032972640942657, + +1.2472903868878749, 0.7149401846020106, 0.0034717544971213966, 0.0008409477479813854, 0.24599133854242075, 1.7996260724902138, 0.2399133704286251, 0.728108158144521, 0.03250298738504968, 0.003271716521926188, 0.5319194600339338, 2.1541622462034, 7.751722474870615, 0.08193253023289011, 1.52607969046303, 0.0002086811131899754, 0.005611466658864538, 0.018304952326087726, 0.0024888171138406773, 0.9061879299736817 +] + + +parameters = [ +2.9912988764832833, 0.8725, 0.0027, 0.028948770826150612, 8.04, 4.076413176215408, 0.06375413238034794, 0.24284340766769424, 0.5634017580097571, 0.009549630552246828, 0.6342888355132347, 0.5275522227754195, 1.0, 0.06178989216048817, 0.5234277812131813, 0.422, 0.011209254402846185, 0.5047, 0.6020757011698457, 0.7688, + +1.9479518608134938, 0.02343520604394183, 5.125002799990568, 0.02387522857907376, 0.2239226474715968, 4.889172213411495, 1.747880258818237, 2.8683242331457, 0.938229356687311, 1.4890887655876235, 1.6261504814901664, 11.26863249187599, 36.05486169712279, 6.091535897587629, 11.73936761697657, 3.189349432626493, 0.21045178305336348, 0.17122196312330415, 13.251662547139363, 5.282429995876679, + +1.0242323883590136, 0.5892723157762478, 0.0006988523559835617, 0.009036867721330505, 0.14457591298892497, 1.3282546133453548, 0.7955753778741823, 1.7661485851863441e-6, 2.6206711939142943e-7, 7.052160321659248e-12, 1.06497513443326e-6, 5.118937128189348, 90.94952163302091, 3.1268025435012207e-13, 1.691251847378593, 0.5455751102495228, 0.1201767636895742, 0.0007802908980930664, 0.011310267585075185, 1.0032972640942657, + +1.2472903868878749, 0.7149401846020106, 0.0034717544971213966, 0.0008409477479813854, 0.24599133854242075, 1.7996260724902138, 0.2399133704286251, 0.728108158144521, 0.03250298738504968, 0.003271716521926188, 0.5319194600339338, 2.1541622462034, 7.751722474870615, 0.08193253023289011, 1.52607969046303, 0.0002086811131899754, 0.005611466658864538, 0.018304952326087726, 0.0024888171138406773, 0.9061879299736817 +] + + +log_lik = 0.0 + +num_cols = length(parameters) ÷ 20 + +model_runtimes = zeros(Union{Missing, Float64},length(all_models), num_cols) +model_runtimes .+= 1e4 + +pars_mat = reshape(parameters, 20, num_cols) + +for k in 1:num_cols + pars_mat[1:2, k] = sort(pars_mat[1:2, k], rev = true) + + # Apply prior distributions + log_lik -= -sum(pars[1:19]) # logpdf of a gamma dist with mean and variance 1 + log_lik -= -log(5 * sqrt(2 * π)) - (pars[20]^2 / (2 * 5^2)) # logpdf of a normal dist with mean = 0 and +end + +total_runtime = @elapsed for (i,model) in enumerate(all_models) + for k in 1:num_cols + # Example solver parameters - this needs to be replaced with actual logic + par_inputs = MacroModelling.solver_parameters(eps(), eps(), maxiters, pars_mat[1:19, k]..., transformation, 0.0, 2) + + # Iterate over all models and calculate the total iterations + total_runtimes = calc_total_runtime(model, par_inputs, pars_mat[20, k]) + # model_runtimes[i] = 1e1 * total_runtimes + model_runtimes[i, k] = total_runtimes + + # if total_runtimes < 1e4 + # break + # end + end +end + +model_runtimes + +mins = minimum(model_runtimes, dims = 2) +model_runtimes[model_runtimes .== 10000] .= missing + +mtimes = model_runtimes ./ mins + +mean_cols = [mean(mtimes[:, i][.!(ismissing.(mtimes[:, i]))]) for i in 1:size(mtimes, 2)] +median_cols = [median(mtimes[:, i][.!(ismissing.(mtimes[:, i]))]) for i in 1:size(mtimes, 2)] +min_cols = [minimum(mtimes[:, i][.!(ismissing.(mtimes[:, i]))]) for i in 1:size(mtimes, 2)] +count_cols = [length(mtimes[:, i][.!(ismissing.(mtimes[:, i]))]) for i in 1:size(mtimes, 2)] + +hcat(mean_cols, median_cols, min_cols, count_cols) + + +Float64(log_lik / 1e4 + total_runtime * 1e3 + sum(minimum(model_runtimes, dims = 2))) + +# individual optim + +# best for Guerrieri +# pars = [1.9479518608134938, 0.02343520604394183, 5.125002799990568, 0.02387522857907376, 0.2239226474715968, 4.889172213411495, 1.747880258818237, 2.8683242331457, 0.938229356687311, 1.4890887655876235, 1.6261504814901664, 11.26863249187599, 36.05486169712279, 6.091535897587629, 11.73936761697657, 3.189349432626493, 0.21045178305336348, 0.17122196312330415, 13.251662547139363, 5.282429995876679] + +# best which solves all +# parameters = [15.223285246843304, 0.95517, 38.52678, 43.54497, 0.0008500000000000058, 0.62934, 75.54509549110291, 7.261945059036699, 85.51936289088874, 87.41658873754673, 55.07229950750884, 4.11876, 39.10866, 19.048629999998944, 10.314559999999997, 28.678813991497712, 36.343002891808354, 20.09102186880269, 8.49258045180932, 2.4593900000000004] + +# parameters = [33.22212, 0.95517, 38.52678, 43.54497, 0.00085, 0.62934, 46.08991, 7.42148, 88.03616, 95.55800, 85.29771, 4.11876, 39.10866, 19.04863, 10.31456, 40.92975, 36.34300, 69.75309, 30.12526, 2.45939] +# parameters = [37.43453157340342, 0.955165023642146, 38.52677779968875, 95.04867034722088, 0.000853689773926441, 0.6293394580085896, 93.73768759873417, 2.1182394698715467e-11, 12.95559055961808, 99.99999999999662, 24.3348635729501, 4.118758409516733, 39.10864859959332, 99.99999999999999, 10.31461007643029, 40.85122820001249, 15.98399822778196, 6.030696898083779e-8, 95.4840354280116, 2.4593914105545123] +# parameters = [37.848315380908126, 0.9526763793111475, 38.57687571822749, 95.06299787106212, 0.0008502803638540511, 0.6325649634774726, 93.75, 2.136387910452622e-11, 12.938130858544689, 99.99999999999662, 24.31858091208389, 4.11777400869617, 39.204774174235276, 100.0, 10.324167321843138, 40.72731100951839, 15.9844287184187, 6.03635340082695e-8, 81.9907380880773, 2.3287839364442786] +# parameters = [37.848315380909575, 0.9526763793111475, 38.57687571822749, 95.06299787106212, 0.0008502803638540511, 0.6325649634774871, 93.75, 2.2813386285476825e-11, 12.938130858546138, 99.99999999999807, 24.318580912085338, 4.11777400869617, 39.204774174235276, 100.0, 10.324167321843138, 40.7273110095184, 15.98442871842015, 6.036498351545045e-8, 81.9907380880773, 2.3287839364442786] +# parameters = [38.237414502003325, 0.9527636074246202, 38.57687571822749, 95.06299787106212, 0.0008502803638540511, 0.6325649634774871, 100.0, 2.8077962648754957e-11, 12.938130858546138, 99.99999999999807, 24.318580912085338, 4.11777400869617, 39.204774174235276, 100.0, 10.324167321843138, 40.7273110095184, 15.98442871842015, 6.036498351545045e-8, 81.9907380880773, 2.3287839364442786] +# parameters = [40.653449421030615, 0.9579543617960843, 9.97332192578991, 81.98802086152607, 0.008909032074826044, 0.5645562343804136, 89.01800964358117, 60.85834318907328, 53.862153957134666, 79.94101658022927, 66.47498026777562, 13.524117918347589, 4.664804437126141, 79.64865112828011, 31.157157536515367, 26.612793916106224, 77.91244651627218, 1.8858853864455494, 63.60002535111804, 2.41565115787875] +# parameters = [0.12093703888495441, 2.220446049250313e-16, 61.878895561555915, 65.84447938424393, 2.220446049250313e-16, 2.220446049250313e-16, 6.933804874728828, 0.03550533269177629, 2.320205642186332, 2.220446049250313e-16, 0.11105635242360294, 26.04149988887009, 2.2262295630876796, 15.050993533154083, 0.46563877913151125, 0.0011852170148789498, 7.918691209270494, 0.058009549651149024, 0.38452735521908066, 2.4680472122656134] +# parameters = [2.9699835653158626, 2.220446049250313e-16, 2.220446049250313e-16, 100.0, 2.220446049250313e-16, 2.220446049250313e-16, 15.70610701003443, 0.7621920764720541, 81.36639856950987, 2.220446049250313e-16, 100.0, 98.89303867353514, 22.02471417808018, 84.44731715339454, 2.220446049250313e-16, 2.220446049250313e-16, 100.0, 37.624811147776846, 13.281021688292757, 4.318100177071883] +# parameters = [2.0613343866845275, 0.8640348498807412, 98.12952506814149, 8.391075855914728, 2.220446049250313e-16, 0.00039247645151413365, 0.39152149242423145, 3.271716018599044, 2.220446049250313e-16, 0.5396861590700143, 0.024481377276542992, 38.2048416891502, 78.47102658051715, 61.533985856719, 0.016794191100658155, 2.220446049250313e-16, 0.8770574214422433, 0.0026513744112316136, 0.785831661396662, 2.769459604291346] + +# original +# parameters = [2.9912988764832833, 0.8725, 0.0027, 0.028948770826150612, 8.04, 4.076413176215408, 0.06375413238034794, 0.24284340766769424, 0.5634017580097571, 0.009549630552246828, 0.6342888355132347, 0.5275522227754195, 1.0, 0.06178989216048817, 0.5234277812131813, 0.422, 0.011209254402846185, 0.5047, 0.6020757011698457, 0.7688] + +parameters = rand(20) .+ 1 +parameters[20] -= 1 +# +# parameters[1:2] = sort(parameters[1:2], rev = true) + +# # # Example solver parameters - this needs to be replaced with actual logic +# par_inputs = MacroModelling.solver_parameters(eps(), eps(), maxiters, parameters[1:19]..., transformation, 0.0, 2) + +# outmodel = Smets_Wouters_2007.SS_solve_func(Smets_Wouters_2007.parameter_values, Smets_Wouters_2007, false, parameters[20], par_inputs) + +# iters = outmodel isa Tuple{Vector{Float64}, Tuple{Float64, Int64}} ? +# (outmodel[2][1] > 1e-12) || !isfinite(outmodel[2][1]) ? +# 10000 : +# outmodel[2][2] : +# 10000 + +# iters = outmodel[1][indexin([:ygap], Smets_Wouters_2007.var)][1] > .01 ? iters : 100000 + + +lbs = fill(eps(),length(parameters)) +lbs[20] = -20 + +ubs = fill(100.0,length(parameters)) + + + +all_models = [ + Smets_Wouters_2007, + # Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + # GNSS_2010, + # Ascari_Sbordone_2014, + # Smets_Wouters_2003, + # Backus_Kehoe_Kydland_1992, + # m, + # Baxter_King_1993, + # Ghironi_Melitz_2005, + # SGU_2003_debt_premium, + # JQ_2012_RBC, + # Ireland_2004, + # Caldara_et_al_2012, + # Gali_Monacelli_2005_CITR, + # Gali_2015_chapter_3_nonlinear, + # Aguiar_Gopinath_2007, + # FS2000, + # Smets_Wouters_2007 +]; + + +evaluate_pars_loglikelihood(parameters, all_models) + + +pars = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time) + +# pars = [1.3297775271726404, 0.15319852379823493, 0.6699860803856564, 0.6900232265277791, 0.20475425381819404, 2.262685062460725, 2.2699742966136798, 1.2291724039360243, 0.021285654449971443, 1.0340066995030113, 0.8056829713933548, 11.92136102981244, 8.982777633585407, 1.2387705193031366, 2.020240978873358, 0.9772105023172172, 0.8758962165861031, 1.6775999050973718, 0.17285722944375806, 2.3642317805128723] + + +all_models = [ + # Smets_Wouters_2007, + Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + # GNSS_2010, + # Ascari_Sbordone_2014, + # Smets_Wouters_2003, + # Backus_Kehoe_Kydland_1992, + # m, + # Baxter_King_1993, + # Ghironi_Melitz_2005, + # SGU_2003_debt_premium, + # JQ_2012_RBC, + # Ireland_2004, + # Caldara_et_al_2012, + # Gali_Monacelli_2005_CITR, + # Gali_2015_chapter_3_nonlinear, + # Aguiar_Gopinath_2007, + # FS2000, + # Smets_Wouters_2007 +]; + + +max_time = 5 * 60^2 +pars2 = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time) + +# pars = [0.8018861924730344, 0.35239298915976797, 0.2646475929658103, 1.186368814356376, 0.524025988271922, 10.716281966365939, 2.029733636528348, 2.2454645781759983, 0.9512589173571688, 1.2446190885719692, 2.230105642973023, 4.789929974394461, 8.380570181553736, 0.3967470094955483, 4.120697086148709, 0.16607831975540038, 3.1181759287637996, 5.9373761688423015, 0.9912587488183398, 7.914764797861666] + + +all_models = [ + # Smets_Wouters_2007, + # Guerrieri_Iacoviello_2017, + NAWM_EAUS_2008, + # GNSS_2010, + # Ascari_Sbordone_2014, + # Smets_Wouters_2003, + # Backus_Kehoe_Kydland_1992, + # m, + # Baxter_King_1993, + # Ghironi_Melitz_2005, + # SGU_2003_debt_premium, + # JQ_2012_RBC, + # Ireland_2004, + # Caldara_et_al_2012, + # Gali_Monacelli_2005_CITR, + # Gali_2015_chapter_3_nonlinear, + # Aguiar_Gopinath_2007, + # FS2000, + # Smets_Wouters_2007 +]; + + +max_time = 8 * 60^2 +pars3 = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time, max_evals = 250000) +# pars = [1.3085202378210083, 0.6105549045960956, 0.03852983653587412, 0.08808948562001635, 0.7013754861667181, 0.7197509835511993, 0.0140910151224454, 0.632379435443292, 0.8804360170508678, 8.900794787180901e-5, 0.26078954123808185, 0.012356130300425807, 2.1261322455643277, 0.012242714503695308, 3.847413047615463e-5, 0.03025833174488186, 0.1363582300112309, 1.44308892579897, 0.37248766077122875, 1.108766811279455] + + + +all_models = [ + # Smets_Wouters_2007, + # Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + GNSS_2010, + # Ascari_Sbordone_2014, + # Smets_Wouters_2003, + # Backus_Kehoe_Kydland_1992, + # m, + # Baxter_King_1993, + # Ghironi_Melitz_2005, + # SGU_2003_debt_premium, + # JQ_2012_RBC, + # Ireland_2004, + # Caldara_et_al_2012, + # Gali_Monacelli_2005_CITR, + # Gali_2015_chapter_3_nonlinear, + # Aguiar_Gopinath_2007, + # FS2000, + # Smets_Wouters_2007 +]; + + +max_time = 8 * 60^2 +pars4 = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time, max_evals = 250000) + +# pars = [9.861895121230758, 0.8149503715148578, 0.9678020443929615, 0.18557020181492592, 4.030611919120903, 0.752295946458232, 2.6645217191702217, 0.48862922551351196, 2.691920187300656, 0.1481681514337109, 21.361810615227746, 9.874698215009003, 4.6879339377305325, 1.4175229801847284, 0.9181067256779919, 0.059514897395779566, 1.7242569574632507, 2.5049303237604046, 11.183060736240922, 1.1199048614715326] + + + + + +all_models = [ + # Smets_Wouters_2007, + # Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + # GNSS_2010, + Ascari_Sbordone_2014, + # Smets_Wouters_2003, + # Backus_Kehoe_Kydland_1992, + # m, + # Baxter_King_1993, + # Ghironi_Melitz_2005, + # SGU_2003_debt_premium, + # JQ_2012_RBC, + # Ireland_2004, + # Caldara_et_al_2012, + # Gali_Monacelli_2005_CITR, + # Gali_2015_chapter_3_nonlinear, + # Aguiar_Gopinath_2007, + # FS2000, + # Smets_Wouters_2007 +]; + + +max_time = 8 * 60^2 +pars5 = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time, max_evals = 500000) +# pars = [2.3501880185956425, 0.34719465026279933, 0.17940177610230787, 3.3208811288225013e-7, 2.3594279405914094, 0.01744795164958195, 0.3760309936238473, 0.5558583990737875, 0.4552242235443654, 0.00806368022406653, 0.15220396104940526, 0.1989463492329444, 0.2444244510687956, 0.2714545659358831, 0.540719120976854, 0.004678690087611936, 0.7814520924679657, 0.36042250877546034, 0.8677525614007071, 1.000000007280896] + + + +all_models = [ + # Smets_Wouters_2007, + # Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + # GNSS_2010, + # Ascari_Sbordone_2014, + Smets_Wouters_2003, + # Backus_Kehoe_Kydland_1992, + # m, + # Baxter_King_1993, + # Ghironi_Melitz_2005, + # SGU_2003_debt_premium, + # JQ_2012_RBC, + # Ireland_2004, + # Caldara_et_al_2012, + # Gali_Monacelli_2005_CITR, + # Gali_2015_chapter_3_nonlinear, + # Aguiar_Gopinath_2007, + # FS2000, + # Smets_Wouters_2007 +]; + + +max_time = 8 * 60^2 +pars6 = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time, max_evals = 250000) +# pars = [1.6547113200789028, 0.2888180697750419, 2.6131946125574808, 1.0951585278957863, 0.4032764541534676, 0.22740583391740837, 0.06292806556843489, 0.3063814695233383, 2.18936892936353, 0.08097914377788905, 0.801015608756103, 0.6310333037406995, 2.541128858413585, 1.1584233799831622, 0.19449153292438376, 0.01062818770703848, 0.006105451489346563, 1.7875265604307713, 0.009242344285457445, 1.5580112273980442] + + + +all_models = [ + # Smets_Wouters_2007, + # Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + # GNSS_2010, + # Ascari_Sbordone_2014, + # Smets_Wouters_2003, + # Backus_Kehoe_Kydland_1992, + # m, + # Baxter_King_1993, + # Ghironi_Melitz_2005, + # SGU_2003_debt_premium, + # JQ_2012_RBC, + # Ireland_2004, + # Caldara_et_al_2012, + # Gali_Monacelli_2005_CITR, + # Gali_2015_chapter_3_nonlinear, + # Aguiar_Gopinath_2007, + FS2000, + # Smets_Wouters_2007 +]; + + +max_time = 8 * 60^2 +pars7 = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time, max_evals = 500000) +# pars = [7.5545497047246535, 0.7240882313900331, 0.026826520249843368, 0.10205911465204487, 0.5956561762004062, 2.1081959797078547, 14.668199530847641, 3.80569870943874, 2.220446049250313e-16, 7.849834643004542, 0.6171679895257539, 17.060417824592612, 28.30288205638385, 2.954162387825047, 18.017706573812315, 1.2105079901981806, 2.3419161784026286, 2.8150807254369727, 3.5005572136867653, 0.7479730479526492] + + + + + + +all_models = [ + # Smets_Wouters_2007, + # Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + # GNSS_2010, + # Ascari_Sbordone_2014, + # Smets_Wouters_2003, + # Backus_Kehoe_Kydland_1992, + # m, + # Baxter_King_1993, + # Ghironi_Melitz_2005, + # SGU_2003_debt_premium, + # JQ_2012_RBC, + # Ireland_2004, + # Caldara_et_al_2012, + # Gali_Monacelli_2005_CITR, + # Gali_2015_chapter_3_nonlinear, + Aguiar_Gopinath_2007, + # FS2000, + # Smets_Wouters_2007 +]; + + +max_time = 8 * 60^2 +pars8 = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time, max_evals = 250000) +# pars = [42.236595565806624, 12.014745765229392, 0.02203921025452384, 10.201979789860719, 2.1553941367567515, 3.2293988973657584, 18.98556976873586, 1.9765758516959744, 3.023326338882099, 0.8237577165890975, 7.360777287790799, 32.16501424615938, 32.54261688213752, 31.713230025016163, 3.857051987722223, 13.28701330015268, 4.046226705080187, 15.656054606371212, 27.022465242976605, 1.5097432076326989] + + + + +all_models = [ + # Smets_Wouters_2007, + # Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + # GNSS_2010, + # Ascari_Sbordone_2014, + # Smets_Wouters_2003, + # Backus_Kehoe_Kydland_1992, + # m, + # Baxter_King_1993, + # Ghironi_Melitz_2005, + # SGU_2003_debt_premium, + # JQ_2012_RBC, + # Ireland_2004, + # Caldara_et_al_2012, + # Gali_Monacelli_2005_CITR, + Gali_2015_chapter_3_nonlinear, + # Aguiar_Gopinath_2007, + # FS2000, + # Smets_Wouters_2007 +]; + + +max_time = 8 * 60^2 +pars9 = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time, max_evals = 250000) +# pars = [0.018374593136845512, 0.0038499468663194024, 0.018067627240156547, 0.005128997752625631, 1.3857636249255316, 0.4063190895216115, 2.6109739336078506, 9.15361624221388, 4.135315960111046, 8.490912854294038, 2.18937426052877, 9.180611286117626, 51.7961214848368, 0.5448952939846764, 3.1120295202227974, 0.9581635851842967, 0.024597005356203933, 3.5532652135992904, 6.275410304068712, 0.9756811656138908] + + + + + +all_models = [ + # Smets_Wouters_2007, + # Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + # GNSS_2010, + # Ascari_Sbordone_2014, + # Smets_Wouters_2003, + # Backus_Kehoe_Kydland_1992, + # m, + # Baxter_King_1993, + # Ghironi_Melitz_2005, + # SGU_2003_debt_premium, + # JQ_2012_RBC, + # Ireland_2004, + # Caldara_et_al_2012, + Gali_Monacelli_2005_CITR, + # Gali_2015_chapter_3_nonlinear, + # Aguiar_Gopinath_2007, + # FS2000, + # Smets_Wouters_2007 +]; + + +max_time = 8 * 60^2 +pars10 = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time, max_evals = 250000) +# pars = [0.4962191951232305, 0.12405479877054953, 0.6695167602982844, 2.1006462351919585e-9, 1.053146766586542, 0.14910773315223777, 0.027116129072231022, 1.256812542554111, 0.1557692851835663, 0.05493586207222183, 0.31919453560163635, 0.07325819085405584, 0.2597000556732767, 0.14821778589797047, 0.012891720477424292, 0.29090329230116474, 0.445491689587889, 0.1685397832608439, 0.02117295897791548, 0.0011754472077501322] + + + + + + +all_models = [ + # Smets_Wouters_2007, + # Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + # GNSS_2010, + # Ascari_Sbordone_2014, + # Smets_Wouters_2003, + # Backus_Kehoe_Kydland_1992, + # m, + # Baxter_King_1993, + # Ghironi_Melitz_2005, + # SGU_2003_debt_premium, + # JQ_2012_RBC, + # Ireland_2004, + Caldara_et_al_2012, + # Gali_Monacelli_2005_CITR, + # Gali_2015_chapter_3_nonlinear, + # Aguiar_Gopinath_2007, + # FS2000, + # Smets_Wouters_2007 +]; + + +max_time = 8 * 60^2 +pars11 = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time, max_evals = 250000) +# pars = [5.3719596604917825, 1.0629845997885847, 0.15771151885194457, 0.14720197886201114, 0.5935754820726649, 0.6436991724194971, 3.720439601043781, 8.047753721169693, 2.882349026317014, 1.4437880974850783, 2.3067390900986693, 4.620197460427168, 10.511318402228515, 0.06669323243998078, 4.910958483843366, 0.6904243207750654, 0.7943469864736756, 2.4086193062418824, 1.3508461744925238, 1.751335770814352] + + + + + + + + + +all_models = [ + # Smets_Wouters_2007, + # Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + # GNSS_2010, + # Ascari_Sbordone_2014, + # Smets_Wouters_2003, + # Backus_Kehoe_Kydland_1992, + # m, + # Baxter_King_1993, + # Ghironi_Melitz_2005, + # SGU_2003_debt_premium, + # JQ_2012_RBC, + Ireland_2004, + # Caldara_et_al_2012, + # Gali_Monacelli_2005_CITR, + # Gali_2015_chapter_3_nonlinear, + # Aguiar_Gopinath_2007, + # FS2000, + # Smets_Wouters_2007 +]; + + +max_time = 8 * 60^2 +pars12 = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time, max_evals = 250000) +# pars = [1.3398738344541519, 0.35187697402609885, 0.9423918915080955, 0.12873941995734006, 1.2364316363700447, 12.831348413414263, 0.07195388729374519, 0.5336582047882454, 0.7190979615613164, 0.35923760018153417, 0.027519281838197678, 0.23570674787197157, 0.002933984194285578, 0.27195333778365594, 0.11024658432932247, 1.4381762810336909, 0.406128679882458, 0.20626040416709104, 0.10169014504383994, -5.351901133543868e-7] + + + + + + + + + +all_models = [ + # Smets_Wouters_2007, + # Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + # GNSS_2010, + # Ascari_Sbordone_2014, + # Smets_Wouters_2003, + # Backus_Kehoe_Kydland_1992, + # m, + # Baxter_King_1993, + # Ghironi_Melitz_2005, + # SGU_2003_debt_premium, + JQ_2012_RBC, + # Ireland_2004, + # Caldara_et_al_2012, + # Gali_Monacelli_2005_CITR, + # Gali_2015_chapter_3_nonlinear, + # Aguiar_Gopinath_2007, + # FS2000, + # Smets_Wouters_2007 +]; + + +max_time = 8 * 60^2 +pars13 = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time, max_evals = 250000) +# pars = [4.294035907826813, 2.3347332598422255, 1.4875337056636178, 20.74907132926113, 4.7859315720403615, 6.1297263913535796, 5.872332511263355, 9.459647455599736, 4.569075808027596, 16.76730895449611, 20.259762521296032, 47.59601647655178, 47.985157266888514, 16.01765806147523, 7.751873368928798, 14.845916250683704, 3.559233815238337, 2.747206002686553, 17.76784661990265, 1.881192515028712] + + + + + + + + + + + + + + +all_models = [ + # Smets_Wouters_2007, + # Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + # GNSS_2010, + # Ascari_Sbordone_2014, + # Smets_Wouters_2003, + # Backus_Kehoe_Kydland_1992, + # m, + # Baxter_King_1993, + # Ghironi_Melitz_2005, + SGU_2003_debt_premium, + # JQ_2012_RBC, + # Ireland_2004, + # Caldara_et_al_2012, + # Gali_Monacelli_2005_CITR, + # Gali_2015_chapter_3_nonlinear, + # Aguiar_Gopinath_2007, + # FS2000, + # Smets_Wouters_2007 +]; + + +max_time = 8 * 60^2 +pars14 = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time, max_evals = 250000) +# pars = [2.280700601842886, 0.0031625974039871485, 0.9146749481680747, 2.72467107885148, 2.982409316485249, 7.6153887182877895, 32.60301422472388, 5.021154629315351, 2.1078579221645652, 9.191155788503199, 0.4216796538649238, 37.766075894950546, 60.753552950460005, 22.51917943015377, 32.0901748751557, 10.415198072919477, 2.3696254859060844, 4.948347574159594, 2.1030134006293153, 1.44525912242339] + + + + + + + + + + + + + + + + + +all_models = [ + # Smets_Wouters_2007, + # Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + # GNSS_2010, + # Ascari_Sbordone_2014, + # Smets_Wouters_2003, + # Backus_Kehoe_Kydland_1992, + # m, + # Baxter_King_1993, + Ghironi_Melitz_2005, + # SGU_2003_debt_premium, + # JQ_2012_RBC, + # Ireland_2004, + # Caldara_et_al_2012, + # Gali_Monacelli_2005_CITR, + # Gali_2015_chapter_3_nonlinear, + # Aguiar_Gopinath_2007, + # FS2000, + # Smets_Wouters_2007 +]; + + +max_time = 8 * 60^2 +pars15 = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time, max_evals = 250000) +# pars = [7.297048793403832, 0.004615358619737044, 0.14800106069823574, 0.42069895836508886, 0.9392423798218741, 0.015544798831901664, 4.497954810530372, 8.358852594112914, 5.3742160977607565, 0.31094581188772913, 0.7858408109182204, 19.225167181040128, 43.78549778722635, 8.577704390472906, 43.77110326774883, 39.790296456122626, 31.5172379725736, 7.008689861906436, 5.643260746602744, 0.8872967209964785] + + + + + + + + + + + + +all_models = [ + # Smets_Wouters_2007, + # Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + # GNSS_2010, + # Ascari_Sbordone_2014, + # Smets_Wouters_2003, + # Backus_Kehoe_Kydland_1992, + # m, + Baxter_King_1993, + # Ghironi_Melitz_2005, + # SGU_2003_debt_premium, + # JQ_2012_RBC, + # Ireland_2004, + # Caldara_et_al_2012, + # Gali_Monacelli_2005_CITR, + # Gali_2015_chapter_3_nonlinear, + # Aguiar_Gopinath_2007, + # FS2000, + # Smets_Wouters_2007 +]; + + +max_time = 8 * 60^2 +pars16 = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time, max_evals = 250000) +# pars = [8.530598532730615, 2.051681699063373, 6.924289455785735, 0.3544727300751251, 0.0864227300863801, 2.0826443401111407, 15.605609318003374, 2.6784312188740573, 2.694130852304065, 4.499139568059303, 1.6997354284432789, 14.884155927459053, 17.554915222164354, 5.996189373290768, 8.028613935355631, 3.6036903156179316, 0.7865356506932696, 1.581020742008601, 7.323928443120537, 1.2704654330282996] + + + + + + + + + + + + + +all_models = [ + # Smets_Wouters_2007, + # Guerrieri_Iacoviello_2017, + # NAWM_EAUS_2008, + # GNSS_2010, + # Ascari_Sbordone_2014, + # Smets_Wouters_2003, + Backus_Kehoe_Kydland_1992, + # m, + # Baxter_King_1993, + # Ghironi_Melitz_2005, + # SGU_2003_debt_premium, + # JQ_2012_RBC, + # Ireland_2004, + # Caldara_et_al_2012, + # Gali_Monacelli_2005_CITR, + # Gali_2015_chapter_3_nonlinear, + # Aguiar_Gopinath_2007, + # FS2000, + # Smets_Wouters_2007 +]; + + +max_time = 8 * 60^2 +pars17 = optimize_parameters(parameters, all_models, lbs, ubs, algo, max_time, max_evals = 250000) +# pars = [41.67156470636132, 4.1615294292873255, 1.7731538958193431, 2.8143797468298404, 5.816672553434534, 13.69961109645873, 9.48462337784073, 5.372800952946997, 2.334576768672413, 4.978435398686042, 1.530970770596612, 40.420562680682984, 45.6996241723041, 18.91855001681407, 9.655624836436182, 4.991722372699691, 16.668868812046295, 6.5821480424719505, 10.052798836648709, 1.0057035856900112] + + + + + + +# Smets_Wouters_2007 nonlinear +# [0.5892723157762478, 0.5887527065005829, 0.0006988523559835617, 0.009036867721330505, 0.14457591298892497, 1.3282546133453548, 1.378515451210324, 1.7661485851863441e-6, 2.6206711939142943e-7, 7.052160321659248e-12, 1.8442212583051863e-6, 5.118937128189348, 13.301617690046848, 6.044293140571821e-13, 1.691251847378593, 0.03319322730594751, 0.1201767636895742, 0.0007802908980930664, 0.011310267585075185, 1.0032972640942657] +# Iterations per model: [37, 10000, 10000, 35, 38, 10000, 18, 10000, 9, 21, 10, 22, 5, 27, 6, 12, 15, 10000, 21] + +# Smets_Wouters_2007 nonlinear (w/o help) +# pars = [1.2472903868878749, 0.7149401846020106, 0.0034717544971213966, 0.0008409477479813854, 0.24599133854242075, 1.7996260724902138, 0.2399133704286251, 0.728108158144521, 0.03250298738504968, 0.003271716521926188, 0.5319194600339338, 2.1541622462034, 7.751722474870615, 0.08193253023289011, 1.52607969046303, 0.0002086811131899754, 0.005611466658864538, 0.018304952326087726, 0.0024888171138406773, 0.9061879299736817] + +# pars = [3.7349994707848047e-14, 3.2974680693518946e-16, 0.258893178398098, 0.1841022751661884, 0.18068090216955102, 1.7014636514070283, 1.5677760746357532, 4.254677962816626e-15, 1.3405031384692835e-14, 5.882185606106154e-16, 8.44054984080944e-15, 11.096566648501781, 15.17067544296616, 1.816986379232247e-15, 1.638084025340988, 1.061110875865641e-15, 1.9860323089578468e-14, 3.4679045837714834e-15, 6.15209491181507e-16, 1.2375251201307327] + +# refinement across models which solved (see above) +# pars = [1.0242323883590136, 0.5892723157762478, 0.0006988523559835617, 0.009036867721330505, 0.14457591298892497, 1.3282546133453548, 0.7955753778741823, 1.7661485851863441e-6, 2.6206711939142943e-7, 7.052160321659248e-12, 1.06497513443326e-6, 5.118937128189348, 90.94952163302091, 3.1268025435012207e-13, 1.691251847378593, 0.5455751102495228, 0.1201767636895742, 0.0007802908980930664, 0.011310267585075185, 1.0032972640942657] +# [44, 10000, 83, 36, 40, 10000, 13, 22, 9, 18, 9, 11, 5, 24, 5, 11, 15, 10000, 20] + + +# Guerrieri_Iacoviello_2017, Smets_Wouters_2003, FS2000 +# [2.2166000934038386, 0.3342989316385292, 1.322105676270657, 2.4423579385973486, 5.28291512449182, 0.2436333363251138, 2.0392909437375537, 2.220446049250313e-16, 0.1179149349062645, 1.7950574466127827, 5.645113651574673e-14, 29.199406403144636, 21.508413489197178, 7.358430465764362, 1.139797041569637, 3.5086499739182466, 2.4965112615295393, 2.268534694762562, 12.120815210691354, 0.884940029673057] +# [10000, 16, 10000, 10000, 10000, 45, 22, 10000, 21, 35, 26, 10000, 7, 10000, 7, 16, 12, 10, 200] + +# fastest +# pars = [0.23022017261701624, 0.057947478368039436, 2.050623670243813, 0.25798053905612295, 0.1346335928352713, 2.7714294808025235, 1.1130650983532044, 1.2344486350727972, 0.6642281619281802, 0.2031332525060804, 0.10227058522397389, 11.42975890372093, 8.3491860144678, 0.3613395453790425, 10.047092374968718, 0.6554878071823927, 0.9230694479458228, 1.6633545864057182, 2.2950163256589042, 6.4487472041066] + +# NAWM_EAUS_2008 +# pars = [1.3896552573576109, 0.6915222077426001, 0.012467712883948469, 0.018802847828250483, 0.9624569018294489, 0.6026774053933583, 0.1355083075950215, 0.042329354435774166, 0.09034427312182672, 0.22618648947550593, 0.003110894050168958, 0.09995892894212706, 0.0097745176622862, 0.05210647519438576, 1.9473317584623753, 0.10986866008506377, 0.08618293402922794, 0.09930705118741172, 0.8178624002342283, 1.1907988747625304] + +println("Transform: $transformation") +println("Parameters: $pars") + +model_runtimes = zeros(length(all_models)) + +pars[1:2] = sort(pars[1:2], rev = true) + +# Example solver parameters - this needs to be replaced with actual logic +par_inputs = MacroModelling.solver_parameters(eps(), eps(), maxiters, pars[1:19]..., transformation, 0.0, 2) + +# Iterate over all models and calculate the total iterations +for (i,model) in enumerate(all_models) + total_runtimes = calc_total_runtime(model, par_inputs, pars[20]) + model_runtimes[i] = total_runtimes +end + +println("Runtimes per model [ms]: $model_runtimes") +println("Total runtimes across model: $(sum(model_runtimes))") + +# SWnonlinear.SS_solve_func(SWnonlinear.parameter_values, SWnonlinear, false, pars[20], par_inputs) +# Guerrieri_Iacoviello_2017.SS_solve_func(Guerrieri_Iacoviello_2017.parameter_values, Guerrieri_Iacoviello_2017, false, pars[20], par_inputs) + +# SS(Guerrieri_Iacoviello_2017) + +# SWnonlinear.bounds \ No newline at end of file diff --git a/benchmark/test_solver.jl b/benchmark/test_solver.jl deleted file mode 100644 index 3147af6a..00000000 --- a/benchmark/test_solver.jl +++ /dev/null @@ -1,795 +0,0 @@ -using MacroModelling - -include("../test/models/RBC_CME_calibration_equations_and_parameter_definitions_lead_lags_numsolve.jl") -# include("../test/models/RBC_CME_calibration_equations_and_parameter_definitions.jl") -include("../models/Backus_Kehoe_Kydland_1992.jl") -include("../models/Baxter_King_1993.jl") -include("../models/SW03.jl") -include("../models/GNSS_2010.jl") -include("../models/Ghironi_Melitz_2005.jl") -include("../models/SGU_2003_debt_premium.jl") -include("../models/NAWM_EAUS_2008.jl") # stands out -include("../models/JQ_2012_RBC.jl") -include("../models/Ireland_2004.jl") -include("../models/Caldara_et_al_2012.jl") -include("../models/Gali_Monacelli_2005_CITR.jl") -include("../models/Gali_2015_chapter_3_nonlinear.jl") -include("../models/Aguiar_Gopinath_2007.jl") -include("../models/Ascari_Sbordone_2014.jl") # stands out -include("../models/FS2000.jl") -include("../models/SW07.jl") -include("../models/RBC_baseline.jl") -include("../models/Guerrieri_Iacoviello_2017.jl") # stands out - - -all_models = [ - m, - Backus_Kehoe_Kydland_1992, - Baxter_King_1993, - SW03, - GNSS_2010, - Ghironi_Melitz_2005, - SGU_2003_debt_premium, - NAWM_EAUS_2008, - JQ_2012_RBC, - Ireland_2004, - Caldara_et_al_2012, - Gali_Monacelli_2005_CITR, - Gali_2015_chapter_3_nonlinear, - Aguiar_Gopinath_2007, - Ascari_Sbordone_2014, - FS2000, - SW07, - Guerrieri_Iacoviello_2017 -]; - - - -function calc_total_iters(model, par_inputs, starting_point) - outmodel = try model.SS_solve_func(model.parameter_values, model, false, starting_point, par_inputs) catch end - # outmodel = model.SS_solve_func(model.parameter_values, model, false, starting_point, par_inputs) - - outmodel isa Tuple{Vector{Float64}, Tuple{Float64, Int64}} ? - (outmodel[2][1] > eps(Float64)) || !isfinite(outmodel[2][1]) ? - 1000000 : - outmodel[2][2] : - 1000000 -end - -par_inputs = m.solver_parameters - -calc_total_iters(m, par_inputs, 0.897) - -using Optimization, OptimizationNLopt - -f = OptimizationFunction((x,verbose)-> begin - total_iters = 0 - - x[1:2] = sort(x[1:2], rev = true) - - par_inputs = MacroModelling.solver_parameters( - eps(),eps(),250, x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15], x[16], x[17], x[18], x[19],Int(abs(round(x[20]))),x[21],Int(abs(round(x[22]))) - ) - - total_iters = 0 - for model in all_models - total_iters += calc_total_iters(model, par_inputs, x[end]) - end - - total_iters_pars = sum(abs2,vcat(x[[3,4]]..., [1 .- x[12:19]]..., x[21] / 100)) * 10 - - # println(total_iters) - return Float64(total_iters + total_iters_pars), total_iters -end) - -# innit = [ -# 3.307670699324403 -# 0.8887 -# 0.023813243535282552 -# 0.026833357448752496 -# 2.442999997612768 -# 1.49949375 -# 0.0008014110419103691 -# 0.041527311524283926 -# 0.048143903530580914 -# 0.0033122894690720854 -# 0.5401102854078268 -# 0.11292946464826276 -# 0.00011413295389511516 -# 0.6553524666109665 -# 0.02388678809616366 -# 0.99778 -# 0.00011413295389511516 -# 0.6553524666109665 -# 0.02388678809616366 -# 0.99778 -# 1.0 -# 3.0 -# ] - - - -# innit = [ -# 2.1463884211036226 -# 0.9929437566596109 -# 0.6773423825308124 -# 0.0 -# 4.435883184171622 -# 0.1545259444769216 -# 0.16236330077946382 -# 0.04628182054753979 -# 0.5711216406099425 -# 0.0 -# 0.6804997522959056 -# 0.8391805314686501 -# 0.15117829923684067 -# 0.08883112140047633 -# 0.7130603312464207 -# 0.935850006981596 -# ] - -# innit = [ -# 5.0 -# 0.8725 -# 0.0027 -# 0.0 -# 8.04 -# 0.0 -# 0.076 -# 0.235 -# 0.51 -# 0.0 -# 0.62 -# 0.422 -# 1.0 -# 0.5047 -# 1.0 -# 0.422 -# 1.0 -# 0.5047 -# 1.0 -# 1.0 -# 0.0 -# 2.0 -# 0.7688 -# ] - - -innit = [ - .55 - .45 - 0.5 - 0.5 - 1 - 1 - 0.005 - 0.5 - 0.5 - 0.5 - 0.01 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 2.5 - 0.0 - 2.55 - 0.5 -] - - - -lbs = zero(innit) -# lbs .+= eps()*2 -lbs[20] = -.5 -lbs[21] = -100 -lbs[22] = 2.45 -lbs[end] = -100 - -ubs = zero(innit) -ubs .+= 1 -ubs[1:2] .= 10 -ubs[5:6] .= 100 -ubs[20] = 4.5 -ubs[21] = 100 -ubs[22] = 2.55 -ubs[end] = 100 - -prob = OptimizationProblem(f, innit, false, lb = lbs, ub = ubs) - -f(innit,true) -# using BenchmarkTools - -# max_minutes = 1 * 60 -max_hours = 24 * 60 ^ 2 -# Start 1200 (PT time) - -sol_ESCH = solve(prob, NLopt.GN_ESCH(), maxtime = max_hours); sol_ESCH.minimum - -innit2 = deepcopy(sol_ESCH.u) - - - -@benchmark f(innit2,true) - - - -x = innit2 - - - - -x[1:2] = sort(x[1:2], rev = true) - -par_inputs = MacroModelling.solver_parameters( - eps(),eps(),250, x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15], x[16], x[17], x[18], x[19],Int(abs(round(x[20]))),x[21],Int(abs(round(x[22]))) -) - -total_iters = 0 -for model in all_models - iter = calc_total_iters(model, par_inputs, x[end]) - println(iter, "\t ", model.model_name) - total_iters += iter -end -total_iters - - -x[1:2] = sort(x[1:2], rev = true) - -par_inputs = MacroModelling.solver_parameters( - eps(),eps(),250, x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15], x[16], x[17], x[18], x[19],Int(abs(round(x[20]))),x[21],Int(abs(round(x[22]))) -) - -@benchmark calc_total_iters(NAWM_EAUS_2008, par_inputs, x[23]) - -@benchmark calc_total_iters(Guerrieri_Iacoviello_2017, par_inputs, x[23]) - -calc_total_iters(Aguiar_Gopinath_2007, par_inputs, x[end]) - -calc_total_iters(Ascari_Sbordone_2014, par_inputs, x[23]) - -calc_total_iters(FS2000, par_inputs, x[23]) - -calc_total_iters(SW03, par_inputs, x[end]) - -calc_total_iters(SW07, par_inputs, x[end]) - - -model = Backus_Kehoe_Kydland_1992 -starting_point = .9#x[end] -outmodel = model.SS_solve_func(model.parameter_values, model, false, starting_point, par_inputs) - - outmodel isa Tuple{Vector{Float64}, Tuple{Float64, Int64}} ? - (outmodel[2][1] > eps(Float64)) || !isfinite(outmodel[2][1]) ? - 1000000 : - outmodel[2][2] : - 1000000 - - - -innit2 = [ 2.9286687462521286 -1.0934322881820666 -8.040292279055312e-5 -0.0010349673716525869 -9.612040527215113 -50.1236879266217 -0.5669837295436179 -0.5151760400524997 -0.44424209515580787 -0.0017803001645317015 -0.20165426073261922 -0.9893989333367081 -0.9992664322446558 -0.9947474775878444 -0.9947619544912081 -0.9758001846468876 -0.992316474092166 -0.9753918769395817 -0.9907848466210624 -0.5322997748902552 -0.0007004948302871516 -2.4590286886069483 -25.260971258391464] - -x = sol_ESCH.u - - -x[1:2] = sort(x[1:2], rev = true) - -par_inputs = MacroModelling.solver_parameters( - eps(),eps(),250, x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15], x[16], x[17], x[18], x[19],Int(abs(round(x[20]))),x[21],Int(abs(round(x[22]))) -) - -calc_total_iters(NAWM_EAUS_2008, par_inputs, x[end]) - -calc_total_iters(Guerrieri_Iacoviello_2017,innit2[1:end-1],innit[end]) -innit2 -sort(innit2[1:2], rev = true) -x = innit2 -par_inputs = MacroModelling.solver_parameters( - eps(),eps(),250, x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15], x[16], x[17], x[18], x[19],Int(abs(round(x[20]))),x[21],Int(abs(round(x[22]))) - ) - - -calc_total_iters(Guerrieri_Iacoviello_2017,par_inputs,innit2[end]) - -Guerrieri_Iacoviello_2017.SS_solve_func(Guerrieri_Iacoviello_2017.parameter_values, Guerrieri_Iacoviello_2017, false, innit2[end], par_inputs) - - - - - -innit = [7.971710350206478 -0.9041767277613695 -0.02578560981066282 -0.0 -1.0 -22.097277731204894 -0.10321154244168337 -0.16697538814219845 -0.07074783314454779 -0.010182004981312102 -0.7942104062189025 -0.8394091639953956 -0.5276256406439965 -0.2298040121252335 -0.7636812309458207 -0.012227999306191117 -0.5112774682252668 -0.9814967913661943 -0.862118389647011 -2.6999735986281466 -2.050375187497662 -0.8955836847010801] - - - -innit = [7.971710350206478 -0.9041767277613695 -0.02578560981066282 -0.0 -1.0 -0.0 -0.0987991963495973 -0.16697538814219845 -0.07074783314454779 -0.010182004981312102 -0.7942104062189025 -0.8394091639953956 -1.0 -0.49101785714380347 -1.0 -0.012802334805329335 -1.0 -0.9814967913661943 -1.0 -3 -2 -0.8955836847010801] - - -innit = [ -8 -0.904 -0.026 -0.0 -1.0 -0.0 -0.1 -0.17 -0.07 -0.01 -0.8 -0.84 -1.0 -0.5 -1.0 -0.0128 -1.0 -0.9815 -1.0 -3.0 -2.0 -0.897] - -f(innit, false) - -f(innit, true) - -f(round.(innit, digits = 8),false) - - -prob = OptimizationProblem(f, innit2, false, lb = lbs, ub = ubs) - -sol_BOBYQA = solve(prob, NLopt.LN_BOBYQA()); sol_BOBYQA.minimum # fast and solves -sol_SBPLX = solve(prob, NLopt.LN_SBPLX()); sol_SBPLX.minimum - - - -sol_COBYLA = solve(prob, NLopt.LN_COBYLA()); sol_COBYLA.minimum # slow -sol_NM = solve(prob, NLopt.LN_NELDERMEAD()); sol_NM.minimum -sol_PRAXIS = solve(prob, NLopt.LN_PRAXIS()); sol_PRAXIS.minimum - -using OptimizationBBO -sol_BBO = solve(prob, BBO_adaptive_de_rand_1_bin_radiuslimited(), maxtime = maxt); sol_BBO.minimum #gets the far off parameters when only few models are involved -sol_BBO = solve(prob, BBO_dxnes(), maxtime = maxt); sol_BBO.minimum -# sol_BBO = solve(prob, BBO_resampling_inheritance_memetic_search(), maxtime = maxt); sol_BBO.minimum - - -sol_AGS = solve(prob, NLopt.GN_AGS()); sol_AGS.minimum # slow and unreliable -sol_CRS2 = solve(prob, NLopt.GN_CRS2_LM(), maxtime = maxt); sol_CRS2.minimum -sol_DIRECT = solve(prob, NLopt.GN_DIRECT_L_RAND(), maxtime = maxt); sol_DIRECT.minimum -sol_ISRES = solve(prob, NLopt.GN_ISRES(), maxtime = maxt); sol_ISRES.minimum - -sol_Multi = solve(prob, NLopt.G_MLSL_LDS(), local_method = NLopt.LN_BOBYQA(), maxtime = maxt); sol_Multi.minimum - - -using OptimizationMetaheuristics -sol_Metaheuristics = solve(prob, ECA(), maxtime = maxt); sol_Metaheuristics.minimum - - -using OptimizationMultistartOptimization -sol_Multi = solve(prob, MultistartOptimization.TikTak(40), NLopt.LN_SBPLX()); sol_Multi.minimum - -sol_Multi = solve(prob, NLopt.G_MLSL_LDS(), local_method = NLopt.LN_SBPLX(), maxtime = maxt) - - - - - - - - - - - - -all_models = [ - # m, - # Backus_Kehoe_Kydland_1992, - # Baxter_King_1993, - # SW03, - # GNSS_2010, - # Ghironi_Melitz_2005, - # SGU_2003_debt_premium, - # NAWM_EAUS_2008, - # JQ_2012_RBC, - # Ireland_2004, - # Caldara_et_al_2012, - # Gali_Monacelli_2005_CITR, - # Gali_2015_chapter_3_nonlinear, - # Aguiar_Gopinath_2007, - # Ascari_Sbordone_2014, - # FS2000, - # SW07, - Guerrieri_Iacoviello_2017 -]; - - - -function calc_total_iters(model, par_inputs, starting_point) - outmodel = try model.SS_solve_func(model.parameter_values, model, false, starting_point, par_inputs) catch end - # outmodel = model.SS_solve_func(model.parameter_values, model, false, starting_point, par_inputs) - - outmodel isa Tuple{Vector{Float64}, Tuple{Float64, Int64}} ? - (outmodel[2][1] > eps(Float64)) || !isfinite(outmodel[2][1]) ? - 1000000 : - outmodel[2][2] : - 1000000 -end - - -f = OptimizationFunction((x,verbose)-> begin - total_iters = 0 - - # x[1:2] = sort(x[1:2], rev = true) - - # par_inputs = MacroModelling.solver_parameters( - # eps(),eps(),250, x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15], x[16], x[17], x[18], x[19],Int(abs(round(x[20]))),x[21],Int(abs(round(x[22]))) - # ) - - total_iters = 0 - for model in all_models - total_iters += calc_total_iters(model, model.solver_parameters, x[end]) - end - - # total_iters_pars = sum(abs2,vcat(x[[3,4]]..., [1 .- x[12:19]]..., x[21] / 100)) * 10 - - return Float64(total_iters), total_iters -end) - -innit = [ - 0.5 -] - - - -lbs = zero(innit) -# lbs .+= eps()*2 -# lbs[20] = -.5 -# lbs[21] = -100 -# lbs[22] = 2.45 -lbs[end] = -100 - -ubs = zero(innit) -ubs .+= 1 -# ubs[1:2] .= 10 -# ubs[5:6] .= 100 -# ubs[20] = 4.5 -# ubs[21] = 100 -# ubs[22] = 2.55 -ubs[end] = 100 - -prob = OptimizationProblem(f, innit, false, lb = lbs, ub = ubs) - -maxt = 10 * 60 -using OptimizationBBO -sol_BBO = solve(prob, BBO_adaptive_de_rand_1_bin_radiuslimited(), maxtime = maxt); sol_BBO.minimum #gets the far off parameters when only few models are involved - -sol_BBO.u -f(sol_BBO.u, false) - - -# 71.69060992965288 works -Guerrieri_Iacoviello_2017.SS_solve_func(Guerrieri_Iacoviello_2017.parameter_values, Guerrieri_Iacoviello_2017, false, sol_BBO.u[1], Guerrieri_Iacoviello_2017.solver_parameters) - - -sol_ESCH = solve(prob, NLopt.GN_ESCH(), maxtime = maxt); sol_ESCH.minimum - -f(71.69,[]) -Guerrieri_Iacoviello_2017.SS_solve_func(Guerrieri_Iacoviello_2017.parameter_values, Guerrieri_Iacoviello_2017, false, sol_ESCH.u[1], Guerrieri_Iacoviello_2017.solver_parameters) -Guerrieri_Iacoviello_2017.SS_solve_func(Guerrieri_Iacoviello_2017.parameter_values, Guerrieri_Iacoviello_2017, false, 0.0-10*eps(Float32), Guerrieri_Iacoviello_2017.solver_parameters) - - -innit = xx -xx = innit -sqrt(170) -xx = sol_SBPLX.u -xx = sol_ESCH.u - - -xx[20:21] .= Int.(round.(xx[20:21])) - -SW07.SS_solve_func(SW07.parameter_values, SW07, false, true, - Dict( - :ϕ̄ => maximum(xx[1:2]), - :ϕ̂ => minimum(xx[1:2]), - :μ̄¹ => xx[3], - :μ̄² => xx[4], - :p̄¹ => xx[5], - :p̄² => xx[6], - :ρ => xx[7], - :ρ¹ => xx[8], - :ρ² => xx[9], - :ρ³ => xx[10], - :ν => xx[11], - :λ¹ => xx[12], - :λ² => xx[13], - :λ̂¹ => xx[14], - :λ̂² => xx[15], - :λ̅¹ => xx[16], - :λ̅² => xx[17], - :λ̂̅¹ => xx[18], - :λ̂̅² => xx[19], - :transformation_level => Int(abs(round(xx[20]))), - :backtracking_order => Int(abs(round(xx[21]))) - ),xx[end]) - - -m.SS_solve_func(m.parameter_values, m, false, true, -Dict( - :ϕ̄ => maximum(xx[1:2]), - :ϕ̂ => minimum(xx[1:2]), - :μ̄¹ => xx[3], - :μ̄² => xx[4], - :p̄¹ => xx[5], - :p̄² => xx[6], - :ρ => xx[7], - :ρ¹ => xx[8], - :ρ² => xx[9], - :ρ³ => xx[10], - :ν => xx[11], - :λ¹ => xx[12], - :λ² => xx[13], - :λ̂¹ => xx[14], - :λ̂² => xx[15], - :λ̅¹ => xx[16], - :λ̅² => xx[17], - :λ̂̅¹ => xx[18], - :λ̂̅² => xx[19], - :transformation_level => Int(abs(round(xx[20]))), - :backtracking_order => Int(abs(round(xx[21]))) -),xx[end]) - - -GNSS_2010.SS_solve_func(GNSS_2010.parameter_values, GNSS_2010, false, true, -Dict( - :ϕ̄ => maximum(xx[1:2]), - :ϕ̂ => minimum(xx[1:2]), - :μ̄¹ => xx[3], - :μ̄² => xx[4], - :p̄¹ => xx[5], - :p̄² => xx[6], - :ρ => xx[7], - :ρ¹ => xx[8], - :ρ² => xx[9], - :ρ³ => xx[10], - :ν => xx[11], - :λ¹ => xx[12], - :λ² => xx[13], - :λ̂¹ => xx[14], - :λ̂² => xx[15], - :λ̅¹ => xx[16], - :λ̅² => xx[17], - :λ̂̅¹ => xx[18], - :λ̂̅² => xx[19], - :transformation_level => Int(abs(round(xx[20]))), - :backtracking_order => Int(abs(round(xx[21]))) -),xx[end]) - - -asdasd = Ascari_Sbordone_2014.SS_solve_func(Ascari_Sbordone_2014.parameter_values, Ascari_Sbordone_2014, false, true, -Dict( - :ϕ̄ => maximum(xx[1:2]), - :ϕ̂ => minimum(xx[1:2]), - :μ̄¹ => xx[3], - :μ̄² => xx[4], - :p̄¹ => xx[5], - :p̄² => xx[6], - :ρ => xx[7], - :ρ¹ => xx[8], - :ρ² => xx[9], - :ρ³ => xx[10], - :ν => xx[11], - :λ¹ => xx[12], - :λ² => xx[13], - :λ̂¹ => xx[14], - :λ̂² => xx[15], - :λ̅¹ => xx[16], - :λ̅² => xx[17], - :λ̂̅¹ => xx[18], - :λ̂̅² => xx[19], - :transformation_level => Int(abs(round(xx[20]))), - :backtracking_order => Int(abs(round(xx[21]))) -),xx[end]) - -asdasd[1] - typeof(asdasd) - - - SW03.SS_solve_func(SW03.parameter_values, SW03, false, true, - Dict( - :ϕ̄ => maximum(xx[1:2]), - :ϕ̂ => minimum(xx[1:2]), - :μ̄¹ => xx[3], - :μ̄² => xx[4], - :p̄¹ => xx[5], - :p̄² => xx[6], - :ρ => xx[7], - :ρ¹ => xx[8], - :ρ² => xx[9], - :ρ³ => xx[10], - :ν => xx[11], - :λ¹ => xx[12], - :λ² => xx[13], - :λ̂¹ => xx[14], - :λ̂² => xx[15], - :λ̅¹ => xx[16], - :λ̅² => xx[17], - :λ̂̅¹ => xx[18], - :λ̂̅² => xx[19], - :transformation_level => Int(abs(round(xx[20]))), - :backtracking_order => Int(abs(round(xx[21]))) - ),xx[end]) - - - -NAWM_EAUS_2008.SS_solve_func(NAWM_EAUS_2008.parameter_values, NAWM_EAUS_2008, false, true, -Dict( - :ϕ̄ => maximum(xx[1:2]), - :ϕ̂ => minimum(xx[1:2]), - :μ̄¹ => xx[3], - :μ̄² => xx[4], - :p̄¹ => xx[5], - :p̄² => xx[6], - :ρ => xx[7], - :ρ¹ => xx[8], - :ρ² => xx[9], - :ρ³ => xx[10], - :ν => xx[11], - :λ¹ => xx[12], - :λ² => xx[13], - :λ̂¹ => xx[14], - :λ̂² => xx[15], - :λ̅¹ => xx[16], - :λ̅² => xx[17], - :λ̂̅¹ => xx[18], - :λ̂̅² => xx[19], - :transformation_level => Int(abs(round(xx[20]))), - :backtracking_order => Int(abs(round(xx[21]))) -),xx[end]) - - -prob = OptimizationProblem(f, -transformer(previous_sol_init,lbs,ubs, option = transformer_option), -(parameters_and_solved_vars,transformer_option, ss_solve_blocks, lbs, ubs), -lb = transformer(lbs,lbs,ubs, option = transformer_option), -ub = transformer(ubs,lbs,ubs, option = transformer_option)) - - # sol_new = solve(prob, SS_optimizer(), local_maxtime = timeout, maxtime = timeout) - - -m.SS_solve_func(m.parameter_values, m, false, false, Dict(), [.9]) - - - -using NLboxsolve -nlboxsolve - - - -if norm(f(xn)) > γ*norm(f(xk)) - g .= jk'f(xk) - if g'dk <= -ρ*norm(dk)^p - α = 1.0 - while norm(f(xk+α*dk))^2 > norm(f(xk))^2 + 2*α*β*g'dk - α = β*α - end - xn .= xk + α*dk - box_projection!(xn,lb,ub) - else - α = 1.0 - while true - xt .= xk-α*g - box_projection!(xt,lb,ub) - if norm(f(xt))^2 <= norm(f(xk))^2 + 2*σ*g'*(xt-xk) - xn .= xt - break - else - α = β*α - end - end - end -end - - - -if sum(abs2,f(previous_guess + α * guess_update)) > ρ * ḡ - while sum(abs2,f(previous_guess + α * guess_update)) > ḡ - 0.005 * α^2 * sum(abs2,guess_update) - α *= r - end - μ¹ = μ¹ * λ¹ #max(μ¹ * λ¹, 1e-7) - μ² = μ² * λ² #max(μ² * λ², 1e-7) - p = λᵖ * p + (1 - λᵖ) -else - μ¹ = min(μ¹ / λ¹, 1e-3) - μ² = min(μ² / λ², 1e-3) -end - - - - -if norm(f(z)) <= ρ*norm(f(xk)) - α = 1.0 -else - if f(xk)'jk*dk > -γ - dk = d1k - z .= xk+dk - box_projection!(z,lb,ub) - s .= z-xk - end - α = 1.0 - epsilon = 1/10 - while true - if norm(f(xk+α*s))^2 > (1+epsilon)*norm(f(xk))^2 - σ1*α^2*norm(s)^2 - σ2*α^2*norm(f(xk))^2 - α = r*α - epsilon = r*epsilon - else - break - end - end -end diff --git a/benchmark/usmodel.csv b/benchmark/usmodel.csv deleted file mode 100644 index 704e118a..00000000 --- a/benchmark/usmodel.csv +++ /dev/null @@ -1,231 +0,0 @@ -dc,dinve ,dy ,labobs,pinfobs,dw,robs -0.125190343495092,3.74590245809472,-0.346646871942539,2.40599138364354,1.73321288857178,-0.390910855357731,0.209166666666667 --0.311350549973952,7.8632665246694,1.15161239527572,3.12008510042125,2.48223977335953,0.149491058377834,0.251666666666667 -0.429219445192359,3.03630734680101,1.16038522796237,3.72278058296871,0.760128270556626,1.80411479077715,0.2725 -1.10204814758356,1.05355467484111,1.53376234618327,3.70532905517229,0.883676382216336,0.374201838469659,0.275 --0.514535875011632,-0.054366832738566,0.247688219858674,3.71684726813908,1.8409541555473,0.628307103489846,0.2875 -0.0960511445626366,-0.410564067900935,0.0739084412649618,2.97850194689238,0.247338225209548,0.964797828024913,0.31 --0.382119840181304,-5.98467636772344,-1.66438273365395,2.09049185540141,-0.398455006770648,0.398455006770689,0.3175 -1.7562547965365,-2.40616152192817,-0.539529184386311,0.365709158814639,-1.10095087276125,1.10095087276125,0.3175 --0.0381809032957676,-1.24411612082761,0.83676666115764,-0.440932473002363,-0.576582594719133,1.77420169939067,0.285833333333333 -0.952915189957594,2.92601419881703,-1.31267961165202,-0.0888388694548326,0.0983767910132549,-0.0983767910132656,0.294166666666667 -1.50105472828255,5.8565465387299,3.72752944647471,0.0559662336831934,-0.307749365805066,2.66079910682451,0.300833333333333 -1.44021227274669,9.86864732111715,2.66242880952962,1.8613449412685,0.39374973967865,0.762332500428933,0.313333333333333 -4.76315338667251,7.80250117903879,3.62979390543319,3.26170775836761,2.09024501598964,0.182580091765963,0.33 --2.9568287628029,-1.84539139398265,2.058564265717,3.91358887387815,1.9059540621623,0.316359616308709,0.359166666666667 -2.16327190545343,-3.77026343348561,1.47994349966473,4.70659391993809,3.6607817602528,-0.417254184937363,0.366666666666667 --2.50974652162233,-3.57856052816862,1.86293638822508,4.88353991762739,0.61238567427071,0.445825258782982,0.3975 -1.21688658652727,-1.09397220814569,1.94214491685773,4.32712691767745,0.0565131408089226,2.02689554947523,0.425833333333333 -0.610431493283898,-1.29620395693397,-0.023129631364327,4.39869574064284,1.10125846080451,-0.0756084440855744,0.4275 -0.595631179795532,1.78197084111221,0.923349585105143,4.90854911753718,-0.0950384418145323,2.11530917356649,0.416666666666667 -1.62515565444977,1.43990445664903,-0.0666815494147386,3.96348327702958,0.189986646328189,-0.189986646328215,0.436666666666667 --0.318993889670651,-7.68357054064359,0.327554218218211,3.79748637530838,1.14344052210056,-0.148407436783714,0.470833333333333 -2.9853311740012,6.555164697121,2.88999951632206,4.6646951106124,0.29208364431863,2.63495458569266,0.498333333333333 -0.654750608618315,3.05398252039646,0.952820153383414,5.74498734691275,0,0.956945101615069,0.52 -0.369727760692172,0.700180829241106,0.538329847851514,4.41089669055464,0.186926218594019,1.69992221184427,0.563333333333333 --0.303738495757159,0.308251212012095,-0.825008405488461,3.14346091194261,0.383751361792806,0.546487904438564,0.514166666666667 --0.771388492760025,-1.83604089758222,-1.9284216912896,1.52694793053138,0.218627109382386,0.703038401110007,0.393333333333333 -0.184604161746449,-2.33652946899923,-0.84055180936241,0.685806016455445,0.321605030405125,0.591643325922114,0.29 -0.811455305093318,1.66473112516078,-0.186697025815988,-0.0510200591484704,0.0924742361980258,-0.092474236198008,0.2225 -0.576932144730677,3.52508037392226,0.852539362231937,-0.534355056351558,0.179265061451961,0.725718490539784,0.256666666666667 -1.37724385989509,1.66561742841617,1.64573708766568,0.218354868806387,0.281827729761597,0.615039268514487,0.246666666666667 -1.73727018612993,3.08579685685316,2.5216388894263,1.28093757713066,0.480523560472479,0.408371181252143,0.335833333333333 -1.21702814101496,4.2169299862436,1.25665977356471,2.35358463136157,0.41924275327534,0.461820214940111,0.375 -0.559847440552005,2.34409224081927,1.00393866449497,3.81921870729673,0.742782692078903,0.130585304796583,0.485 -0.239131064013975,0.0793325106021996,0.260082683213227,4.69263825896616,1.00647104507132,-0.140664770759884,0.589166666666667 --0.674629817078255,-1.27636160637712,-0.738394948457312,4.46514247724218,1.00687829505217,0.702565040877836,0.620833333333333 -0.154695641712237,0.933174102883356,0.512520496195066,4.15766958538524,0.577509994556813,1.93308211855084,0.673333333333333 --0.391066896167047,0.0375058825424048,-0.415640990585189,4.15437407907569,1.27836792468146,-0.455318011029931,0.7025 -1.29266641096888,-0.523860374086951,1.33329583247587,3.95707268877595,0.383406650182216,1.24264543699585,0.731666666666667 --0.0924196744412598,-0.796952592974748,0.344246290951674,3.66254592573938,1.40344292133512,0.196591213308992,0.733333333333333 --0.161245780470836,-1.40436076141302,-0.538321163619685,2.71575407190414,0.681911988588446,0.892923708225467,0.75 -0.666621175366686,0.638635102370841,0.627411213239952,2.30817559335992,0.592882189073274,0.185331855132233,0.808333333333334 -0.189812524157333,-1.82673255990676,-1.45102220801482,0.511900531323704,0.00993443275203454,1.52855745119588,0.813333333333333 --1.59647721231283,-8.74667249546337,-3.08040127876234,-1.37178920220987,1.09663221107303,-1.09663221107304,0.465833333333333 -0.418637603338539,-2.9277410793724,0.327354028454693,-1.86791845273086,0.313925798595571,1.20125470346468,0.235 -0.792714101415072,0.487870888233203,2.00772025516142,-1.32138142370786,0.654107574797402,0.0949595981183506,0.330833333333333 -0.381989134703531,5.33582661868968,1.89195027747485,-0.3466837297197,0.499891841541489,0.981616736972576,0.540833333333333 -1.90670765404735,5.52311048353062,1.51622364168611,0.237782659215213,0.232108421420341,0.500495587786944,0.6425 -1.54748019781727,3.16346472289075,2.22625843468643,1.5174915893445,0,0.727275932907986,0.770833333333333 -1.03888601836798,0.996146604245098,-0.432872323177094,1.05269801260982,0.236389622103284,0.485635175245399,0.894166666666667 --0.0840638060431616,-1.92543746310577,0.0340328845528575,0.548440562406256,0.418340234564329,1.01025549018335,0.9975 --0.00726558060227944,2.41284371161083,1.52111080911084,0.0408303535523942,0.435709674004281,1.66963124577892,0.983333333333333 -1.12902437794247,-2.44318375590541,-0.781887187950019,1.14077712442491,0.348158215040373,-0.348158215040364,0.924166666666667 --0.699488697061895,-3.48296859640629,-0.162716021786991,0.853816226596052,0.380156321734759,0.311887962722629,0.734166666666667 --0.0755912706160871,-1.31936321193436,-1.65512195343695,-0.134784709974667,0.293630331737438,0.393657597038754,0.574166666666667 --0.432264100951159,-2.08127199515684,0.236514944153782,-0.833138594130219,0.21729896594338,0.465297541096604,0.500833333333333 -0.94671961854948,1.10056369171392,1.54005165302362,-1.447272343728,0.212119149039314,1.13925276763298,0.433333333333333 -0.231867722777849,1.65409893142217,1.30079325301347,-1.57034377485627,0.310296440790436,0.358602374289205,0.420833333333333 -1.60984095839706,2.75304136543315,1.86469060745196,-0.825505406655282,0.337410695475793,0.327043576391091,0.6 -0.755469055327865,1.52951042395864,1.6234953082627,-0.628525516737966,0.587743085706771,1.37953347416369,0.614166666666667 -1.04535825810768,2.55999233447503,0.717578585387628,-0.253213252728301,0.148719644457929,0.498531806103827,0.651666666666667 -0.375881615681806,0.0265757558824191,0.45957431767215,-0.34332975746679,0.241198688296995,0.401890344732053,0.711666666666667 -0.807952050495317,-1.47945733509604,-0.317507694048118,-1.1308607689603,0.314538397071162,0.324441412805932,0.730833333333333 -0.249057539344847,0.487545239834049,0.812986170892373,-1.26308989288128,0.226040921986348,1.03979876520602,0.741666666666667 -0.457708763954201,3.70071490538822,0.808603271257084,-0.794425988626529,0.197942385158578,0.42901891620096,0.740833333333333 -1.22167778456702,1.65666385001623,1.45426983614084,-0.942665406043204,0.197551347182623,0.425503627880985,0.8325 -0.0427345745158618,2.13673667753181,0.352997846141534,-0.711096838440881,0.745333704857432,0.489249877372476,0.863333333333333 -1.71106043802899,2.69184464206651,1.79635920943849,0.367014179673788,0.29567651809308,-0.295676518093046,0.865833333333333 -1.32088780240753,-0.0315985813364534,0.755169413167096,1.3749607673825,0.258568040814167,0.960959268567663,0.8725 -1.33209022442065,0.929263850764329,0.92484937690881,0.791506900215836,0.3933719720008,0.811461879616605,0.864166666666667 --0.313577723902199,0.888912605084414,-0.170734634880091,0.85977586885673,0.495161939019351,0.101854759631074,0.894166666666667 -1.59260985030284,3.4946993052146,2.00832398881482,1.653126511908,0.506126088821057,0.0873474631603699,0.993333333333333 -0.752581486153531,2.1901704502383,0.937676503611556,2.0780228722125,0.432428286800324,0.157543925918496,1.01916666666667 -1.38079781930566,2.1474231236009,1.67625647933926,2.14471268615733,0.368537148688564,0.801066827630592,1.01833333333333 -2.11624597668481,2.41369751652351,2.05601746978596,2.44969671196424,0.636185048276428,0.519897191831156,1.04166666666667 -1.31457239966488,2.27031276882315,2.1474273608826,2.8386658124877,0.649666478856759,1.62315862889886,1.13916666666667 --0.0437709789341056,-0.697561706681654,0.0659646860557359,2.87508445051509,0.840908599851975,0.27642145996057,1.22833333333333 -0.580089313263045,-1.4183398543631,0.371337432584937,2.82516728917369,1.04880220750427,0.604127987616746,1.3525 --0.0250503382756619,-3.09029022972808,0.502367855014768,2.85668743017135,0.914614461882346,0.172352761808039,1.39083333333333 -0.0863998645534707,-2.69847636152343,0.551218405046939,1.8738144201244,0.454189290234908,1.15442448492753,1.20583333333333 -0.901536358215196,2.02269260500407,-0.368192671766451,1.45204148644029,0.544845391508808,1.03830113015928,0.9975 --0.036067005149107,0.134124498830403,0.298466667745288,1.8278754141499,0.980810947597099,0.577662154072698,0.973333333333333 --0.102115650942437,2.79339776395042,0.299893663714784,1.95451900972893,1.10337937060963,-0.077729353890696,1.04333333333333 -1.93120469907205,1.91922978717085,1.64934919063955,1.05194292835472,1.08725710516566,1.92804671190308,1.19666666666667 -1.17216692000295,-0.994498065708484,1.34488852824461,2.01649944497791,1.04326181158747,0.430966362132903,1.495 -1.50478134434434,0.674764757670005,0.270479643860426,1.80729714443765,0.984517003599139,0.947910279041118,1.48583333333333 --0.32447756323478,2.78147043841241,-0.0542259746338232,1.39975906987803,1.40562171335872,0.490169661102719,1.47916666666667 -0.611787689018058,2.69452948126065,1.11695102400597,1.73019909795039,1.03554702746766,0.363077170006328,1.64166666666667 -0.224381844552795,-0.180085283682587,-0.122044369887135,1.79895787589788,1.28723861781825,0.092093595415303,2.08166666666667 --0.15600244017736,0.637531508690898,0.191441724216816,1.80089475239208,1.4305082340063,0.379495930355482,2.24583333333333 -0.170294231183732,-2.98363593646593,-0.958862076727655,1.49053185376613,1.29418675821871,0.483637843909705,2.235 --0.168378339814012,-1.60005692018828,-0.685406487299474,0.77287256205625,1.41819949684074,0.760535921649991,2.14333333333333 --0.332198226277285,-1.89889171573429,-0.345503029077122,-0.684320091944414,1.36555972658932,-0.0807454788044471,1.97 -0.484330725396717,0.103805404140388,0.316114907955239,-1.65000920913775,0.79528335639325,1.31005756339001,1.67583333333333 --0.849223977248585,-0.616037354395132,-1.66119100858316,-2.29236260503996,1.2830134128901,-0.453133131420584,1.39166666666667 -0.779733908318917,1.86206781559005,2.17739087173163,-2.66242004628498,1.49216825216483,0.552892794964215,0.964166666666667 -0.176429525146773,3.57352431578028,-0.00678783990133525,-3.01581366648901,1.3036900649479,0.302770185432797,1.14083333333333 -0.209813641807273,1.54946590519603,0.237171000973945,-3.06138510933738,1.00541555559084,0.182717233084411,1.36833333333333 -0.913289518364309,2.20836253713924,-0.281339920395794,-2.35635843635703,0.797799167408586,-0.0134814213059684,1.1875 --0.305452079379961,2.95125058145442,0.633677505326887,-2.17117576262876,1.55325187596214,1.14440689385804,0.885 -1.35715302497158,1.27213291476562,1.80947746532547,-1.88515430844944,0.59591739791558,0.538310262477884,1.075 -0.909001870907844,0.589379404983248,0.417873406567765,-1.80802009619111,0.966640422200049,0.525924599467532,1.185 -1.33864117535325,4.21105623981151,1.14615638245868,-1.80545672040722,1.32017286313073,0.514741003688906,1.28583333333333 -1.30903892701593,3.42121529607758,1.99276526081144,-1.40693395554325,1.19342446402348,1.67415553364315,1.63416666666667 --0.184482837171174,0.527384407984556,0.633280441308216,-0.789678028067613,1.53553880831945,-0.132006996681117,1.95416666666667 --0.27616034250417,-0.61927413729552,-1.04914735496129,-0.678841283001987,1.93045262959055,0.138586696154078,2.64 --0.729801808639763,-2.20848852717162,0.443845509961648,-0.50293707599144,1.96108899537681,0.0660074419850947,2.49916666666667 --0.351031405737444,-2.8793163707233,-1.38211344352715,-1.2200151871827,1.89341167371011,0.420741182459347,2.33083333333333 -0.308690238022223,-1.37849792028706,-0.219386958255768,-1.86923117574833,2.32768363975069,0.253104755836544,2.8125 --0.326784574154658,-1.29083309630565,-1.47382392011093,-2.37207402093583,2.89657915064785,-0.0706454192074997,3.0225 --2.41406047980945,-5.34166374771797,-0.893328100636609,-4.00898429626125,2.94765260968033,-0.19938804029715,2.33666666666667 --0.0695735326093541,-5.64304653359247,-1.68865167773401,-6.78927742669629,2.27121189229451,0.40353894440832,1.57583333333333 -0.887962743600269,-1.11291399288302,0.256553071540225,-7.38777956287987,1.51079697777905,0.521203271316676,1.355 -0.867452325660111,1.2079239960249,1.10952390863008,-6.82627387472877,1.84129426623487,-0.131850930304821,1.54 -0.476061147341795,1.09440483473068,0.811257139643089,-6.32375179062433,1.7438993046174,0.21420521529325,1.35333333333333 -1.50419576014883,3.46950232002848,1.74769124489217,-5.14967657995794,1.09943075418935,1.09243781657525,1.20666666666667 -0.23875222685723,1.88749290105028,0.294544003978899,-5.24198281363874,1.06488679460952,0.814363140327244,1.29916666666667 -0.71908078234145,0.581883379886449,-0.00470312037339227,-5.2731452961163,1.35869961778621,1.00671947200276,1.32083333333333 -0.612876752062505,4.31088098112642,0.270216055867877,-5.35688015089181,1.808482920215,0.248144837932677,1.21833333333333 -0.868170999086999,3.67945337223046,0.763368041001854,-5.01331602639664,1.62573830754549,0.139755216326615,1.165 -0.332954624047943,5.39069350396372,1.4760179570178,-3.8583717615582,1.43713056935884,0.543132160259107,1.28916666666667 -0.754423906505394,1.84550053259423,1.28588887145258,-3.82412742007023,1.20960709704114,0.732201488669051,1.455 -0.30714957448123,1.32228341677089,-0.454753001423455,-3.04264136987695,2.15523099764292,-0.486539119141474,1.62833333333333 -0.331021454651477,0.795258492486283,-0.107518363730037,-3.27706176248711,1.47812145986013,1.31926374438048,1.68916666666667 -1.90648611188021,6.83302678941104,3.43265404542467,-1.48912755945565,1.81689588188028,0.00547801376488222,1.82083333333333 -0.0695540932417771,2.65422108930164,0.523474875747638,-1.55508752517517,1.64348889746737,0.146268048286905,2.025 -0.109078744927274,1.55137972534553,0.841241746722517,-1.08373816696428,2.09417118387707,0.315583974028982,2.39583333333333 -0.176087142252925,0.689026637387912,-0.253478971104869,-1.04830252575186,1.74672329679821,1.02826799849204,2.51833333333333 --0.223523184600538,-1.06104500560622,-0.32557479823106,-1.83556889548561,2.43889365797672,-0.355484967692531,2.545 -0.823953212108108,1.63806465616742,0.260984201530164,-1.32123030858776,2.13170928859383,0.1109942901506,2.73666666666667 -0.162148154893941,-1.41059880655629,-0.223439342796382,-1.33456540178685,1.97967584243823,0.410876242917207,3.39416666666667 -0.270271440997817,-1.64026638258838,-0.106994466072706,-2.02244659556521,2.08695819590496,0.823043452739099,3.76166666666667 --2.45506627646796,-9.38633690596544,-2.42908482403868,-4.11450889974486,2.18685285693714,0.454810187457052,3.17166666666667 -0.725263246697011,0.447779718695159,-0.581364138675895,-4.68247253795119,2.24457801055737,0.329093453847617,2.45916666666667 -0.691670179703237,2.95860941237575,1.49165889587266,-4.12815215303152,2.73177312906308,-0.0458462240362348,3.96333333333333 -0.087455199362239,0.481814242284287,1.66010977796418,-3.63474885475694,2.5461811454889,0.0694867193839652,4.1425 --0.52597979805546,0.684579276839344,-1.11288008264535,-3.7997506886847,1.8620010026976,-0.155474947278978,4.445 --0.0667060690821018,-0.430387424250085,0.864404597089902,-4.8506100805584,1.76426907185547,0.411548981016281,4.39416666666667 --1.39589608119115,-0.591312594467013,-1.59321072461853,-5.39500658255463,1.80780864212924,-0.328734841989656,3.39666666666667 -0.259209384759004,-3.36588162067889,-1.94892637881469,-6.95436036740711,1.35097406520286,1.22565801122008,3.55666666666667 --0.210999330841787,-3.89334609373518,0.230702569312029,-6.52555811781468,1.20624439072801,-0.414474617049413,3.62833333333333 -0.626937882375614,-3.98145114804964,-0.669146054121939,-7.01915334588534,1.40259224532642,0.162384921386284,2.75166666666667 -1.53523562744346,-1.39465955897978,-0.214518230372732,-7.7491341974519,1.07207134869514,0.162512233534833,2.32166666666667 -0.751643602632271,0.604436005531454,0.960855168582953,-7.69331559088613,0.818711639690939,0.249185617894485,2.16333333333333 -1.89965651466298,2.38574920515879,1.96989927447646,-6.95037293727017,0.719588994986875,0.03627250240578,2.20083333333333 -1.76884245259595,4.35513998183211,1.6718675180424,-4.89131331890343,1.0186480656893,-0.418045659668098,2.365 -1.19846576693806,4.78515398288937,1.73896193449923,-4.22084608942475,0.752689273057605,0.289762460530745,2.3575 -0.268183757919189,1.51790444212506,1.52187217481821,-3.20150733150422,1.24202757351757,0.0824951014845881,2.42166666666667 -1.27573604704384,3.35555519757702,1.45204840654662,-2.0391951131727,0.859589206549405,0.0137787903259654,2.63916666666667 -0.47772181971709,1.35583713264253,0.700693609718428,-2.29209347146798,0.796357825094951,0.642515920115007,2.8475 -1.00027454935952,1.12308782650445,0.514695395169497,-2.14306919626875,0.633721260057385,0.0780255168290123,2.31666666666667 -1.39618449179193,-0.268256022415699,0.700584498751027,-1.73164730309628,1.11968597431575,0.148829978415919,2.11916666666667 -0.856154666288148,0.58873406885516,0.611478709925677,-1.70767925156122,0.569555629278007,0.267269337773583,1.98083333333333 -1.84278816989831,-1.06842379727604,1.28957416743367,-1.79615064295803,0.413235586754457,0.966096626479142,1.975 -0.0710181743050953,1.58907598146845,0.46937498887371,-1.50970393605189,0.643704007482615,0.986766895011768,2.02583333333333 -0.544178039350697,-0.406613186032558,0.458668530616592,-1.54319272944753,0.515110298137511,0.823597780108453,1.95666666666667 -0.326252498049257,-0.27081756372661,0.121088067991423,-1.97833929505293,0.512470503989349,0.414074840589595,1.73 -1.60527893903395,-0.564336170392977,0.667996503001859,-1.76428598214096,0.577082638577231,0.340956595918969,1.55166666666667 -0.400089733961863,0.399036824619316,0.210244767069867,-1.48404825929714,0.651695382770434,1.03119223024523,1.56666666666667 --0.00923405229406171,-2.85473580948485,0.306036045002315,-0.597099427250385,0.822833289121228,-0.69454590783228,1.555 -1.38103238669055,1.06341789817995,0.805451617581753,-0.230139524927495,0.543445950840926,0.349986922535658,1.6625 -1.12296850240637,1.28016825044145,0.635879761713795,0.131989467962512,0.742278213849446,0.269108409843377,1.71083333333333 -0.119619758239367,-0.165882686162661,1.48497022417826,0.666162470989661,0.723288742447625,0.526727533975484,1.72916666666667 -1.39303192354464,-0.360525847763881,0.215328369000986,0.298843173317209,0.846886478045672,0.755119440372768,1.66583333333333 -0.632957496726931,1.36183262460486,1.03450145610054,0.82976579991896,0.951390551623099,0.14284529047128,1.78916666666667 -0.662890954428349,-0.509296492154334,0.287225645453646,0.918128346660069,1.11067497633348,0.0912625702449841,1.99583333333333 -1.16974375155604,0.991736088407464,1.08835575485762,1.70847815663251,0.747126528219777,-0.151532152934678,2.1175 -0.147636796945449,0.0894480675246427,0.729802796951617,2.38852503459816,1.12515121604408,-0.887903180681059,2.36083333333333 -0.594718841406348,-0.433412546841907,0.435507733355053,2.58456751489877,0.954440742925922,-0.599620737316234,2.43166666666667 -0.648556418838609,1.21610746067717,0.483145824664803,2.70146258453212,0.706096328815242,-0.000211044852767017,2.27083333333333 -0.371275472319951,-2.05768557449272,0.0307172983364126,2.32402517783675,0.68981474263472,0.707181201385354,2.15333333333333 -0.290621071858197,-0.18308572342292,0.348174213848893,2.3591491406425,1.18900024022039,0.643811660209636,2.0625 -0.0386311423858956,-3.38568166104113,0.0448378415075013,1.55321811579159,1.15781261965919,0.975901119153892,2.06083333333333 -0.543259065299651,-1.57282272332907,-0.223814218084158,0.585872361659085,0.881591584793018,0.661989228190922,2.04 --0.449797987498187,-3.29228562756691,-1.02958944171655,0.0188529915169511,0.746920163935716,0.124545046308658,1.93583333333333 --1.0721999274744,-4.15415888591548,-0.72366653829647,-0.984652080396813,1.17880502817185,-0.422453502447395,1.60666666666667 -0.578987771466473,-1.00602481436127,0.444640987769049,-1.43187566420426,0.642468134766361,1.17091488903764,1.46583333333333 -0.186237784950322,-0.66442724341087,0.23835810529124,-1.53413035516479,0.706817128653725,0.449265111453899,1.41083333333333 --0.094296526365099,-0.948322466532744,0.191069270167077,-1.79484578907977,0.522452473334845,0.517057926699119,1.20416666666667 -1.58045440035426,0.0194601258561136,0.809697596112301,-1.77846641300687,0.602598253534037,1.3431876614001,1.00583333333333 -0.443792178140484,3.12803429844956,0.73500852743723,-1.42356888960887,0.545632523303663,0.262452682090203,0.9425 -0.963756808801122,0.940311070772509,0.707295462775505,-1.40004855556901,0.451468035452685,0.947156162021317,0.814166666666667 -0.961834289805324,2.50744001254387,0.789754758182312,-1.43822664437084,0.517255443086917,-0.121215321477269,0.759166666666667 --0.152850242722309,0.105435071694586,-0.131793817732842,-1.20198472812643,0.776031730804494,-0.578598300432672,0.76 -0.746927848495943,1.73406107146735,0.274167588954583,-0.481535473952988,0.549186414734049,-0.155485118800142,0.75 -0.735887916916227,1.3123355567017,0.248790458001281,-0.290398853713782,0.429962192140199,-0.0378048268220361,0.765 -0.60315452962783,3.67777137658223,1.05361121647752,-0.0387475382106004,0.527004507861317,-0.136379011154791,0.7475 -0.655235582864236,0.988726763679892,0.774516204829638,0.0187502639078616,0.604650921766581,0.558152877745318,0.803333333333333 -0.619042543161527,2.05768034625504,1.07337788332063,1.08300213465463,0.418867443957627,-0.611731534598141,0.985 -0.692356232170312,0.478613456701055,0.290319051559095,1.34267496415367,0.638285893000212,-0.734857604996176,1.12166666666667 -0.695674209158938,2.18513192502132,0.886988356788493,2.03632003648897,0.465060733945677,0.112975557604306,1.29166666666667 --0.13629675445776,1.8974539165884,0.135120406197188,2.11518436914457,0.633489256988273,0.132064721144578,1.4525 -0.81057930107437,-0.612951072213264,-0.0302963924410733,1.53247355200392,0.358800531063608,0.211543220323367,1.505 -0.566764029506203,0.729755735170983,0.553798381808406,1.81584340460392,0.4670165101337,0.100092760247856,1.44916666666667 -0.345964234547694,1.30582943777858,0.455169317397576,1.47506426342147,0.479943846980646,0.458149336395959,1.43 -0.644676222993383,1.32063508322921,0.490597779543691,0.821486302600363,0.639577373281419,0.382261522586397,1.34083333333333 -1.11375907158339,2.29193665008899,1.37403448233181,1.25566766650866,0.354035677060871,0.565934012781487,1.31083333333333 -0.438904497893077,1.99307181315166,0.550585560601576,1.81153070016018,0.311284298049053,0.418645950112129,1.32666666666667 -0.664410644718487,0.766504390071532,0.859941188172456,2.39501585510294,0.529722418513767,-0.0762069019746487,1.32 -0.427418927173278,0.676124457374442,0.305518305326473,2.73927007830616,0.637455721560087,-0.00596963569262421,1.31916666666667 -0.277934657334754,1.63262818446404,1.291772942134,3.07773452723876,0.159781385827884,0.557067562033314,1.38083333333333 -1.2943997932079,3.19248604750266,0.97569626721122,3.4851745817619,0.343924004727647,0.633427177970351,1.38333333333333 -0.755759478875461,0.090134152423957,0.455419838506032,3.43281837706047,0.326053167946228,1.42684009263006,1.37666666666667 -0.697280372351372,1.96876920633719,0.875217173331294,3.52019982304159,0.253210857669828,1.55484528383764,1.38 -1.32709997507044,2.26035807575244,0.409786835756336,3.33742357921142,0.16637381786957,1.27371883751282,1.375 -0.88531202752381,0.704141207032023,0.863268913179809,2.99267688766003,0.364015771494142,1.1385166691809,1.38333333333333 -1.06308963239957,2.19016256015749,1.20885323014136,4.13603268696932,0.345159332822398,0.233115719368804,1.215 -0.462499468709495,0.942232527584793,0.468627159773291,3.9523792259597,0.40563830316529,1.3903283366539,1.18333333333333 -1.5732869366758,1.79686529253036,0.555612238267941,3.98699031238579,0.354868527607799,-0.0317664694631681,1.18666666666667 -0.949492130996873,1.11565401095891,0.86610968398179,4.05813225128964,0.346472007972931,0.536713178809926,1.27333333333333 -1.09910107519522,-0.0724456805704108,1.46539379241449,4.0902605206652,0.426583150896764,1.63045140566613,1.32666666666667 -0.122946014964555,0.944866024986311,-1.18051725516216,4.18893530278592,0.895080034395157,2.4924648145834,1.42 -0.417638062299034,1.88643854344883,1.29022726704488,3.76265129151977,0.430017441329778,-0.127674051530086,1.56833333333333 -0.589930840077784,-0.524245043384156,-0.433010731732338,3.06124307383124,0.51399085178172,1.42926910220591,1.63 -0.578441118484307,-0.298732183236552,0.217694988508697,2.8317993364584,0.405126845008397,0.111670170835929,1.61833333333333 -0.161646627345931,-1.78347312066506,-0.376035971588294,2.4519507805187,0.80339200516848,0.876092523896539,1.39833333333333 --0.172709114345992,-2.88228040821491,0.0107063410557657,1.19438147970055,0.759832841385943,-0.110245569841389,1.08166666666667 --0.149230347689411,-1.33187658020631,-0.671393919933962,0.206238608853937,0.412830520880281,0.0178951988777101,0.874166666666667 -1.00251695438243,-3.60760800779718,0.0742633694899268,-0.688298432615568,0.501298009956219,0.283579369250905,0.533333333333333 -0.166504093667356,-1.90349573045552,0.583238395877856,-0.832836684820563,0.250676424936813,1.02052713389944,0.433333333333333 -0.711646999732977,-1.61049328681082,0.340853686381706,-0.680085923833474,0.444635933952409,0.463508623871704,0.4375 -0.57708492580656,-0.675429124646257,0.33625691610996,-0.751883550010632,0.318994861044786,0.0281071882430552,0.435 -0.16804908125664,-0.33038731334284,-0.125306365705796,-1.39752979495165,0.487093955721107,-0.210277169959817,0.360833333333333 --0.0205252293212652,-0.42810961574645,-0.285066330985046,-1.79949697620765,0.711530121738591,0.661175029411204,0.3125 -0.593974742483908,1.97908039708489,0.752780433887438,-1.98259646486827,0.283011466756822,1.07110536496052,0.311666666666667 -0.963100368463358,3.77434088854915,1.45254639128268,-2.47480348336313,0.329327912571209,1.07303229820342,0.254166666666667 -0.477770530240775,2.48717621866388,0.681041328242827,-2.09159392019234,0.352657756486163,0.637122676239891,0.251666666666667 -1.06272365803494,0.843084076624677,1.01716103905153,-1.88739671956142,0.676433680105237,-0.152529403853073,0.250833333333333 -0.134490769038962,3.27115245186013,0.579110626934039,-2.28738981395816,0.786670661654654,0.640072087445695,0.2525 -0.890420982568628,2.16798602005923,0.664565005542386,-1.87907140900137,0.359229290844265,0.983931292021872,0.358333333333333 -0.788226274207716,2.18192499178394,0.614386847994297,-1.76049362247306,0.568063223871995,0.254465931034027,0.4875 diff --git a/docs/src/tutorials/estimation.md b/docs/src/tutorials/estimation.md index 7711bfb5..0da73df8 100644 --- a/docs/src/tutorials/estimation.md +++ b/docs/src/tutorials/estimation.md @@ -96,24 +96,28 @@ data = data(observables,:) ## Define bayesian model -Next we define the parameter priors using the Turing package. The `@model` macro of the Turing package allows us to define the prior distributions over the parameters and combine it with the (Kalman filter) loglikelihood of the model and parameters given the data with the help of the `get_loglikelihood` function. Inside the macro we first define the prior distribution and their mean and standard deviation. Note that the `μσ` parameter allows us to hand over the moments (`μ` and `σ`) of the distribution as parameters in case of the non-normal distributions (Gamma, Beta, InverseGamma). Last but not least, we define the loglikelihood and add it to the posterior loglikelihood with the help of the `@addlogprob!` macro. +Next we define the parameter priors using the Turing package. The `@model` macro of the Turing package allows us to define the prior distributions over the parameters and combine it with the (Kalman filter) loglikelihood of the model and parameters given the data with the help of the `get_loglikelihood` function. We define the prior distributions in an array and pass it on to the `arraydist` function inside the `@model` macro from the Turing package. It is also possible to define the prior distributions inside the macro but especially for reverse mode auto differentiation the `arraydist` function is substantially faster. When defining the prior distributions we can rely n the distribution implemented in the Distributions package. Note that the `μσ` parameter allows us to hand over the moments (`μ` and `σ`) of the distribution as parameters in case of the non-normal distributions (Gamma, Beta, InverseGamma), and we can also define upper and lower bounds truncating the distribution as third and fourth arguments to the distribution functions. Last but not least, we define the loglikelihood and add it to the posterior loglikelihood with the help of the `@addlogprob!` macro. ```@repl tutorial_2 import Turing import Turing: NUTS, sample, logpdf -Turing.@model function FS2000_loglikelihood_function(data, m) - alp ~ Beta(0.356, 0.02, μσ = true) - bet ~ Beta(0.993, 0.002, μσ = true) - gam ~ Normal(0.0085, 0.003) - mst ~ Normal(1.0002, 0.007) - rho ~ Beta(0.129, 0.223, μσ = true) - psi ~ Beta(0.65, 0.05, μσ = true) - del ~ Beta(0.01, 0.005, μσ = true) - z_e_a ~ InverseGamma(0.035449, Inf, μσ = true) - z_e_m ~ InverseGamma(0.008862, Inf, μσ = true) - # println([alp, bet, gam, mst, rho, psi, del, z_e_a, z_e_m]) - Turing.@addlogprob! get_loglikelihood(m, data, [alp, bet, gam, mst, rho, psi, del, z_e_a, z_e_m]) +prior_distributions = [ + Beta(0.356, 0.02, μσ = true), # alp + Beta(0.993, 0.002, μσ = true), # bet + Normal(0.0085, 0.003), # gam + Normal(1.0002, 0.007), # mst + Beta(0.129, 0.223, μσ = true), # rho + Beta(0.65, 0.05, μσ = true), # psi + Beta(0.01, 0.005, μσ = true), # del + InverseGamma(0.035449, Inf, μσ = true), # z_e_a + InverseGamma(0.008862, Inf, μσ = true) # z_e_m +] + +Turing.@model function FS2000_loglikelihood_function(data, model) + parameters ~ Turing.arraydist(prior_distributions) + + Turing.@addlogprob! get_loglikelihood(model, data, parameters) end ``` diff --git a/docs/src/tutorials/rbc.md b/docs/src/tutorials/rbc.md index 23bfd1a4..d8ae074c 100644 --- a/docs/src/tutorials/rbc.md +++ b/docs/src/tutorials/rbc.md @@ -122,9 +122,11 @@ end Parameter definitions are similar to assigning values in julia. Note that we have to write one parameter definition per line. +Given the equations and parameters, the package will first attempt to solve the system of nonlinear equations symbolically (including possible calibration equations - see next tutorial for an example). If an analytical solution is not possible, numerical solution methods are used to try and solve it. There is no guarantee that a solution can be found, but it is highly likely, given that a solution exists. The problem setup tries to incorporate parts of the structure of the problem, e.g. bounds on variables: if one equation contains `log(k)` it must be that `k > 0`. Nonetheless, the user can also provide useful information such as variable bounds or initial guesses. Bounds can be set by adding another expression to the parameter block e.g.: `c > 0`. Large values are typically a problem for numerical solvers. Therefore, providing a guess for these values will increase the speed of the solver. Guesses can be provided as a `Dict` after the model name and before the parameter definitions block, e.g.: `@parameters RBC guess = Dict(k => 10) begin ... end`. + ## Plot impulse response functions (IRFs) -Given the equations and parameters, we have everything to solve the model and do some analysis. A common output are IRFs for the exogenous shocks. Calling [`plot_irf`](@ref) (different names for the same function are also supported: [`plot_irfs`](@ref), or [`plot_IRF`](@ref)) will take care of this. Please note that you need to import the `StatsPlots` packages once before the first plot. In the background the package solves (symbolically in this simple case) for the non stochastic steady state (SS) and calculates the first order perturbation solution. +A useful output to analyze are IRFs for the exogenous shocks. Calling [`plot_irf`](@ref) (different names for the same function are also supported: [`plot_irfs`](@ref), or [`plot_IRF`](@ref)) will take care of this. Please note that you need to import the `StatsPlots` packages once before the first plot. In the background the package solves (symbolically in this simple case) for the non stochastic steady state (SS) and calculates the first order perturbation solution. ```@repl tutorial_1 import StatsPlots diff --git a/docs/src/tutorials/sw03.md b/docs/src/tutorials/sw03.md index 9e364d46..a57e8162 100644 --- a/docs/src/tutorials/sw03.md +++ b/docs/src/tutorials/sw03.md @@ -126,19 +126,19 @@ Next we need to add the parameters of the model. The macro [`@parameters`](@ref) end ``` -The block defining the parameters above has three different inputs. +The block defining the parameters above has two different inputs. First, there are simple parameter definition the same way you assign values (e.g. `Phi = .819`). Second, there are calibration equations where we treat the value of a parameter as unknown (e.g. `calibr_pi_obj`) and want an additional equation to hold (e.g. `1 = pi_obj[ss]`). The additional equation can contain variables in SS or parameters. Putting it together a calibration equation is defined by the unknown parameter, and the calibration equation, separated by `|` (e.g. `calibr_pi_obj | 1 = pi_obj[ss]` and also `1 = pi_obj[ss] | calibr_pi_obj`). - - Note that we have to write one parameter definition per line. +Given the equations and parameters, the package will first attempt to solve the system of nonlinear equations symbolically (including possible calibration equations). If an analytical solution is not possible, numerical solution methods are used to try and solve it. There is no guarantee that a solution can be found, but it is highly likely, given that a solution exists. The problem setup tries to incorporate parts of the structure of the problem, e.g. bounds on variables: if one equation contains `log(k)` it must be that `k > 0`. Nonetheless, the user can also provide useful information such as variable bounds or initial guesses. Bounds can be set by adding another expression to the parameter block e.g.: `c > 0`. Large values are typically a problem for numerical solvers. Therefore, providing a guess for these values will increase the speed of the solver. Guesses can be provided as a `Dict` after the model name and before the parameter definitions block, e.g.: `@parameters RBC guess = Dict(k => 10) begin ... end`. + ## Plot impulse response functions (IRFs) -Given the equations and parameters, we have everything to solve the model and do some analysis. A common output are IRFs for the exogenous shocks. Calling [`plot_irf`](@ref) (different names for the same function are also supported: [`plot_irfs`](@ref), or [`plot_IRF`](@ref)) will take care of this. Please note that you need to import the `StatsPlots` packages once before the first plot. In the background the package solves (numerically in this complex case) for the non stochastic steady state (SS) and calculates the first order perturbation solution. +A useful output to analyze are IRFs for the exogenous shocks. Calling [`plot_irf`](@ref) (different names for the same function are also supported: [`plot_irfs`](@ref), or [`plot_IRF`](@ref)) will take care of this. Please note that you need to import the `StatsPlots` packages once before the first plot. In the background the package solves (numerically in this complex case) for the non stochastic steady state (SS) and calculates the first order perturbation solution. ```@repl tutorial_2 import StatsPlots diff --git a/docs/src/unfinished_docs/todo.md b/docs/src/unfinished_docs/todo.md index 314007af..77182172 100644 --- a/docs/src/unfinished_docs/todo.md +++ b/docs/src/unfinished_docs/todo.md @@ -1,61 +1,64 @@ # Todo list ## High priority -- [ ] ss transition by entering new prameters at given periods -- [ ] add technical details about SS solver, obc solver, and other algorithms + +- [ ] ss transition by entering new parameters at given periods +- [ ] check downgrade tests +- [ ] figure out why PG and IS return basically the prior +- [ ] allow external functions to calculate the steady state (and hand it over via SS or get_loglikelihood function) - need to use the check function for implicit derivatives and cannot use it to get him a guess from which he can use internal solver going forward +- [ ] go through custom SS solver once more and try to find parameters and logic that achieves best results +- [ ] SS solver with less equations than variables +- [ ] improve docs: timing in first sentence seems off; have something more general in first sentence; why is the syntax user friendly? give an example; make the former and the latter a footnote +- [ ] write tests/docs/technical details for nonlinear obc, forecasting, (non-linear) solution algorithms, SS solver, obc solver, and other algorithms +- [ ] change docs to reflect that the output of irfs include aux vars and also the model info Base.show includes aux vars +- [ ] recheck function examples and docs (include output description) +- [ ] Docs: document outputs and associated functions to work with function +- [ ] write documentation/docstrings using copilot +- [ ] feedback: sell the sampler better (ESS vs dynare), more details on algorithm (SS solver) +- [ ] NaNMath pow does not work (is not substituted) +- [ ] check whether its possible to run parameters macro/block without rerunning model block +- [ ] eliminate possible log, ^ terms in parameters block equations - because of nonnegativity errors - [ ] throw error when equations appear more than once - [ ] plot multiple solutions or models - multioptions in one graph - [ ] make SS calc faster (func and optim, maybe inplace ops) - [ ] try preallocation tools for forwarddiff - [ ] add nonlinear shock decomposition - [ ] check obc once more +- [ ] rm obc vars from get_SS - [ ] check why warmup_iterations = 0 makes estimated shocks larger -- [ ] make inversion filter / higher order sols suitable for HMC (forward and reverse diff!!, currently only analytical pushforward, no implicitdiff) - [ ] use analytical derivatives also for shocks matching optim (and HMC - implicit diff) - [ ] info on when what filter is used and chosen options are overridden - [ ] check warnings, errors throughout. check suppress not interfering with pigeons -- [ ] rm obc vars from get_SS -- [ ] write tests/docs for nonlinear obc and forecasting - [ ] functions to reverse state_update (input: previous shock and current state, output previous state), find shocks corresponding to bringing one state to the next - [ ] cover nested case: min(50,a+b+max(c,10)) - [ ] add balanced growth path handling -- [ ] feedback: provide option for external SS guess, sell the sampler better (ESS vs dynare), more details on algorithm (SS solver) - [ ] higher order solutions: some kron matrix mults are later compressed. write custom compressed kron mult; check if sometimes dense mult is faster? (e.g. GNSS2010 seems dense at higher order) -- [ ] recheck function examples and docs (include output description) -- [ ] riccati with analytical derivatives (much faster if sparse) instead of implicit diff +- [ ] make inversion filter / higher order sols suitable for HMC (forward and reverse diff!!, currently only analytical pushforward, no implicitdiff) | analytic derivatives +- [ ] speed up sparse matrix calcs in implicit diff of higher order funcs +- [ ] compressed higher order derivatives and sparsity of jacobian - [ ] add user facing option to choose sylvester solver - [ ] autocorr and covariance with derivatives. return 3d array -- [ ] Docs: document outputs and associated functions to work with function - [ ] use ID for sparse output sylvester solvers (filed issue) - [ ] add pydsge and econpizza to overview - [ ] add for loop parser in @parameters -- [ ] compressed higher order derivatives and sparsity of jacobian - [ ] implement more multi country models - [ ] speed benchmarking (focus on ImplicitDiff part) -- [ ] write docs for (non-linear) solution algorithms -- [ ] have initial_state accept SS and SSS as arguments - [ ] for cond forecasting allow less shocks than conditions with a warning. should be svd then - [ ] have parser accept rss | (r[ss] - 1) * 400 = rss - [ ] when doing calibration with optimiser have better return values when he doesnt find a solution (probably NaN) - [ ] sampler returned negative std. investigate and come up with solution ensuring sampler can continue -- [ ] automatically adjust plots for different legend widhts and heights +- [ ] automatically adjust plots for different legend widths and heights - [ ] include weakdeps: https://pkgdocs.julialang.org/dev/creating-packages/#Weak-dependencies - [ ] have get_std take variables as an input - [ ] more informative errors when something goes wrong when writing a model -- [ ] initial state accept keyed array +- [ ] initial state accept keyed array, SS and SSS as arguments - [ ] plot_model_estimates with unconditional forecast at the end -- [ ] check if you can do analytic derivatives for higher order derivatives - [ ] kick out unused parameters from m.parameters - [ ] use cache for gradient calc in estimation (see DifferentiableStateSpaceModels) -- [ ] speed up sparse matrix calcs in implicit diff of higher order funcs -- [ ] improve docs: timing in first sentence seems off; have something more general in first sentence; why is the syntax user friendly? give an example; make the former and the latter a footnote -- [ ] streamline estimation part (dont do string matching... but rely on precomputed indices...) -- [ ] change docs to reflect that the output of irfs include aux vars and also the model info Base.show includes aux vars - [ ] write functions to debug (fix_SS.jl...) - [ ] model compression (speed up 2nd moment calc (derivatives) for large models; gradient loglikelihood is very slow due to large matmuls) -> model setup as maximisation problem (gEcon) -> HANK models - [ ] implement global solution methods - [ ] add more models -- [ ] write documentation/docstrings - [ ] use @assert for errors and @test_throws - [ ] print SS dependencies (get parameters (in function of parameters) into the dependencies), show SS solver @@ -66,10 +69,20 @@ - [ ] clean up printouts/reporting - [ ] clean up function inputs and harmonise AD and standard commands - [ ] figure out combinations for inputs (parameters and variables in different formats for get_irf for example) -- [ ] Find any SS by optimising over both SS guesses and parameter inputs - [ ] weed out SS solver and saved objects - +- [x] streamline estimation part (dont do string matching... but rely on precomputed indices...) +- [x] estimation: run auto-tune before and use solver treating parameters as given +- [x] use arraydist in tests and docs +- [x] include guess in docs +- [x] Find any SS by optimising over both SS guesses and parameter inputs +- [x] riccati with analytical derivatives (much faster if sparse) instead of implicit diff; done for ChainRules; ForwardDiff only feasible for smaller problems -> ID is fine there +- [x] log in parameters block is recognized as variable +- [x] add termination condition if relative change in ss solver is smaller than tol (relevant when values get very large) +- [x] provide option for external SS guess; provided in parameters macro +- [x] make it possible to run multiple ss solver parameter combination including starting points when solving a model +- [x] automatically put the combi first which solves it fastest the first time +- [x] write auto-tune in case he cant find SS (add it to the warning when he cant find the SS) - [x] nonlinear conditional forecasts for higher order and obc - [x] for cond forecasting and kalman, get rid of observables input and use axis key of data input - [x] fix translate dynare mod file from file written using write to dynare file (see test models): added retranslation to test diff --git a/models/Gali_2015_chapter_3_obc.jl b/models/Gali_2015_chapter_3_obc.jl index e45d7806..09212af7 100644 --- a/models/Gali_2015_chapter_3_obc.jl +++ b/models/Gali_2015_chapter_3_obc.jl @@ -83,5 +83,5 @@ end std_nu = .0025 - R > 1.000001 + R > 1.0001 end diff --git a/models/Guerrieri_Iacoviello_2017.jl b/models/Guerrieri_Iacoviello_2017.jl index 3f9f0941..f8b5412e 100644 --- a/models/Guerrieri_Iacoviello_2017.jl +++ b/models/Guerrieri_Iacoviello_2017.jl @@ -51,7 +51,7 @@ log(aj[0]) = RHO_J * log(aj[-1]) + z_j[0] - z_j[0] = RHO_J2 * z_j[-1] + eps_j[x] + z_j[0] = RHO_J2 * z_j[-1] + STD_J * eps_j[x] log(ak[0]) = RHO_K * log(ak[-1]) + STD_K * eps_k[x] diff --git a/models/SW07.jl b/models/SW07.jl deleted file mode 100644 index 8f16da79..00000000 --- a/models/SW07.jl +++ /dev/null @@ -1,156 +0,0 @@ -@model SW07 begin - a[0] = calfa * rkf[0] + (1 - calfa) * (wf[0]) - - zcapf[0] = (1 / (czcap / (1 - czcap))) * rkf[0] - - rkf[0] = wf[0] + labf[0] - kf[0] - - kf[0] = kpf[-1] + zcapf[0] - - invef[0] = (1 / (1 + cbetabar * cgamma)) * (invef[-1] + cbetabar * cgamma * invef[1] + (1 / (cgamma ^ 2 * csadjcost)) * pkf[0]) + qs[0] - - pkf[0] = - rrf[0] + (1 / ((1 - chabb / cgamma) / (csigma * (1 + chabb / cgamma)))) * b[0] + (crk / (crk + (1 - ctou))) * rkf[1] + ((1 - ctou) / (crk + (1 - ctou))) * pkf[1] - - cf[0] = (chabb / cgamma) / (1 + chabb / cgamma) * cf[-1] + (1 / (1 + chabb / cgamma)) * cf[1] + ((csigma - 1) * cwhlc / (csigma * (1 + chabb / cgamma))) * (labf[0] - labf[1]) - (1 - chabb / cgamma) / (csigma * (1 + chabb / cgamma)) * (rrf[0]) + b[0] - - yf[0] = ccy * cf[0] + ciy * invef[0] + g[0] + crkky * zcapf[0] - - yf[0] = cfc * (calfa * kf[0] + (1 - calfa) * labf[0] + a[0]) - - wf[0] = csigl * labf[0] + (1 / (1 - chabb / cgamma)) * cf[0] - (chabb / cgamma) / (1 - chabb / cgamma) * cf[-1] - - kpf[0] = (1 - cikbar) * kpf[-1] + (cikbar) * invef[0] + (cikbar) * (cgamma ^ 2 * csadjcost) * qs[0] - - mc[0] = calfa * rk[0] + (1 - calfa) * (w[0]) - a[0] - - zcap[0] = (1 / (czcap / (1 - czcap))) * rk[0] - - rk[0] = w[0] + lab[0] - k[0] - - k[0] = kp[-1] + zcap[0] - - inve[0] = (1 / (1 + cbetabar * cgamma)) * (inve[-1] + cbetabar * cgamma * inve[1] + (1 / (cgamma ^ 2 * csadjcost)) * pk[0]) + qs[0] - - pk[0] = - r[0] + pinf[1] + (1 / ((1 - chabb / cgamma) / (csigma * (1 + chabb / cgamma)))) * b[0] + (crk / (crk + (1 - ctou))) * rk[1] + ((1 - ctou) / (crk + (1 - ctou))) * pk[1] - - c[0] = (chabb / cgamma) / (1 + chabb / cgamma) * c[-1] + (1 / (1 + chabb / cgamma)) * c[1] + ((csigma - 1) * cwhlc / (csigma * (1 + chabb / cgamma))) * (lab[0] - lab[1]) - (1 - chabb / cgamma) / (csigma * (1 + chabb / cgamma)) * (r[0] - pinf[1]) + b[0] - - y[0] = ccy * c[0] + ciy * inve[0] + g[0] + crkky * zcap[0] - - y[0] = cfc * (calfa * k[0] + (1 - calfa) * lab[0] + a[0]) - - pinf[0] = (1 / (1 + cbetabar * cgamma * cindp)) * (cbetabar * cgamma * pinf[1] + cindp * pinf[-1] + ((1 - cprobp) * (1 - cbetabar * cgamma * cprobp) / cprobp) / ((cfc - 1) * curvp + 1) * (mc[0])) + spinf[0] - - w[0] = (1 / (1 + cbetabar * cgamma)) * w[-1] + (cbetabar * cgamma / (1 + cbetabar * cgamma)) * w[1] + (cindw / (1 + cbetabar * cgamma)) * pinf[-1] - (1 + cbetabar * cgamma * cindw) / (1 + cbetabar * cgamma) * pinf[0] + (cbetabar * cgamma) / (1 + cbetabar * cgamma) * pinf[1] + (1 - cprobw) * (1 - cbetabar * cgamma * cprobw) / ((1 + cbetabar * cgamma) * cprobw) * (1 / ((clandaw - 1) * curvw + 1)) * (csigl * lab[0] + (1 / (1 - chabb / cgamma)) * c[0] - ((chabb / cgamma) / (1 - chabb / cgamma)) * c[-1] - w[0]) + sw[0] - - r[0] = crpi * (1 - crr) * pinf[0] + cry * (1 - crr) * (y[0] - yf[0]) + crdy * (y[0] - yf[0] - y[-1] + yf[-1]) + crr * r[-1] + ms[0] - - a[0] = crhoa * a[-1] + z_ea * ea[x] - - b[0] = crhob * b[-1] + z_eb * eb[x] - - g[0] = crhog * g[-1] + z_eg * eg[x] + cgy * z_ea * ea[x] - - qs[0] = crhoqs * qs[-1] + z_eqs * eqs[x] - - ms[0] = crhoms * ms[-1] + z_em * em[x] - - spinf[0] = crhopinf * spinf[-1] + epinfma[0] - cmap * epinfma[-1] - - epinfma[0] = z_epinf * epinf[x] - - sw[0] = crhow * sw[-1] + ewma[0] - cmaw * ewma[-1] - - ewma[0] = z_ew * ew[x] - - kp[0] = (1 - cikbar) * kp[-1] + cikbar * inve[0] + cikbar * cgamma ^ 2 * csadjcost * qs[0] - - dy[0] = y[0] - y[-1] + ctrend - - dc[0] = c[0] - c[-1] + ctrend - - dinve[0] = inve[0] - inve[-1] + ctrend - - dw[0] = w[0] - w[-1] + ctrend - - pinfobs[0] = (pinf[0]) + constepinf - - robs[0] = (r[0]) + conster - - labobs[0] = lab[0] + constelab - -end - - -@parameters SW07 begin - ctou=.025 - clandaw=1.5 - cg=0.18 - curvp=10 - curvw=10 - - calfa=.24 - csigma=1.5 - cfc=1.5 - cgy=0.51 - - csadjcost= 6.0144 - chabb= 0.6361 - cprobw= 0.8087 - csigl= 1.9423 - cprobp= 0.6 - cindw= 0.3243 - cindp= 0.47 - czcap= 0.2696 - crpi= 1.488 - crr= 0.8762 - cry= 0.0593 - crdy= 0.2347 - - crhoa= 0.9977 - crhob= 0.5799 - crhog= 0.9957 - crhols= 0.9928 - crhoqs= 0.7165 - crhoas=1 - crhoms=0 - crhopinf=0 - crhow=0 - cmap = 0 - cmaw = 0 - - clandap=cfc - cbetabar=cbeta*cgamma^(-csigma) - cr=cpie/(cbeta*cgamma^(-csigma)) - crk=(cbeta^(-1))*(cgamma^csigma) - (1-ctou) - cw = (calfa^calfa*(1-calfa)^(1-calfa)/(clandap*crk^calfa))^(1/(1-calfa)) - cikbar=(1-(1-ctou)/cgamma) - cik=(1-(1-ctou)/cgamma)*cgamma - clk=((1-calfa)/calfa)*(crk/cw) - cky=cfc*(clk)^(calfa-1) - ciy=cik*cky - ccy=1-cg-cik*cky - crkky=crk*cky - cwhlc=(1/clandaw)*(1-calfa)/calfa*crk*cky/ccy - cwly=1-crk*cky - - conster=(cr-1)*100 - ctrend=(1.004-1)*100 - constepinf=(1.005-1)*100 - - cpie=1+constepinf/100 - cgamma=1+ctrend/100 - - cbeta=1/(1+constebeta/100) - constebeta = 100 / .9995 - 100 - - constelab=0 - - z_ea = 0.4618 - z_eb = 1.8513 - z_eg = 0.6090 - z_eqs = 0.6017 - z_em = 0.2397 - z_epinf = 0.1455 - z_ew = 0.2089 -end \ No newline at end of file diff --git a/models/SW03.jl b/models/Smets_Wouters_2003.jl similarity index 99% rename from models/SW03.jl rename to models/Smets_Wouters_2003.jl index 542c4e58..55751a9c 100644 --- a/models/SW03.jl +++ b/models/Smets_Wouters_2003.jl @@ -1,4 +1,4 @@ -@model SW03 begin +@model Smets_Wouters_2003 begin -q[0] + beta * ((1 - tau) * q[1] + epsilon_b[1] * (r_k[1] * z[1] - psi^-1 * r_k[ss] * (-1 + exp(psi * (-1 + z[1])))) * (C[1] - h * C[0])^(-sigma_c)) -q_f[0] + beta * ((1 - tau) * q_f[1] + epsilon_b[1] * (r_k_f[1] * z_f[1] - psi^-1 * r_k_f[ss] * (-1 + exp(psi * (-1 + z_f[1])))) * (C_f[1] - h * C_f[0])^(-sigma_c)) @@ -112,7 +112,7 @@ end -@parameters SW03 begin +@parameters Smets_Wouters_2003 begin lambda_p = 0.368 G_bar = 0.362 lambda_w = 0.5 diff --git a/models/SW03_obc.jl b/models/Smets_Wouters_2003_obc.jl similarity index 99% rename from models/SW03_obc.jl rename to models/Smets_Wouters_2003_obc.jl index e27ab5ff..6ecf5ea0 100644 --- a/models/SW03_obc.jl +++ b/models/Smets_Wouters_2003_obc.jl @@ -1,4 +1,4 @@ -@model SW03_obc begin +@model Smets_Wouters_2003_obc begin -q[0] + beta * ((1 - tau) * q[1] + epsilon_b[1] * (r_k[1] * z[1] - psi^-1 * r_k[ss] * (-1 + exp(psi * (-1 + z[1])))) * (C[1] - h * C[0])^(-sigma_c)) -q_f[0] + beta * ((1 - tau) * q_f[1] + epsilon_b[1] * (r_k_f[1] * z_f[1] - psi^-1 * r_k_f[ss] * (-1 + exp(psi * (-1 + z_f[1])))) * (C_f[1] - h * C_f[0])^(-sigma_c)) @@ -112,7 +112,7 @@ end -@parameters SW03_obc begin +@parameters Smets_Wouters_2003_obc begin R̄ = 0.0 # effective lower bound lambda_p = 0.368 diff --git a/models/Smets_Wouters_2007.jl b/models/Smets_Wouters_2007.jl new file mode 100644 index 00000000..bf083adf --- /dev/null +++ b/models/Smets_Wouters_2007.jl @@ -0,0 +1,243 @@ +@model Smets_Wouters_2007 begin + y[0] = c[0] + inve[0] + y[ss] * gy[0] + afunc[0] * kp[-1] / cgamma + + y[0] * (pdot[0] + curvP) / (1 + curvP) = a[0] * k[0] ^ calfa * lab[0] ^ (1 - calfa) - (cfc - 1) * y[ss] + + k[0] = kp[-1] * zcap[0] / cgamma + + kp[0] = inve[0] * qs[0] * (1 - Sfunc[0]) + kp[-1] * (1 - ctou) / cgamma + + pdot[0] = (1 - cprobp) * (Pratio[0] / dp[0]) ^ (( - cfc) * (1 + curvP) / (cfc - 1)) + pdot[-1] * cprobp * (dp[-1] / dp[0] * pinf[-1] ^ cindp * pinf[ss] ^ (1 - cindp) / pinf[0]) ^ (( - cfc) * (1 + curvP) / (cfc - 1)) + + wdot[0] = (1 - cprobw) * (wnew[0] / dw[0]) ^ (( - clandaw) * (1 + curvW) / (clandaw - 1)) + wdot[-1] * cprobw * (dw[-1] / dw[0] * pinf[-1] ^ cindw * pinf[ss] ^ (1 - cindw) / pinf[0]) ^ (( - clandaw) * (1 + curvW) / (clandaw - 1)) + + 1 = (1 - cprobp) * (Pratio[0] / dp[0]) ^ (( - (1 + curvp * (1 - cfc))) / (cfc - 1)) + cprobp * (dp[-1] / dp[0] * pinf[-1] ^ cindp * pinf[ss] ^ (1 - cindp) / pinf[0]) ^ (( - (1 + curvp * (1 - cfc))) / (cfc - 1)) + + 1 = (1 - cprobw) * (wnew[0] / dw[0]) ^ (( - (1 + curvw * (1 - clandaw))) / (clandaw - 1)) + cprobw * (dw[-1] / dw[0] * pinf[-1] ^ cindw * pinf[ss] ^ (1 - cindw) / pinf[0]) ^ (( - (1 + curvw * (1 - clandaw))) / (clandaw - 1)) + + 1 = dp[0] * (1 + pdotl[0] * curvP) / (1 + curvP) + + w[0] = dw[0] * (1 + curvW * wdotl[0]) / (1 + curvW) + + pdotl[0] = (1 - cprobp) * Pratio[0] / dp[0] + cprobp * dp[-1] / dp[0] * pinf[-1] ^ cindp * pinf[ss] ^ (1 - cindp) / pinf[0] * pdotl[-1] + + wdotl[0] = (1 - cprobw) * wnew[0] / dw[0] + cprobw * dw[-1] / dw[0] * pinf[-1] ^ cindw * pinf[ss] ^ (1 - cindw) / pinf[0] * wdotl[-1] + + xi[0] = exp((csigma - 1) / (1 + csigl) * (lab[0] * (curvW + wdot[0]) / (1 + curvW)) ^ (1 + csigl)) * (c[0] - c[-1] * chabb / cgamma) ^ (-csigma) + + 1 = qs[0] * pk[0] * (1 - Sfunc[0] - cgamma * inve[0] * SfuncD[0] / inve[-1]) + SfuncD[1] * xi[1] / xi[0] * qsaux[0] * pk[1] * (cgamma * inve[1] / inve[0]) ^ 2 * cbetabar + + xi[0] = xi[1] * b[0] * r[0] * cbetabar / pinf[1] + + rk[0] = afuncD[0] + + pk[0] = (rk[1] * zcap[1] - afunc[1] + (1 - ctou) * pk[1]) * xi[1] * cbetabar / xi[0] + + k[0] = lab[0] * w[0] * calfa / (1 - calfa) / rk[0] + + mc[0] = w[0] ^ (1 - calfa) * rk[0] ^ calfa / (a[0] * calfa ^ calfa * (1 - calfa) ^ (1 - calfa)) + + wnew[0] * gamw1[0] * (1 + curvw * (1 - clandaw)) / (1 + curvW) = clandaw * gamw2[0] + gamw3[0] * curvW * (clandaw - 1) / (1 + curvW) * wnew[0] ^ (1 + clandaw * (1 + curvW) / (clandaw - 1)) + + gamw1[0] = lab[0] * dw[0] ^ (clandaw * (1 + curvW) / (clandaw - 1)) + gamw1[1] * (pinf[ss] ^ (1 - cindw) * pinf[0] ^ cindw / pinf[1]) ^ (( - (1 + curvw * (1 - clandaw))) / (clandaw - 1)) * xi[1] / xi[0] * cgamma * cprobw * cbetabar + + gamw2[0] = (c[0] - c[-1] * chabb / cgamma) * lab[0] * sw[0] * dw[0] ^ (clandaw * (1 + curvW) / (clandaw - 1)) * (lab[0] * (curvW + wdot[0]) / (1 + curvW)) ^ csigl + gamw2[1] * (pinf[ss] ^ (1 - cindw) * pinf[0] ^ cindw / pinf[1]) ^ (( - clandaw) * (1 + curvW) / (clandaw - 1)) * xi[1] / xi[0] * cgamma * cprobw * cbetabar + + gamw3[0] = lab[0] + gamw3[1] * pinf[ss] ^ (1 - cindw) * pinf[0] ^ cindw / pinf[1] * xi[1] / xi[0] * cgamma * cprobw * cbetabar + + Pratio[0] * gam1[0] * (1 + curvp * (1 - cfc)) / (1 + curvP) = cfc * gam2[0] + gam3[0] * (cfc - 1) * curvP / (1 + curvP) * Pratio[0] ^ (1 + cfc * (1 + curvP) / (cfc - 1)) + + gam1[0] = y[0] * dp[0] ^ (cfc * (1 + curvP) / (cfc - 1)) + gam1[1] * xi[1] / xi[0] * cgamma * cprobp * cbetabar * (pinf[ss] ^ (1 - cindp) * pinf[0] ^ cindp / pinf[1]) ^ (( - (1 + curvp * (1 - cfc))) / (cfc - 1)) + + gam2[0] = y[0] * mc[0] * spinf[0] * dp[0] ^ (cfc * (1 + curvP) / (cfc - 1)) + gam2[1] * xi[1] / xi[0] * cgamma * cprobp * cbetabar * (pinf[ss] ^ (1 - cindp) * pinf[0] ^ cindp / pinf[1]) ^ (( - cfc) * (1 + curvP) / (cfc - 1)) + + gam3[0] = y[0] + gam3[1] * pinf[ss] ^ (1 - cindp) * pinf[0] ^ cindp / pinf[1] * xi[1] / xi[0] * cgamma * cprobp * cbetabar + + qsaux[0] = qs[1] + + # r[0] = max(1.00025,r[ss] ^ (1 - crr) * r[-1] ^ crr * (pinf[0] / pinfss) ^ ((1 - crr) * crpi) * (y[0] / yflex[0]) ^ ((1 - crr) * cry) * (y[0] / yflex[0] / (y[-1] / yflex[-1])) ^ crdy * ms[0]) + + r[0] = r[ss] ^ (1 - crr) * r[-1] ^ crr * (pinf[0] / cpie) ^ ((1 - crr) * crpi) * (y[0] / yflex[0]) ^ ((1 - crr) * cry) * (y[0] / yflex[0] / (y[-1] / yflex[-1])) ^ crdy * ms[0] + + afunc[0] = rk[ss] * 1 / cZcap * (exp(cZcap * (zcap[0] - 1)) - 1) + + afuncD[0] = rk[ss] * exp(cZcap * (zcap[0] - 1)) + + Sfunc[0] = csadjcost / 2 * (cgamma * inve[0] / inve[-1] - cgamma) ^ 2 + + SfuncD[0] = csadjcost * (cgamma * inve[0] / inve[-1] - cgamma) + + a[0] = 1 - crhoa + crhoa * a[-1] + z_ea * ea[x] + + b[0] = 1 - crhob + crhob * b[-1] + z_eb * eb[x] + + gy[0] - cg = crhog * (gy[-1] - cg) + z_eg * eg[x] + z_ea * ea[x] * cgy + + qs[0] = 1 - crhoqs + crhoqs * qs[-1] + z_eqs * eqs[x] + + ms[0] = 1 - crhoms + crhoms * ms[-1] + z_em * em[x] + + spinf[0] = 1 - crhopinf + crhopinf * spinf[-1] + epinfma[0] - cmap * epinfma[-1] + + epinfma[0] = z_epinf * epinf[x] + + sw[0] = 1 - crhow + crhow * sw[-1] + ewma[0] - cmaw * ewma[-1] + + ewma[0] = z_ew * ew[x] + + yflex[0] = cflex[0] + inveflex[0] + gy[0] * yflex[ss] + afuncflex[0] * kpflex[-1] / cgamma + + yflex[0] = a[0] * kflex[0] ^ calfa * labflex[0] ^ (1 - calfa) - (cfc - 1) * yflex[ss] + + kflex[0] = kpflex[-1] * zcapflex[0] / cgamma + + kpflex[0] = inveflex[0] * qs[0] * (1 - Sfuncflex[0]) + kpflex[-1] * (1 - ctou) / cgamma + + xiflex[0] = exp((csigma - 1) / (1 + csigl) * labflex[0] ^ (1 + csigl)) * (cflex[0] - cflex[-1] * chabb / cgamma) ^ (-csigma) + + 1 = qs[0] * pkflex[0] * (1 - Sfuncflex[0] - cgamma * inveflex[0] * SfuncDflex[0] / inveflex[-1]) + SfuncDflex[1] * qsaux[0] * xiflex[1] / xiflex[0] * pkflex[1] * (cgamma * inveflex[1] / inveflex[0]) ^ 2 * cbetabar + + xiflex[0] = xiflex[1] * b[0] * rrflex[0] * cbetabar + + rkflex[0] = afuncDflex[0] + + pkflex[0] = (rkflex[1] * zcapflex[1] - afuncflex[1] + (1 - ctou) * pkflex[1]) * xiflex[1] * cbetabar / xiflex[0] + + kflex[0] = labflex[0] * calfa / (1 - calfa) * wflex[0] / rkflex[0] + + mcflex = wflex[0] ^ (1 - calfa) * rkflex[0] ^ calfa / (a[0] * calfa ^ calfa * (1 - calfa) ^ (1 - calfa)) + + wflex[0] * (1 + curvw * (1 - clandaw)) / (1 + curvW) = sw[ss] * (labflex[0] ^ csigl * clandaw * (cflex[0] - cflex[-1] * chabb / cgamma) + wflex[0] * curvW * (clandaw - 1) / (1 + curvW)) + + # (1 + curvp * (1 - cfc)) / (1 + curvP) = spinf[ss] * cfc * mcflex + spinf[ss] * (cfc - 1) * curvP / (1 + curvP) + + afuncflex[0] = rkflex[ss] * 1 / cZcap * (exp(cZcap * (zcapflex[0] - 1)) - 1) + + afuncDflex[0] = rkflex[ss] * exp(cZcap * (zcapflex[0] - 1)) + + Sfuncflex[0] = csadjcost / 2 * (cgamma * inveflex[0] / inveflex[-1] - cgamma) ^ 2 + + SfuncDflex[0] = csadjcost * (cgamma * inveflex[0] / inveflex[-1] - cgamma) + + ygap[0] = 100 * log(y[0] / yflex[0]) + + dy[0] = ctrend + 100 * (y[0] / y[-1] - 1) + + dc[0] = ctrend + 100 * (c[0] / c[-1] - 1) + + dinve[0] = ctrend + 100 * (inve[0] / inve[-1] - 1) + + pinfobs[0] = 100 * (pinf[0] - pinf[ss]) + constepinf + + robs[0] = 100 * (r[0] - 1) + + dwobs[0] = ctrend + 100 * (w[0] / w[-1] - 1) + + labobs[0] = 100 * (lab[0] / lab[ss] - 1) + +end + + +@parameters Smets_Wouters_2007 begin + cgamma = 1 + ctrend / 100 # gross growth rate + + cbeta = 1 / (1 + constebeta / 100) # discount factor + + cZcap = czcap / (1 - czcap) + + curvP = curvp * (1 - clandap) / clandap + + curvW = curvw * (1 - clandaw) / clandaw + + clandap = cfc # fixed cost share/gross price markup + + cbetabar= cbeta * cgamma ^ (-csigma) # growth-adjusted discount factor in Euler equation + + mcflex = mc[ss] | mcflex + + pinf[ss] = 1 + constepinf / 100 | cpie + + ctou = .025 + + clandaw = 1.5 + + cg = 0.18 + + curvp = 10 + + curvw = 10 + + calfa = .24 + + csigma = 1.5 + + cfc = 1.5 + + cgy = 0.51 + + csadjcost = 6.0144 + + chabb = 0.6361 + + cprobw = 0.8087 + + csigl = 1.9423 + + cprobp = 0.6 + + cindw = 0.3243 + + cindp = 0.47 + + czcap = 0.2696 + + crpi = 1.488 + + crr = 0.8762 + + cry = 0.0593 + + crdy = 0.2347 + + crhoa = 0.9977 + + crhob = 0.5799 + + crhog = 0.9957 + + crhoqs = 0.7165 + + crhoms = 0 + + crhopinf = 0 + + crhow = 0 + + cmap = 0 + + cmaw = 0 + + constelab = 0 + + constepinf = 0.7 + + constebeta = 0.7420 + + ctrend = 0.3982 + + z_ea = 0.4618 + + z_eb = 1.8513 + + z_eg = 0.6090 + + z_em = 0.2397 + + z_ew = 0.2089 + + z_eqs = 0.6017 + + z_epinf = 0.1455 + + 1e-6 > ygap > -1e-6 +end diff --git a/models/Smets_Wouters_2007_linear.jl b/models/Smets_Wouters_2007_linear.jl new file mode 100644 index 00000000..f3853d77 --- /dev/null +++ b/models/Smets_Wouters_2007_linear.jl @@ -0,0 +1,203 @@ +@model Smets_Wouters_2007_linear begin + a[0] = calfa * rkf[0] + (1 - calfa) * wf[0] + + zcapf[0] = rkf[0] * 1 / (czcap / (1 - czcap)) + + rkf[0] = wf[0] + labf[0] - kf[0] + + kf[0] = zcapf[0] + kpf[-1] + + invef[0] = qs[0] + 1 / (1 + cgamma * cbetabar) * (pkf[0] * 1 / (csadjcost * cgamma ^ 2) + invef[-1] + invef[1] * cgamma * cbetabar) + + pkf[0] = b[0] * (1 / ((1 - chabb / cgamma) / (csigma * (1 + chabb / cgamma)))) - rrf[0] + rkf[1] * (crk / (crk + (1 - ctou))) + pkf[1] * ((1 - ctou) / (crk + (1 - ctou))) + + cf[0] = b[0] + cf[-1] * chabb / cgamma / (1 + chabb / cgamma) + cf[1] * 1 / (1 + chabb / cgamma) + (labf[0] - labf[1]) * ((csigma - 1) * cwhlc / (csigma *(1 + chabb / cgamma))) - rrf[0] * (1 - chabb / cgamma) / (csigma * (1 + chabb / cgamma)) + + yf[0] = g[0] + cf[0] * ccy + invef[0] * ciy + zcapf[0] * crkky + + yf[0] = cfc * (a[0] + calfa * kf[0] + (1 - calfa) * labf[0]) + + wf[0] = labf[0] * csigl + cf[0] * 1 / (1 - chabb / cgamma) - cf[-1] * chabb / cgamma / (1 - chabb / cgamma) + + kpf[0] = kpf[-1] * (1 - cikbar) + invef[0] * cikbar + qs[0] * csadjcost * cgamma ^ 2 * cikbar + + mc[0] = calfa * rk[0] + (1 - calfa) * w[0] - a[0] + + zcap[0] = 1 / (czcap / (1 - czcap)) * rk[0] + + rk[0] = w[0] + lab[0] - k[0] + + k[0] = zcap[0] + kp[-1] + + inve[0] = qs[0] + 1 / (1 + cgamma * cbetabar) * (pk[0] * 1 / (csadjcost * cgamma ^ 2) + inve[-1] + inve[1] * cgamma * cbetabar) + + pk[0] = pinf[1] - r[0] + b[0] * 1 / ((1 - chabb / cgamma) / (csigma * (1 + chabb / cgamma))) + rk[1] * (crk / (crk + (1 - ctou))) + pk[1] * ((1 - ctou) / (crk + (1 - ctou))) + + c[0] = b[0] + c[-1] * chabb / cgamma / (1 + chabb / cgamma) + c[1] * 1 / (1 + chabb / cgamma) + + (lab[0] - lab[1]) * ((csigma - 1) * cwhlc / (csigma * (1 + chabb / cgamma))) - (r[0] - pinf[1]) * (1 - chabb / cgamma) / (csigma * (1 + chabb / cgamma)) + + y[0] = g[0] + c[0] * ccy + inve[0] * ciy + zcap[0] * crkky + + y[0] = cfc * (a[0] + calfa * k[0] + (1 - calfa) * lab[0]) + + pinf[0] = spinf[0] + 1 / (1 + cindp * cgamma * cbetabar) * (cindp * pinf[-1] + pinf[1] * cgamma * cbetabar + mc[0] * (1 - cprobp) * (1 - cprobp * cgamma * cbetabar) / cprobp / (1 + (cfc - 1) * curvp)) + + w[0] = sw[0] + w[-1] * 1 / (1 + cgamma * cbetabar) + w[1] * cgamma * cbetabar / (1 + cgamma * cbetabar) + pinf[-1] * cindw / (1 + cgamma * cbetabar) - pinf[0] * (1 + cindw * cgamma * cbetabar) / (1 + cgamma * cbetabar) + pinf[1] * cgamma * cbetabar / (1 + cgamma * cbetabar) + (csigl * lab[0] + c[0] * 1 / (1 - chabb / cgamma) - c[-1] * chabb / cgamma / (1 - chabb / cgamma) - w[0]) * 1 / (1 + (clandaw - 1) * curvw) * (1 - cprobw) * (1 - cprobw * cgamma * cbetabar) / (cprobw * (1 + cgamma * cbetabar)) + + r[0] = pinf[0] * crpi * (1 - crr) + (1 - crr) * cry * (y[0] - yf[0]) + crdy * (y[0] - yf[0] - y[-1] + yf[-1]) + crr * r[-1] + ms[0] + + a[0] = crhoa * a[-1] + z_ea * ea[x] + + b[0] = crhob * b[-1] + z_eb * eb[x] + + g[0] = crhog * g[-1] + z_eg * eg[x] + z_ea * ea[x] * cgy + + qs[0] = crhoqs * qs[-1] + z_eqs * eqs[x] + + ms[0] = crhoms * ms[-1] + z_em * em[x] + + spinf[0] = crhopinf * spinf[-1] + epinfma[0] - cmap * epinfma[-1] + + epinfma[0] = z_epinf * epinf[x] + + sw[0] = crhow * sw[-1] + ewma[0] - cmaw * ewma[-1] + + ewma[0] = z_ew * ew[x] + + kp[0] = kp[-1] * (1 - cikbar) + inve[0] * cikbar + qs[0] * csadjcost * cgamma ^ 2 * cikbar + + dy[0] = ctrend + y[0] - y[-1] + + dc[0] = ctrend + c[0] - c[-1] + + dinve[0] = ctrend + inve[0] - inve[-1] + + dw[0] = ctrend + w[0] - w[-1] + + pinfobs[0] = constepinf + pinf[0] + + robs[0] = r[0] + conster + + labobs[0] = lab[0] + constelab + +end + + +@parameters Smets_Wouters_2007_linear begin + ctou = .025 + + clandaw = 1.5 + + cg = 0.18 + + curvp = 10 + + curvw = 10 + + calfa = .24 + + csigma = 1.5 + + cfc = 1.5 + + cgy = 0.51 + + csadjcost = 6.0144 + + chabb = 0.6361 + + cprobw = 0.8087 + + csigl = 1.9423 + + cprobp = 0.6 + + cindw = 0.3243 + + cindp = 0.47 + + czcap = 0.2696 + + crpi = 1.488 + + crr = 0.8762 + + cry = 0.0593 + + crdy = 0.2347 + + crhoa = 0.9977 + + crhob = 0.5799 + + crhog = 0.9957 + + crhoqs = 0.7165 + + crhoms = 0 + + crhopinf = 0 + + crhow = 0 + + cmap = 0 + + cmaw = 0 + + constelab = 0 + + constepinf = 0.7 + + constebeta = 0.7420 + + ctrend = 0.3982 + + z_ea = 0.4618 + + z_eb = 1.8513 + + z_eg = 0.6090 + + z_em = 0.2397 + + z_ew = 0.2089 + + z_eqs = 0.6017 + + z_epinf = 0.1455 + + cpie = 1 + constepinf / 100 # gross inflation rate + + cgamma = 1 + ctrend / 100 # gross growth rate + + cbeta = 1 / (1 + constebeta / 100) # discount factor + + clandap = cfc # fixed cost share/gross price markup + + cbetabar= cbeta * cgamma ^ (-csigma) # growth-adjusted discount factor in Euler equation + + cr = cpie / cbetabar # steady state gross real interest rate + + crk = 1 / cbetabar - (1 - ctou) # steady state rental rate + + cw = (calfa ^ calfa * (1 - calfa) ^ (1 - calfa) / (clandap * crk ^ calfa)) ^ (1 / (1 - calfa)) # steady state real wage + + cikbar = 1 - (1 - ctou) / cgamma # (1-k_1) in equation LOM capital, equation (8) + + cik = cikbar * cgamma # i_k: investment-capital ratio + + clk = (1 - calfa) / calfa * crk / cw # labor to capital ratio + + cky = cfc * clk ^ (calfa - 1) # k_y: steady state output ratio + + ciy = cik * cky # investment-output ratio + + ccy = 1 - cg - cik * cky # consumption-output ratio + + crkky = crk * cky # z_y=R_{*}^k*k_y + + cwhlc = (1 / clandaw) * (1 - calfa) / calfa * crk * cky / ccy # W^{h}_{*}*L_{*}/C_{*} used in c_2 in equation (2) + + conster = (cr - 1) * 100 # steady state federal funds rate ($\bar r$) + +end diff --git a/src/MacroModelling.jl b/src/MacroModelling.jl index 890959b4..5d9982e0 100644 --- a/src/MacroModelling.jl +++ b/src/MacroModelling.jl @@ -8,6 +8,9 @@ using PrecompileTools import SpecialFunctions: erfcinv, erfc import SymPyPythonCall as SPyPyC import Symbolics +# import NaNMath +# import Memoization: @memoize +# import LRUCache: LRU import AbstractDifferentiation as 𝒜 import ForwardDiff as ℱ @@ -21,6 +24,7 @@ import Optim, LineSearches import SparseArrays: SparseMatrixCSC, SparseVector, AbstractSparseArray#, sparse, spzeros, droptol!, sparsevec, spdiagm, findnz#, sparse! import LinearAlgebra as ℒ # import ComponentArrays as 𝒞 +import Combinatorics: combinations import BlockTriangularForm import Subscripts: super, sub import Krylov @@ -36,7 +40,7 @@ import MatrixEquations # good overview: https://cscproxy.mpi-magdeburg.mpg.de/mp # using NamedArrays # using AxisKeys -import ChainRulesCore: @ignore_derivatives, ignore_derivatives +import ChainRulesCore: @ignore_derivatives, ignore_derivatives, rrule, NoTangent import RecursiveFactorization as RF using RuntimeGeneratedFunctions @@ -102,6 +106,7 @@ export get_irfs, get_irf, get_IRF, simulate, get_simulation, get_simulations export get_conditional_forecast, plot_conditional_forecast export get_solution, get_first_order_solution, get_perturbation_solution, get_second_order_solution, get_third_order_solution export get_steady_state, get_SS, get_ss, get_non_stochastic_steady_state, get_stochastic_steady_state, get_SSS, steady_state, SS, SSS, ss, sss +export get_non_stochastic_steady_state_residuals, get_residuals, check_residuals export get_moments, get_statistics, get_covariance, get_standard_deviation, get_variance, get_var, get_std, get_stdev, get_cov, var, std, stdev, cov, get_mean #, mean export get_autocorrelation, get_correlation, get_variance_decomposition, get_corr, get_autocorr, get_var_decomp, corr, autocorr export get_fevd, fevd, get_forecast_error_variance_decomposition, get_conditional_variance_decomposition @@ -803,6 +808,9 @@ function translate_symbol_to_ascii(x::Symbol) outstr *= string(i) else outstr *= replace(out, + r"\!" => s"_", + r"\(" => s"_", + r"\)" => s"_", r"\^" => s"_", r"\_\^" => s"_", r"\+" => s"plus", @@ -1709,13 +1717,14 @@ end function levenberg_marquardt(f::Function, initial_guess::Array{T,1}, lower_bounds::Array{T,1}, - upper_bounds::Array{T,1}; - parameters::solver_parameters = solver_parameters(eps(), eps(), 250, 2.9912988764832833, 0.8725, 0.0027, 0.028948770826150612, 8.04, 4.076413176215408, 0.06375413238034794, 0.24284340766769424, 0.5634017580097571, 0.009549630552246828, 0.6342888355132347, 0.5275522227754195, 1.0, 0.06178989216048817, 0.5234277812131813, 0.422, 0.011209254402846185, 0.5047, 0.6020757011698457, 1, 0.0, 2) + upper_bounds::Array{T,1}, + parameters::solver_parameters ) where {T <: AbstractFloat} # issues with optimization: https://www.gurobi.com/documentation/8.1/refman/numerics_gurobi_guidelines.html xtol = parameters.xtol ftol = parameters.ftol + rel_xtol = parameters.rel_xtol iterations = parameters.iterations ϕ̄ = parameters.ϕ̄ ϕ̂ = parameters.ϕ̂ @@ -1863,10 +1872,11 @@ function levenberg_marquardt(f::Function, end largest_step = maximum(abs, previous_guess - current_guess) + largest_relative_step = maximum(abs, (previous_guess - current_guess) ./ previous_guess) largest_residual = maximum(abs, f(undo_transform(current_guess,transformation_level))) # largest_residual = maximum(abs, f(undo_transform(current_guess,transformation_level,shift))) - if largest_step <= xtol || largest_residual <= ftol + if largest_step <= xtol || largest_residual <= ftol || largest_relative_step <= rel_xtol return undo_transform(current_guess,transformation_level), (iter, largest_step, largest_residual, f(undo_transform(current_guess,transformation_level))) # return undo_transform(current_guess,transformation_level,shift), (iter, largest_step, largest_residual, f(undo_transform(current_guess,transformation_level,shift))) end @@ -1912,18 +1922,15 @@ function create_symbols_eqs!(𝓂::ℳ) symbols_in_equation = union(𝓂.parameters_in_equations,𝓂.parameters,𝓂.parameters_as_function_of_parameters,symbols_in_dynamic_equations,symbols_in_dynamic_equations_wo_subscripts,symbols_in_ss_equations)#,𝓂.dynamic_variables_future) - l_bnds = Dict(𝓂.bounded_vars .=> 𝓂.lower_bounds) - u_bnds = Dict(𝓂.bounded_vars .=> 𝓂.upper_bounds) - symbols_pos = [] symbols_neg = [] symbols_none = [] for symb in symbols_in_equation - if symb in 𝓂.bounded_vars - if l_bnds[symb] >= 0 + if haskey(𝓂.bounds, symb) + if 𝓂.bounds[symb][1] >= 0 push!(symbols_pos, symb) - elseif u_bnds[symb] <= 0 + elseif 𝓂.bounds[symb][2] <= 0 push!(symbols_neg, symb) else push!(symbols_none, symb) @@ -2014,6 +2021,7 @@ function remove_redundant_SS_vars!(𝓂::ℳ, Symbolics::symbolics) intersect.(Symbolics.ss_list,Symbolics.var_future_list) ), Symbolics.var_list) + redundant_idx = getindex(1:length(redundant_vars), (length.(redundant_vars) .> 0) .& (length.(Symbolics.var_list) .> 1)) for i in redundant_idx @@ -2037,10 +2045,1048 @@ function remove_redundant_SS_vars!(𝓂::ℳ, Symbolics::symbolics) end +function write_block_solution!(𝓂, SS_solve_func, vars_to_solve, eqs_to_solve, relevant_pars_across, NSSS_solver_cache_init_tmp, eq_idx_in_block_to_solve, atoms_in_equations_list) + # ➕_vars = Symbol[] + unique_➕_eqs = Dict{Union{Expr,Symbol},Symbol}() + + vars_to_exclude = [vcat(Symbol.(vars_to_solve), 𝓂.➕_vars),Symbol[]] + + rewritten_eqs, ss_and_aux_equations, ss_and_aux_equations_dep, ss_and_aux_equations_error, ss_and_aux_equations_error_dep = make_equation_rebust_to_domain_errors(Meta.parse.(string.(eqs_to_solve)), vars_to_exclude, 𝓂.bounds, 𝓂.➕_vars, unique_➕_eqs) + + + push!(𝓂.solved_vars, Symbol.(vars_to_solve)) + push!(𝓂.solved_vals, rewritten_eqs) + + + syms_in_eqs = Set{Symbol}() + + for i in vcat(ss_and_aux_equations_dep, ss_and_aux_equations, rewritten_eqs) + push!(syms_in_eqs, get_symbols(i)...) + end + + setdiff!(syms_in_eqs,𝓂.➕_vars) + + syms_in_eqs2 = Set{Symbol}() + + for i in ss_and_aux_equations + push!(syms_in_eqs2, get_symbols(i)...) + end + + ➕_vars_alread_in_eqs = intersect(𝓂.➕_vars,reduce(union,get_symbols.(Meta.parse.(string.(eqs_to_solve))))) + + union!(syms_in_eqs, intersect(union(➕_vars_alread_in_eqs, syms_in_eqs2), 𝓂.➕_vars)) + + push!(atoms_in_equations_list,setdiff(syms_in_eqs, 𝓂.solved_vars[end])) + + calib_pars = Expr[] + calib_pars_input = Symbol[] + relevant_pars = union(intersect(reduce(union, vcat(𝓂.par_list_aux_SS, 𝓂.par_calib_list)[eq_idx_in_block_to_solve]), syms_in_eqs),intersect(syms_in_eqs, 𝓂.➕_vars)) + + union!(relevant_pars_across, relevant_pars) + + iii = 1 + for parss in union(𝓂.parameters, 𝓂.parameters_as_function_of_parameters) + if :($parss) ∈ relevant_pars + push!(calib_pars, :($parss = parameters_and_solved_vars[$iii])) + push!(calib_pars_input, :($parss)) + iii += 1 + end + end + + guess = Expr[] + result = Expr[] + + sorted_vars = sort(Symbol.(vars_to_solve)) + + for (i, parss) in enumerate(sorted_vars) + push!(guess,:($parss = guess[$i])) + push!(result,:($parss = sol[$i])) + end + + # separate out auxilliary variables (nonnegativity) + # nnaux = [] + # nnaux_linear = [] + # nnaux_error = [] + # push!(nnaux_error, :(aux_error = 0)) + solved_vals = Expr[] + partially_solved_block = Expr[] + + other_vrs_eliminated_by_sympy = Set{Symbol}() + + for (i,val) in enumerate(𝓂.solved_vals[end]) + if eq_idx_in_block_to_solve[i] ∈ 𝓂.ss_equations_with_aux_variables + val = vcat(𝓂.ss_aux_equations, 𝓂.calibration_equations)[eq_idx_in_block_to_solve[i]] + # push!(nnaux,:($(val.args[2]) = max(eps(),$(val.args[3])))) + push!(other_vrs_eliminated_by_sympy, val.args[2]) + # push!(nnaux_linear,:($val)) + # push!(nnaux_error, :(aux_error += min(eps(),$(val.args[3])))) + end + end + + + + for (i,val) in enumerate(rewritten_eqs) + push!(solved_vals, postwalk(x -> x isa Expr ? x.args[1] == :conjugate ? x.args[2] : x : x, val)) + end + + # if length(nnaux) > 1 + # all_symbols = map(x->x.args[1],nnaux) #relevant symbols come first in respective equations + + # nn_symbols = map(x->intersect(all_symbols,x), get_symbols.(nnaux)) + + # inc_matrix = fill(0,length(all_symbols),length(all_symbols)) + + # for i in 1:length(all_symbols) + # for k in 1:length(nn_symbols) + # inc_matrix[i,k] = collect(all_symbols)[i] ∈ collect(nn_symbols)[k] + # end + # end + + # QQ, P, R, nmatch, n_blocks = BlockTriangularForm.order(sparse(inc_matrix)) + + # nnaux = nnaux[QQ] + # nnaux_linear = nnaux_linear[QQ] + # end + + other_vars = Expr[] + other_vars_input = Symbol[] + other_vrs = intersect( setdiff( union(𝓂.var, 𝓂.calibration_equations_parameters, 𝓂.➕_vars), + sort(𝓂.solved_vars[end]) ), + union(syms_in_eqs, other_vrs_eliminated_by_sympy ) ) + # union(syms_in_eqs, other_vrs_eliminated_by_sympy, setdiff(reduce(union, get_symbols.(nnaux), init = []), map(x->x.args[1],nnaux)) ) ) + + for var in other_vrs + push!(other_vars,:($(var) = parameters_and_solved_vars[$iii])) + push!(other_vars_input,:($(var))) + iii += 1 + end + + # solved_vals[end] = Expr(:call, :+, solved_vals[end], ss_and_aux_equations_error_dep...) + + funcs = :(function block(parameters_and_solved_vars::Vector, guess::Vector) + $(guess...) + $(calib_pars...) # add those variables which were previously solved and are used in the equations + $(other_vars...) # take only those that appear in equations - DONE + + $(ss_and_aux_equations_dep...) + # return [$(solved_vals...),$(nnaux_linear...)] + return [$(solved_vals...)] + end) + + push!(NSSS_solver_cache_init_tmp, [haskey(𝓂.guess, v) ? 𝓂.guess[v] : Inf for v in sorted_vars]) + push!(NSSS_solver_cache_init_tmp, [Inf]) + + # WARNING: infinite bounds are transformed to 1e12 + lbs = Float64[] + ubs = Float64[] + + limit_boundaries = 1e12 + + for i in vcat(sorted_vars, calib_pars_input, other_vars_input) + if haskey(𝓂.bounds,i) + push!(lbs,𝓂.bounds[i][1]) + push!(ubs,𝓂.bounds[i][2]) + else + push!(lbs,-limit_boundaries) + push!(ubs, limit_boundaries) + end + end + + push!(SS_solve_func,ss_and_aux_equations...) + + push!(SS_solve_func,:(params_and_solved_vars = [$(calib_pars_input...), $(other_vars_input...)])) + + push!(SS_solve_func,:(lbs = [$(lbs...)])) + push!(SS_solve_func,:(ubs = [$(ubs...)])) + + n_block = length(𝓂.ss_solve_blocks) + 1 + + push!(SS_solve_func,:(inits = [max.(lbs[1:length(closest_solution[$(2*(n_block-1)+1)])], min.(ubs[1:length(closest_solution[$(2*(n_block-1)+1)])], closest_solution[$(2*(n_block-1)+1)])), closest_solution[$(2*n_block)]])) + + if VERSION >= v"1.9" + push!(SS_solve_func,:(block_solver_AD = ℐ.ImplicitFunction(block_solver, 𝓂.ss_solve_blocks[$(n_block)]; linear_solver = ℐ.DirectLinearSolver(), conditions_backend = 𝒷()))) + else + push!(SS_solve_func,:(block_solver_AD = ℐ.ImplicitFunction(block_solver, 𝓂.ss_solve_blocks[$(n_block)]; linear_solver = ℐ.DirectLinearSolver()))) + end + + push!(SS_solve_func,:(solution = block_solver_AD(params_and_solved_vars, + $(n_block), + 𝓂.ss_solve_blocks[$(n_block)], + # 𝓂.ss_solve_blocks_no_transform[$(n_block)], + # f, + inits, + lbs, + ubs, + solver_parameters, + # fail_fast_solvers_only = fail_fast_solvers_only, + cold_start, + verbose))) + + push!(SS_solve_func,:(iters += solution[2][2])) + push!(SS_solve_func,:(solution_error += solution[2][1])) + + if length(ss_and_aux_equations_error) > 0 + push!(SS_solve_func,:(solution_error += $(Expr(:call, :+, ss_and_aux_equations_error...)))) + end + + push!(SS_solve_func,:(sol = solution[1])) + + push!(SS_solve_func,:($(result...))) + + push!(SS_solve_func,:(NSSS_solver_cache_tmp = [NSSS_solver_cache_tmp..., typeof(sol) == Vector{Float64} ? sol : ℱ.value.(sol)])) + push!(SS_solve_func,:(NSSS_solver_cache_tmp = [NSSS_solver_cache_tmp..., typeof(params_and_solved_vars) == Vector{Float64} ? params_and_solved_vars : ℱ.value.(params_and_solved_vars)])) + + push!(𝓂.ss_solve_blocks,@RuntimeGeneratedFunction(funcs)) +end + + + + +# function write_domain_safe_block_solution!(𝓂, SS_solve_func, vars_to_solve, eqs_to_solve, relevant_pars_across, NSSS_solver_cache_init_tmp, eq_idx_in_block_to_solve, atoms_in_equations_list, unique_➕_eqs) +# # ➕_vars = Symbol[] +# # unique_➕_vars = Union{Symbol,Expr}[] + +# vars_to_exclude = [Symbol.(vars_to_solve),Symbol[]] + +# rewritten_eqs, ss_and_aux_equations, ss_and_aux_equations_dep, ss_and_aux_equations_error, ss_and_aux_equations_error_dep = make_equation_rebust_to_domain_errors(Meta.parse.(string.(eqs_to_solve)), vars_to_exclude, 𝓂.bounds, 𝓂.➕_vars, unique_➕_eqs) + + +# push!(𝓂.solved_vars, Symbol.(vars_to_solve)) +# push!(𝓂.solved_vals, rewritten_eqs) + + +# syms_in_eqs = Set{Symbol}() + +# for i in vcat(ss_and_aux_equations_dep, ss_and_aux_equations, rewritten_eqs) +# push!(syms_in_eqs, get_symbols(i)...) +# end + +# setdiff!(syms_in_eqs, 𝓂.➕_vars) + +# syms_in_eqs2 = Set{Symbol}() + +# for i in ss_and_aux_equations +# push!(syms_in_eqs2, get_symbols(i)...) +# end + +# union!(syms_in_eqs, intersect(syms_in_eqs2, 𝓂.➕_vars)) + +# push!(atoms_in_equations_list,setdiff(syms_in_eqs, 𝓂.solved_vars[end])) + +# calib_pars = Expr[] +# calib_pars_input = Symbol[] +# relevant_pars = union(intersect(reduce(union, vcat(𝓂.par_list_aux_SS, 𝓂.par_calib_list)[eq_idx_in_block_to_solve]), syms_in_eqs),intersect(syms_in_eqs, 𝓂.➕_vars)) + +# union!(relevant_pars_across, relevant_pars) + +# iii = 1 +# for parss in union(𝓂.parameters, 𝓂.parameters_as_function_of_parameters) +# if :($parss) ∈ relevant_pars +# push!(calib_pars, :($parss = parameters_and_solved_vars[$iii])) +# push!(calib_pars_input, :($parss)) +# iii += 1 +# end +# end + +# guess = Expr[] +# result = Expr[] + +# sorted_vars = sort(Symbol.(vars_to_solve)) + +# # ss_and_aux_equations_dep[1]|>dump +# # ss_and_aux_equations_dep[1].args[1] +# # [i.args[1] for i in ss_and_aux_equations_dep] +# aux_vars = sort([i.args[1] for i in ss_and_aux_equations_dep]) + +# for (i, parss) in enumerate(vcat(sorted_vars, aux_vars)) +# push!(guess,:($parss = guess[$i])) +# push!(result,:($parss = sol[$i])) +# end + +# # separate out auxilliary variables (nonnegativity) +# # nnaux = [] +# # nnaux_linear = [] +# # nnaux_error = [] +# # push!(nnaux_error, :(aux_error = 0)) +# solved_vals = Expr[] +# partially_solved_block = Expr[] + +# other_vrs_eliminated_by_sympy = Set{Symbol}() + +# for (i,val) in enumerate(𝓂.solved_vals[end]) +# if eq_idx_in_block_to_solve[i] ∈ 𝓂.ss_equations_with_aux_variables +# val = vcat(𝓂.ss_aux_equations, 𝓂.calibration_equations)[eq_idx_in_block_to_solve[i]] +# # push!(nnaux,:($(val.args[2]) = max(eps(),$(val.args[3])))) +# push!(other_vrs_eliminated_by_sympy, val.args[2]) +# # push!(nnaux_linear,:($val)) +# # push!(nnaux_error, :(aux_error += min(eps(),$(val.args[3])))) +# end +# end + + + +# for (i,val) in enumerate(rewritten_eqs) +# push!(solved_vals, postwalk(x -> x isa Expr ? x.args[1] == :conjugate ? x.args[2] : x : x, val)) +# end + +# # if length(nnaux) > 1 +# # all_symbols = map(x->x.args[1],nnaux) #relevant symbols come first in respective equations + +# # nn_symbols = map(x->intersect(all_symbols,x), get_symbols.(nnaux)) + +# # inc_matrix = fill(0,length(all_symbols),length(all_symbols)) + +# # for i in 1:length(all_symbols) +# # for k in 1:length(nn_symbols) +# # inc_matrix[i,k] = collect(all_symbols)[i] ∈ collect(nn_symbols)[k] +# # end +# # end + +# # QQ, P, R, nmatch, n_blocks = BlockTriangularForm.order(sparse(inc_matrix)) + +# # nnaux = nnaux[QQ] +# # nnaux_linear = nnaux_linear[QQ] +# # end + +# other_vars = Expr[] +# other_vars_input = Symbol[] +# other_vrs = intersect( setdiff( union(𝓂.var, 𝓂.calibration_equations_parameters, 𝓂.➕_vars), +# sort(𝓂.solved_vars[end]) ), +# union(syms_in_eqs, other_vrs_eliminated_by_sympy ) ) +# # union(syms_in_eqs, other_vrs_eliminated_by_sympy, setdiff(reduce(union, get_symbols.(nnaux), init = []), map(x->x.args[1],nnaux)) ) ) + +# for var in other_vrs +# push!(other_vars,:($(var) = parameters_and_solved_vars[$iii])) +# push!(other_vars_input,:($(var))) +# iii += 1 +# end + +# # solved_vals[end] = Expr(:call, :+, solved_vals[end], ss_and_aux_equations_error_dep...) + +# aux_equations = [:($(i.args[1]) - $(i.args[2].args[3].args[3])) for i in ss_and_aux_equations_dep] + +# funcs = :(function block(parameters_and_solved_vars::Vector, guess::Vector) +# $(guess...) +# $(calib_pars...) # add those variables which were previously solved and are used in the equations +# $(other_vars...) # take only those that appear in equations - DONE + +# # $(ss_and_aux_equations_dep...) +# # return [$(solved_vals...),$(nnaux_linear...)] +# return [$(solved_vals...), $(aux_equations...)] +# end) + +# push!(NSSS_solver_cache_init_tmp,fill(1.205996189998029, length(vcat(sorted_vars,aux_vars)))) +# push!(NSSS_solver_cache_init_tmp,[Inf]) + +# # WARNING: infinite bounds are transformed to 1e12 +# lbs = Float64[] +# ubs = Float64[] + +# limit_boundaries = 1e12 + +# for i in vcat(sorted_vars, aux_vars, calib_pars_input, other_vars_input) +# if haskey(𝓂.bounds,i) +# push!(lbs,𝓂.bounds[i][1]) +# push!(ubs,𝓂.bounds[i][2]) +# else +# push!(lbs,-limit_boundaries) +# push!(ubs, limit_boundaries) +# end +# end + +# push!(SS_solve_func,ss_and_aux_equations...) + +# push!(SS_solve_func,:(params_and_solved_vars = [$(calib_pars_input...), $(other_vars_input...)])) + +# push!(SS_solve_func,:(lbs = [$(lbs...)])) +# push!(SS_solve_func,:(ubs = [$(ubs...)])) + +# n_block = length(𝓂.ss_solve_blocks) + 1 + +# push!(SS_solve_func,:(inits = [max.(lbs[1:length(closest_solution[$(2*(n_block-1)+1)])], min.(ubs[1:length(closest_solution[$(2*(n_block-1)+1)])], closest_solution[$(2*(n_block-1)+1)])), closest_solution[$(2*n_block)]])) + +# if VERSION >= v"1.9" +# push!(SS_solve_func,:(block_solver_AD = ℐ.ImplicitFunction(block_solver, 𝓂.ss_solve_blocks[$(n_block)]; linear_solver = ℐ.DirectLinearSolver(), conditions_backend = 𝒷()))) +# else +# push!(SS_solve_func,:(block_solver_AD = ℐ.ImplicitFunction(block_solver, 𝓂.ss_solve_blocks[$(n_block)]; linear_solver = ℐ.DirectLinearSolver()))) +# end + +# push!(SS_solve_func,:(solution = block_solver_AD(params_and_solved_vars, +# $(n_block), +# 𝓂.ss_solve_blocks[$(n_block)], +# # 𝓂.ss_solve_blocks_no_transform[$(n_block)], +# # f, +# inits, +# lbs, +# ubs, +# solver_parameters, +# # fail_fast_solvers_only = fail_fast_solvers_only, +# cold_start, +# verbose))) + +# push!(SS_solve_func,:(iters += solution[2][2])) +# push!(SS_solve_func,:(solution_error += solution[2][1])) + +# if length(ss_and_aux_equations_error) > 0 +# push!(SS_solve_func,:(solution_error += $(Expr(:call, :+, ss_and_aux_equations_error...)))) +# end + +# push!(SS_solve_func,:(sol = solution[1])) + +# push!(SS_solve_func,:($(result...))) + +# if length(ss_and_aux_equations_error_dep) > 0 +# push!(SS_solve_func,:(solution_error += $(Expr(:call, :+, ss_and_aux_equations_error_dep...)))) +# end + +# push!(SS_solve_func,:(NSSS_solver_cache_tmp = [NSSS_solver_cache_tmp..., typeof(sol) == Vector{Float64} ? sol : ℱ.value.(sol)])) +# push!(SS_solve_func,:(NSSS_solver_cache_tmp = [NSSS_solver_cache_tmp..., typeof(params_and_solved_vars) == Vector{Float64} ? params_and_solved_vars : ℱ.value.(params_and_solved_vars)])) + +# push!(𝓂.ss_solve_blocks,@RuntimeGeneratedFunction(funcs)) +# end + + + + +function partial_solve(eqs_to_solve, vars_to_solve, incidence_matrix_subset) + for n in length(eqs_to_solve)-1:-1:2 + for eq_combo in combinations(1:length(eqs_to_solve), n) + var_indices_to_select_from = findall([sum(incidence_matrix_subset[:,eq_combo],dims = 2)...] .> 0) + + var_indices_in_remaining_eqs = findall([sum(incidence_matrix_subset[:,setdiff(1:length(eqs_to_solve),eq_combo)],dims = 2)...] .> 0) + + for var_combo in combinations(var_indices_to_select_from, n) + remaining_vars_in_remaining_eqs = setdiff(var_indices_in_remaining_eqs, var_combo) + # println("Solving for: ",vars_to_solve[var_combo]," in: ",eqs_to_solve[eq_combo]) + if length(remaining_vars_in_remaining_eqs) == length(eqs_to_solve) - n # not sure whether this condition needs to be there. could be because if the last remaining vars not solved for in the block is not present in the remaining block he will not be able to solve it for the same reasons he wasnt able to solve the unpartitioned block + soll = try SPyPyC.solve(eqs_to_solve[eq_combo], vars_to_solve[var_combo]) + catch + end + + if !(isnothing(soll) || length(soll) == 0) + soll_collected = soll isa Dict ? collect(values(soll)) : collect(soll[end]) + + return (vars_to_solve[setdiff(1:length(eqs_to_solve),var_combo)], + vars_to_solve[var_combo], + eqs_to_solve[setdiff(1:length(eqs_to_solve),eq_combo)], + soll_collected) + end + end + end + end + end +end + + + +function make_equation_rebust_to_domain_errors(eqs,#::Vector{Union{Symbol,Expr}}, + vars_to_exclude::Vector{Vector{Symbol}}, + bounds::Dict{Symbol,Tuple{Float64,Float64}}, + ➕_vars::Vector{Symbol}, + unique_➕_eqs,#::Dict{Union{Expr,Symbol},Symbol}(); + precompile::Bool = false) + ss_and_aux_equations = Expr[] + ss_and_aux_equations_dep = Expr[] + ss_and_aux_equations_error = Expr[] + ss_and_aux_equations_error_dep = Expr[] + rewritten_eqs = Union{Expr,Symbol}[] + # write down ss equations including nonnegativity auxilliary variables + # find nonegative variables, parameters, or terms + for eq in eqs + if eq isa Symbol + push!(rewritten_eqs, eq) + elseif eq isa Expr + rewritten_eq = postwalk(x -> + x isa Expr ? + # x.head == :(=) ? + # Expr(:call,:(-),x.args[1],x.args[2]) : #convert = to - + # x.head == :ref ? + # occursin(r"^(x|ex|exo|exogenous){1}"i,string(x.args[2])) ? 0 : # set shocks to zero and remove time scripts + # x : + x.head == :call ? + x.args[1] == :* ? + x.args[2] isa Int ? + x.args[3] isa Int ? + x : + Expr(:call, :*, x.args[3:end]..., x.args[2]) : # 2beta => beta * 2 + x : + x.args[1] ∈ [:^] ? + !(x.args[3] isa Int) ? + x.args[2] isa Symbol ? # nonnegative parameters + x.args[2] ∈ vars_to_exclude[1] ? + begin + bounds[x.args[2]] = haskey(bounds, x.args[2]) ? (max(bounds[x.args[2]][1], eps()), min(bounds[x.args[2]][2], 1e12)) : (eps(), 1e12) + x + end : + begin + if haskey(unique_➕_eqs, x.args[2]) + replacement = unique_➕_eqs[x.args[2]] + else + if x.args[2] in vars_to_exclude[1] + push!(ss_and_aux_equations_dep, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(1e12,max(eps(),$(x.args[2]))))) + push!(ss_and_aux_equations_error_dep, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + else + push!(ss_and_aux_equations, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(1e12,max(eps(),$(x.args[2]))))) + push!(ss_and_aux_equations_error, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + end + + bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))] = haskey(bounds, Symbol("➕" * sub(string(length(➕_vars)+1)))) ? (max(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][1], eps()), min(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][2], 1e12)) : (eps(), 1e12) + push!(➕_vars,Symbol("➕" * sub(string(length(➕_vars)+1)))) + replacement = Symbol("➕" * sub(string(length(➕_vars)))) + + unique_➕_eqs[x.args[2]] = replacement + end + + :($(replacement) ^ $(x.args[3])) + end : + x.args[2] isa Float64 ? + x : + x.args[2].head == :call ? # nonnegative expressions + begin + if precompile + replacement = x.args[2] + else + replacement = simplify(x.args[2]) + end + + if !(replacement isa Int) # check if the nonnegative term is just a constant + if haskey(unique_➕_eqs, x.args[2]) + replacement = unique_➕_eqs[x.args[2]] + else + if isempty(intersect(get_symbols(x.args[2]), vars_to_exclude[1])) + push!(ss_and_aux_equations, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(1e12,max(eps(),$(x.args[2]))))) + push!(ss_and_aux_equations_error, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + else + push!(ss_and_aux_equations_dep, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(1e12,max(eps(),$(x.args[2]))))) + push!(ss_and_aux_equations_error_dep, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + end + + bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))] = haskey(bounds, Symbol("➕" * sub(string(length(➕_vars)+1)))) ? (max(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][1], eps()), min(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][2], 1e12)) : (eps(), 1e12) + push!(➕_vars,Symbol("➕" * sub(string(length(➕_vars)+1)))) + replacement = Symbol("➕" * sub(string(length(➕_vars)))) + + unique_➕_eqs[x.args[2]] = replacement + end + end + + :($(replacement) ^ $(x.args[3])) + end : + x : + x : + x.args[2] isa Float64 ? + x : + x.args[1] ∈ [:log] ? + x.args[2] isa Symbol ? # nonnegative parameters + x.args[2] ∈ vars_to_exclude[1] ? + begin + bounds[x.args[2]] = haskey(bounds, x.args[2]) ? (max(bounds[x.args[2]][1], eps()), min(bounds[x.args[2]][2], 1e12)) : (eps(), 1e12) + x + end : + begin + if haskey(unique_➕_eqs, x.args[2]) + replacement = unique_➕_eqs[x.args[2]] + else + if x.args[2] in vars_to_exclude[1] + push!(ss_and_aux_equations_dep, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(1e12,max(eps(),$(x.args[2]))))) + push!(ss_and_aux_equations_error_dep, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + else + push!(ss_and_aux_equations, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(1e12,max(eps(),$(x.args[2]))))) + push!(ss_and_aux_equations_error, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + end + + bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))] = haskey(bounds, Symbol("➕" * sub(string(length(➕_vars)+1)))) ? (max(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][1], eps()), min(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][2], 1e12)) : (eps(), 1e12) + push!(➕_vars,Symbol("➕" * sub(string(length(➕_vars)+1)))) + replacement = Symbol("➕" * sub(string(length(➕_vars)))) + + unique_➕_eqs[x.args[2]] = replacement + end + + :($(Expr(:call, x.args[1], replacement))) + end : + x.args[2].head == :call ? # nonnegative expressions + begin + if precompile + replacement = x.args[2] + else + replacement = simplify(x.args[2]) + end + + if !(replacement isa Int) # check if the nonnegative term is just a constant + if haskey(unique_➕_eqs, x.args[2]) + replacement = unique_➕_eqs[x.args[2]] + else + if isempty(intersect(get_symbols(x.args[2]), vars_to_exclude[1])) + push!(ss_and_aux_equations, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(1e12,max(eps(),$(x.args[2]))))) + push!(ss_and_aux_equations_error, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + else + push!(ss_and_aux_equations_dep, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(1e12,max(eps(),$(x.args[2]))))) + push!(ss_and_aux_equations_error_dep, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + end + + bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))] = haskey(bounds, Symbol("➕" * sub(string(length(➕_vars)+1)))) ? (max(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][1], eps()), min(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][2], 1e12)) : (eps(), 1e12) + push!(➕_vars,Symbol("➕" * sub(string(length(➕_vars)+1)))) + replacement = Symbol("➕" * sub(string(length(➕_vars)))) + + unique_➕_eqs[x.args[2]] = replacement + end + end + + :($(Expr(:call, x.args[1], replacement))) + end : + x : + x.args[1] ∈ [:norminvcdf, :norminv, :qnorm] ? + x.args[2] isa Symbol ? # nonnegative parameters + x.args[2] ∈ vars_to_exclude[1] ? + begin + bounds[x.args[2]] = haskey(bounds, x.args[2]) ? (max(bounds[x.args[2]][1], eps()), min(bounds[x.args[2]][2], 1-eps())) : (eps(), 1 - eps()) + x + end : + begin + if haskey(unique_➕_eqs, x.args[2]) + replacement = unique_➕_eqs[x.args[2]] + else + if x.args[2] in vars_to_exclude[1] + push!(ss_and_aux_equations_dep, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(1-eps(),max(eps(),$(x.args[2]))))) + push!(ss_and_aux_equations_error_dep, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + else + push!(ss_and_aux_equations, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(1-eps(),max(eps(),$(x.args[2]))))) + push!(ss_and_aux_equations_error, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + end + + bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))] = haskey(bounds, Symbol("➕" * sub(string(length(➕_vars)+1)))) ? (max(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][1], eps()), min(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][2], 1 - eps())) : (eps(), 1 - eps()) + push!(➕_vars,Symbol("➕" * sub(string(length(➕_vars)+1)))) + replacement = Symbol("➕" * sub(string(length(➕_vars)))) + + unique_➕_eqs[x.args[2]] = replacement + end + + :($(Expr(:call, x.args[1], replacement))) + end : + x.args[2].head == :call ? # nonnegative expressions + begin + if precompile + replacement = x.args[2] + else + replacement = simplify(x.args[2]) + end + + if !(replacement isa Int) # check if the nonnegative term is just a constant + if haskey(unique_➕_eqs, x.args[2]) + replacement = unique_➕_eqs[x.args[2]] + else + if isempty(intersect(get_symbols(x.args[2]), vars_to_exclude[1])) + push!(ss_and_aux_equations, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(1-eps(),max(eps(),$(x.args[2]))))) + push!(ss_and_aux_equations_error, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + else + push!(ss_and_aux_equations_dep, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(1-eps(),max(eps(),$(x.args[2]))))) + push!(ss_and_aux_equations_error_dep, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + end + + bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))] = haskey(bounds, Symbol("➕" * sub(string(length(➕_vars)+1)))) ? (max(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][1], eps()), min(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][2], 1 - eps())) : (eps(), 1 - eps()) + push!(➕_vars,Symbol("➕" * sub(string(length(➕_vars)+1)))) + replacement = Symbol("➕" * sub(string(length(➕_vars)))) + + unique_➕_eqs[x.args[2]] = replacement + end + end + + :($(Expr(:call, x.args[1], replacement))) + end : + x : + x.args[1] ∈ [:exp] ? + x.args[2] isa Symbol ? # have exp terms bound so they dont go to Inf + x.args[2] ∈ vars_to_exclude[1] ? + begin + bounds[x.args[2]] = haskey(bounds, x.args[2]) ? (max(bounds[x.args[2]][1], -1e12), min(bounds[x.args[2]][2], 700)) : (-1e12, 700) + x + end : + begin + if haskey(unique_➕_eqs, x.args[2]) + replacement = unique_➕_eqs[x.args[2]] + else + if x.args[2] in vars_to_exclude[1] + push!(ss_and_aux_equations_dep, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(700,max(-1e12,$(x.args[2]))))) + push!(ss_and_aux_equations_error_dep, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + else + push!(ss_and_aux_equations, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(700,max(-1e12,$(x.args[2]))))) + push!(ss_and_aux_equations_error, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + end + + bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))] = haskey(bounds, Symbol("➕" * sub(string(length(➕_vars)+1)))) ? (max(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][1], -1e12), min(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][2], 700)) : (-1e12, 700) + push!(➕_vars,Symbol("➕" * sub(string(length(➕_vars)+1)))) + replacement = Symbol("➕" * sub(string(length(➕_vars)))) + + unique_➕_eqs[x.args[2]] = replacement + end + + :($(Expr(:call, x.args[1], replacement))) + end : + x.args[2].head == :call ? # have exp terms bound so they dont go to Inf + begin + if precompile + replacement = x.args[2] + else + replacement = simplify(x.args[2]) + end + + if !(replacement isa Int) # check if the nonnegative term is just a constant + if haskey(unique_➕_eqs, x.args[2]) + replacement = unique_➕_eqs[x.args[2]] + else + if isempty(intersect(get_symbols(x.args[2]), vars_to_exclude[1])) + push!(ss_and_aux_equations, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(700,max(-1e12,$(x.args[2]))))) + push!(ss_and_aux_equations_error, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + else + push!(ss_and_aux_equations_dep, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(700,max(-1e12,$(x.args[2]))))) + push!(ss_and_aux_equations_error_dep, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + end + + bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))] = haskey(bounds, Symbol("➕" * sub(string(length(➕_vars)+1)))) ? (max(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][1], -1e12), min(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][2], 700)) : (-1e12, 700) + push!(➕_vars,Symbol("➕" * sub(string(length(➕_vars)+1)))) + replacement = Symbol("➕" * sub(string(length(➕_vars)))) + + unique_➕_eqs[x.args[2]] = replacement + end + end + + :($(Expr(:call, x.args[1], replacement))) + end : + x : + x.args[1] ∈ [:erfcinv] ? + x.args[2] isa Symbol ? # nonnegative parameters + x.args[2] ∈ vars_to_exclude[1] ? + begin + bounds[x.args[2]] = haskey(bounds, x.args[2]) ? (max(bounds[x.args[2]][1], eps()), min(bounds[x.args[2]][2], 2 - eps())) : (eps(), 2 - eps()) + x + end : + begin + if haskey(unique_➕_eqs, x.args[2]) + replacement = unique_➕_eqs[x.args[2]] + else + if x.args[2] in vars_to_exclude[1] + push!(ss_and_aux_equations_dep, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(2-eps(),max(eps(),$(x.args[2]))))) + push!(ss_and_aux_equations_error_dep, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + else + push!(ss_and_aux_equations, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(2-eps(),max(eps(),$(x.args[2]))))) + push!(ss_and_aux_equations_error, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + end + + bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))] = haskey(bounds, Symbol("➕" * sub(string(length(➕_vars)+1)))) ? (max(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][1], eps()), min(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][2], 2 - eps())) : (eps(), 2 - eps()) + push!(➕_vars,Symbol("➕" * sub(string(length(➕_vars)+1)))) + replacement = Symbol("➕" * sub(string(length(➕_vars)))) + + unique_➕_eqs[x.args[2]] = replacement + end + + :($(Expr(:call, x.args[1], replacement))) + end : + x.args[2].head == :call ? # nonnegative expressions + begin + if precompile + replacement = x.args[2] + else + replacement = simplify(x.args[2]) + end + + if !(replacement isa Int) # check if the nonnegative term is just a constant + if haskey(unique_➕_eqs, x.args[2]) + replacement = unique_➕_eqs[x.args[2]] + else + if isempty(intersect(get_symbols(x.args[2]), vars_to_exclude[1])) + push!(ss_and_aux_equations, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(2-eps(),max(eps(),$(x.args[2]))))) + push!(ss_and_aux_equations_error, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + else + push!(ss_and_aux_equations_dep, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(2-eps(),max(eps(),$(x.args[2]))))) + push!(ss_and_aux_equations_error_dep, Expr(:call,:abs, Expr(:call,:-, :($(Symbol("➕" * sub(string(length(➕_vars)+1))))), x.args[2]))) + end + + bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))] = haskey(bounds, Symbol("➕" * sub(string(length(➕_vars)+1)))) ? (max(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][1], eps()), min(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][2], 2 - eps())) : (eps(), 2 - eps()) + push!(➕_vars,Symbol("➕" * sub(string(length(➕_vars)+1)))) + replacement = Symbol("➕" * sub(string(length(➕_vars)))) + + unique_➕_eqs[x.args[2]] = replacement + end + end + + :($(Expr(:call, x.args[1], replacement))) + end : + x : + x : + x : + x, + eq) + push!(rewritten_eqs,rewritten_eq) + else + @assert typeof(eq) in [Symbol, Expr] + end + end + + vars_to_exclude_from_block = vcat(vars_to_exclude...) + + found_new_dependecy = true + + while found_new_dependecy + found_new_dependecy = false + + for ssauxdep in ss_and_aux_equations_dep + push!(vars_to_exclude_from_block, ssauxdep.args[1]) + end + + for (iii, ssaux) in enumerate(ss_and_aux_equations) + if !isempty(intersect(get_symbols(ssaux), vars_to_exclude_from_block)) + found_new_dependecy = true + push!(vars_to_exclude_from_block, ssaux.args[1]) + push!(ss_and_aux_equations_dep, ssaux) + push!(ss_and_aux_equations_error_dep, ss_and_aux_equations_error[iii]) + deleteat!(ss_and_aux_equations, iii) + deleteat!(ss_and_aux_equations_error, iii) + end + end + end + + return rewritten_eqs, ss_and_aux_equations, ss_and_aux_equations_dep, ss_and_aux_equations_error, ss_and_aux_equations_error_dep +end + + + + +# function write_reduced_block_solution!(𝓂, SS_solve_func, solved_system, relevant_pars_across, NSSS_solver_cache_init_tmp, eq_idx_in_block_to_solve, +# ➕_vars, unique_➕_eqs) +# # ➕_vars = Symbol[] +# # unique_➕_vars = Dict{Union{Expr, Symbol},Symbol}() + +# vars_to_exclude = [Symbol.(solved_system[1]),Symbol.(solved_system[2])] + +# rewritten_eqs, ss_and_aux_equations, ss_and_aux_equations_dep, ss_and_aux_equations_error, ss_and_aux_equations_error_dep = make_equation_rebust_to_domain_errors(Meta.parse.(string.(solved_system[3])), vars_to_exclude, 𝓂.bounds, ➕_vars, unique_➕_eqs) + +# vars_to_exclude = [Symbol.(vcat(solved_system[1])),Symbol[]] + +# rewritten_eqs2, ss_and_aux_equations2, ss_and_aux_equations_dep2, ss_and_aux_equations_error2, ss_and_aux_equations_error_dep2 = make_equation_rebust_to_domain_errors(Meta.parse.(string.(solved_system[4])), vars_to_exclude, 𝓂.bounds, ➕_vars, unique_➕_eqs) + +# push!(𝓂.solved_vars, Symbol.(vcat(solved_system[1], solved_system[2]))) +# push!(𝓂.solved_vals, vcat(rewritten_eqs, rewritten_eqs2)) + +# syms_in_eqs = Set{Symbol}() + +# for i in vcat(rewritten_eqs, rewritten_eqs2, ss_and_aux_equations_dep, ss_and_aux_equations_dep2, ss_and_aux_equations, ss_and_aux_equations2) +# push!(syms_in_eqs, get_symbols(i)...) +# end + +# setdiff!(syms_in_eqs,➕_vars) + +# syms_in_eqs2 = Set{Symbol}() + +# for i in vcat(ss_and_aux_equations, ss_and_aux_equations2) +# push!(syms_in_eqs2, get_symbols(i)...) +# end + +# union!(syms_in_eqs, intersect(syms_in_eqs2, ➕_vars)) + +# calib_pars = Expr[] +# calib_pars_input = Symbol[] +# relevant_pars = union(intersect(reduce(union, vcat(𝓂.par_list_aux_SS, 𝓂.par_calib_list)[eq_idx_in_block_to_solve]), syms_in_eqs),intersect(syms_in_eqs, ➕_vars)) + +# union!(relevant_pars_across, relevant_pars) + +# iii = 1 +# for parss in union(𝓂.parameters, 𝓂.parameters_as_function_of_parameters) +# if :($parss) ∈ relevant_pars +# push!(calib_pars, :($parss = parameters_and_solved_vars[$iii])) +# push!(calib_pars_input, :($parss)) +# iii += 1 +# end +# end + +# guess = Expr[] +# result = Expr[] + +# sorted_vars = sort(Symbol.(solved_system[1])) + +# for (i, parss) in enumerate(sorted_vars) +# push!(guess,:($parss = guess[$i])) +# push!(result,:($parss = sol[$i])) +# end + +# # separate out auxilliary variables (nonnegativity) +# # nnaux = [] +# # nnaux_linear = [] +# # nnaux_error = [] +# # push!(nnaux_error, :(aux_error = 0)) +# solved_vals = Expr[] +# partially_solved_block = Expr[] + +# other_vrs_eliminated_by_sympy = Set{Symbol}() + +# for (i,val) in enumerate(𝓂.solved_vals[end]) +# if eq_idx_in_block_to_solve[i] ∈ 𝓂.ss_equations_with_aux_variables +# val = vcat(𝓂.ss_aux_equations, 𝓂.calibration_equations)[eq_idx_in_block_to_solve[i]] +# # push!(nnaux,:($(val.args[2]) = max(eps(),$(val.args[3])))) +# push!(other_vrs_eliminated_by_sympy, val.args[2]) +# # push!(nnaux_linear,:($val)) +# # push!(nnaux_error, :(aux_error += min(eps(),$(val.args[3])))) +# end +# end + + + +# for (var,val) in Dict(Symbol.(solved_system[2]) .=> rewritten_eqs2) +# push!(partially_solved_block, :($var = $(postwalk(x -> x isa Expr ? x.args[1] == :conjugate ? x.args[2] : x : x, val)))) +# end + +# for (i,val) in enumerate(rewritten_eqs) +# push!(solved_vals, postwalk(x -> x isa Expr ? x.args[1] == :conjugate ? x.args[2] : x : x, val)) +# end + +# # if length(nnaux) > 1 +# # all_symbols = map(x->x.args[1],nnaux) #relevant symbols come first in respective equations + +# # nn_symbols = map(x->intersect(all_symbols,x), get_symbols.(nnaux)) + +# # inc_matrix = fill(0,length(all_symbols),length(all_symbols)) + +# # for i in 1:length(all_symbols) +# # for k in 1:length(nn_symbols) +# # inc_matrix[i,k] = collect(all_symbols)[i] ∈ collect(nn_symbols)[k] +# # end +# # end + +# # QQ, P, R, nmatch, n_blocks = BlockTriangularForm.order(sparse(inc_matrix)) + +# # nnaux = nnaux[QQ] +# # nnaux_linear = nnaux_linear[QQ] +# # end + +# other_vars = Expr[] +# other_vars_input = Symbol[] +# other_vrs = intersect( setdiff( union(𝓂.var, 𝓂.calibration_equations_parameters, ➕_vars), +# sort(𝓂.solved_vars[end]) ), +# union(syms_in_eqs, other_vrs_eliminated_by_sympy ) ) +# # union(syms_in_eqs, other_vrs_eliminated_by_sympy, setdiff(reduce(union, get_symbols.(nnaux), init = []), map(x->x.args[1],nnaux)) ) ) + +# for var in other_vrs +# push!(other_vars,:($(var) = parameters_and_solved_vars[$iii])) +# push!(other_vars_input,:($(var))) +# iii += 1 +# end + +# solved_vals[end] = Expr(:call, :+, solved_vals[end], ss_and_aux_equations_error_dep2...) + +# funcs = :(function block(parameters_and_solved_vars::Vector, guess::Vector) +# $(guess...) +# $(calib_pars...) # add those variables which were previously solved and are used in the equations +# $(other_vars...) # take only those that appear in equations - DONE + +# $(ss_and_aux_equations_dep2...) + +# $(partially_solved_block...) # add those variables which were previously solved and are used in the equations + +# $(ss_and_aux_equations_dep...) +# # return [$(solved_vals...),$(nnaux_linear...)] +# return [$(solved_vals...)] +# end) + +# push!(NSSS_solver_cache_init_tmp,fill(1.205996189998029, length(sorted_vars))) +# push!(NSSS_solver_cache_init_tmp,[Inf]) + +# # WARNING: infinite bounds are transformed to 1e12 +# lbs = Float64[] +# ubs = Float64[] + +# limit_boundaries = 1e12 + +# for i in vcat(sorted_vars, calib_pars_input, other_vars_input) +# if haskey(𝓂.bounds,i) +# push!(lbs,𝓂.bounds[i][1]) +# push!(ubs,𝓂.bounds[i][2]) +# else +# push!(lbs,-limit_boundaries) +# push!(ubs, limit_boundaries) +# end +# end + +# push!(SS_solve_func,ss_and_aux_equations...) +# push!(SS_solve_func,ss_and_aux_equations2...) + +# push!(SS_solve_func,:(params_and_solved_vars = [$(calib_pars_input...), $(other_vars_input...)])) + +# push!(SS_solve_func,:(lbs = [$(lbs...)])) +# push!(SS_solve_func,:(ubs = [$(ubs...)])) + +# n_block = length(𝓂.ss_solve_blocks) + 1 + +# push!(SS_solve_func,:(inits = [max.(lbs[1:length(closest_solution[$(2*(n_block-1)+1)])], min.(ubs[1:length(closest_solution[$(2*(n_block-1)+1)])], closest_solution[$(2*(n_block-1)+1)])), closest_solution[$(2*n_block)]])) + +# if VERSION >= v"1.9" +# push!(SS_solve_func,:(block_solver_AD = ℐ.ImplicitFunction(block_solver, 𝓂.ss_solve_blocks[$(n_block)]; linear_solver = ℐ.DirectLinearSolver(), conditions_backend = 𝒷()))) +# else +# push!(SS_solve_func,:(block_solver_AD = ℐ.ImplicitFunction(block_solver, 𝓂.ss_solve_blocks[$(n_block)]; linear_solver = ℐ.DirectLinearSolver()))) +# end + +# push!(SS_solve_func,:(solution = block_solver_AD(params_and_solved_vars, +# $(n_block), +# 𝓂.ss_solve_blocks[$(n_block)], +# # 𝓂.ss_solve_blocks_no_transform[$(n_block)], +# # f, +# inits, +# lbs, +# ubs, +# solver_parameters, +# # fail_fast_solvers_only = fail_fast_solvers_only, +# cold_start, +# verbose))) + +# push!(SS_solve_func,:(iters += solution[2][2])) +# push!(SS_solve_func,:(solution_error += solution[2][1])) + +# if length(ss_and_aux_equations_error) + length(ss_and_aux_equations_error2) > 0 +# push!(SS_solve_func,:(solution_error += $(Expr(:call, :+, ss_and_aux_equations_error..., ss_and_aux_equations_error2...)))) +# end + +# push!(SS_solve_func,:(sol = solution[1])) + +# push!(SS_solve_func,:($(result...))) +# push!(SS_solve_func,:($(ss_and_aux_equations_dep2...))) +# push!(SS_solve_func,:($(partially_solved_block...))) + +# push!(SS_solve_func,:(NSSS_solver_cache_tmp = [NSSS_solver_cache_tmp..., typeof(sol) == Vector{Float64} ? sol : ℱ.value.(sol)])) +# push!(SS_solve_func,:(NSSS_solver_cache_tmp = [NSSS_solver_cache_tmp..., typeof(params_and_solved_vars) == Vector{Float64} ? params_and_solved_vars : ℱ.value.(params_and_solved_vars)])) + +# push!(𝓂.ss_solve_blocks,@RuntimeGeneratedFunction(funcs)) +# end + + +function write_ss_check_function!(𝓂::ℳ) + vars_in_ss_equations = sort(collect(setdiff(reduce(union,get_symbols.(𝓂.ss_equations)),union(𝓂.parameters_in_equations)))) + + unknowns = union(vars_in_ss_equations, 𝓂.calibration_equations_parameters) + + ss_equations = vcat(𝓂.ss_equations,𝓂.calibration_equations) + + pars = [] + for (i, p) in enumerate(𝓂.parameters) + push!(pars, :($p = parameters[$i])) + end + + unknwns = [] + for (i, u) in enumerate(union(vars_in_ss_equations, 𝓂.calibration_equations_parameters)) + push!(unknwns, :($u = unknowns[$i])) + end + + solve_exp = :(function solve_SS(parameters::Vector{Real}, unknowns::Vector{Real}) + $(pars...) + $(𝓂.calibration_equations_no_var...) + $(unknwns...) + return [$(ss_equations...)] + end) + + 𝓂.SS_check_func = @RuntimeGeneratedFunction(solve_exp) +end function solve_steady_state!(𝓂::ℳ, symbolic_SS, Symbolics::symbolics; verbose::Bool = false) - unknowns = union(Symbolics.vars_in_ss_equations,Symbolics.calibration_equations_parameters) + write_ss_check_function!(𝓂) + + unknowns = union(Symbolics.vars_in_ss_equations, Symbolics.calibration_equations_parameters) @assert length(unknowns) <= length(Symbolics.ss_equations) + length(Symbolics.calibration_equations) "Unable to solve steady state. More unknowns than equations." @@ -2053,7 +3099,6 @@ function solve_steady_state!(𝓂::ℳ, symbolic_SS, Symbolics::symbolics; verbo union.(Symbolics.ss_calib_list, Symbolics.par_calib_list)) - for i in 1:length(unknowns) for k in 1:length(unknowns) incidence_matrix[i,k] = collect(unknowns)[i] ∈ collect(eq_list)[k] @@ -2082,12 +3127,12 @@ function solve_steady_state!(𝓂::ℳ, symbolic_SS, Symbolics::symbolics; verbo atoms_in_equations = Set{Symbol}() atoms_in_equations_list = [] - relevant_pars_across = [] + relevant_pars_across = Symbol[] NSSS_solver_cache_init_tmp = [] min_max_errors = [] - n_block = 1 + unique_➕_eqs = Dict{Union{Expr,Symbol},Symbol}() while n > 0 if length(eqs[:,eqs[2,:] .== n]) == 2 @@ -2122,15 +3167,14 @@ function solve_steady_state!(𝓂::ℳ, symbolic_SS, Symbolics::symbolics; verbo catch end - if isnothing(soll) - # println("Could not solve single variables case symbolically.") + if isnothing(soll) || isempty(soll) println("Failed finding solution symbolically for: ",var_to_solve_for," in: ",eq_to_solve) - # solve numerically - continue - # elseif PythonCall.pyconvert(Bool,soll[1].is_number) + + eq_idx_in_block_to_solve = eqs[:,eqs[2,:] .== n][1,:] + write_block_solution!(𝓂, SS_solve_func, [var_to_solve_for], [eq_to_solve], relevant_pars_across, NSSS_solver_cache_init_tmp, eq_idx_in_block_to_solve, atoms_in_equations_list) + # write_domain_safe_block_solution!(𝓂, SS_solve_func, [var_to_solve_for], [eq_to_solve], relevant_pars_across, NSSS_solver_cache_init_tmp, eq_idx_in_block_to_solve, atoms_in_equations_list, unique_➕_eqs) elseif soll[1].is_number == true - # ss_equations = ss_equations.subs(var_to_solve,soll[1]) ss_equations = [eq.subs(var_to_solve_for,soll[1]) for eq in ss_equations] push!(𝓂.solved_vars,Symbol(var_to_solve_for)) @@ -2144,29 +3188,34 @@ function solve_steady_state!(𝓂::ℳ, symbolic_SS, Symbolics::symbolics; verbo push!(atoms_in_equations_list,[]) else - push!(𝓂.solved_vars,Symbol(var_to_solve_for)) push!(𝓂.solved_vals,Meta.parse(string(soll[1]))) - # atoms = reduce(union,soll[1].atoms()) - [push!(atoms_in_equations, Symbol(a)) for a in soll[1].atoms()] push!(atoms_in_equations_list, Set(union(setdiff(get_symbols(parsed_eq_to_solve_for), get_symbols(minmax_fixed_eqs)),Symbol.(soll[1].atoms())))) - # println(atoms_in_equations) - # push!(atoms_in_equations, soll[1].atoms()) - - if (𝓂.solved_vars[end] ∈ 𝓂.➕_vars) - push!(SS_solve_func,:($(𝓂.solved_vars[end]) = min(max($(𝓂.lower_bounds[indexin([𝓂.solved_vars[end]],𝓂.bounded_vars)][1]),$(𝓂.solved_vals[end])),$(𝓂.upper_bounds[indexin([𝓂.solved_vars[end]],𝓂.bounded_vars)][1])))) + if (𝓂.solved_vars[end] ∈ 𝓂.➕_vars) + push!(SS_solve_func,:($(𝓂.solved_vars[end]) = min(max($(𝓂.bounds[𝓂.solved_vars[end]][1]), $(𝓂.solved_vals[end])), $(𝓂.bounds[𝓂.solved_vars[end]][2])))) + push!(SS_solve_func,:(solution_error += $(Expr(:call,:abs, Expr(:call, :-, 𝓂.solved_vars[end], 𝓂.solved_vals[end]))))) + unique_➕_eqs[𝓂.solved_vals[end]] = 𝓂.solved_vars[end] else - push!(SS_solve_func,:($(𝓂.solved_vars[end]) = $(𝓂.solved_vals[end]))) + vars_to_exclude = [vcat(Symbol.(var_to_solve_for), 𝓂.➕_vars), Symbol[]] + + rewritten_eqs, ss_and_aux_equations, ss_and_aux_equations_dep, ss_and_aux_equations_error, ss_and_aux_equations_error_dep = make_equation_rebust_to_domain_errors([𝓂.solved_vals[end]], vars_to_exclude, 𝓂.bounds, 𝓂.➕_vars, unique_➕_eqs) + + if length(vcat(ss_and_aux_equations_error, ss_and_aux_equations_error_dep)) > 0 + push!(SS_solve_func,vcat(ss_and_aux_equations, ss_and_aux_equations_dep)...) + push!(SS_solve_func,:(solution_error += $(Expr(:call, :+, vcat(ss_and_aux_equations_error, ss_and_aux_equations_error_dep)...)))) + end + + push!(SS_solve_func,:($(𝓂.solved_vars[end]) = $(rewritten_eqs[1]))) end - end - # push!(single_eqs,:($(𝓂.solved_vars[end]) = $(𝓂.solved_vals[end]))) - # solve symbolically + if haskey(𝓂.bounds, 𝓂.solved_vars[end]) && 𝓂.solved_vars[end] ∉ 𝓂.➕_vars + push!(SS_solve_func,:(solution_error += abs(min(max($(𝓂.bounds[𝓂.solved_vars[end]][1]), $(𝓂.solved_vars[end])), $(𝓂.bounds[𝓂.solved_vars[end]][2])) - $(𝓂.solved_vars[end])))) + end + end else - vars_to_solve = collect(unknowns)[vars[:,vars[2,:] .== n][1,:]] eqs_to_solve = ss_equations[eqs[:,eqs[2,:] .== n][1,:]] @@ -2175,319 +3224,64 @@ function solve_steady_state!(𝓂::ℳ, symbolic_SS, Symbolics::symbolics; verbo if symbolic_SS soll = try SPyPyC.solve(eqs_to_solve,vars_to_solve) - # soll = try solve(SPyPyC.Sym(eqs_to_solve),var_order)#,check=false,force = true,manual=true) catch end - if isnothing(soll) - if verbose - println("Failed finding solution symbolically for: ",vars_to_solve," in: ",eqs_to_solve,". Solving numerically.") - end - numerical_sol = true - # continue - elseif length(soll) == 0 - if verbose - println("Failed finding solution symbolically for: ",vars_to_solve," in: ",eqs_to_solve,". Solving numerically.") - end - numerical_sol = true - # continue - # elseif length(intersect(vars_to_solve,reduce(union,map(x->x.atoms(),collect(soll[1]))))) > 0 - elseif length(intersect((union(SPyPyC.free_symbols.(soll[1])...) .|> SPyPyC.:↓),(vars_to_solve .|> SPyPyC.:↓))) > 0 - # elseif length(intersect(union(SPyPyC.free_symbols.(soll[1])...),vars_to_solve)) > 0 - if verbose - println("Failed finding solution symbolically for: ",vars_to_solve," in: ",eqs_to_solve,". Solving numerically.") - end - numerical_sol = true - # println("Could not solve for: ",intersect(var_list,reduce(union,map(x->x.atoms(),solll)))...) - # break_ind = true - # break - else - if verbose - println("Solved: ",string.(eqs_to_solve)," for: ",Symbol.(vars_to_solve), " symbolically.") - end - # relevant_pars = reduce(union,vcat(𝓂.par_list,𝓂.par_calib_list)[eqs[:,eqs[2,:] .== n][1,:]]) - # relevant_pars = reduce(union,map(x->x.atoms(),collect(soll[1]))) - atoms = reduce(union,map(x->x.atoms(),collect(soll[1]))) - # println(atoms) - [push!(atoms_in_equations, Symbol(a)) for a in atoms] - - for (k, vars) in enumerate(vars_to_solve) - push!(𝓂.solved_vars,Symbol(vars)) - push!(𝓂.solved_vals,Meta.parse(string(soll[1][k]))) #using convert(Expr,x) leads to ugly expressions - - push!(atoms_in_equations_list, Set(Symbol.(soll[1][k].atoms()))) - # push!(atoms_in_equations_list, Set(Symbol.(soll[vars].atoms()))) # to be fixed - push!(SS_solve_func,:($(𝓂.solved_vars[end]) = $(𝓂.solved_vals[end]))) - end - end - - - end - - # try symbolically and use numerical if it does not work - if numerical_sol || !symbolic_SS - if !symbolic_SS && verbose - println("Solved: ",string.(eqs_to_solve)," for: ",Symbol.(vars_to_solve), " numerically.") - end - - push!(𝓂.solved_vars,Symbol.(vars_to_solve)) - push!(𝓂.solved_vals,Meta.parse.(string.(eqs_to_solve))) - - syms_in_eqs = Set() - - for i in eqs_to_solve - # push!(syms_in_eqs, Symbol.(PythonCall.pystr.(i.atoms()))...) - push!(syms_in_eqs, Symbol.(SPyPyC.:↓(SPyPyC.free_symbols(i)))...) - end - - # println(syms_in_eqs) - push!(atoms_in_equations_list,setdiff(syms_in_eqs, 𝓂.solved_vars[end])) - - calib_pars = [] - calib_pars_input = [] - relevant_pars = reduce(union,vcat(𝓂.par_list_aux_SS,𝓂.par_calib_list)[eqs[:,eqs[2,:] .== n][1,:]]) - relevant_pars_across = union(relevant_pars_across,relevant_pars) - - iii = 1 - for parss in union(𝓂.parameters,𝓂.parameters_as_function_of_parameters) - # valss = 𝓂.parameter_values[i] - if :($parss) ∈ relevant_pars - push!(calib_pars,:($parss = parameters_and_solved_vars[$iii])) - push!(calib_pars_input,:($parss)) - iii += 1 - end - end - + if isnothing(soll) || length(soll) == 0 || length(intersect((union(SPyPyC.free_symbols.(soll[1])...) .|> SPyPyC.:↓),(vars_to_solve .|> SPyPyC.:↓))) > 0 + if verbose println("Failed finding solution symbolically for: ",vars_to_solve," in: ",eqs_to_solve,". Solving numerically.") end - guess = [] - result = [] - sorted_vars = sort(𝓂.solved_vars[end]) - # sorted_vars = sort(setdiff(𝓂.solved_vars[end],𝓂.➕_vars)) - for (i, parss) in enumerate(sorted_vars) - push!(guess,:($parss = guess[$i])) - # push!(guess,:($parss = undo_transformer(guess[$i]))) - push!(result,:($parss = sol[$i])) - end - - - # separate out auxilliary variables (nonnegativity) - nnaux = [] - nnaux_linear = [] - nnaux_error = [] - push!(nnaux_error, :(aux_error = 0)) - solved_vals = [] - - eq_idx_in_block_to_solve = eqs[:,eqs[2,:] .== n][1,:] - - - other_vrs_eliminated_by_sympy = Set() - - for (i,val) in enumerate(𝓂.solved_vals[end]) - if typeof(val) ∈ [Symbol,Float64,Int] - push!(solved_vals,val) - else - if eq_idx_in_block_to_solve[i] ∈ 𝓂.ss_equations_with_aux_variables - val = vcat(𝓂.ss_aux_equations,𝓂.calibration_equations)[eq_idx_in_block_to_solve[i]] - push!(nnaux,:($(val.args[2]) = max(eps(),$(val.args[3])))) - push!(other_vrs_eliminated_by_sympy, val.args[2]) - push!(nnaux_linear,:($val)) - push!(nnaux_error, :(aux_error += min(eps(),$(val.args[3])))) - else - push!(solved_vals,postwalk(x -> x isa Expr ? x.args[1] == :conjugate ? x.args[2] : x : x, val)) - end - end - end - - # println(other_vrs_eliminated_by_sympy) - # sort nnaux vars so that they enter in right order. avoid using a variable before it is declared - # println(nnaux) - if length(nnaux) > 1 - all_symbols = map(x->x.args[1],nnaux) #relevant symbols come first in respective equations - - nn_symbols = map(x->intersect(all_symbols,x), get_symbols.(nnaux)) - - inc_matrix = fill(0,length(all_symbols),length(all_symbols)) - - for i in 1:length(all_symbols) - for k in 1:length(nn_symbols) - inc_matrix[i,k] = collect(all_symbols)[i] ∈ collect(nn_symbols)[k] - end - end - - QQ, P, R, nmatch, n_blocks = BlockTriangularForm.order(sparse(inc_matrix)) - - nnaux = nnaux[QQ] - nnaux_linear = nnaux_linear[QQ] - end - - - - other_vars = [] - other_vars_input = [] - # other_vars_inverse = [] - other_vrs = intersect( setdiff( union(𝓂.var, 𝓂.calibration_equations_parameters, 𝓂.➕_vars), - sort(𝓂.solved_vars[end]) ), - union(syms_in_eqs, other_vrs_eliminated_by_sympy, setdiff(reduce(union, get_symbols.(nnaux), init = []), map(x->x.args[1],nnaux)) ) ) - - # println(intersect( setdiff( union(𝓂.var, 𝓂.calibration_equations_parameters, 𝓂.➕_vars), sort(𝓂.solved_vars[end]) ), union(syms_in_eqs, other_vrs_eliminated_by_sympy ) )) - # println(other_vrs) - for var in other_vrs - # var_idx = findfirst(x -> x == var, union(𝓂.var,𝓂.calibration_equations_parameters)) - push!(other_vars,:($(var) = parameters_and_solved_vars[$iii])) - push!(other_vars_input,:($(var))) - iii += 1 - # push!(other_vars_inverse,:(𝓂.SS_init_guess[$var_idx] = $(var))) - end - - # augment system for bound constraint violations - # aug_lag = [] - # aug_lag_penalty = [] - # push!(aug_lag_penalty, :(bound_violation_penalty = 0)) - - # for varpar in intersect(𝓂.bounded_vars,union(other_vrs,sorted_vars,relevant_pars)) - # i = indexin([varpar],𝓂.bounded_vars) - # push!(aug_lag,:($varpar = min(max($varpar,$(𝓂.lower_bounds[i...])),$(𝓂.upper_bounds[i...])))) - # push!(aug_lag_penalty,:(bound_violation_penalty += max(0,$(𝓂.lower_bounds[i...]) - $varpar) + max(0,$varpar - $(𝓂.upper_bounds[i...])))) - # end + numerical_sol = true + else + if verbose println("Solved: ",string.(eqs_to_solve)," for: ",Symbol.(vars_to_solve), " symbolically.") end + + atoms = reduce(union,map(x->x.atoms(),collect(soll[1]))) + for a in atoms push!(atoms_in_equations, Symbol(a)) end + + for (k, vars) in enumerate(vars_to_solve) + push!(𝓂.solved_vars,Symbol(vars)) + push!(𝓂.solved_vals,Meta.parse(string(soll[1][k]))) #using convert(Expr,x) leads to ugly expressions - # add it also to output from optimisation, in case you use optimiser without bounds - # aug_lag_results = [] + push!(atoms_in_equations_list, Set(Symbol.(soll[1][k].atoms()))) + push!(SS_solve_func,:($(𝓂.solved_vars[end]) = $(𝓂.solved_vals[end]))) + end + end + end - # for varpar in intersect(𝓂.bounded_vars,sorted_vars) - # i = indexin([varpar],𝓂.bounded_vars) - # push!(aug_lag_results,:($varpar = min(max($varpar,𝓂.lower_bounds[$i...]),𝓂.upper_bounds[$i...]))) - # end + eq_idx_in_block_to_solve = eqs[:,eqs[2,:] .== n][1,:] - # funcs_no_transform = :(function block(parameters_and_solved_vars::Vector{Float64}, guess::Vector{Float64}) - # # if guess isa Tuple guess = guess[1] end - # # guess = undo_transformer(guess) - # # println(guess) - # $(guess...) - # $(calib_pars...) # add those variables which were previously solved and are used in the equations - # $(other_vars...) # take only those that appear in equations - DONE - - # # $(aug_lag...) - # # $(nnaux_linear...) - # return [$(solved_vals...),$(nnaux_linear...)] - # end) - -# println(solved_vals) - funcs = :(function block(parameters_and_solved_vars::Vector, guess::Vector) - # if guess isa Tuple guess = guess[1] end - # guess = undo_transformer(guess,lbs,ubs, option = transformer_option) - # println(guess) - $(guess...) - $(calib_pars...) # add those variables which were previously solved and are used in the equations - $(other_vars...) # take only those that appear in equations - DONE - - # $(aug_lag...) - # $(nnaux...) - # $(nnaux_linear...) - return [$(solved_vals...),$(nnaux_linear...)] - end) - - # push!(solved_vals,:(aux_error)) - # push!(solved_vals,:(bound_violation_penalty)) - - #funcs_optim = :(function block(guess::Vector{Float64},transformer_parameters_and_solved_vars::Tuple{Vector{Float64},Int}) - #guess = undo_transformer(guess,option = transformer_parameters_and_solved_vars[2]) - #parameters_and_solved_vars = transformer_parameters_and_solved_vars[1] - # $(guess...) - # $(calib_pars...) # add those variables which were previously solved and are used in the equations - # $(other_vars...) # take only those that appear in equations - DONE - - # $(aug_lag_penalty...) - # $(aug_lag...) - # $(nnaux...) # not needed because the aux vars are inputs - # $(nnaux_error...) - #return sum(abs2,[$(solved_vals...),$(nnaux_linear...)]) - #end) - - push!(NSSS_solver_cache_init_tmp,fill(0.897,length(sorted_vars))) + incidence_matrix_subset = incidence_matrix[vars[:,vars[2,:] .== n][1,:], eq_idx_in_block_to_solve] - # WARNING: infinite bounds are transformed to 1e12 - lbs = [] - ubs = [] - - limit_boundaries = 1e12 + # try symbolically and use numerical if it does not work + if numerical_sol || !symbolic_SS + pv = sortperm(vars_to_solve, by = Symbol) + pe = sortperm(eqs_to_solve, by = string) - for i in sorted_vars - if i ∈ 𝓂.bounded_vars - push!(lbs,𝓂.lower_bounds[i .== 𝓂.bounded_vars][1] == -Inf ? -limit_boundaries+rand() : 𝓂.lower_bounds[i .== 𝓂.bounded_vars][1]) - push!(ubs,𝓂.upper_bounds[i .== 𝓂.bounded_vars][1] == Inf ? limit_boundaries-rand() : 𝓂.upper_bounds[i .== 𝓂.bounded_vars][1]) - else - push!(lbs,-limit_boundaries+rand()) - push!(ubs,limit_boundaries+rand()) - end - end - push!(SS_solve_func,:(lbs = [$(lbs...)])) - push!(SS_solve_func,:(ubs = [$(ubs...)])) - # push!(SS_solve_func,:(𝓂.SS_init_guess = initial_guess)) - # push!(SS_solve_func,:(f = OptimizationFunction(𝓂.ss_solve_blocks_optim[$(n_block)], Optimization.AutoForwardDiff()))) - # push!(SS_solve_func,:(inits = max.(lbs,min.(ubs,𝓂.SS_init_guess[$([findfirst(x->x==y,union(𝓂.var,𝓂.calibration_equations_parameters)) for y in sorted_vars])])))) - # push!(SS_solve_func,:(closest_solution = 𝓂.NSSS_solver_cache[findmin([sum(abs2,pars[end] - params_flt) for pars in 𝓂.NSSS_solver_cache])[2]])) - # push!(SS_solve_func,:(inits = [transformer(max.(lbs,min.(ubs, closest_solution[$(n_block)] ))),closest_solution[end]])) - push!(SS_solve_func,:(inits = max.(lbs,min.(ubs, closest_solution[$(n_block)])))) - - # push!(SS_solve_func,:(println([$(calib_pars_input...),$(other_vars_input...)]))) - - if VERSION >= v"1.9" - push!(SS_solve_func,:(block_solver_AD = ℐ.ImplicitFunction(block_solver, 𝓂.ss_solve_blocks[$(n_block)]; linear_solver = ℐ.DirectLinearSolver(), conditions_backend = 𝒷()))) + if length(pe) > 5 + write_block_solution!(𝓂, SS_solve_func, vars_to_solve, eqs_to_solve, relevant_pars_across, NSSS_solver_cache_init_tmp, eq_idx_in_block_to_solve, atoms_in_equations_list) + # write_domain_safe_block_solution!(𝓂, SS_solve_func, vars_to_solve, eqs_to_solve, relevant_pars_across, NSSS_solver_cache_init_tmp, eq_idx_in_block_to_solve, atoms_in_equations_list, unique_➕_eqs) else - push!(SS_solve_func,:(block_solver_AD = ℐ.ImplicitFunction(block_solver, 𝓂.ss_solve_blocks[$(n_block)]; linear_solver = ℐ.DirectLinearSolver()))) + solved_system = partial_solve(eqs_to_solve[pe], vars_to_solve[pv], incidence_matrix_subset[pv,pe]) + + # if !isnothing(solved_system) && !any(contains.(string.(vcat(solved_system[3],solved_system[4])), "LambertW")) && !any(contains.(string.(vcat(solved_system[3],solved_system[4])), "Heaviside")) + # write_reduced_block_solution!(𝓂, SS_solve_func, solved_system, relevant_pars_across, NSSS_solver_cache_init_tmp, eq_idx_in_block_to_solve, + # 𝓂.➕_vars, unique_➕_eqs) + # else + write_block_solution!(𝓂, SS_solve_func, vars_to_solve, eqs_to_solve, relevant_pars_across, NSSS_solver_cache_init_tmp, eq_idx_in_block_to_solve, atoms_in_equations_list) + # write_domain_safe_block_solution!(𝓂, SS_solve_func, vars_to_solve, eqs_to_solve, relevant_pars_across, NSSS_solver_cache_init_tmp, eq_idx_in_block_to_solve, atoms_in_equations_list, unique_➕_eqs) + # end end - push!(SS_solve_func,:(solution = block_solver_AD([$(calib_pars_input...),$(other_vars_input...)], - $(n_block), - 𝓂.ss_solve_blocks[$(n_block)], - # 𝓂.ss_solve_blocks_no_transform[$(n_block)], - # f, - inits, - lbs, - ubs, - solver_parameters, - # fail_fast_solvers_only = fail_fast_solvers_only, - cold_start, - verbose))) - - # push!(SS_solve_func,:(solution = block_solver_RD([$(calib_pars_input...),$(other_vars_input...)])))#, - # $(n_block), - # 𝓂.ss_solve_blocks[$(n_block)], - # # 𝓂.SS_optimizer, - # f, - # inits, - # lbs, - # ubs, - # fail_fast_solvers_only = fail_fast_solvers_only, - # verbose = verbose))) - push!(SS_solve_func,:(iters += solution[2][2])) - push!(SS_solve_func,:(solution_error += solution[2][1])) - push!(SS_solve_func,:(sol = solution[1])) - # push!(SS_solve_func,:(solution_error += sum(abs2,𝓂.ss_solve_blocks[$(n_block)]([$(calib_pars_input...),$(other_vars_input...)],solution)))) - # push!(SS_solve_func,:(sol = solution)) - - # push!(SS_solve_func,:(println(sol))) - - push!(SS_solve_func,:($(result...))) - # push!(SS_solve_func,:($(aug_lag_results...))) - - # push!(SS_solve_func,:(NSSS_solver_cache_tmp = [])) - # push!(SS_solve_func,:(push!(NSSS_solver_cache_tmp, typeof(sol) == Vector{Float64} ? sol : ℱ.value.(sol)))) - push!(SS_solve_func,:(NSSS_solver_cache_tmp = [NSSS_solver_cache_tmp..., typeof(sol) == Vector{Float64} ? sol : ℱ.value.(sol)])) - - push!(𝓂.ss_solve_blocks,@RuntimeGeneratedFunction(funcs)) - # push!(𝓂.ss_solve_blocks_no_transform,@RuntimeGeneratedFunction(funcs_no_transform)) - # push!(𝓂.ss_solve_blocks_optim,@RuntimeGeneratedFunction(funcs_optim)) - - n_block += 1 + if !symbolic_SS && verbose + println("Solved: ",string.(eqs_to_solve)," for: ",Symbol.(vars_to_solve), " numerically.") + end end end n -= 1 end - push!(NSSS_solver_cache_init_tmp,fill(Inf,length(𝓂.parameters))) - push!(𝓂.NSSS_solver_cache,NSSS_solver_cache_init_tmp) + push!(NSSS_solver_cache_init_tmp, fill(Inf, length(𝓂.parameters))) + push!(𝓂.NSSS_solver_cache, NSSS_solver_cache_init_tmp) unknwns = Symbol.(collect(unknowns)) @@ -2505,7 +3299,7 @@ function solve_steady_state!(𝓂::ℳ, symbolic_SS, Symbolics::symbolics; verbo for (i, parss) in enumerate(𝓂.parameters) if parss ∈ union(atoms_in_equations, relevant_pars_across) - push!(parameters_in_equations,:($parss = params[$i])) + push!(parameters_in_equations,:($parss = parameters[$i])) end end @@ -2529,20 +3323,20 @@ function solve_steady_state!(𝓂::ℳ, symbolic_SS, Symbolics::symbolics; verbo push!(SS_solve_func, min_max_errors...) # push!(SS_solve_func,:(push!(NSSS_solver_cache_tmp, params_scaled_flt))) - push!(SS_solve_func,:(if length(NSSS_solver_cache_tmp) == 0 NSSS_solver_cache_tmp = [params_scaled_flt] else NSSS_solver_cache_tmp = [NSSS_solver_cache_tmp...,params_scaled_flt] end)) - push!(SS_solve_func,:(current_best = sqrt(sum(abs2,𝓂.NSSS_solver_cache[end][end] - params_flt))))# / max(sum(abs2,𝓂.NSSS_solver_cache[end][end]), sum(abs2,params_flt)))) + push!(SS_solve_func,:(if length(NSSS_solver_cache_tmp) == 0 NSSS_solver_cache_tmp = [copy(params_flt)] else NSSS_solver_cache_tmp = [NSSS_solver_cache_tmp...,copy(params_flt)] end)) + - push!(SS_solve_func,:(for pars in 𝓂.NSSS_solver_cache - latest = sqrt(sum(abs2,pars[end] - params_flt))# / max(sum(abs2,pars[end]), sum(abs,params_flt)) - if latest <= current_best - current_best = latest - end - end)) + # push!(SS_solve_func,:(for pars in 𝓂.NSSS_solver_cache + # latest = sqrt(sum(abs2,pars[end] - params_flt))# / max(sum(abs2,pars[end]), sum(abs,params_flt)) + # if latest <= current_best + # current_best = latest + # end + # end)) - push!(SS_solve_func,:(if (current_best > 1e-5) && (solution_error < eps(Float64)) + push!(SS_solve_func,:(if (current_best > 1e-5) && (solution_error < 1e-12) reverse_diff_friendly_push!(𝓂.NSSS_solver_cache, NSSS_solver_cache_tmp) - solved_scale = scale + # solved_scale = scale end)) # push!(SS_solve_func,:(if length(𝓂.NSSS_solver_cache) > 100 popfirst!(𝓂.NSSS_solver_cache) end)) @@ -2555,36 +3349,37 @@ function solve_steady_state!(𝓂::ℳ, symbolic_SS, Symbolics::symbolics; verbo # fix parameter bounds par_bounds = [] - - for varpar in intersect(𝓂.bounded_vars, intersect(𝓂.parameters,union(atoms_in_equations, relevant_pars_across))) - i = indexin([varpar],𝓂.bounded_vars) - push!(par_bounds, :($varpar = min(max($varpar,$(𝓂.lower_bounds[i...])),$(𝓂.upper_bounds[i...])))) - end + for varpar in intersect(𝓂.parameters,union(atoms_in_equations, relevant_pars_across)) + if haskey(𝓂.bounds, varpar) + push!(par_bounds, :($varpar = min(max($varpar,$(𝓂.bounds[varpar][1])),$(𝓂.bounds[varpar][2])))) + end + end solve_exp = :(function solve_SS(parameters::Vector{Real}, 𝓂::ℳ, # fail_fast_solvers_only::Bool, verbose::Bool, - cold_start::Union{Bool,Float64}, - solver_parameters::solver_parameters) - - params_flt = typeof(parameters) == Vector{Float64} ? parameters : ℱ.value.(parameters) - current_best = sum(abs2,𝓂.NSSS_solver_cache[end][end] - params_flt) - closest_solution_init = 𝓂.NSSS_solver_cache[end] - for pars in 𝓂.NSSS_solver_cache - latest = sum(abs2,pars[end] - params_flt) - if latest <= current_best - current_best = latest - closest_solution_init = pars - end - end - solved_scale = 0 - range_length = [1]#fail_fast_solvers_only ? [1] : [ 1, 2, 4, 8,16,32] - for r in range_length - rangee = ignore_derivatives(range(0,1,r+1)) - for scale in rangee[2:end] - if scale <= solved_scale continue end + cold_start::Bool, + solver_parameters::Vector{solver_parameters}) + + # params_flt = typeof(parameters) == Vector{Float64} ? parameters : ℱ.value.(parameters) + # current_best = sum(abs2,𝓂.NSSS_solver_cache[end][end] - params_flt) + # closest_solution_init = 𝓂.NSSS_solver_cache[end] + # for pars in 𝓂.NSSS_solver_cache + # latest = sum(abs2,pars[end] - params_flt) + # if latest <= current_best + # current_best = latest + # closest_solution_init = pars + # end + # end + # solved_scale = 0 + # range_length = [1]#fail_fast_solvers_only ? [1] : [ 1, 2, 4, 8,16,32] + # for r in range_length + # rangee = ignore_derivatives(range(0,1,r+1)) + # for scale in rangee[2:end] + # if scale <= solved_scale continue end + params_flt = typeof(parameters) == Vector{Float64} ? parameters : ℱ.value.(parameters) current_best = sum(abs2,𝓂.NSSS_solver_cache[end][end] - params_flt) closest_solution = 𝓂.NSSS_solver_cache[end] for pars in 𝓂.NSSS_solver_cache @@ -2594,8 +3389,9 @@ function solve_steady_state!(𝓂::ℳ, symbolic_SS, Symbolics::symbolics; verbo closest_solution = pars end end - params = all(isfinite.(closest_solution_init[end])) && parameters != closest_solution_init[end] ? scale * parameters + (1 - scale) * closest_solution_init[end] : parameters - params_scaled_flt = typeof(params) == Vector{Float64} ? params : ℱ.value.(params) + + # params = all(isfinite.(closest_solution_init[end])) && parameters != closest_solution_init[end] ? scale * parameters + (1 - scale) * closest_solution_init[end] : parameters + $(parameters_in_equations...) $(par_bounds...) $(𝓂.calibration_equations_no_var...) @@ -2603,14 +3399,14 @@ function solve_steady_state!(𝓂::ℳ, symbolic_SS, Symbolics::symbolics; verbo solution_error = 0.0 iters = 0 $(SS_solve_func...) - if scale == 1 + # if scale == 1 # return ComponentVector([$(sort(union(𝓂.var,𝓂.exo_past,𝓂.exo_future))...), $(𝓂.calibration_equations_parameters...)], Axis([sort(union(𝓂.exo_present,𝓂.var))...,𝓂.calibration_equations_parameters...])), solution_error # NSSS_solution = [$(Symbol.(replace.(string.(sort(union(𝓂.var,𝓂.exo_past,𝓂.exo_future))), r"ᴸ⁽⁻?[⁰¹²³⁴⁵⁶⁷⁸⁹]+⁾" => ""))...), $(𝓂.calibration_equations_parameters...)] # NSSS_solution[abs.(NSSS_solution) .< 1e-12] .= 0 # doesnt work with Zygote return [$(Symbol.(replace.(string.(sort(union(𝓂.var,𝓂.exo_past,𝓂.exo_future))), r"ᴸ⁽⁻?[⁰¹²³⁴⁵⁶⁷⁸⁹]+⁾" => ""))...), $(𝓂.calibration_equations_parameters...)], (solution_error, iters) - end - end - end + # end + # end + # end end) 𝓂.SS_solve_func = @RuntimeGeneratedFunction(solve_exp) @@ -2721,7 +3517,7 @@ function solve_steady_state!(𝓂::ℳ; verbose::Bool = false) nnaux_linear = [] nnaux_error = [] push!(nnaux_error, :(aux_error = 0)) - solved_vals = [] + solved_vals = Expr[] eq_idx_in_block_to_solve = eqs[:,eqs[2,:] .== n][1,:] @@ -2773,7 +3569,7 @@ function solve_steady_state!(𝓂::ℳ; verbose::Bool = false) other_vrs = intersect( setdiff( union(𝓂.var, 𝓂.calibration_equations_parameters, 𝓂.➕_vars), sort(𝓂.solved_vars[end]) ), union(syms_in_eqs, other_vrs_eliminated_by_sympy, setdiff(reduce(union, get_symbols.(nnaux), init = []), map(x->x.args[1],nnaux)) ) ) - + for var in other_vrs # var_idx = findfirst(x -> x == var, union(𝓂.var,𝓂.calibration_equations_parameters)) push!(other_vars,:($(var) = parameters_and_solved_vars[$iii])) @@ -2796,7 +3592,8 @@ function solve_steady_state!(𝓂::ℳ; verbose::Bool = false) return [$(solved_vals...),$(nnaux_linear...)] end) - push!(NSSS_solver_cache_init_tmp,fill(0.897,length(sorted_vars))) + push!(NSSS_solver_cache_init_tmp,fill(1.205996189998029, length(sorted_vars))) + push!(NSSS_solver_cache_init_tmp,[Inf]) # WARNING: infinite bounds are transformed to 1e12 lbs = [] @@ -2804,19 +3601,22 @@ function solve_steady_state!(𝓂::ℳ; verbose::Bool = false) limit_boundaries = 1e12 - for i in sorted_vars - if i ∈ 𝓂.bounded_vars - push!(lbs,𝓂.lower_bounds[i .== 𝓂.bounded_vars][1] == -Inf ? -limit_boundaries+rand() : 𝓂.lower_bounds[i .== 𝓂.bounded_vars][1]) - push!(ubs,𝓂.upper_bounds[i .== 𝓂.bounded_vars][1] == Inf ? limit_boundaries-rand() : 𝓂.upper_bounds[i .== 𝓂.bounded_vars][1]) + for i in vcat(sorted_vars, calib_pars_input, other_vars_input) + if haskey(𝓂.bounds, i) + push!(lbs,𝓂.bounds[i][1] == -Inf ? -limit_boundaries+rand() : 𝓂.bounds[i][1]) + push!(ubs,𝓂.bounds[i][2] == Inf ? limit_boundaries-rand() : 𝓂.bounds[i][2]) else push!(lbs,-limit_boundaries+rand()) push!(ubs,limit_boundaries+rand()) end end + + push!(SS_solve_func,:(params_and_solved_vars = [$(calib_pars_input...),$(other_vars_input...)])) + push!(SS_solve_func,:(lbs = [$(lbs...)])) push!(SS_solve_func,:(ubs = [$(ubs...)])) - push!(SS_solve_func,:(inits = max.(lbs,min.(ubs, closest_solution[$(n_block)])))) + push!(SS_solve_func,:(inits = [max.(lbs[1:length(closest_solution[$(2*(n_block-1)+1)])], min.(ubs[1:length(closest_solution[$(2*(n_block-1)+1)])], closest_solution[$(2*(n_block-1)+1)])), closest_solution[$(2*n_block)]])) if VERSION >= v"1.9" push!(SS_solve_func,:(block_solver_AD = ℐ.ImplicitFunction(block_solver, 𝓂.ss_solve_blocks[$(n_block)]; linear_solver = ℐ.DirectLinearSolver(), conditions_backend = 𝒷()))) @@ -2824,7 +3624,7 @@ function solve_steady_state!(𝓂::ℳ; verbose::Bool = false) push!(SS_solve_func,:(block_solver_AD = ℐ.ImplicitFunction(block_solver, 𝓂.ss_solve_blocks[$(n_block)]; linear_solver = ℐ.DirectLinearSolver()))) end - push!(SS_solve_func,:(solution = block_solver_AD(length([$(calib_pars_input...),$(other_vars_input...)]) == 0 ? [0.0] : [$(calib_pars_input...),$(other_vars_input...)], + push!(SS_solve_func,:(solution = block_solver_AD(length(params_and_solved_vars) == 0 ? [0.0] : params_and_solved_vars, $(n_block), 𝓂.ss_solve_blocks[$(n_block)], # 𝓂.ss_solve_blocks_no_transform[$(n_block)], @@ -2850,6 +3650,7 @@ function solve_steady_state!(𝓂::ℳ; verbose::Bool = false) push!(SS_solve_func,:($(result...))) push!(SS_solve_func,:(NSSS_solver_cache_tmp = [NSSS_solver_cache_tmp..., typeof(sol) == Vector{Float64} ? sol : ℱ.value.(sol)])) + push!(SS_solve_func,:(NSSS_solver_cache_tmp = [NSSS_solver_cache_tmp..., typeof(params_and_solved_vars) == Vector{Float64} ? params_and_solved_vars : ℱ.value.(params_and_solved_vars)])) push!(𝓂.ss_solve_blocks,@RuntimeGeneratedFunction(funcs)) @@ -2858,6 +3659,7 @@ function solve_steady_state!(𝓂::ℳ; verbose::Bool = false) n -= 1 end + push!(NSSS_solver_cache_init_tmp,[Inf]) push!(NSSS_solver_cache_init_tmp,fill(Inf,length(𝓂.parameters))) push!(𝓂.NSSS_solver_cache,NSSS_solver_cache_init_tmp) @@ -2877,7 +3679,7 @@ function solve_steady_state!(𝓂::ℳ; verbose::Bool = false) for (i, parss) in enumerate(𝓂.parameters) if parss ∈ union(atoms_in_equations, relevant_pars_across) - push!(parameters_in_equations,:($parss = params[$i])) + push!(parameters_in_equations,:($parss = parameters[$i])) end end @@ -2899,7 +3701,7 @@ function solve_steady_state!(𝓂::ℳ; verbose::Bool = false) push!(SS_solve_func,:($(dyn_exos...))) # push!(SS_solve_func,:(push!(NSSS_solver_cache_tmp, params_scaled_flt))) - push!(SS_solve_func,:(if length(NSSS_solver_cache_tmp) == 0 NSSS_solver_cache_tmp = [params_scaled_flt] else NSSS_solver_cache_tmp = [NSSS_solver_cache_tmp...,params_scaled_flt] end)) + push!(SS_solve_func,:(if length(NSSS_solver_cache_tmp) == 0 NSSS_solver_cache_tmp = [copy(params_flt)] else NSSS_solver_cache_tmp = [NSSS_solver_cache_tmp..., copy(params_flt)] end)) push!(SS_solve_func,:(current_best = sqrt(sum(abs2,𝓂.NSSS_solver_cache[end][end] - params_flt))))# / max(sum(abs2,𝓂.NSSS_solver_cache[end][end]), sum(abs2,params_flt)))) @@ -2910,43 +3712,44 @@ function solve_steady_state!(𝓂::ℳ; verbose::Bool = false) end end)) - push!(SS_solve_func,:(if (current_best > 1e-5) && (solution_error < eps(Float64)) + push!(SS_solve_func,:(if (current_best > 1e-5) && (solution_error < 1e-12) reverse_diff_friendly_push!(𝓂.NSSS_solver_cache, NSSS_solver_cache_tmp) - solved_scale = scale + # solved_scale = scale end)) # fix parameter bounds par_bounds = [] - for varpar in intersect(𝓂.bounded_vars, intersect(𝓂.parameters,union(atoms_in_equations, relevant_pars_across))) - i = indexin([varpar],𝓂.bounded_vars) - push!(par_bounds, :($varpar = min(max($varpar,$(𝓂.lower_bounds[i...])),$(𝓂.upper_bounds[i...])))) + for varpar in intersect(𝓂.parameters,union(atoms_in_equations, relevant_pars_across)) + if haskey(𝓂.bounds, varpar) + push!(par_bounds, :($varpar = min(max($varpar,$(𝓂.bounds[varpar][1])),$(𝓂.bounds[varpar][2])))) + end end - solve_exp = :(function solve_SS(parameters::Vector{Real}, 𝓂::ℳ, # fail_fast_solvers_only::Bool, verbose::Bool, - cold_start::Union{Bool,Float64}, - solver_parameters::solver_parameters) - - params_flt = typeof(parameters) == Vector{Float64} ? parameters : ℱ.value.(parameters) - current_best = sum(abs2,𝓂.NSSS_solver_cache[end][end] - params_flt) - closest_solution_init = 𝓂.NSSS_solver_cache[end] - for pars in 𝓂.NSSS_solver_cache - latest = sum(abs2,pars[end] - params_flt) - if latest <= current_best - current_best = latest - closest_solution_init = pars - end - end - solved_scale = 0 - range_length = [1]#fail_fast_solvers_only ? [1] : [ 1, 2, 4, 8,16,32] - for r in range_length - rangee = ignore_derivatives(range(0,1,r+1)) - for scale in rangee[2:end] - if scale <= solved_scale continue end + cold_start::Bool, + solver_parameters::Vector{solver_parameters}) + + # params_flt = typeof(parameters) == Vector{Float64} ? parameters : ℱ.value.(parameters) + # current_best = sum(abs2,𝓂.NSSS_solver_cache[end][end] - params_flt) + # closest_solution_init = 𝓂.NSSS_solver_cache[end] + # for pars in 𝓂.NSSS_solver_cache + # latest = sum(abs2,pars[end] - params_flt) + # if latest <= current_best + # current_best = latest + # closest_solution_init = pars + # end + # end + # solved_scale = 0 + # range_length = [1]#fail_fast_solvers_only ? [1] : [ 1, 2, 4, 8,16,32] + # for r in range_length + # rangee = ignore_derivatives(range(0,1,r+1)) + # for scale in rangee[2:end] + # if scale <= solved_scale continue end + params_flt = typeof(parameters) == Vector{Float64} ? parameters : ℱ.value.(parameters) current_best = sum(abs2,𝓂.NSSS_solver_cache[end][end] - params_flt) closest_solution = 𝓂.NSSS_solver_cache[end] for pars in 𝓂.NSSS_solver_cache @@ -2956,8 +3759,8 @@ function solve_steady_state!(𝓂::ℳ; verbose::Bool = false) closest_solution = pars end end - params = all(isfinite.(closest_solution_init[end])) && parameters != closest_solution_init[end] ? scale * parameters + (1 - scale) * closest_solution_init[end] : parameters - params_scaled_flt = typeof(params) == Vector{Float64} ? params : ℱ.value.(params) + # params = all(isfinite.(closest_solution_init[end])) && parameters != closest_solution_init[end] ? scale * parameters + (1 - scale) * closest_solution_init[end] : parameters + $(parameters_in_equations...) $(par_bounds...) $(𝓂.calibration_equations_no_var...) @@ -2965,12 +3768,12 @@ function solve_steady_state!(𝓂::ℳ; verbose::Bool = false) iters = 0 solution_error = 0.0 $(SS_solve_func...) - if scale == 1 + # if scale == 1 # return ComponentVector([$(sort(union(𝓂.var,𝓂.exo_past,𝓂.exo_future))...), $(𝓂.calibration_equations_parameters...)], Axis([sort(union(𝓂.exo_present,𝓂.var))...,𝓂.calibration_equations_parameters...])), solution_error return [$(Symbol.(replace.(string.(sort(union(𝓂.var,𝓂.exo_past,𝓂.exo_future))), r"ᴸ⁽⁻?[⁰¹²³⁴⁵⁶⁷⁸⁹]+⁾" => ""))...), $(𝓂.calibration_equations_parameters...)] , (solution_error, iters) - end - end - end + # end + # end + # end end) 𝓂.SS_solve_func = @RuntimeGeneratedFunction(solve_exp) @@ -2984,96 +3787,248 @@ function reverse_diff_friendly_push!(x,y) @ignore_derivatives push!(x,y) end +function calculate_SS_solver_runtime_and_loglikelihood(pars::Vector{Float64}, 𝓂::ℳ, tol::AbstractFloat = 1e-12)::Float64 + log_lik = 0.0 + log_lik -= -sum(pars[1:19]) # logpdf of a gamma dist with mean and variance 1 + log_lik -= -log(5 * sqrt(2 * π)) - (pars[20]^2 / (2 * 5^2)) # logpdf of a normal dist with mean = 0 and variance = 5^2 + + pars[1:2] = sort(pars[1:2], rev = true) + + par_inputs = solver_parameters(eps(), eps(), eps(), 250, pars..., 1, 0.0, 2) + + runtime = @elapsed outmodel = try 𝓂.SS_solve_func(𝓂.parameter_values, 𝓂, false, true, [par_inputs]) catch end + + runtime = outmodel isa Tuple{Vector{Float64}, Tuple{Float64, Int64}} ? + (outmodel[2][1] > tol) || !isfinite(outmodel[2][1]) ? + 10 : + runtime : + 10 + + return log_lik / 1e4 + runtime * 1e3 +end + + +function find_SS_solver_parameters!(𝓂::ℳ; maxtime::Int = 60, maxiter::Int = 250000, tol::AbstractFloat = 1e-12) + pars = rand(20) .+ 1 + pars[20] -= 1 + + lbs = fill(eps(), length(pars)) + lbs[20] = -20 + + ubs = fill(100.0,length(pars)) + + sol = Optim.optimize(x -> calculate_SS_solver_runtime_and_loglikelihood(x, 𝓂), + lbs, ubs, pars, + Optim.SAMIN(verbosity = 0), + Optim.Options(time_limit = maxtime, iterations = maxiter)) + + pars = Optim.minimizer(sol) + + par_inputs = solver_parameters(eps(), eps(), eps(), 250, pars..., 1, 0.0, 2) + + SS_and_pars, (solution_error, iters) = 𝓂.SS_solve_func(𝓂.parameter_values, 𝓂, false, true, [par_inputs]) + + if solution_error < tol + push!(𝓂.solver_parameters, par_inputs) + return true + else + return false + end +end + + +function select_fastest_SS_solver_parameters!(𝓂::ℳ; tol::AbstractFloat = 1e-12) + best_param = 𝓂.solver_parameters[1] + + best_time = Inf + + solved = false + + for p in 𝓂.solver_parameters + total_time = 0.0 + + for _ in 1:10 + start_time = time() + + SS_and_pars, (solution_error, iters) = 𝓂.SS_solve_func(𝓂.parameter_values, 𝓂, false, true, [p]) + + elapsed_time = time() - start_time + + total_time += elapsed_time + + if solution_error > tol + total_time = 1e7 + break + end + end + + if total_time < best_time + best_time = total_time + best_param = p + end + + solved = true + end + + if solved + pushfirst!(𝓂.solver_parameters, best_param) + end +end + + +function solve_ss(SS_optimizer::Function, + ss_solve_blocks::Function, + parameters_and_solved_vars::Vector{Float64}, + closest_parameters_and_solved_vars::Vector{Float64}, + lbs::Vector{Float64}, + ubs::Vector{Float64}, + tol::AbstractFloat, + total_iters::Int, + n_block::Int, + verbose::Bool, + guess::Vector{Float64}, + solver_params::solver_parameters, + extended_problem::Bool, + separate_starting_value::Union{Bool,Float64}) + if separate_starting_value isa Float64 + sol_values_init = max.(lbs[1:length(guess)], min.(ubs[1:length(guess)], fill(separate_starting_value, length(guess)))) + sol_values_init[ubs[1:length(guess)] .<= 1] .= .1 # capture cases where part of values is small + else + sol_values_init = max.(lbs[1:length(guess)], min.(ubs[1:length(guess)], [g < 1e12 ? g : solver_params.starting_value for g in guess])) + end + + if extended_problem + function ext_function_to_optimize(guesses) + gss = guesses[1:length(guess)] + + parameters_and_solved_vars_guess = guesses[length(guess)+1:end] + + res = ss_solve_blocks(parameters_and_solved_vars, gss) + + return vcat(res, parameters_and_solved_vars .- parameters_and_solved_vars_guess) + end + else + function function_to_optimize(guesses) ss_solve_blocks(parameters_and_solved_vars, guesses) end + end + + sol_new_tmp, info = SS_optimizer( extended_problem ? ext_function_to_optimize : function_to_optimize, + extended_problem ? vcat(sol_values_init, closest_parameters_and_solved_vars) : sol_values_init, + extended_problem ? lbs : lbs[1:length(guess)], + extended_problem ? ubs : ubs[1:length(guess)], + solver_params ) + + sol_new = isnothing(sol_new_tmp) ? sol_new_tmp : sol_new_tmp[1:length(guess)] + + sol_minimum = isnan(sum(abs, info[4])) ? Inf : sum(abs, info[4]) + + sol_values = max.(lbs[1:length(guess)], min.(ubs[1:length(guess)], sol_new)) + + total_iters += info[1] + + extended_problem_str = extended_problem ? "(extended problem) " : "" + + if separate_starting_value isa Bool + starting_value_str = "" + else + starting_value_str = "and starting point: $separate_starting_value" + end + + if all(guess .< 1e12) && separate_starting_value isa Bool + any_guess_str = "previous solution, " + elseif any(guess .< 1e12) && separate_starting_value isa Bool + any_guess_str = "provided guess, " + else + any_guess_str = "" + end + + max_resid = maximum(abs,ss_solve_blocks(parameters_and_solved_vars, sol_values)) + + if sol_minimum < tol && verbose + println("Block: $n_block - Solved $(extended_problem_str)using ",string(SS_optimizer),", $(any_guess_str)$(starting_value_str); maximum residual = $max_resid") + end + + return sol_values, sol_minimum +end + function block_solver(parameters_and_solved_vars::Vector{Float64}, n_block::Int, ss_solve_blocks::Function, # SS_optimizer, # f::OptimizationFunction, - guess::Vector{Float64}, + guess_and_pars_solved_vars::Vector{Vector{Float64}}, lbs::Vector{Float64}, ubs::Vector{Float64}, - parameters::solver_parameters, - cold_start::Union{Bool,Float64}, + parameters::Vector{solver_parameters}, + cold_start::Bool, verbose::Bool; - tol::AbstractFloat = eps(), + tol::AbstractFloat = 1e-12 #, # eps(), # timeout = 120, - starting_points::Vector{Float64} = [0.7688, 0.897, 1.2, .9, .75, 1.5, -.5, 2, .25] + # starting_points::Vector{Float64} = [1.205996189998029, 0.7688, 0.897, 1.2],#, 0.9, 0.75, 1.5, -0.5, 2.0, .25] # fail_fast_solvers_only = true, # verbose::Bool = false ) - - if cold_start isa Float64 - sol_values = max.(lbs,min.(ubs, fill(cold_start,length(guess)))) - sol_minimum = 1 - elseif cold_start isa Bool - if cold_start - sol_values = max.(lbs,min.(ubs, fill(0.0,length(guess)))) - sol_minimum = sum(abs2,ss_solve_blocks(parameters_and_solved_vars,sol_values)) - else - sol_values = guess - sol_minimum = sum(abs2,ss_solve_blocks(parameters_and_solved_vars,sol_values)) - iters = 0 + guess = guess_and_pars_solved_vars[1] - if verbose && sol_minimum < tol - println("Block: ",n_block," - Solved using previous solution; maximum residual = ",maximum(abs,ss_solve_blocks(parameters_and_solved_vars, sol_values))) - end + sol_values = guess + + closest_parameters_and_solved_vars = sum(abs, guess_and_pars_solved_vars[2]) == Inf ? parameters_and_solved_vars : guess_and_pars_solved_vars[2] + + sol_minimum = sum(abs, ss_solve_blocks(parameters_and_solved_vars, guess)) + + if sol_minimum < tol + if verbose + println("Block: $n_block, - Solved using previous solution; maximum residual = ", maximum(abs, ss_solve_blocks(parameters_and_solved_vars, guess))) end end - # try modified LM to solve hard SS problems - if (sol_minimum > tol)# | (maximum(abs,ss_solve_blocks(sol_values,parameters_and_solved_vars)) > tol)) - SS_optimizer = levenberg_marquardt + total_iters = 0 - previous_sol_init = max.(lbs,min.(ubs, sol_values)) - - sol_new, info = SS_optimizer( - x->ss_solve_blocks(parameters_and_solved_vars, x), - previous_sol_init, - lbs, - ubs, - parameters = parameters - ) # alternatively use .001)#, μ = μ, p = p)# catch e end - - sol_minimum = isnan(sum(abs2,info[4])) ? Inf : sum(abs2,info[4]) - sol_values = max.(lbs,min.(ubs, sol_new )) - iters = info[1] - - if sol_minimum < tol - if verbose - println("Block: ",n_block," - Solved using ",string(SS_optimizer)," and previous best non-converged solution; maximum residual = ",maximum(abs,ss_solve_blocks(parameters_and_solved_vars, sol_values))) - end - elseif cold_start isa Bool && !cold_start - # if the previous non-converged best guess as a starting point does not work, try the standard starting points - for starting_point in starting_points - if sol_minimum > tol - standard_inits = max.(lbs,min.(ubs, fill(starting_point,length(guess)))) - standard_inits[ubs .<= 1] .= .1 # capture cases where part of values is small - - sol_new, info = SS_optimizer( - x->ss_solve_blocks(parameters_and_solved_vars, x), - standard_inits, - lbs, - ubs, - parameters = parameters - )# catch e end - - sol_minimum = isnan(sum(abs2,info[4])) ? Inf : sum(abs2,info[4]) - sol_values = max.(lbs,min.(ubs, sol_new)) - iters = info[1] + SS_optimizer = levenberg_marquardt - if sol_minimum < tol && verbose - println("Block: ",n_block," - Solved using ",string(SS_optimizer)," and starting point: ",starting_point,"; maximum residual = ",maximum(abs,ss_solve_blocks(parameters_and_solved_vars, sol_values))) - end + if cold_start + guesses = any(guess .< 1e12) ? [guess, fill(1e12, length(guess))] : [guess] # if guess were provided, loop over them, and then the starting points only - else - break + for g in guesses + for p in parameters + for ext in [true, false] # try first the system where values and parameters can vary, next try the system where only values can vary + if sol_minimum > tol + sol_values, sol_minimum = solve_ss(SS_optimizer, ss_solve_blocks, parameters_and_solved_vars, closest_parameters_and_solved_vars, lbs, ubs, tol, total_iters, n_block, verbose, + g, + p, + ext, + false) + end end end end + else !cold_start + for ext in [false, true] # try first the system where only values can vary, next try the system where values and parameters can vary + if sol_minimum > tol + sol_values, sol_minimum = solve_ss(SS_optimizer, ss_solve_blocks, parameters_and_solved_vars, closest_parameters_and_solved_vars, lbs, ubs, tol, total_iters, n_block, verbose, + guess, + parameters[1], + ext, + false) + end + end + + for p in unique(parameters) # take unique because some parameters might appear more than once + for s in [p.starting_value, 1.206, 1.5, 2.0, 0.897, 0.7688]#, .9, .75, 1.5, -.5, 2, .25] # try first the guess and then different starting values + # for ext in [false, true] # try first the system where only values can vary, next try the system where values and parameters can vary + if sol_minimum > tol + sol_values, sol_minimum = solve_ss(SS_optimizer, ss_solve_blocks, parameters_and_solved_vars, closest_parameters_and_solved_vars, lbs, ubs, tol, total_iters, n_block, verbose, + guess, + p, + false, + s) + end + # end + end + end end - return sol_values, (sol_minimum, iters) + return sol_values, (sol_minimum, total_iters) end # needed for Julia 1.8 @@ -3082,15 +4037,15 @@ function block_solver(parameters_and_solved_vars::Vector{ℱ.Dual{Z,S,N}}, ss_solve_blocks::Function, # SS_optimizer, # f::OptimizationFunction, - guess::Vector{Float64}, + guess::Vector{Vector{Float64}}, lbs::Vector{Float64}, ubs::Vector{Float64}, - parameters::solver_parameters, - cold_start::Union{Bool,Float64}, + parameters::Vector{solver_parameters}, + cold_start::Bool, verbose::Bool ; - tol::AbstractFloat = eps(), + tol::AbstractFloat = eps() #, # timeout = 120, - starting_points::Vector{Float64} = [0.7688, 0.897, 1.2, .9, .75, 1.5, -.5, 2, .25] + # starting_points::Vector{Float64} = [1.205996189998029, 0.7688, 0.897, 1.2, .9, .75, 1.5, -.5, 2, .25] # fail_fast_solvers_only = true, # verbose::Bool = false ) where {Z,S,N} @@ -3114,9 +4069,10 @@ function block_solver(parameters_and_solved_vars::Vector{ℱ.Dual{Z,S,N}}, parameters, cold_start, verbose; - tol = tol, + tol = tol #, # timeout = timeout, - starting_points = starting_points) + # starting_points = starting_points + ) if min > tol jvp = fill(0,length(val),length(inp)) * ps @@ -3228,7 +4184,7 @@ second_order_stochastic_steady_state_iterative_solution = ℐ.ImplicitFunction(s linear_solver = ℐ.DirectLinearSolver()) -function calculate_second_order_stochastic_steady_state(parameters::Vector{M}, 𝓂::ℳ; verbose::Bool = false, pruning::Bool = false, tol::AbstractFloat = eps())::Tuple{Vector{M}, Bool, Vector{M}, Float64, AbstractMatrix{M}, SparseMatrixCSC{M}, AbstractMatrix{M}, SparseMatrixCSC{M}} where M +function calculate_second_order_stochastic_steady_state(parameters::Vector{M}, 𝓂::ℳ; verbose::Bool = false, pruning::Bool = false, tol::AbstractFloat = 1e-12)::Tuple{Vector{M}, Bool, Vector{M}, M, AbstractMatrix{M}, SparseMatrixCSC{M}, AbstractMatrix{M}, SparseMatrixCSC{M}} where M SS_and_pars, (solution_error, iters) = 𝓂.SS_solve_func(parameters, 𝓂, verbose, false, 𝓂.solver_parameters) if solution_error > tol || isnan(solution_error) @@ -3374,7 +4330,7 @@ function third_order_stochastic_steady_state_iterative_solution_forward(𝐒₁ end -function calculate_third_order_stochastic_steady_state(parameters::Vector{M}, 𝓂::ℳ; verbose::Bool = false, pruning::Bool = false, tol::AbstractFloat = eps())::Tuple{Vector{M}, Bool, Vector{M}, Float64, AbstractMatrix{M}, SparseMatrixCSC{M}, SparseMatrixCSC{M}, AbstractMatrix{M}, SparseMatrixCSC{M}, SparseMatrixCSC{M}} where M +function calculate_third_order_stochastic_steady_state(parameters::Vector{M}, 𝓂::ℳ; verbose::Bool = false, pruning::Bool = false, tol::AbstractFloat = 1e-12)::Tuple{Vector{M}, Bool, Vector{M}, M, AbstractMatrix{M}, SparseMatrixCSC{M}, SparseMatrixCSC{M}, AbstractMatrix{M}, SparseMatrixCSC{M}, SparseMatrixCSC{M}} where M SS_and_pars, (solution_error, iters) = 𝓂.SS_solve_func(parameters, 𝓂, verbose, false, 𝓂.solver_parameters) if solution_error > tol || isnan(solution_error) @@ -3450,7 +4406,7 @@ function solve!(𝓂::ℳ; obc::Bool = false, verbose::Bool = false, silent::Bool = false, - tol::AbstractFloat = eps()) + tol::AbstractFloat = 1e-12) @assert algorithm ∈ all_available_algorithms @@ -3979,7 +4935,15 @@ function write_functions_mapping!(𝓂::ℳ, max_perturbation_order::Int) # if deriv_first != 0 # deriv_expr = Meta.parse(string(deriv_first.subs(SPyPyC.PI,SPyPyC.N(SPyPyC.PI)))) # push!(first_order, :($(postwalk(x -> x isa Expr ? x.args[1] == :conjugate ? x.args[2] : x : x, deriv_expr)))) - push!(first_order, Symbolics.toexpr(deriv_first)) + deriv_first_expr = Symbolics.toexpr(deriv_first) + # deriv_first_expr_safe = postwalk(x -> x isa Expr ? + # x.args[1] == :^ ? + # :(NaNMath.pow($(x.args[2:end]...))) : + # x : + # x, + # deriv_first_expr) + + push!(first_order, deriv_first_expr) push!(row1,r) push!(column1,c1) i1 += 1 @@ -4223,18 +5187,15 @@ function write_parameters_input!(𝓂::ℳ, parameters::Dict{Symbol,Float64}; ve bounds_broken = false - for i in 1:length(parameters) - bnd_idx = findfirst(x->x==collect(keys(parameters))[i],𝓂.bounded_vars) - if !isnothing(bnd_idx) - if collect(values(parameters))[i] > 𝓂.upper_bounds[bnd_idx] - # println("Calibration is out of bounds for ",collect(keys(parameters))[i],":\t",collect(values(parameters))[i]," > ",𝓂.upper_bounds[bnd_idx] + eps()) - println("Bounds error for ",collect(keys(parameters))[i]," < ",𝓂.upper_bounds[bnd_idx] + eps(),"\tparameter value: ",collect(values(parameters))[i]) + for (par,val) in parameters + if haskey(𝓂.bounds,par) + if val > 𝓂.bounds[par][2] + println("Calibration is out of bounds for $par < $(𝓂.bounds[par][2])\t parameter value: $val") bounds_broken = true continue end - if collect(values(parameters))[i] < 𝓂.lower_bounds[bnd_idx] - # println("Calibration is out of bounds for ",collect(keys(parameters))[i],":\t",collect(values(parameters))[i]," < ",𝓂.lower_bounds[bnd_idx] - eps()) - println("Bounds error for ",collect(keys(parameters))[i]," > ",𝓂.lower_bounds[bnd_idx] + eps(),"\tparameter value: ",collect(values(parameters))[i]) + if val < 𝓂.bounds[par][1] + println("Calibration is out of bounds for $par > $(𝓂.bounds[par][1])\t parameter value: $val") bounds_broken = true continue end @@ -4288,16 +5249,15 @@ function write_parameters_input!(𝓂::ℳ, parameters::Vector{Float64}; verbose bounds_broken = false - for i in 1:length(parameters) - bnd_idx = findfirst(x -> x == 𝓂.parameters[i], 𝓂.bounded_vars) - if !isnothing(bnd_idx) - if collect(values(parameters))[i] > 𝓂.upper_bounds[bnd_idx] - println("Bounds error for ",𝓂.parameters[i]," < ",𝓂.upper_bounds[bnd_idx] + eps(),"\tparameter value: ",𝓂.parameter_values[i]) + for (par,val) in Dict(𝓂.parameters .=> parameters) + if haskey(𝓂.bounds,par) + if val > 𝓂.bounds[par][2] + println("Calibration is out of bounds for $par < $(𝓂.bounds[par][2])\t parameter value: $val") bounds_broken = true continue end - if collect(values(parameters))[i] < 𝓂.lower_bounds[bnd_idx] - println("Bounds error for ",𝓂.parameters[i]," > ",𝓂.lower_bounds[bnd_idx] + eps(),"\tparameter value: ",𝓂.parameter_values[i]) + if val < 𝓂.bounds[par][1] + println("Calibration is out of bounds for $par > $(𝓂.bounds[par][1])\t parameter value: $val") bounds_broken = true continue end @@ -4659,6 +5619,53 @@ end +function calculate_quadratic_iteration_solution_AD(∇₁::AbstractMatrix{S}; T::timings, tol::AbstractFloat = 1e-12) where S + # see Binder and Pesaran (1997) for more details on this approach + expand = @ignore_derivatives [ℒ.diagm(ones(T.nVars))[T.future_not_past_and_mixed_idx,:], + ℒ.diagm(ones(T.nVars))[T.past_not_future_and_mixed_idx,:]] + + ∇₊ = @views ∇₁[:,1:T.nFuture_not_past_and_mixed] * expand[1] + ∇₀ = @views ∇₁[:,T.nFuture_not_past_and_mixed .+ range(1,T.nVars)] + ∇₋ = @views ∇₁[:,T.nFuture_not_past_and_mixed + T.nVars .+ range(1,T.nPast_not_future_and_mixed)] * expand[2] + ∇ₑ = @views ∇₁[:,(T.nFuture_not_past_and_mixed + T.nVars + T.nPast_not_future_and_mixed + 1):end] + + A = ∇₀ \ ∇₋ + B = ∇₀ \ ∇₊ + + # A = sparse(∇̂₀ \ ∇₋) # sparsity desnt make it faster + # B = sparse(∇̂₀ \ ∇₊) + + # droptol!(A,eps()) + # droptol!(B,eps()) + + C = copy(A) + C̄ = similar(A) + + maxiter = 10000 # Maximum number of iterations + + error = one(tol) + tol + iter = 0 + + while error > tol && iter <= maxiter + C̄ = copy(C) # Store the current C̄ before updating it + + # Update C̄ based on the given formula + C = A + B * C^2 + + # Check for convergence + if iter % 100 == 0 + error = maximum(abs, C - C̄) + end + + iter += 1 + end + + D = -(∇₊ * -C + ∇₀) \ ∇ₑ + + return hcat(-C[:, T.past_not_future_and_mixed_idx], D), error <= tol +end + + function riccati_forward(∇₁::Matrix{Float64}; T::timings, explosive::Bool = false)::Tuple{Matrix{Float64},Bool} ∇₊ = @view ∇₁[:,1:T.nFuture_not_past_and_mixed] ∇₀ = @view ∇₁[:,T.nFuture_not_past_and_mixed .+ range(1, T.nVars)] @@ -4760,7 +5767,7 @@ function riccati_forward(∇₁::Matrix{Float64}; T::timings, explosive::Bool = A = @views vcat(-(Ā̂₀ᵤ \ (A₊ᵤ * D * L + Ã₀ᵤ * sol[T.dynamic_order,:] + A₋ᵤ)), sol) - return @view(A[T.reorder,:]), true + return A[T.reorder,:], true end function riccati_conditions(∇₁::AbstractMatrix{M}, sol_d::AbstractMatrix{N}, solved::Bool; T::timings, explosive::Bool = false) where {M,N} @@ -4811,16 +5818,110 @@ function riccati_forward(∇₁::Matrix{ℱ.Dual{Z,S,N}}; T::timings, explosive: end,size(val)), solved end +# @memoize LRU(maxsize=50) +function calculate_jacobian_transpose(∇₁::AbstractMatrix{Float64}; T::timings, explosive::Bool = false) + 𝐒₁, solved = MacroModelling.riccati_forward(∇₁;T = T, explosive = false) + + sp𝐒₁ = sparse(𝐒₁) |> ThreadedSparseArrays.ThreadedSparseMatrixCSC + sp∇₁ = sparse(∇₁) |> ThreadedSparseArrays.ThreadedSparseMatrixCSC + + droptol!(sp𝐒₁, 10*eps()) + droptol!(sp∇₁, 10*eps()) + + # expand = [ℒ.diagm(ones(T.nVars))[T.future_not_past_and_mixed_idx,:], ℒ.diagm(ones(T.nVars))[T.past_not_future_and_mixed_idx,:]] + expand = [ + spdiagm(ones(T.nVars))[T.future_not_past_and_mixed_idx,:] |> ThreadedSparseArrays.ThreadedSparseMatrixCSC, + spdiagm(ones(T.nVars))[T.past_not_future_and_mixed_idx,:] |> ThreadedSparseArrays.ThreadedSparseMatrixCSC + ] + + A = sp∇₁[:,1:T.nFuture_not_past_and_mixed] * expand[1] + B = sp∇₁[:,T.nFuture_not_past_and_mixed .+ range(1,T.nVars)] + + sol_buf = sp𝐒₁ * expand[2] + sol_buf2 = sol_buf * sol_buf + + spd𝐒₁a = (ℒ.kron(expand[2] * sp𝐒₁, A') + + ℒ.kron(expand[2] * expand[2]', sol_buf' * A' + B')) + + droptol!(spd𝐒₁a, 10*eps()) + + d𝐒₁a = spd𝐒₁a' |> collect + + # Initialize empty spd∇₁a + spd∇₁a = spzeros(length(sp𝐒₁), length(∇₁)) + + # Directly allocate dA, dB, dC into spd∇₁a + # Note: You need to calculate the column indices where each matrix starts and ends + # This is conceptual; actual implementation would depend on how you can obtain or compute these indices + dA_cols = 1:(T.nFuture_not_past_and_mixed * size(𝐒₁,1)) + dB_cols = dA_cols[end] .+ (1 : size(𝐒₁, 1)^2) + dC_cols = dB_cols[end] .+ (1 : length(sp𝐒₁)) + + spd∇₁a[:,dA_cols] = ℒ.kron(expand[1] * sol_buf2 * expand[2]' , ℒ.I(size(𝐒₁, 1)))' + spd∇₁a[:,dB_cols] = ℒ.kron(sp𝐒₁, ℒ.I(size(𝐒₁, 1)))' + spd∇₁a[:,dC_cols] = ℒ.I(length(𝐒₁)) + + d𝐒₁â = ℒ.lu(d𝐒₁a, check = false) + + if !ℒ.issuccess(d𝐒₁â) + tmp = spd∇₁a' + solved = false + else + tmp = -(d𝐒₁â \ spd∇₁a)' + end + + return 𝐒₁, solved, tmp +end + + + +function rrule(::typeof(riccati_forward), ∇₁::AbstractMatrix{Float64}; T::timings, explosive::Bool = false) + # Forward pass to compute the output and intermediate values needed for the backward pass + 𝐒₁, solved, tmp = calculate_jacobian_transpose(∇₁, T = T, explosive = explosive) + + function calculate_riccati_pullback(Δ𝐒₁) + # Backward pass to compute the derivatives with respect to inputs + # This would involve computing the derivatives for each operation in reverse order + # and applying chain rule to propagate through the function + return NoTangent(), reshape(tmp * sparsevec(Δ𝐒₁[1]), size(∇₁)) # Return NoTangent() for non-Array inputs or if there's no derivative w.r.t. them + # return NoTangent(), (reshape(-d𝐒₁a \ d∇₁a * vec(Δ𝐒₁) , size(∇₁))) # Return NoTangent() for non-Array inputs or if there's no derivative w.r.t. them + end + + return (𝐒₁, solved), calculate_riccati_pullback +end + -riccati_AD_direct = ℐ.ImplicitFunction(riccati_forward, - riccati_conditions; +riccati_AD_direct = ℐ.ImplicitFunction(riccati_forward, + riccati_conditions; + # conditions_backend = 𝒷(), # ForwardDiff is slower in combination with Zygote as overall backend linear_solver = ℐ.DirectLinearSolver()) riccati_AD = ℐ.ImplicitFunction(riccati_forward, riccati_conditions) # doesnt converge!? -function calculate_first_order_solution(∇₁::Matrix{S}; T::timings, explosive::Bool = false)::Tuple{Matrix{S},Bool} where S <: Real +function calculate_first_order_solution(∇₁::Matrix{Float64}; T::timings, explosive::Bool = false)::Tuple{Matrix{Float64},Bool} + # A, solved = riccati_AD_direct(∇₁; T = T, explosive = explosive) + A, solved = riccati_forward(∇₁; T = T, explosive = explosive) + + if !solved + return hcat(A, zeros(size(A,1),T.nExo)), solved + end + + Jm = @view(ℒ.diagm(ones(T.nVars))[T.past_not_future_and_mixed_idx,:]) + + ∇₊ = @views ∇₁[:,1:T.nFuture_not_past_and_mixed] * ℒ.diagm(ones(T.nVars))[T.future_not_past_and_mixed_idx,:] + ∇₀ = @view ∇₁[:,T.nFuture_not_past_and_mixed .+ range(1,T.nVars)] + ∇ₑ = @view ∇₁[:,(T.nFuture_not_past_and_mixed + T.nVars + T.nPast_not_future_and_mixed + 1):end] + + B = -((∇₊ * A * Jm + ∇₀) \ ∇ₑ) + + return hcat(A, B), solved +end + + +function calculate_first_order_solution(∇₁::Matrix{ℱ.Dual{Z,S,N}}; T::timings, explosive::Bool = false)::Tuple{Matrix{ℱ.Dual{Z,S,N}},Bool} where {Z,S,N} A, solved = riccati_AD_direct(∇₁; T = T, explosive = explosive) + # A, solved = riccati_forward(∇₁; T = T, explosive = explosive) if !solved return hcat(A, zeros(size(A,1),T.nExo)), solved @@ -5180,8 +6281,12 @@ function irf(state_update::Function, end end - axis2 = shocks isa Union{Symbol_input,String_input} ? [T.exo[shock_idx]...] : [:Shock_matrix] - + axis2 = shocks isa Union{Symbol_input,String_input} ? + shock_idx isa Int ? + [T.exo[shock_idx]] : + T.exo[shock_idx] : + [:Shock_matrix] + if any(x -> contains(string(x), "◖"), axis2) axis2_decomposed = decompose_name.(axis2) axis2 = [length(a) > 1 ? string(a[1]) * "{" * join(a[2],"}{") * "}" * (a[end] isa Symbol ? string(a[end]) : "") : string(a[1]) for a in axis2_decomposed] @@ -5300,7 +6405,11 @@ function irf(state_update::Function, end end - axis2 = shocks isa Union{Symbol_input,String_input} ? [T.exo[shock_idx]...] : [:Shock_matrix] + axis2 = shocks isa Union{Symbol_input,String_input} ? + shock_idx isa Int ? + [T.exo[shock_idx]] : + T.exo[shock_idx] : + [:Shock_matrix] if any(x -> contains(string(x), "◖"), axis2) axis2_decomposed = decompose_name.(axis2) @@ -5420,8 +6529,12 @@ function girf(state_update::Function, axis1 = [length(a) > 1 ? string(a[1]) * "{" * join(a[2],"}{") * "}" * (a[end] isa Symbol ? string(a[end]) : "") : string(a[1]) for a in axis1_decomposed] end - axis2 = shocks isa Union{Symbol_input,String_input} ? [T.exo[shock_idx]...] : [:Shock_matrix] - + axis2 = shocks isa Union{Symbol_input,String_input} ? + shock_idx isa Int ? + [T.exo[shock_idx]] : + T.exo[shock_idx] : + [:Shock_matrix] + if any(x -> contains(string(x), "◖"), axis2) axis2_decomposed = decompose_name.(axis2) axis2 = [length(a) > 1 ? string(a[1]) * "{" * join(a[2],"}{") * "}" * (a[end] isa Symbol ? string(a[end]) : "") : string(a[1]) for a in axis2_decomposed] @@ -5468,7 +6581,7 @@ function parse_variables_input_to_index(variables::Union{Symbol_input,String_inp end -function parse_shocks_input_to_index(shocks::Union{Symbol_input,String_input}, T::timings) +function parse_shocks_input_to_index(shocks::Union{Symbol_input,String_input}, T::timings)#::Union{UnitRange{Int64}, Int64, Vector{Int64}} shocks = shocks isa String_input ? shocks .|> Meta.parse .|> replace_indices : shocks if shocks == :all @@ -5481,27 +6594,37 @@ function parse_shocks_input_to_index(shocks::Union{Symbol_input,String_input}, T shock_idx = 1 elseif shocks isa Matrix{Symbol} if length(setdiff(shocks,T.exo)) > 0 - return @warn "Following shocks are not part of the model: " * join(string.(setdiff(shocks,T.exo)),", ") + @warn "Following shocks are not part of the model: " * join(string.(setdiff(shocks,T.exo)),", ") + shock_idx = Int64[] + else + shock_idx = getindex(1:T.nExo,convert(Vector{Bool},vec(sum(shocks .== T.exo,dims= 2)))) end - shock_idx = getindex(1:T.nExo,convert(Vector{Bool},vec(sum(shocks .== T.exo,dims= 2)))) elseif shocks isa Vector{Symbol} if length(setdiff(shocks,T.exo)) > 0 - return @warn "Following shocks are not part of the model: " * join(string.(setdiff(shocks,T.exo)),", ") + @warn "Following shocks are not part of the model: " * join(string.(setdiff(shocks,T.exo)),", ") + shock_idx = Int64[] + else + shock_idx = getindex(1:T.nExo,convert(Vector{Bool},vec(sum(reshape(shocks,1,length(shocks)) .== T.exo, dims= 2)))) end - shock_idx = getindex(1:T.nExo,convert(Vector{Bool},vec(sum(reshape(shocks,1,length(shocks)) .== T.exo, dims= 2)))) elseif shocks isa Tuple{Symbol, Vararg{Symbol}} if length(setdiff(shocks,T.exo)) > 0 - return @warn "Following shocks are not part of the model: " * join(string.(setdiff(Symbol.(collect(shocks)),T.exo)),", ") + @warn "Following shocks are not part of the model: " * join(string.(setdiff(Symbol.(collect(shocks)),T.exo)),", ") + shock_idx = Int64[] + else + shock_idx = getindex(1:T.nExo,convert(Vector{Bool},vec(sum(reshape(collect(shocks),1,length(shocks)) .== T.exo,dims= 2)))) end - shock_idx = getindex(1:T.nExo,convert(Vector{Bool},vec(sum(reshape(collect(shocks),1,length(shocks)) .== T.exo,dims= 2)))) elseif shocks isa Symbol if length(setdiff([shocks],T.exo)) > 0 - return @warn "Following shock is not part of the model: " * join(string(setdiff([shocks],T.exo)[1]),", ") + @warn "Following shock is not part of the model: " * join(string(setdiff([shocks],T.exo)[1]),", ") + shock_idx = Int64[] + else + shock_idx = getindex(1:T.nExo,shocks .== T.exo) end - shock_idx = getindex(1:T.nExo,shocks .== T.exo) else - return @warn "Invalid argument in shocks" + @warn "Invalid argument in shocks" + shock_idx = Int64[] end + return shock_idx end @@ -5661,7 +6784,7 @@ function solve_matrix_equation_forward(ABC::Vector{Float64}; coords::Vector{Tuple{Vector{Int}, Vector{Int}}}, dims::Vector{Tuple{Int,Int}}, sparse_output::Bool = false, - solver::Symbol = :doubling) + solver::Symbol = :doubling)#::Tuple{Matrix{Float64}, Bool} if length(coords) == 1 lengthA = length(coords[1][1]) @@ -6330,13 +7453,25 @@ function calculate_third_order_moments(parameters::Vector{T}, end -function calculate_kalman_filter_loglikelihood(𝓂::ℳ, observables::Union{Vector{String}, Vector{Symbol}}, 𝐒₁::Matrix{S}, data_in_deviations::Matrix{S}) where S - observables_and_states = @ignore_derivatives sort(union(𝓂.timings.past_not_future_and_mixed_idx,indexin(observables,sort(union(𝓂.aux,𝓂.var,𝓂.exo_present))))) +function calculate_kalman_filter_loglikelihood(𝓂::ℳ, observables::Vector{Symbol}, 𝐒₁::Matrix{S}, data_in_deviations::Matrix{S})::S where S + obs_idx = @ignore_derivatives convert(Vector{Int},indexin(observables,sort(union(𝓂.aux,𝓂.var,𝓂.exo_present)))) + + calculate_kalman_filter_loglikelihood(𝓂, obs_idx, 𝐒₁, data_in_deviations) +end + +function calculate_kalman_filter_loglikelihood(𝓂::ℳ, observables::Vector{String}, 𝐒₁::Matrix{S}, data_in_deviations::Matrix{S})::S where S + obs_idx = @ignore_derivatives convert(Vector{Int},indexin(observables,sort(union(𝓂.aux,𝓂.var,𝓂.exo_present)))) + + calculate_kalman_filter_loglikelihood(𝓂, obs_idx, 𝐒₁, data_in_deviations) +end + +function calculate_kalman_filter_loglikelihood(𝓂::ℳ, observables_index::Vector{Int}, 𝐒₁::Matrix{S}, data_in_deviations::Matrix{S})::S where S + observables_and_states = @ignore_derivatives sort(union(𝓂.timings.past_not_future_and_mixed_idx,observables_index)) - A = @views 𝐒₁[observables_and_states,1:𝓂.timings.nPast_not_future_and_mixed] * ℒ.diagm(ones(length(observables_and_states)))[@ignore_derivatives(indexin(𝓂.timings.past_not_future_and_mixed_idx,observables_and_states)),:] - B = @views 𝐒₁[observables_and_states,𝓂.timings.nPast_not_future_and_mixed+1:end] + A = 𝐒₁[observables_and_states,1:𝓂.timings.nPast_not_future_and_mixed] * ℒ.diagm(ones(length(observables_and_states)))[@ignore_derivatives(indexin(𝓂.timings.past_not_future_and_mixed_idx,observables_and_states)),:] + B = 𝐒₁[observables_and_states,𝓂.timings.nPast_not_future_and_mixed+1:end] - C = @views ℒ.diagm(ones(length(observables_and_states)))[@ignore_derivatives(indexin(sort(indexin(observables,sort(union(𝓂.aux,𝓂.var,𝓂.exo_present)))),observables_and_states)),:] + C = ℒ.diagm(ones(length(observables_and_states)))[@ignore_derivatives(indexin(sort(observables_index),observables_and_states)),:] 𝐁 = B * B' @@ -6349,49 +7484,73 @@ function calculate_kalman_filter_loglikelihood(𝓂::ℳ, observables::Union{Vec P, _ = solve_matrix_equation_AD(values, coords = coordinates, dims = dimensions, solver = :doubling) # P = reshape((ℒ.I - ℒ.kron(A, A)) \ reshape(𝐁, prod(size(A)), 1), size(A)) - - u = zeros(length(observables_and_states)) + # P = collect(ℒ.I(length(observables_and_states)) * 10.0) + + u = zeros(S, length(observables_and_states)) # u = SS_and_pars[sort(union(𝓂.timings.past_not_future_and_mixed,observables))] |> collect z = C * u - - loglik = 0.0 - for t in 1:size(data_in_deviations)[2] - v = data_in_deviations[:,t] - z + loglik = S(0) + for t in 1:size(data_in_deviations, 2) + v = data_in_deviations[:, t] - z F = C * P * C' - # F = (F + F') / 2 - - # loglik += log(max(eps(),ℒ.det(F))) + v' * ℒ.pinv(F) * v - # K = P * C' * ℒ.pinv(F) - - # loglik += log(max(eps(),ℒ.det(F))) + v' / F * v - Fdet = ℒ.det(F) + F̄ = ℒ.lu(F, check = false) - if Fdet < eps() return -Inf end + if !ℒ.issuccess(F̄) + return -Inf + end - F̄ = ℒ.lu(F, check = false) + Fdet = ℒ.det(F̄) - if !ℒ.issuccess(F̄) return -Inf end + # Early return if determinant is too small, indicating numerical instability. + if Fdet < eps(S) + return -Inf + end invF = inv(F̄) loglik += log(Fdet) + v' * invF * v - + K = P * C' * invF P = A * (P - K * C * P) * A' + 𝐁 u = A * (u + K * v) - - z = C * u + + z = C * u end return -(loglik + length(data_in_deviations) * log(2 * 3.141592653589793)) / 2 end +# function update_loglikelihood!(loglik::S, P::Matrix{S}, u::Vector{S}, z::Vector{S}, C::Matrix{T}, A::Matrix{S}, 𝐁::Matrix{S}, data_point::Vector{S}) where {S,T} +# v = data_point - z +# F = C * P * C' + +# F̄ = ℒ.lu(F, check = false) +# if !ℒ.issuccess(F̄) +# return -Inf, P, u, z +# end + +# Fdet = ℒ.det(F̄) + +# # Early return if determinant is too small, indicating numerical instability. +# if Fdet < eps(S) +# return -Inf, P, u, z +# end + +# invF = inv(F̄) +# loglik_increment = log(Fdet) + v' * invF * v +# K = P * C' * invF +# P = A * (P - K * C * P) * A' + 𝐁 +# u = A * (u + K * v) +# z = C * u + +# return loglik + loglik_increment, P, u, z +# end function calculate_inversion_filter_loglikelihood(𝓂::ℳ, state::Union{Vector{Float64},Vector{Vector{Float64}}}, state_update::Function, data_in_deviations::Matrix{Float64}, observables::Union{Vector{String}, Vector{Symbol}}, warmup_iterations::Int) if state isa Vector{Float64} @@ -6504,7 +7663,7 @@ function inversion_filter(𝓂::ℳ, algorithm::Symbol; warmup_iterations::Int = 0, verbose::Bool = false, - tol::AbstractFloat = eps()) + tol::AbstractFloat = 1e-12) observables = collect(axiskeys(data_in_deviations,1)) @@ -6691,7 +7850,11 @@ function inversion_filter(𝓂::ℳ, end -function filter_and_smooth(𝓂::ℳ, data_in_deviations::AbstractArray{Float64}, observables::Vector{Symbol}; verbose::Bool = false, tol::AbstractFloat = eps()) +function filter_and_smooth(𝓂::ℳ, + data_in_deviations::AbstractArray{Float64}, + observables::Vector{Symbol}; + verbose::Bool = false, + tol::AbstractFloat = 1e-12) # Based on Durbin and Koopman (2012) # https://jrnold.github.io/ssmodels-in-stan/filtering-and-smoothing.html#smoothing diff --git a/src/dynare.jl b/src/dynare.jl index 50e10f79..d098aa01 100644 --- a/src/dynare.jl +++ b/src/dynare.jl @@ -8,6 +8,8 @@ Reads in a `dynare` .mod-file, adapts the syntax, tries to capture parameter def The recommended workflow is to use this function to translate a .mod-file, and then adapt the output so that it runs and corresponds to the input. +Note that this function copies the .mod-file to a temporary folder and executes it there. All references within that .mod-file are therefore not valid (because those filesare not copied) and must be made copied into the .mod-file. + # Arguments - `path_to_mod_file` [Type: `AbstractString`]: path including filename of the .mod-file to be translated """ @@ -32,13 +34,19 @@ function translate_mod_file(path_to_mod_file::AbstractString) dynare_preprocessor_path = dynare_preprocessor() function parse_model() - run(pipeline(`$dynare_preprocessor_path $args`, stdout = "log.txt")) + try + run(pipeline(`$dynare_preprocessor_path $args`, stdout = "log.txt")) + catch + error("Failed to parse the model. Dynare preprocessor output:\n\n", read("log.txt", String)) + end end cd(parse_model, tmp) son = JSON.parsefile(tmp * "/" * directory_2 * "/model/json/modfile.json") + @assert son isa Dict "Failed to parse the model." + vars = [i["name"] for i in son["endogenous"]] shocks = [i["name"] for i in son["exogenous"]] eqs_orig = [i["lhs"] * " = " * i["rhs"] for i in son["model"]] diff --git a/src/get_functions.jl b/src/get_functions.jl index a8a2c904..7ca0af3b 100644 --- a/src/get_functions.jl +++ b/src/get_functions.jl @@ -1276,7 +1276,7 @@ function get_steady_state(𝓂::ℳ; return_variables_only::Bool = false, verbose::Bool = false, silent::Bool = true, - tol::AbstractFloat = eps()) + tol::AbstractFloat = 1e-12) if !(algorithm == :first_order) stochastic = true end @@ -1302,11 +1302,11 @@ function get_steady_state(𝓂::ℳ; length_par = length(parameter_derivatives) end - SS, (solution_error, iters) = 𝓂.SS_solve_func(𝓂.parameter_values, 𝓂, verbose, false, 𝓂.solver_parameters, false, 𝓂.solver_parameters) + SS, (solution_error, iters) = 𝓂.SS_solve_func(𝓂.parameter_values, 𝓂, verbose, false, 𝓂.solver_parameters) # SS, solution_error = 𝓂.solution.outdated_NSSS ? 𝓂.SS_solve_func(𝓂.parameter_values, 𝓂, verbose) : (copy(𝓂.solution.non_stochastic_steady_state), eps()) if solution_error > tol - @warn "Could not find non-stochastic steady state." + @warn "Could not find non-stochastic steady state. Solution error: $solution_error > $tol" end if stochastic @@ -1644,23 +1644,18 @@ function get_solution(𝓂::ℳ, parameters::Vector{<: Real}; algorithm::Symbol = :first_order, verbose::Bool = false, - tol::AbstractFloat = eps()) + tol::AbstractFloat = 1e-12) @ignore_derivatives solve!(𝓂, verbose = verbose, algorithm = algorithm) - ub = @ignore_derivatives fill(1e12+rand(),length(𝓂.parameters)) - lb = @ignore_derivatives -ub - - for (i,v) in enumerate(𝓂.bounded_vars) - if v ∈ 𝓂.parameters - @ignore_derivatives lb[i] = 𝓂.lower_bounds[i] - @ignore_derivatives ub[i] = 𝓂.upper_bounds[i] + + for (k,v) in 𝓂.bounds + if k ∈ 𝓂.parameters + if min(max(parameters[indexin([k], 𝓂.parameters)][1], v[1]), v[2]) != parameters[indexin([k], 𝓂.parameters)][1] + return -Inf + end end end - if min(max(parameters,lb),ub) != parameters - return -Inf - end - SS_and_pars, (solution_error, iters) = 𝓂.SS_solve_func(parameters, 𝓂, verbose, false, 𝓂.solver_parameters) if solution_error > tol || isnan(solution_error) @@ -2886,7 +2881,7 @@ function get_loglikelihood(𝓂::ℳ, algorithm::Symbol = :first_order, filter::Symbol = :kalman, warmup_iterations::Int = 0, - tol::AbstractFloat = eps(), + tol::AbstractFloat = 1e-12, verbose::Bool = false)::S where S # checks to avoid errors further down the line and inform the user @@ -2900,21 +2895,15 @@ function get_loglikelihood(𝓂::ℳ, @ignore_derivatives solve!(𝓂, verbose = verbose, algorithm = algorithm) - # keep the parameters wihtin bounds - ub = @ignore_derivatives fill(1e12+rand(),length(𝓂.parameters) + length(𝓂.➕_vars)) - lb = @ignore_derivatives -ub - - for (i,v) in enumerate(𝓂.bounded_vars) - if v ∈ 𝓂.parameters - @ignore_derivatives lb[i] = 𝓂.lower_bounds[i] - @ignore_derivatives ub[i] = 𝓂.upper_bounds[i] + # keep the parameters within bounds + for (k,v) in 𝓂.bounds + if k ∈ 𝓂.parameters + if @ignore_derivatives min(max(parameter_values[indexin([k], 𝓂.parameters)][1], v[1]), v[2]) != parameter_values[indexin([k], 𝓂.parameters)][1] + return -Inf + end end end - if min(max(parameter_values,lb),ub) != parameter_values - return -Inf - end - # solve model given the parameters if algorithm == :second_order sss, converged, SS_and_pars, solution_error, ∇₁, ∇₂, 𝐒₁, 𝐒₂ = calculate_second_order_stochastic_steady_state(parameter_values, 𝓂) @@ -2992,6 +2981,7 @@ function get_loglikelihood(𝓂::ℳ, ∇₁ = calculate_jacobian(parameter_values, SS_and_pars, 𝓂) |> Matrix 𝐒₁, solved = calculate_first_order_solution(∇₁; T = 𝓂.timings) + # 𝐒₁, solved = calculate_quadratic_iteration_solution_AD(∇₁; T = 𝓂.timings) if !solved return -Inf end @@ -3017,3 +3007,122 @@ function get_loglikelihood(𝓂::ℳ, return loglikelihood end + + + +""" +$(SIGNATURES) +Calculate the residuals of the non-stochastic steady state equations of the model for a given set of values. Values not provided, will be filled with the non-stochastic steady state values corresponding to the current parameters. + +# Arguments +- $MODEL +- `values` [Type: `Union{Vector{Float64}, Dict{Symbol, Float64}, Dict{String, Float64}, KeyedArray{Float64, 1}}`]: A Vector, Dict, or KeyedArray containing the values of the variables and calibrated parameters in the non-stochastic steady state equations (including calibration equations). + +# Keyword Arguments +- $PARAMETERS + +# Returns +- A KeyedArray containing the absolute values of the residuals of the non-stochastic steady state equations. + +# Examples +```jldoctest +using MacroModelling + +@model RBC begin + 1 / c[0] = (β / c[1]) * (α * exp(z[1]) * k[0]^(α - 1) + (1 - δ)) + c[0] + k[0] = (1 - δ) * k[-1] + q[0] + q[0] = exp(z[0]) * k[-1]^α + z[0] = ρ * z[-1] + std_z * eps_z[x] +end + +@parameters RBC begin + std_z = 0.01 + ρ = 0.2 + δ = 0.02 + k[ss] / q[ss] = 2.5 | α + β = 0.95 +end + +steady_state = SS(RBC, derivatives = false) + +get_non_stochastic_steady_state_residuals(RBC, steady_state) +# output +1-dimensional KeyedArray(NamedDimsArray(...)) with keys: +↓ Equation ∈ 5-element Vector{Symbol} +And data, 5-element Vector{Float64}: + (:Equation₁) 0.0 + (:Equation₂) 0.0 + (:Equation₃) 0.0 + (:Equation₄) 0.0 + (:CalibrationEquation₁) 0.0 +``` + +get_non_stochastic_steady_state_residuals(RBC, [1.1641597, 3.0635781, 1.2254312, 0.0, 0.18157895]) +# output +1-dimensional KeyedArray(NamedDimsArray(...)) with keys: +↓ Equation ∈ 5-element Vector{Symbol} +And data, 5-element Vector{Float64}: + (:Equation₁) 2.7360991250446887e-10 + (:Equation₂) 6.199999980083248e-8 + (:Equation₃) 2.7897102183871425e-8 + (:Equation₄) 0.0 + (:CalibrationEquation₁) 8.160392850342646e-8 +``` +""" +function get_non_stochastic_steady_state_residuals( + 𝓂::ℳ, + values::Union{Vector{Float64}, Dict{Symbol, Float64}, Dict{String, Float64}, KeyedArray{Float64, 1}}; + parameters::ParameterType = nothing + ) + + solve!(𝓂, parameters = parameters) + + SS_and_pars, _ = 𝓂.SS_solve_func(𝓂.parameter_values, 𝓂, false, false, 𝓂.solver_parameters) + + aux_and_vars_in_ss_equations = sort(collect(setdiff(reduce(union, get_symbols.(𝓂.ss_aux_equations)), union(𝓂.parameters_in_equations, 𝓂.➕_vars)))) + + axis1 = vcat(aux_and_vars_in_ss_equations, 𝓂.calibration_equations_parameters) + + vars_in_ss_equations = sort(collect(setdiff(reduce(union, get_symbols.(𝓂.ss_equations)), union(𝓂.parameters_in_equations)))) + + unknowns = vcat(vars_in_ss_equations, 𝓂.calibration_equations_parameters) + + combined_values = Dict(unknowns .=> SS_and_pars[indexin(unknowns, axis1)]) + + if isa(values, Vector) + @assert length(values) == length(unknowns) "Invalid input. Expected a vector of length $(length(unknowns))." + for (i, value) in enumerate(values) + combined_values[unknowns[i]] = value + end + elseif isa(values, Dict) + for (key, value) in values + if key isa String + key = replace_indices(key) + end + combined_values[key] = value + end + elseif isa(values, KeyedArray) + for (key, value) in Dict(axiskeys(values, 1) .=> collect(values)) + if key isa String + key = replace_indices(key) + end + combined_values[key] = value + end + end + + vals = [combined_values[i] for i in unknowns] + + axis1 = vcat([Symbol("Equation" * sub(string(i))) for i in 1:length(vars_in_ss_equations)], [Symbol("CalibrationEquation" * sub(string(i))) for i in 1:length(𝓂.calibration_equations_parameters)]) + + KeyedArray(abs.(𝓂.SS_check_func(𝓂.parameter_values, vals)), Equation = axis1) +end + +""" +See [`get_non_stochastic_steady_state_residuals`](@ref) +""" +get_residuals = get_non_stochastic_steady_state_residuals + +""" +See [`get_non_stochastic_steady_state_residuals`](@ref) +""" +check_residuals = get_non_stochastic_steady_state_residuals \ No newline at end of file diff --git a/src/macros.jl b/src/macros.jl index ec024ba1..0592fad0 100644 --- a/src/macros.jl +++ b/src/macros.jl @@ -92,23 +92,23 @@ macro model(𝓂,ex...) NSSS_solver_cache = CircularBuffer{Vector{Vector{Float64}}}(500) SS_solve_func = x->x + SS_check_func = x->x SS_dependencies = nothing original_equations = [] calibration_equations = [] calibration_equations_parameters = [] - bounded_vars = [] - lower_bounds = [] - upper_bounds = [] + bounds = Dict{Symbol,Tuple{Float64,Float64}}() dyn_equations = [] ➕_vars = [] ss_and_aux_equations = [] + ss_equations = [] aux_vars_created = Set() - unique_➕_vars = [] + unique_➕_eqs = Dict{Union{Expr,Symbol},Expr}() ss_eq_aux_ind = Int[] dyn_eq_aux_ind = Int[] @@ -281,6 +281,28 @@ macro model(𝓂,ex...) push!(dyn_equations,unblock(t_ex)) + + # write down ss equations + eqs = postwalk(x -> + x isa Expr ? + x.head == :(=) ? + Expr(:call,:(-),x.args[1],x.args[2]) : #convert = to - + x.head == :ref ? + occursin(r"^(x|ex|exo|exogenous){1}"i,string(x.args[2])) ? 0 : # set shocks to zero and remove time scripts + x.args[1] : + x.head == :call ? + x.args[1] == :* ? + x.args[2] isa Int ? + x.args[3] isa Int ? + x : + Expr(:call, :*, x.args[3:end]..., x.args[2]) : # 2beta => beta * 2 + x : + x : + x : + x, + model_ex.args[i]) + push!(ss_equations,unblock(eqs)) + # write down ss equations including nonnegativity auxilliary variables # find nonegative variables, parameters, or terms eqs = postwalk(x -> @@ -301,17 +323,13 @@ macro model(𝓂,ex...) !(x.args[3] isa Int) ? x.args[2] isa Symbol ? # nonnegative parameters begin - push!(bounded_vars,x.args[2]) - push!(lower_bounds,eps(Float32)) - push!(upper_bounds,1e12+rand()) + bounds[x.args[2]] = haskey(bounds, x.args[2]) ? (max(bounds[x.args[2]][1], eps()), min(bounds[x.args[2]][2], 1e12)) : (eps(), 1e12) x end : x.args[2].head == :ref ? x.args[2].args[1] isa Symbol ? # nonnegative variables begin - push!(bounded_vars,x.args[2].args[1]) - push!(lower_bounds,eps(Float32)) - push!(upper_bounds,1e12+rand()) + bounds[x.args[2].args[1]] = haskey(bounds, x.args[2].args[1]) ? (max(bounds[x.args[2].args[1]][1], eps()), min(bounds[x.args[2].args[1]][2], 1e12)) : (eps(), 1e12) x end : x : @@ -324,19 +342,23 @@ macro model(𝓂,ex...) end if !(replacement isa Int) # check if the nonnegative term is just a constant - if x.args[2] ∈ unique_➕_vars - ➕_vars_idx = findfirst([x.args[2]] .== unique_➕_vars) - replacement = Expr(:ref,Symbol("➕" * sub(string(➕_vars_idx))),0) - else - push!(unique_➕_vars,x.args[2]) - push!(bounded_vars,:($(Symbol("➕" * sub(string(length(➕_vars)+1)))))) - push!(lower_bounds,eps(Float32)) - push!(upper_bounds,1e12+rand()) - push!(ss_and_aux_equations, Expr(:call,:-, :($(Expr(:ref,Symbol("➕" * sub(string(length(➕_vars)+1))),0))), x.args[2])) # take position of equation in order to get name of vars which are being replaced and substitute accordingly or rewrite to have substitutuion earlier in the cond_var_decomp + if haskey(unique_➕_eqs, x.args[2]) + replacement = unique_➕_eqs[x.args[2]] + else + lb = eps() + ub = 1e12 + + # push!(ss_and_aux_equations, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(ub,max(lb,$(x.args[2]))))) + push!(ss_and_aux_equations, Expr(:call,:-, :($(Expr(:ref,Symbol("➕" * sub(string(length(➕_vars)+1))),0))), x.args[2])) + + bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))] = haskey(bounds, Symbol("➕" * sub(string(length(➕_vars)+1)))) ? (max(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][1], lb), min(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][2], ub)) : (lb, ub) + push!(ss_eq_aux_ind,length(ss_and_aux_equations)) push!(➕_vars,Symbol("➕" * sub(string(length(➕_vars)+1)))) replacement = Expr(:ref,Symbol("➕" * sub(string(length(➕_vars)))),0) + + unique_➕_eqs[x.args[2]] = replacement end end @@ -349,17 +371,13 @@ macro model(𝓂,ex...) x.args[1] ∈ [:log] ? x.args[2] isa Symbol ? # nonnegative parameters begin - push!(bounded_vars,x.args[2]) - push!(lower_bounds,eps(Float32)) - push!(upper_bounds,1e12+rand()) + bounds[x.args[2]] = haskey(bounds, x.args[2]) ? (max(bounds[x.args[2]][1], eps()), min(bounds[x.args[2]][2], 1e12)) : (eps(), 1e12) x end : x.args[2].head == :ref ? x.args[2].args[1] isa Symbol ? # nonnegative variables begin - push!(bounded_vars,x.args[2].args[1]) - push!(lower_bounds,eps(Float32)) - push!(upper_bounds,1e12+rand()) + bounds[x.args[2].args[1]] = haskey(bounds, x.args[2].args[1]) ? (max(bounds[x.args[2].args[1]][1], eps()), min(bounds[x.args[2].args[1]][2], 1e12)) : (eps(), 1e12) x end : x : @@ -372,19 +390,23 @@ macro model(𝓂,ex...) end if !(replacement isa Int) # check if the nonnegative term is just a constant - if x.args[2] ∈ unique_➕_vars - ➕_vars_idx = findfirst([x.args[2]] .== unique_➕_vars) - replacement = Expr(:ref,Symbol("➕" * sub(string(➕_vars_idx))),0) + if haskey(unique_➕_eqs, x.args[2]) + replacement = unique_➕_eqs[x.args[2]] else - push!(unique_➕_vars,x.args[2]) - push!(bounded_vars,:($(Symbol("➕" * sub(string(length(➕_vars)+1)))))) - push!(lower_bounds,eps(Float32)) - push!(upper_bounds,1e12+rand()) - push!(ss_and_aux_equations, Expr(:call,:-, :($(Expr(:ref,Symbol("➕" * sub(string(length(➕_vars)+1))),0))), x.args[2])) # take position of equation in order to get name of vars which are being replaced and substitute accordingly or rewrite to have substitutuion earlier in the code + lb = eps() + ub = 1e12 + + # push!(ss_and_aux_equations, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(ub,max(lb,$(x.args[2]))))) + push!(ss_and_aux_equations, Expr(:call,:-, :($(Expr(:ref,Symbol("➕" * sub(string(length(➕_vars)+1))),0))), x.args[2])) + + bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))] = haskey(bounds, Symbol("➕" * sub(string(length(➕_vars)+1)))) ? (max(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][1], lb), min(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][2], ub)) : (lb, ub) + push!(ss_eq_aux_ind,length(ss_and_aux_equations)) - + push!(➕_vars,Symbol("➕" * sub(string(length(➕_vars)+1)))) replacement = Expr(:ref,Symbol("➕" * sub(string(length(➕_vars)))),0) + + unique_➕_eqs[x.args[2]] = replacement end end :($(Expr(:call, x.args[1], replacement))) @@ -393,17 +415,13 @@ macro model(𝓂,ex...) x.args[1] ∈ [:norminvcdf, :norminv, :qnorm] ? x.args[2] isa Symbol ? # nonnegative parameters begin - push!(bounded_vars,x.args[2]) - push!(lower_bounds,eps()) - push!(upper_bounds,1-eps()) + bounds[x.args[2]] = haskey(bounds, x.args[2]) ? (max(bounds[x.args[2]][1], eps()), min(bounds[x.args[2]][2], 1-eps())) : (eps(), 1-eps()) x end : x.args[2].head == :ref ? x.args[2].args[1] isa Symbol ? # nonnegative variables begin - push!(bounded_vars,x.args[2].args[1]) - push!(lower_bounds,eps()) - push!(upper_bounds,1-eps()) + bounds[x.args[2].args[1]] = haskey(bounds, x.args[2].args[1]) ? (max(bounds[x.args[2].args[1]][1], eps()), min(bounds[x.args[2].args[1]][2], 1-eps())) : (eps(), 1-eps()) x end : x : @@ -416,39 +434,38 @@ macro model(𝓂,ex...) end if !(replacement isa Int) # check if the nonnegative term is just a constant - if x.args[2] ∈ unique_➕_vars - ➕_vars_idx = findfirst([x.args[2]] .== unique_➕_vars) - replacement = Expr(:ref,Symbol("➕" * sub(string(➕_vars_idx))),0) + if haskey(unique_➕_eqs, x.args[2]) + replacement = unique_➕_eqs[x.args[2]] else - push!(unique_➕_vars,x.args[2]) - push!(bounded_vars,:($(Symbol("➕" * sub(string(length(➕_vars)+1)))))) - push!(lower_bounds,eps()) - push!(upper_bounds,1-eps()) + lb = eps() + ub = 1-eps() + + # push!(ss_and_aux_equations, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(ub,max(lb,$(x.args[2]))))) + push!(ss_and_aux_equations, Expr(:call,:-, :($(Expr(:ref,Symbol("➕" * sub(string(length(➕_vars)+1))),0))), x.args[2])) + + bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))] = haskey(bounds, Symbol("➕" * sub(string(length(➕_vars)+1)))) ? (max(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][1], lb), min(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][2], ub)) : (lb, ub) - push!(ss_and_aux_equations, Expr(:call,:-, :($(Expr(:ref,Symbol("➕" * sub(string(length(➕_vars)+1))),0))), x.args[2])) # take position of equation in order to get name of vars which are being replaced and substitute accordingly or rewrite to have substitutuion earlier in the code push!(ss_eq_aux_ind,length(ss_and_aux_equations)) - + push!(➕_vars,Symbol("➕" * sub(string(length(➕_vars)+1)))) replacement = Expr(:ref,Symbol("➕" * sub(string(length(➕_vars)))),0) + + unique_➕_eqs[x.args[2]] = replacement end end :($(Expr(:call, x.args[1], replacement))) end : x : x.args[1] ∈ [:exp] ? - x.args[2] isa Symbol ? # nonnegative parameters + x.args[2] isa Symbol ? # have exp terms bound so they dont go to Inf begin - push!(bounded_vars,x.args[2]) - push!(lower_bounds,-1e12+rand()) - push!(upper_bounds,700) + bounds[x.args[2]] = haskey(bounds, x.args[2]) ? (max(bounds[x.args[2]][1], -1e12), min(bounds[x.args[2]][2], 700)) : (-1e12, 700) x end : x.args[2].head == :ref ? - x.args[2].args[1] isa Symbol ? # nonnegative variables + x.args[2].args[1] isa Symbol ? # have exp terms bound so they dont go to Inf begin - push!(bounded_vars,x.args[2].args[1]) - push!(lower_bounds,-1e12+rand()) - push!(upper_bounds,700) + bounds[x.args[2].args[1]] = haskey(bounds, x.args[2].args[1]) ? (max(bounds[x.args[2].args[1]][1], -1e12), min(bounds[x.args[2].args[1]][2], 700)) : (-1e12, 700) x end : x : @@ -460,22 +477,24 @@ macro model(𝓂,ex...) replacement = simplify(x.args[2]) end - # println(replacement) if !(replacement isa Int) # check if the nonnegative term is just a constant - if x.args[2] ∈ unique_➕_vars - ➕_vars_idx = findfirst([x.args[2]] .== unique_➕_vars) - replacement = Expr(:ref,Symbol("➕" * sub(string(➕_vars_idx))),0) + if haskey(unique_➕_eqs, x.args[2]) + replacement = unique_➕_eqs[x.args[2]] else - push!(unique_➕_vars,x.args[2]) - push!(bounded_vars,:($(Symbol("➕" * sub(string(length(➕_vars)+1)))))) - push!(lower_bounds,-1e12+rand()) - push!(upper_bounds,700) + lb = -1e12 + ub = 700 + + # push!(ss_and_aux_equations, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(ub,max(lb,$(x.args[2]))))) + push!(ss_and_aux_equations, Expr(:call,:-, :($(Expr(:ref,Symbol("➕" * sub(string(length(➕_vars)+1))),0))), x.args[2])) + + bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))] = haskey(bounds, Symbol("➕" * sub(string(length(➕_vars)+1)))) ? (max(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][1], lb), min(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][2], ub)) : (lb, ub) - push!(ss_and_aux_equations, Expr(:call,:-, :($(Expr(:ref,Symbol("➕" * sub(string(length(➕_vars)+1))),0))), x.args[2])) # take position of equation in order to get name of vars which are being replaced and substitute accordingly or rewrite to have substitutuion earlier in the code push!(ss_eq_aux_ind,length(ss_and_aux_equations)) - + push!(➕_vars,Symbol("➕" * sub(string(length(➕_vars)+1)))) replacement = Expr(:ref,Symbol("➕" * sub(string(length(➕_vars)))),0) + + unique_➕_eqs[x.args[2]] = replacement end end :($(Expr(:call, x.args[1], replacement))) @@ -484,17 +503,13 @@ macro model(𝓂,ex...) x.args[1] ∈ [:erfcinv] ? x.args[2] isa Symbol ? # nonnegative parameters begin - push!(bounded_vars,x.args[2]) - push!(lower_bounds,eps()) - push!(upper_bounds,2-eps()) + bounds[x.args[2]] = haskey(bounds, x.args[2]) ? (max(bounds[x.args[2]][1], eps()), min(bounds[x.args[2]][2], 2-eps())) : (eps(), 2-eps()) x end : x.args[2].head == :ref ? x.args[2].args[1] isa Symbol ? # nonnegative variables begin - push!(bounded_vars,x.args[2].args[1]) - push!(lower_bounds,eps()) - push!(upper_bounds,2-eps()) + bounds[x.args[2].args[1]] = haskey(bounds, x.args[2].args[1]) ? (max(bounds[x.args[2].args[1]][1], eps()), min(bounds[x.args[2].args[1]][2], 2-eps())) : (eps(), 2-eps()) x end : x : @@ -506,21 +521,24 @@ macro model(𝓂,ex...) replacement = simplify(x.args[2]) end - # println(replacement) if !(replacement isa Int) # check if the nonnegative term is just a constant - if x.args[2] ∈ unique_➕_vars - ➕_vars_idx = findfirst([x.args[2]] .== unique_➕_vars) - replacement = Expr(:ref,Symbol("➕" * sub(string(➕_vars_idx))),0) + if haskey(unique_➕_eqs, x.args[2]) + replacement = unique_➕_eqs[x.args[2]] else - push!(unique_➕_vars,x.args[2]) - push!(bounded_vars,:($(Symbol("➕" * sub(string(length(➕_vars)+1)))))) - push!(lower_bounds,eps()) - push!(upper_bounds,2-eps()) - push!(ss_and_aux_equations, Expr(:call,:-, :($(Expr(:ref,Symbol("➕" * sub(string(length(➕_vars)+1))),0))), x.args[2])) # take position of equation in order to get name of vars which are being replaced and substitute accordingly or rewrite to have substitutuion earlier in the code + lb = eps() + ub = 2-eps() + + # push!(ss_and_aux_equations, :($(Symbol("➕" * sub(string(length(➕_vars)+1)))) = min(ub,max(lb,$(x.args[2]))))) + push!(ss_and_aux_equations, Expr(:call,:-, :($(Expr(:ref,Symbol("➕" * sub(string(length(➕_vars)+1))),0))), x.args[2])) + + bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))] = haskey(bounds, Symbol("➕" * sub(string(length(➕_vars)+1)))) ? (max(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][1], lb), min(bounds[Symbol("➕" * sub(string(length(➕_vars)+1)))][2], ub)) : (lb, ub) + push!(ss_eq_aux_ind,length(ss_and_aux_equations)) - + push!(➕_vars,Symbol("➕" * sub(string(length(➕_vars)+1)))) replacement = Expr(:ref,Symbol("➕" * sub(string(length(➕_vars)))),0) + + unique_➕_eqs[x.args[2]] = replacement end end :($(Expr(:call, x.args[1], replacement))) @@ -766,21 +784,6 @@ macro model(𝓂,ex...) collect.(dyn_exo_list))) .== 1) @assert length(single_dyn_vars_equations) == 0 "Equations must contain more than 1 dynamic variable. This is not the case for: " * repr([original_equations[indexin(single_dyn_vars_equations,setdiff(1:length(dyn_equations),dyn_eq_aux_ind .- 1))]...]) - - - # unique bounded_vars. before they can be defined multiple times with different bounds - unique_bounded_vars = [] - unique_lower_bounds = [] - unique_upper_bounds = [] - - for i in unique(bounded_vars) - idx = indexin([i],bounded_vars) - if length(idx) > 0 - push!(unique_lower_bounds,maximum(lower_bounds[idx])) - push!(unique_upper_bounds,minimum(upper_bounds[idx])) - push!(unique_bounded_vars,i) - end - end duplicate_equations = [] for item in unique(dyn_equations) @@ -809,6 +812,8 @@ macro model(𝓂,ex...) $parameters, $parameter_values, + Dict{Symbol, Float64}(), # guess + sort($aux), sort(collect($aux_present)), sort(collect($aux_future)), @@ -851,11 +856,13 @@ macro model(𝓂,ex...) $ss_solve_blocks, $NSSS_solver_cache, $SS_solve_func, + $SS_check_func, $SS_dependencies, $➕_vars, $ss_eq_aux_ind, $dyn_equations, + $ss_equations, $original_equations, $calibration_equations, #no_var_ @@ -863,9 +870,7 @@ macro model(𝓂,ex...) $calibration_equations, $calibration_equations_parameters, - $unique_bounded_vars, - $unique_lower_bounds, - $unique_upper_bounds, + $bounds, x->x, # FWrap{Tuple{Vector{Float64}, Vector{Number}, Vector{Float64}}, SparseMatrixCSC{Float64}}(model_jacobian), @@ -879,8 +884,28 @@ macro model(𝓂,ex...) $max_obc_horizon, x->x, - solver_parameters(eps(), eps(), 250, 2.9912988764832833, 0.8725, 0.0027, 0.028948770826150612, 8.04, 4.076413176215408, 0.06375413238034794, 0.24284340766769424, 0.5634017580097571, 0.009549630552246828, 0.6342888355132347, 0.5275522227754195, 1.0, 0.06178989216048817, 0.5234277812131813, 0.422, 0.011209254402846185, 0.5047, 0.6020757011698457, 1, 0.0, 2), - + [ + solver_parameters(eps(), eps(), eps(), 250, + 1.0242323883590136, 0.5892723157762478, 0.0006988523559835617, 0.009036867721330505, 0.14457591298892497, 1.3282546133453548, 0.7955753778741823, 1.7661485851863441e-6, 2.6206711939142943e-7, 7.052160321659248e-12, 1.06497513443326e-6, 5.118937128189348, 90.94952163302091, 3.1268025435012207e-13, 1.691251847378593, 0.5455751102495228, 0.1201767636895742, 0.0007802908980930664, 0.011310267585075185, 1.0032972640942657, + 1, 0.0, 2), + + solver_parameters(eps(), eps(), eps(), 250, + 1.2472903868878749, 0.7149401846020106, 0.0034717544971213966, 0.0008409477479813854, 0.24599133854242075, 1.7996260724902138, 0.2399133704286251, 0.728108158144521, 0.03250298738504968, 0.003271716521926188, 0.5319194600339338, 2.1541622462034, 7.751722474870615, 0.08193253023289011, 1.52607969046303, 0.0002086811131899754, 0.005611466658864538, 0.018304952326087726, 0.0024888171138406773, 0.9061879299736817, + 1, 0.0, 2), + + solver_parameters(eps(), eps(), eps(), 250, + 1.9479518608134938, 0.02343520604394183, 5.125002799990568, 0.02387522857907376, 0.2239226474715968, 4.889172213411495, 1.747880258818237, 2.8683242331457, 0.938229356687311, 1.4890887655876235, 1.6261504814901664, 11.26863249187599, 36.05486169712279, 6.091535897587629, 11.73936761697657, 3.189349432626493, 0.21045178305336348, 0.17122196312330415, 13.251662547139363, 5.282429995876679, + 1, 0.0, 2), + + solver_parameters(eps(), eps(), eps(), 250, + 2.9912988764832833, 0.8725, 0.0027, 0.028948770826150612, 8.04, 4.076413176215408, 0.06375413238034794, 0.24284340766769424, 0.5634017580097571, 0.009549630552246828, 0.6342888355132347, 0.5275522227754195, 1.0, 0.06178989216048817, 0.5234277812131813, 0.422, 0.011209254402846185, 0.5047, 0.6020757011698457, 0.7688, + 1, 0.0, 2), + + solver_parameters(eps(), eps(), eps(), 250, + 2.9912988764832833, 0.8725, 0.0027, 0.028948770826150612, 8.04, 4.076413176215408, 0.06375413238034794, 0.24284340766769424, 0.5634017580097571, 0.009549630552246828, 0.6342888355132347, 0.5275522227754195, 1.0, 0.06178989216048817, 0.5234277812131813, 0.422, 0.011209254402846185, 0.5047, 0.6020757011698457, 0.897, + 1, 0.0, 2) + ], + solution( perturbation( perturbation_solution(SparseMatrixCSC{Float64, Int64}(ℒ.I,0,0), (x,y)->nothing, nothing), perturbation_solution(SparseMatrixCSC{Float64, Int64}(ℒ.I,0,0), (x,y)->nothing, nothing), @@ -910,7 +935,7 @@ end """ $(SIGNATURES) -Adds parameter values and calibration equations to the previously defined model. +Adds parameter values and calibration equations to the previously defined model. Allows to provide an initial guess for the non-stochastic steady state (NSSS). # Arguments - `𝓂`: name of the object previously created containing the model information. @@ -923,6 +948,7 @@ Parameters can be defined in either of the following ways: - expressions containing a target parameter and an equations with endogenous variables in the non-stochastic steady state, and other parameters, or numbers: `k[ss] / (4 * q[ss]) = 1.5 | δ` or `α | 4 * q[ss] = δ * k[ss]` in this case the target parameter will be solved simultaneaously with the non-stochastic steady state using the equation defined with it. # Optional arguments to be placed between `𝓂` and `ex` +- `guess` [Type: `Dict{Symbol, <:Real}, Dict{String, <:Real}}`]: Guess for the non-stochastic steady state. The keys must be the variable (and calibrated parameters) names and the values the guesses. Missing values are filled with standard starting values. - `verbose` [Default: `false`, Type: `Bool`]: print more information about how the non stochastic steady state is solved - `silent` [Default: `false`, Type: `Bool`]: do not print any information - `symbolic` [Default: `false`, Type: `Bool`]: try to solve the non stochastic steady state symbolically and fall back to a numerical solution if not possible @@ -948,6 +974,21 @@ end α = 0.5 β = 0.95 end + +@model RBC_calibrated begin + 1 / c[0] = (β / c[1]) * (α * exp(z[1]) * k[0]^(α - 1) + (1 - δ)) + c[0] + k[0] = (1 - δ) * k[-1] + q[0] + q[0] = exp(z[0]) * k[-1]^α + z[0] = ρ * z[-1] + std_z * eps_z[x] +end + +@parameters RBC_calibrated verbose = true guess = Dict(:k => 3) begin + std_z = 0.01 + ρ = 0.2 + δ = 0.02 + k[ss] / q[ss] = 2.5 | α + β = 0.95 +end ``` # Programmatic model writing @@ -978,7 +1019,7 @@ macro parameters(𝓂,ex...) par_defined_more_than_once = Set() - bounds = [] + bounded_vars = [] # parse options verbose = false @@ -986,6 +1027,7 @@ macro parameters(𝓂,ex...) symbolic = false precompile = false perturbation_order = 1 + guess = Dict{Symbol,Float64}() for exp in ex[1:end-1] postwalk(x -> @@ -1001,8 +1043,10 @@ macro parameters(𝓂,ex...) precompile = x.args[2] : x.args[1] == :perturbation_order && x.args[2] isa Int ? perturbation_order = x.args[2] : + x.args[1] == :guess && (isa(eval(x.args[2]), Dict{Symbol, <:Real}) || isa(eval(x.args[2]), Dict{String, <:Real})) ? + guess = x.args[2] : begin - @warn "Invalid options." + @warn "Invalid options. See docs: `?@parameters` for valid options." x end : x : @@ -1045,10 +1089,10 @@ macro parameters(𝓂,ex...) end : x : x.head == :comparison ? - push!(bounds,x) : + push!(bounded_vars,x) : x.head == :call ? issubset([x.args[1]], [:(<) :(>) :(<=) :(>=)]) ? - push!(bounds,x) : + push!(bounded_vars,x) : x : x : x, @@ -1133,7 +1177,7 @@ macro parameters(𝓂,ex...) occursin(r"^(\+|\-|\*|\/|\^|ss|stst|steady|steadystate|steady_state){1}$"i,string(x)) ? x : begin - diffed = setdiff([x],ss_tmp) + diffed = intersect(setdiff([x], ss_tmp), get_symbols(cal_eq)) if !isempty(diffed) push!(par_tmp,diffed[1]) end @@ -1241,69 +1285,51 @@ macro parameters(𝓂,ex...) #parse bounds - bounded_vars = [] - upper_bounds = [] - lower_bounds = [] + bounds = Dict{Symbol,Tuple{Float64,Float64}}() - for bound in bounds + for bound in bounded_vars postwalk(x -> x isa Expr ? x.head == :comparison ? x.args[2] == :(<) ? x.args[4] == :(<) ? begin - push!(bounded_vars,x.args[3]) - push!(lower_bounds,x.args[1]+eps(Float32)) - push!(upper_bounds,x.args[5]-eps(Float32)) + bounds[x.args[3]] = haskey(bounds, x.args[3]) ? (max(bounds[x.args[3]][1], x.args[1]+eps(Float32)), min(bounds[x.args[3]][2], x.args[5]-eps(Float32))) : (x.args[1]+eps(Float32), x.args[5]-eps(Float32)) end : x.args[4] == :(<=) ? begin - push!(bounded_vars,x.args[3]) - push!(lower_bounds,x.args[1]+eps(Float32)) - push!(upper_bounds,x.args[5]) + bounds[x.args[3]] = haskey(bounds, x.args[3]) ? (max(bounds[x.args[3]][1], x.args[1]+eps(Float32)), min(bounds[x.args[3]][2], x.args[5])) : (x.args[1]+eps(Float32), x.args[5]) end : x : x.args[2] == :(<=) ? x.args[4] == :(<) ? begin - push!(bounded_vars,x.args[3]) - push!(lower_bounds,x.args[1]) - push!(upper_bounds,x.args[5]-eps(Float32)) + bounds[x.args[3]] = haskey(bounds, x.args[3]) ? (max(bounds[x.args[3]][1], x.args[1]), min(bounds[x.args[3]][2], x.args[5]-eps(Float32))) : (x.args[1], x.args[5]-eps(Float32)) end : x.args[4] == :(<=) ? begin - push!(bounded_vars,x.args[3]) - push!(lower_bounds,x.args[1]) - push!(upper_bounds,x.args[5]) + bounds[x.args[3]] = haskey(bounds, x.args[3]) ? (max(bounds[x.args[3]][1], x.args[1]), min(bounds[x.args[3]][2], x.args[5])) : (x.args[1], x.args[5]) end : x : x.args[2] == :(>) ? x.args[4] == :(>) ? begin - push!(bounded_vars,x.args[3]) - push!(lower_bounds,x.args[5]+eps(Float32)) - push!(upper_bounds,x.args[1]-eps(Float32)) + bounds[x.args[3]] = haskey(bounds, x.args[3]) ? (max(bounds[x.args[3]][1], x.args[5]+eps(Float32)), min(bounds[x.args[3]][2], x.args[1]-eps(Float32))) : (x.args[5]+eps(Float32), x.args[1]-eps(Float32)) end : x.args[4] == :(>=) ? begin - push!(bounded_vars,x.args[3]) - push!(lower_bounds,x.args[5]+eps(Float32)) - push!(upper_bounds,x.args[1]) + bounds[x.args[3]] = haskey(bounds, x.args[3]) ? (max(bounds[x.args[3]][1], x.args[5]+eps(Float32)), min(bounds[x.args[3]][2], x.args[1])) : (x.args[5]+eps(Float32), x.args[1]) end : x : x.args[2] == :(>=) ? x.args[4] == :(>) ? begin - push!(bounded_vars,x.args[3]) - push!(lower_bounds,x.args[5]) - push!(upper_bounds,x.args[1]-eps(Float32)) + bounds[x.args[3]] = haskey(bounds, x.args[3]) ? (max(bounds[x.args[3]][1], x.args[5]), min(bounds[x.args[3]][2], x.args[1]-eps(Float32))) : (x.args[5], x.args[1]-eps(Float32)) end : x.args[4] == :(>=) ? begin - push!(bounded_vars,x.args[3]) - push!(lower_bounds,x.args[5]) - push!(upper_bounds,x.args[1]) + bounds[x.args[3]] = haskey(bounds, x.args[3]) ? (max(bounds[x.args[3]][1], x.args[5]), min(bounds[x.args[3]][2], x.args[1])) : (x.args[5], x.args[1]) end : x : x : @@ -1312,57 +1338,41 @@ macro parameters(𝓂,ex...) x.args[1] == :(<) ? x.args[2] isa Symbol ? begin - push!(bounded_vars,x.args[2]) - push!(upper_bounds,x.args[3]-eps(Float32)) - push!(lower_bounds,-1e12+rand()) + bounds[x.args[2]] = haskey(bounds, x.args[2]) ? (max(bounds[x.args[2]][1], -1e12+rand()), min(bounds[x.args[2]][2], x.args[3]-eps(Float32))) : (-1e12+rand(), x.args[3]-eps(Float32)) end : x.args[3] isa Symbol ? begin - push!(bounded_vars,x.args[3]) - push!(lower_bounds,x.args[2]+eps(Float32)) - push!(upper_bounds,1e12+rand()) + bounds[x.args[3]] = haskey(bounds, x.args[3]) ? (max(bounds[x.args[3]][1], x.args[2]+eps(Float32)), min(bounds[x.args[3]][2], 1e12+rand())) : (x.args[2]+eps(Float32), 1e12+rand()) end : x : x.args[1] == :(>) ? x.args[2] isa Symbol ? begin - push!(bounded_vars,x.args[2]) - push!(lower_bounds,x.args[3]+eps(Float32)) - push!(upper_bounds,1e12+rand()) + bounds[x.args[2]] = haskey(bounds, x.args[2]) ? (max(bounds[x.args[2]][1], x.args[3]+eps(Float32)), min(bounds[x.args[2]][2], 1e12+rand())) : (x.args[3]+eps(Float32), 1e12+rand()) end : x.args[3] isa Symbol ? begin - push!(bounded_vars,x.args[3]) - push!(upper_bounds,x.args[2]-eps(Float32)) - push!(lower_bounds,-1e12+rand()) + bounds[x.args[3]] = haskey(bounds, x.args[3]) ? (max(bounds[x.args[3]][1], -1e12+rand()), min(bounds[x.args[3]][2], x.args[2]-eps(Float32))) : (-1e12+rand(), x.args[2]-eps(Float32)) end : x : x.args[1] == :(>=) ? x.args[2] isa Symbol ? begin - push!(bounded_vars,x.args[2]) - push!(lower_bounds,x.args[3]) - push!(upper_bounds,1e12+rand()) + bounds[x.args[2]] = haskey(bounds, x.args[2]) ? (max(bounds[x.args[2]][1], x.args[3]), min(bounds[x.args[2]][2], 1e12+rand())) : (x.args[3], 1e12+rand()) end : x.args[3] isa Symbol ? begin - push!(bounded_vars,x.args[3]) - push!(upper_bounds,x.args[2]) - push!(lower_bounds,-1e12+rand()) + bounds[x.args[3]] = haskey(bounds, x.args[3]) ? (max(bounds[x.args[3]][1], -1e12+rand()), min(bounds[x.args[3]][2], x.args[2])) : (-1e12+rand(), x.args[2]) end : x : x.args[1] == :(<=) ? x.args[2] isa Symbol ? begin - push!(bounded_vars,x.args[2]) - push!(upper_bounds,x.args[3]) - push!(lower_bounds,-1e12+rand()) + bounds[x.args[2]] = haskey(bounds, x.args[2]) ? (max(bounds[x.args[2]][1], -1e12+rand()), min(bounds[x.args[2]][2], x.args[3])) : (-1e12+rand(), x.args[3]) end : x.args[3] isa Symbol ? begin - push!(bounded_vars,x.args[3]) - push!(lower_bounds,x.args[2]) - push!(upper_bounds,1e12+rand()) + bounds[x.args[3]] = haskey(bounds, x.args[3]) ? (max(bounds[x.args[3]][1], x.args[2]), min(bounds[x.args[3]][2],1e12+rand())) : (x.args[2],1e12+rand()) end : x : x : @@ -1382,22 +1392,23 @@ macro parameters(𝓂,ex...) calib_parameters, calib_values = expand_indices($calib_parameters, $calib_values, [mod.$𝓂.parameters_in_equations; mod.$𝓂.var]) calib_eq_parameters, calib_equations_list, ss_calib_list, par_calib_list = expand_calibration_equations($calib_eq_parameters, $calib_equations_list, $ss_calib_list, $par_calib_list, [mod.$𝓂.parameters_in_equations; mod.$𝓂.var]) calib_parameters_no_var, calib_equations_no_var_list = expand_indices($calib_parameters_no_var, $calib_equations_no_var_list, [mod.$𝓂.parameters_in_equations; mod.$𝓂.var]) - - @assert length(setdiff(setdiff(setdiff(union(reduce(union, par_calib_list,init = []),mod.$𝓂.parameters_in_equations),calib_parameters),calib_parameters_no_var),calib_eq_parameters)) == 0 "Undefined parameters: " * repr([setdiff(setdiff(setdiff(union(reduce(union,par_calib_list,init = []),mod.$𝓂.parameters_in_equations),calib_parameters),calib_parameters_no_var),calib_eq_parameters)...]) - $lower_bounds[indexin(intersect(mod.$𝓂.bounded_vars,$bounded_vars),$bounded_vars)] = max.(mod.$𝓂.lower_bounds[indexin(intersect(mod.$𝓂.bounded_vars,$bounded_vars),mod.$𝓂.bounded_vars)],$lower_bounds[indexin(intersect(mod.$𝓂.bounded_vars,$bounded_vars),$bounded_vars)]) + @assert length(setdiff(setdiff(setdiff(union(reduce(union, par_calib_list,init = []),mod.$𝓂.parameters_in_equations),calib_parameters),calib_parameters_no_var),calib_eq_parameters)) == 0 "Undefined parameters: " * repr([setdiff(setdiff(setdiff(union(reduce(union,par_calib_list,init = []),mod.$𝓂.parameters_in_equations),calib_parameters),calib_parameters_no_var),calib_eq_parameters)...]) - $upper_bounds[indexin(intersect(mod.$𝓂.bounded_vars,$bounded_vars),$bounded_vars)] = min.(mod.$𝓂.upper_bounds[indexin(intersect(mod.$𝓂.bounded_vars,$bounded_vars),mod.$𝓂.bounded_vars)],$upper_bounds[indexin(intersect(mod.$𝓂.bounded_vars,$bounded_vars),$bounded_vars)]) + for (k,v) in $bounds + mod.$𝓂.bounds[k] = haskey(mod.$𝓂.bounds, k) ? (max(mod.$𝓂.bounds[k][1], v[1]), min(mod.$𝓂.bounds[k][2], v[2])) : (v[1], v[2]) + end + + invalid_bounds = Symbol[] - mod.$𝓂.lower_bounds = vcat($lower_bounds, mod.$𝓂.lower_bounds[indexin(setdiff(mod.$𝓂.bounded_vars,$bounded_vars),mod.$𝓂.bounded_vars)]) - mod.$𝓂.upper_bounds = vcat($upper_bounds, mod.$𝓂.upper_bounds[indexin(setdiff(mod.$𝓂.bounded_vars,$bounded_vars),mod.$𝓂.bounded_vars)]) - mod.$𝓂.bounded_vars = vcat($bounded_vars,setdiff(mod.$𝓂.bounded_vars,$bounded_vars)) + for (k,v) in mod.$𝓂.bounds + if v[1] >= v[2] + push!(invalid_bounds, k) + end + end - # _, mod.$𝓂.upper_bounds = expand_indices(mod.$𝓂.bounded_vars, mod.$𝓂.upper_bounds, [mod.$𝓂.parameters_in_equations; mod.$𝓂.var]) - # mod.$𝓂.bounded_vars, mod.$𝓂.lower_bounds = expand_indices(mod.$𝓂.bounded_vars, mod.$𝓂.lower_bounds, [mod.$𝓂.parameters_in_equations; mod.$𝓂.var]) - - @assert all(mod.$𝓂.lower_bounds .< mod.$𝓂.upper_bounds) "Invalid bounds: " * repr([mod.$𝓂.bounded_vars[findall(mod.$𝓂.lower_bounds .>= mod.$𝓂.upper_bounds)]...]) - + @assert isempty(invalid_bounds) "Invalid bounds: " * repr(invalid_bounds) + mod.$𝓂.ss_calib_list = ss_calib_list mod.$𝓂.par_calib_list = par_calib_list @@ -1411,65 +1422,104 @@ macro parameters(𝓂,ex...) mod.$𝓂.calibration_equations_no_var = calib_equations_no_var_list mod.$𝓂.calibration_equations_parameters = calib_eq_parameters # mod.$𝓂.solution.outdated_NSSS = true + + if isa($guess, Dict{String, <:Real}) + guess_dict = Dict{Symbol, Float64}() + for (key, value) in $guess + if key isa String + key = replace_indices(key) + end + guess_dict[replace_indices(key)] = value + end + elseif isa($guess, Dict{Symbol, <:Real}) + guess_dict = $guess + end + mod.$𝓂.guess = guess_dict + # time_symbolics = @elapsed # time_rm_red_SS_vars = @elapsed if !$precompile start_time = time() + if !$silent print("Remove redundant variables in non stochastic steady state problem:\t") end + symbolics = create_symbols_eqs!(mod.$𝓂) + remove_redundant_SS_vars!(mod.$𝓂, symbolics) - if !$silent println("Remove redundant variables in non stochastic steady state problem:\t",round(time() - start_time, digits = 3), " seconds") end + if !$silent println(round(time() - start_time, digits = 3), " seconds") end start_time = time() + if !$silent print("Set up non stochastic steady state problem:\t\t\t\t") end + solve_steady_state!(mod.$𝓂, $symbolic, symbolics, verbose = $verbose) # 2nd argument is SS_symbolic mod.$𝓂.obc_violation_equations = write_obc_violation_equations(mod.$𝓂) set_up_obc_violation_function!(mod.$𝓂) - if !$silent println("Set up non stochastic steady state problem:\t",round(time() - start_time, digits = 3), " seconds") end + if !$silent println(round(time() - start_time, digits = 3), " seconds") end else start_time = time() + if !$silent print("Set up non stochastic steady state problem:\t\t\t\t") end + solve_steady_state!(mod.$𝓂, verbose = $verbose) - if !$silent println("Set up non stochastic steady state problem:\t",round(time() - start_time, digits = 3), " seconds") end + if !$silent println(round(time() - start_time, digits = 3), " seconds") end end start_time = time() - # time_dynamic_derivs = @elapsed - write_functions_mapping!(mod.$𝓂, $perturbation_order) - mod.$𝓂.solution.outdated_algorithms = Set(all_available_algorithms) - if !$silent if $perturbation_order == 1 - println("Take symbolic derivatives up to first order:\t",round(time() - start_time, digits = 3), " seconds") + print("Take symbolic derivatives up to first order:\t\t\t\t") elseif $perturbation_order == 2 - println("Take symbolic derivatives up to second order:\t",round(time() - start_time, digits = 3), " seconds") + print("Take symbolic derivatives up to second order:\t\t\t\t") elseif $perturbation_order == 3 - println("Take symbolic derivatives up to third order:\t",round(time() - start_time, digits = 3), " seconds") + print("Take symbolic derivatives up to third order:\t\t\t\t") end end + # time_dynamic_derivs = @elapsed + write_functions_mapping!(mod.$𝓂, $perturbation_order) + + mod.$𝓂.solution.outdated_algorithms = Set(all_available_algorithms) + + if !$silent + println(round(time() - start_time, digits = 3), " seconds") + end + start_time = time() mod.$𝓂.solution.functions_written = true if !$precompile + if !$silent + print("Find non stochastic steady state:\t\t\t\t\t") + end # time_SS_real_solve = @elapsed - SS_and_pars, (solution_error, iters) = mod.$𝓂.SS_solve_func(mod.$𝓂.parameter_values, mod.$𝓂, $verbose, false, mod.$𝓂.solver_parameters) + SS_and_pars, (solution_error, iters) = mod.$𝓂.SS_solve_func(mod.$𝓂.parameter_values, mod.$𝓂, $verbose, true, mod.$𝓂.solver_parameters) - if !$silent - println("Find non stochastic steady state:\t",round(time() - start_time, digits = 3), " seconds") + select_fastest_SS_solver_parameters!(mod.$𝓂) - if solution_error > eps() - @warn "Could not find non-stochastic steady state. Consider setting bounds on variables or calibrated parameters in the `@parameters` section (e.g. `k > 10`)." - end + found_solution = true + + if solution_error > 1e-12 + # start_time = time() + found_solution = find_SS_solver_parameters!(mod.$𝓂) + # println("Find SS solver parameters which solve for the NSSS:\t",round(time() - start_time, digits = 3), " seconds") + end + + if !found_solution + @warn "Could not find non-stochastic steady state. Consider setting bounds on variables or calibrated parameters in the `@parameters` section (e.g. `k > 10`)." + end + + if !$silent + println(round(time() - start_time, digits = 3), " seconds") end mod.$𝓂.solution.non_stochastic_steady_state = SS_and_pars diff --git a/src/priors.jl b/src/priors.jl index ee89bdb1..1bc5211a 100644 --- a/src/priors.jl +++ b/src/priors.jl @@ -12,7 +12,7 @@ If `μσ = true` then `μ` and `σ` are translated to the parameters of the dist # Keyword Arguments - `μσ` [Type: `Bool`]: switch whether μ and σ represent the moments of the distribution or their parameters """ -function Beta(μ::T, σ::T, lower_bound::T, upper_bound::T; μσ::Bool) where T <: Real +function Beta(μ::Real, σ::Real, lower_bound::Real, upper_bound::Real; μσ::Bool) μσ ? Turing.truncated(Turing.Beta(((1 - μ) / σ ^ 2 - 1 / μ) * μ ^ 2, ((1 - μ) / σ ^ 2 - 1 / μ) * μ ^ 2 * (1 / μ - 1)), lower_bound, upper_bound) : Turing.truncated(Turing.Beta(μ, σ), lower_bound, upper_bound) end @@ -30,7 +30,7 @@ If `μσ = true` then `μ` and `σ` are translated to the parameters of the dist - `μσ` [Type: `Bool`]: switch whether μ and σ represent the moments of the distribution or their parameters """ -function Beta(μ::T, σ::T; μσ::Bool) where T <: Real +function Beta(μ::Real, σ::Real; μσ::Bool) μσ ? Turing.Beta(((1 - μ) / σ ^ 2 - 1 / μ) * μ ^ 2, ((1 - μ) / σ ^ 2 - 1 / μ) * μ ^ 2 * (1 / μ - 1)) : Turing.Beta(μ, σ) end @@ -50,7 +50,7 @@ If `μσ = true` then `μ` and `σ` are translated to the parameters of the dist - `μσ` [Type: `Bool`]: switch whether μ and σ represent the moments of the distribution or their parameters """ -function InverseGamma(μ::T, σ::T, lower_bound::T, upper_bound::T; μσ::Bool) where T <: Real +function InverseGamma(μ::Real, σ::Real, lower_bound::Real, upper_bound::Real; μσ::Bool) μσ ? Turing.truncated(Turing.InverseGamma((μ / σ) ^ 2 + 2, μ * ((μ / σ) ^ 2 + 1)), lower_bound, upper_bound) : Turing.truncated(Turing.InverseGamma(μ, σ), lower_bound, upper_bound) end @@ -67,7 +67,7 @@ If `μσ = true` then `μ` and `σ` are translated to the parameters of the dist - `μσ` [Type: `Bool`]: switch whether μ and σ represent the moments of the distribution or their parameters """ -function InverseGamma(μ::T, σ::T; μσ::Bool) where T <: Real +function InverseGamma(μ::Real, σ::Real; μσ::Bool) μσ ? Turing.InverseGamma((μ / σ) ^ 2 + 2, μ * ((μ / σ) ^ 2 + 1)) : Turing.InverseGamma(μ, σ) end @@ -87,7 +87,7 @@ If `μσ = true` then `μ` and `σ` are translated to the parameters of the dist - `μσ` [Type: `Bool`]: switch whether μ and σ represent the moments of the distribution or their parameters """ -function Gamma(μ::T, σ::T, lower_bound::T, upper_bound::T; μσ::Bool) where T <: Real +function Gamma(μ::Real, σ::Real, lower_bound::Real, upper_bound::Real; μσ::Bool) μσ ? Turing.truncated(Turing.Gamma(μ^2/σ^2, σ^2 / μ), lower_bound, upper_bound) : Turing.truncated(Turing.Gamma(μ, σ), lower_bound, upper_bound) end @@ -104,7 +104,7 @@ If `μσ = true` then `μ` and `σ` are translated to the parameters of the dist - `μσ` [Type: `Bool`]: switch whether μ and σ represent the moments of the distribution or their parameters """ -function Gamma(μ::T, σ::T; μσ::Bool) where T <: Real +function Gamma(μ::Real, σ::Real; μσ::Bool) μσ ? Turing.Gamma(μ^2/σ^2, σ^2 / μ) : Turing.Gamma(μ, σ) end @@ -122,7 +122,7 @@ Convenience wrapper for the truncated Normal distribution. - `upper_bound` [Type: `Real`]: truncation upper bound of the distribution """ -function Normal(μ::T, σ::T, lower_bound::T, upper_bound::T) where T <: Real +function Normal(μ::Real, σ::Real, lower_bound::Real, upper_bound::Real) Turing.truncated(Turing.Normal(μ, σ), lower_bound, upper_bound) end diff --git a/src/structures.jl b/src/structures.jl index a7cbe7c4..3aa5c53b 100644 --- a/src/structures.jl +++ b/src/structures.jl @@ -235,6 +235,7 @@ end mutable struct solver_parameters xtol::Float64 ftol::Float64 + rel_xtol::Float64 iterations::Int ϕ̄::Float64 ϕ̂::Float64 @@ -255,6 +256,7 @@ mutable struct solver_parameters λ̅²::Float64 λ̂̅¹::Float64 λ̂̅²::Float64 + starting_value::Float64 transformation_level::Int shift::Float64 backtracking_order::Int @@ -268,6 +270,9 @@ mutable struct ℳ parameters_as_function_of_parameters::Vector{Symbol} parameters::Vector{Symbol} parameter_values::Vector{Float64} + + guess::Dict{Symbol, Float64} + # ss # dynamic_variables::Vector{Symbol} # dyn_ss_past::Vector{Symbol} @@ -352,6 +357,7 @@ mutable struct ℳ # SS_init_guess::Vector{Real} NSSS_solver_cache::CircularBuffer{Vector{Vector{Float64}}} SS_solve_func::Function + SS_check_func::Function # nonlinear_solution_helper SS_dependencies::Any @@ -362,6 +368,7 @@ mutable struct ℳ # t_past_equations # t_present_equations dyn_equations::Vector{Expr} + ss_equations::Vector{Expr} # dyn_equations_future::Vector{Expr} original_equations::Vector{Expr} @@ -370,9 +377,7 @@ mutable struct ℳ calibration_equations::Vector{Expr} calibration_equations_parameters::Vector{Symbol} - bounded_vars::Vector{Symbol} - lower_bounds::Vector{Float64} - upper_bounds::Vector{Float64} + bounds::Dict{Symbol,Tuple{Float64,Float64}} model_jacobian::Function # model_jacobian::FWrap{Tuple{Vector{Float64}, Vector{Number}, Vector{Float64}}, SparseMatrixCSC{Float64}}#{typeof(model_jacobian)} @@ -386,7 +391,7 @@ mutable struct ℳ max_obc_horizon::Int obc_violation_function::Function - solver_parameters::solver_parameters + solver_parameters::Vector{solver_parameters} solution::solution # symbolics::symbolics diff --git a/test/functionality_tests.jl b/test/functionality_tests.jl index 7f4b7da1..3c3dca0a 100644 --- a/test/functionality_tests.jl +++ b/test/functionality_tests.jl @@ -30,6 +30,14 @@ function functionality_test(m; algorithm = :first_order, plots = true, verbose = nsss = get_non_stochastic_steady_state(m) nsss = get_SS(m) + + NSSS = get_SS(m, derivatives = false) + + @test maximum(collect(check_residuals(m, NSSS))) < 1e-12 + @test maximum(collect(check_residuals(m, collect(NSSS)))) < 1e-12 + @test maximum(collect(check_residuals(m, Dict(axiskeys(NSSS, 1) .=> collect(NSSS))))) < 1e-12 + + if algorithm ∈ [:pruned_second_order,:second_order] sols_nv = get_second_order_solution(m) elseif algorithm ∈ [:pruned_third_order,:third_order] @@ -269,51 +277,51 @@ function functionality_test(m; algorithm = :first_order, plots = true, verbose = varnames = axiskeys(new_sub_irfs_all,1) shocknames = axiskeys(new_sub_irfs_all,3) sol = get_solution(m) - var_idxs = findall(vec(sum(sol[end-length(shocknames)+1:end,:] .!= 0,dims = 1)) .> 0)[1:2] + var_idxs = findall(vec(sum(sol[end-length(shocknames)+1:end,:] .!= 0,dims = 1)) .> 0)[[1,end]] conditions = Matrix{Union{Nothing, Float64}}(undef,size(new_sub_irfs_all,1),2) conditions[var_idxs[1],1] = .01 conditions[var_idxs[2],2] = .02 - + cond_fcst = get_conditional_forecast(m, conditions, algorithm = algorithm, conditions_in_levels = false) - if all(vec(sum(sol[end-length(shocknames)+1:end,var_idxs[1:2]] .!= 0, dims = 1)) .> 0) + if all(vec(sum(sol[end-length(shocknames)+1:end,var_idxs[[1, end]]] .!= 0, dims = 1)) .> 0) shocks = Matrix{Union{Nothing, Float64}}(undef,size(new_sub_irfs_all,3),1) shocks[1,1] = .1 cond_fcst = get_conditional_forecast(m, conditions, algorithm = algorithm, conditions_in_levels = false, shocks = shocks) end conditions = spzeros(size(new_sub_irfs_all,1),2) - conditions[var_idxs[1],1] = .01 - conditions[var_idxs[2],2] = .02 - + conditions[1,1] = .01 + conditions[2,2] = .02 + cond_fcst = get_conditional_forecast(m, conditions, algorithm = algorithm, conditions_in_levels = false) - if all(vec(sum(sol[end-length(shocknames)+1:end,var_idxs[1:2]] .!= 0, dims = 1)) .> 0) + if all(vec(sum(sol[end-length(shocknames)+1:end,var_idxs[[1, end]]] .!= 0, dims = 1)) .> 0) shocks = spzeros(size(new_sub_irfs_all,3),1) shocks[1,1] = .1 cond_fcst = get_conditional_forecast(m, conditions, algorithm = algorithm, conditions_in_levels = false, shocks = shocks) end - conditions = KeyedArray(Matrix{Union{Nothing, Float64}}(undef,2,2), Variables = string.(varnames[var_idxs[1:2]]), Periods = 1:2) - conditions[var_idxs[1],1] = .01 - conditions[var_idxs[2],2] = .02 + conditions = KeyedArray(Matrix{Union{Nothing, Float64}}(undef,2,2), Variables = string.(varnames[var_idxs[[1, end]]]), Periods = 1:2) + conditions[1,1] = .01 + conditions[2,2] = .02 cond_fcst = get_conditional_forecast(m, conditions, algorithm = algorithm, conditions_in_levels = false) - conditions = KeyedArray(Matrix{Union{Nothing, Float64}}(undef,2,2), Variables = varnames[var_idxs[1:2]], Periods = 1:2) - conditions[var_idxs[1],1] = .01 - conditions[var_idxs[2],2] = .02 + conditions = KeyedArray(Matrix{Union{Nothing, Float64}}(undef,2,2), Variables = varnames[var_idxs[[1, end]]], Periods = 1:2) + conditions[1,1] = .01 + conditions[2,2] = .02 cond_fcst = get_conditional_forecast(m, conditions, algorithm = algorithm, conditions_in_levels = false) - if all(vec(sum(sol[end-length(shocknames)+1:end,var_idxs[1:2]] .!= 0, dims = 1)) .> 0) + if all(vec(sum(sol[end-length(shocknames)+1:end,var_idxs[[1, end]]] .!= 0, dims = 1)) .> 0) shocks = KeyedArray(Matrix{Union{Nothing, Float64}}(undef,1,1), Shocks = [shocknames[1]], Periods = [1]) shocks[1,1] = .1 cond_fcst = get_conditional_forecast(m, conditions, algorithm = algorithm, conditions_in_levels = false, shocks = shocks) end - if all(vec(sum(sol[end-length(shocknames)+1:end,var_idxs[1:2]] .!= 0, dims = 1)) .> 0) + if all(vec(sum(sol[end-length(shocknames)+1:end,var_idxs[[1, end]]] .!= 0, dims = 1)) .> 0) shocks = KeyedArray(Matrix{Union{Nothing, Float64}}(undef,1,1), Shocks = string.([shocknames[1]]), Periods = [1]) shocks[1,1] = .1 cond_fcst = get_conditional_forecast(m, conditions, algorithm = algorithm, conditions_in_levels = false, shocks = shocks) @@ -345,15 +353,15 @@ function functionality_test(m; algorithm = :first_order, plots = true, verbose = full_SS[indexin(m.aux,full_SS)] = map(x -> Symbol(replace(string(x), r"ᴸ⁽⁻[⁰¹²³⁴⁵⁶⁷⁸⁹]+⁾|ᴸ⁽[⁰¹²³⁴⁵⁶⁷⁸⁹]+⁾" => "")), m.aux) reference_steady_state = [s ∈ m.exo_present ? 0 : NSSS(axiskeys(NSSS,1) isa Vector{String} ? MacroModelling.replace_indices_in_symbol(s) : s) for s in full_SS] - conditions_lvl = KeyedArray(Matrix{Union{Nothing, Float64}}(undef,2,2), Variables = varnames[var_idxs[1:2]], Periods = 1:2) - conditions_lvl[var_idxs[1],1] = .01 + reference_steady_state[var_idxs[1]] - conditions_lvl[var_idxs[2],2] = .02 + reference_steady_state[var_idxs[2]] + conditions_lvl = KeyedArray(Matrix{Union{Nothing, Float64}}(undef,2,2), Variables = varnames[var_idxs[[1, end]]], Periods = 1:2) + conditions_lvl[1,1] = .01 + reference_steady_state[var_idxs[1]] + conditions_lvl[2,2] = .02 + reference_steady_state[var_idxs[2]] cond_fcst = get_conditional_forecast(m, conditions_lvl, algorithm = algorithm, periods = 10, parameters = (m.parameters[1:2] .=> m.parameter_values[1:2] * 1.0001), variables = varnames[1], verbose = true) - conditions_lvl = KeyedArray(Matrix{Union{Nothing, Float64}}(undef,2,2), Variables = string.(varnames[var_idxs[1:2]]), Periods = 1:2) - conditions_lvl[var_idxs[1],1] = .01 + reference_steady_state[var_idxs[1]] - conditions_lvl[var_idxs[2],2] = .02 + reference_steady_state[var_idxs[2]] + conditions_lvl = KeyedArray(Matrix{Union{Nothing, Float64}}(undef,2,2), Variables = string.(varnames[var_idxs[[1, end]]]), Periods = 1:2) + conditions_lvl[1,1] = .01 + reference_steady_state[var_idxs[1]] + conditions_lvl[2,2] = .02 + reference_steady_state[var_idxs[2]] cond_fcst = get_conditional_forecast(m, conditions_lvl, algorithm = algorithm, periods = 10, parameters = (m.parameters[1:2] .=> m.parameter_values[1:2] * 1.0001), variables = varnames[1], verbose = true) diff --git a/test/models/RBC_CME_calibration_equations_and_parameter_definitions_and_specfuns.jl b/test/models/RBC_CME_calibration_equations_and_parameter_definitions_and_specfuns.jl index a6c55e85..834512c6 100644 --- a/test/models/RBC_CME_calibration_equations_and_parameter_definitions_and_specfuns.jl +++ b/test/models/RBC_CME_calibration_equations_and_parameter_definitions_and_specfuns.jl @@ -45,7 +45,7 @@ end gamma = .99 eta = 0.01 - 1 => eta > -1 + 1 >= eta > -1 -1 < gamma <= 1 -1 <= std_z_delta < 1 -1 <= rhoz <= 1 diff --git a/test/models/RBC_CME_calibration_equations_and_parameter_definitions_lead_lags_numsolve.jl b/test/models/RBC_CME_calibration_equations_and_parameter_definitions_lead_lags_numsolve.jl index f823232f..a936b6da 100644 --- a/test/models/RBC_CME_calibration_equations_and_parameter_definitions_lead_lags_numsolve.jl +++ b/test/models/RBC_CME_calibration_equations_and_parameter_definitions_lead_lags_numsolve.jl @@ -19,7 +19,7 @@ end cap_share = 1.66 # alpha = .157 - beta | R[ss] = R_ss + beta | log(R[ss]) = R_ss - 1 R_ss = 1.0035 # beta = .999 diff --git a/test/models/SW07_nonlinear.jl b/test/models/SW07_nonlinear.jl new file mode 100644 index 00000000..10f21d8a --- /dev/null +++ b/test/models/SW07_nonlinear.jl @@ -0,0 +1,209 @@ +@model SW07_nonlinear begin + y[0] = c[0] + inve[0] + y[ss] * gy[0] + afunc[0] * kp[-1] / (1 + ctrend / 100) + + y[0] * (pdot[0] + curvp * (1 - cfc) / cfc) / (1 + curvp * (1 - cfc) / cfc) = a[0] * k[0] ^ calfa * lab[0] ^ (1 - calfa) - (cfc - 1) * y[ss] + + k[0] = kp[-1] * zcap[0] / (1 + ctrend / 100) + + kp[0] = inve[0] * qs[0] * (1 - Sfunc[0]) + kp[-1] * (1 - ctou) / (1 + ctrend / 100) + + pdot[0] = (1 - cprobp) * (Pratio[0] / dp[0]) ^ (( - cfc) * (1 + curvp * (1 - cfc) / cfc) / (cfc - 1)) + pdot[-1] * cprobp * (dp[-1] / dp[0] * pinf[-1] ^ cindp * pinf[ss] ^ (1 - cindp) / pinf[0]) ^ (( - cfc) * (1 + curvp * (1 - cfc) / cfc) / (cfc - 1)) + + wdot[0] = (1 - cprobw) * (wnew[0] / dw[0]) ^ (( - clandaw) * (1 + curvw * (1 - clandaw) / clandaw) / (clandaw - 1)) + wdot[-1] * cprobw * (dw[-1] / dw[0] * pinf[-1] ^ cindw * pinf[ss] ^ (1 - cindw) / pinf[0]) ^ (( - clandaw) * (1 + curvw * (1 - clandaw) / clandaw) / (clandaw - 1)) + + 1 = (1 - cprobp) * (Pratio[0] / dp[0]) ^ (( - (1 + curvp * (1 - cfc))) / (cfc - 1)) + cprobp * (dp[-1] / dp[0] * pinf[-1] ^ cindp * pinf[ss] ^ (1 - cindp) / pinf[0]) ^ (( - (1 + curvp * (1 - cfc))) / (cfc - 1)) + + 1 = (1 - cprobw) * (wnew[0] / dw[0]) ^ (( - (1 + curvw * (1 - clandaw))) / (clandaw - 1)) + cprobw * (dw[-1] / dw[0] * pinf[-1] ^ cindw * pinf[ss] ^ (1 - cindw) / pinf[0]) ^ (( - (1 + curvw * (1 - clandaw))) / (clandaw - 1)) + + 1 = dp[0] * (1 + pdotl[0] * curvp * (1 - cfc) / cfc) / (1 + curvp * (1 - cfc) / cfc) + + w[0] = dw[0] * (1 + curvw * (1 - clandaw) / clandaw * wdotl[0]) / (1 + curvw * (1 - clandaw) / clandaw) + + pdotl[0] = (1 - cprobp) * Pratio[0] / dp[0] + cprobp * dp[-1] / dp[0] * pinf[-1] ^ cindp * pinf[ss] ^ (1 - cindp) / pinf[0] * pdotl[-1] + + wdotl[0] = (1 - cprobw) * wnew[0] / dw[0] + cprobw * dw[-1] / dw[0] * pinf[-1] ^ cindw * pinf[ss] ^ (1 - cindw) / pinf[0] * wdotl[-1] + + xi[0] = exp((csigma - 1) / (1 + csigl) * (lab[0] * (curvw * (1 - clandaw) / clandaw + wdot[0]) / (1 + curvw * (1 - clandaw) / clandaw)) ^ (1 + csigl)) * (c[0] - c[-1] * chabb / (1 + ctrend / 100)) ^ (-csigma) + + 1 = qs[0] * pk[0] * (1 - Sfunc[0] - (1 + ctrend / 100) * inve[0] * SfuncD[0] / inve[-1]) + SfuncD[1] * xi[1] / xi[0] * qsaux[0] * pk[1] * ((1 + ctrend / 100) * inve[1] / inve[0]) ^ 2 * 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (-csigma) + + xi[0] = xi[1] * b[0] * r[0] * 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (-csigma) / pinf[1] + + rk[0] = afuncD[0] + + pk[0] = (rk[1] * zcap[1] - afunc[1] + (1 - ctou) * pk[1]) * xi[1] * 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (-csigma) / xi[0] + + k[0] = lab[0] * w[0] * calfa / (1 - calfa) / rk[0] + + mc[0] = w[0] ^ (1 - calfa) * rk[0] ^ calfa / (a[0] * calfa ^ calfa * (1 - calfa) ^ (1 - calfa)) + + wnew[0] * gamw1[0] * (1 + curvw * (1 - clandaw)) / (1 + curvw * (1 - clandaw) / clandaw) = clandaw * gamw2[0] + gamw3[0] * curvw * (1 - clandaw) / clandaw * (clandaw - 1) / (1 + curvw * (1 - clandaw) / clandaw) * wnew[0] ^ (1 + clandaw * (1 + curvw * (1 - clandaw) / clandaw) / (clandaw - 1)) + + gamw1[0] = lab[0] * dw[0] ^ (clandaw * (1 + curvw * (1 - clandaw) / clandaw) / (clandaw - 1)) + gamw1[1] * (pinf[ss] ^ (1 - cindw) * pinf[0] ^ cindw / pinf[1]) ^ (( - (1 + curvw * (1 - clandaw))) / (clandaw - 1)) * xi[1] / xi[0] * (1 + ctrend / 100) * cprobw * 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (-csigma) + + gamw2[0] = (c[0] - c[-1] * chabb / (1 + ctrend / 100)) * lab[0] * sw[0] * dw[0] ^ (clandaw * (1 + curvw * (1 - clandaw) / clandaw) / (clandaw - 1)) * (lab[0] * (curvw * (1 - clandaw) / clandaw + wdot[0]) / (1 + curvw * (1 - clandaw) / clandaw)) ^ csigl + gamw2[1] * (pinf[ss] ^ (1 - cindw) * pinf[0] ^ cindw / pinf[1]) ^ (( - clandaw) * (1 + curvw * (1 - clandaw) / clandaw) / (clandaw - 1)) * xi[1] / xi[0] * (1 + ctrend / 100) * cprobw * 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (-csigma) + + gamw3[0] = lab[0] + gamw3[1] * pinf[ss] ^ (1 - cindw) * pinf[0] ^ cindw / pinf[1] * xi[1] / xi[0] * (1 + ctrend / 100) * cprobw * 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (-csigma) + + Pratio[0] * gam1[0] * (1 + curvp * (1 - cfc)) / (1 + curvp * (1 - cfc) / cfc) = cfc * gam2[0] + gam3[0] * (cfc - 1) * curvp * (1 - cfc) / cfc / (1 + curvp * (1 - cfc) / cfc) * Pratio[0] ^ (1 + cfc * (1 + curvp * (1 - cfc) / cfc) / (cfc - 1)) + + gam1[0] = y[0] * dp[0] ^ (cfc * (1 + curvp * (1 - cfc) / cfc) / (cfc - 1)) + gam1[1] * xi[1] / xi[0] * (1 + ctrend / 100) * cprobp * 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (-csigma) * (pinf[ss] ^ (1 - cindp) * pinf[0] ^ cindp / pinf[1]) ^ (( - (1 + curvp * (1 - cfc))) / (cfc - 1)) + + gam2[0] = y[0] * mc[0] * spinf[0] * dp[0] ^ (cfc * (1 + curvp * (1 - cfc) / cfc) / (cfc - 1)) + gam2[1] * xi[1] / xi[0] * (1 + ctrend / 100) * cprobp * 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (-csigma) * (pinf[ss] ^ (1 - cindp) * pinf[0] ^ cindp / pinf[1]) ^ (( - cfc) * (1 + curvp * (1 - cfc) / cfc) / (cfc - 1)) + + gam3[0] = y[0] + gam3[1] * pinf[ss] ^ (1 - cindp) * pinf[0] ^ cindp / pinf[1] * xi[1] / xi[0] * (1 + ctrend / 100) * cprobp * 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (-csigma) + + qsaux[0] = qs[1] + + r[0] = r[ss] ^ (1 - crr) * r[-1] ^ crr * (pinf[0] / pinfss) ^ ((1 - crr) * crpi) * (y[0] / yflex[0]) ^ ((1 - crr) * cry) * (y[0] / yflex[0] / (y[-1] / yflex[-1])) ^ crdy * ms[0] + + afunc[0] = rk[ss] * 1 / (czcap / (1 - czcap)) * (exp(czcap / (1 - czcap) * (zcap[0] - 1)) - 1) + + afuncD[0] = rk[ss] * exp(czcap / (1 - czcap) * (zcap[0] - 1)) + + Sfunc[0] = csadjcost / 2 * ((1 + ctrend / 100) * inve[0] / inve[-1] - (1 + ctrend / 100)) ^ 2 + + SfuncD[0] = csadjcost * ((1 + ctrend / 100) * inve[0] / inve[-1] - (1 + ctrend / 100)) + + a[0] = 1 - crhoa + crhoa * a[-1] + ea[x] / 100 + + b[0] = 1 - crhob + crhob * b[-1] + eb[x] * ( - (((1 - chabb / (1 + ctrend / 100)) / (csigma * (1 + chabb / (1 + ctrend / 100)))) ^ (-1))) / 100 + + gy[0] - cg = crhog * (gy[-1] - cg) + egy[x] / 100 + ea[x] * cgy / 100 + + qs[0] = 1 - crhoqs + crhoqs * qs[-1] + eqs[x] * csadjcost * (1 + ctrend / 100) ^ 2 * (1 + 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (1 - csigma)) / 100 + + ms[0] = 1 - crhoms + crhoms * ms[-1] + ems[x] / 100 + + spinf[0] = 1 - crhopinf + crhopinf * spinf[-1] + epinfma[0] - cmap * epinfma[-1] + + epinfma[0] = epinf[x] * 1 / (1 / (1 + cindp * (1 + ctrend / 100) * 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (-csigma)) * (1 - cprobp) * (1 - cprobp * (1 + ctrend / 100) * 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (-csigma)) / cprobp / (1 + curvp * (cfc - 1))) / 100 + + sw[0] = 1 - crhow + crhow * sw[-1] + ewma[0] - cmaw * ewma[-1] + + ewma[0] = ew[x] * 1 / (1 / (1 + curvw * (clandaw - 1)) * (1 - cprobw) * (1 - cprobw * (1 + ctrend / 100) * 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (-csigma)) / (cprobw * (1 + (1 + ctrend / 100) * 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (-csigma)))) / 100 + + yflex[0] = cflex[0] + inveflex[0] + gy[0] * yflex[ss] + afuncflex[0] * kpflex[-1] / (1 + ctrend / 100) + + yflex[0] = a[0] * kflex[0] ^ calfa * labflex[0] ^ (1 - calfa) - (cfc - 1) * yflex[ss] + + kflex[0] = kpflex[-1] * zcapflex[0] / (1 + ctrend / 100) + + kpflex[0] = inveflex[0] * qs[0] * (1 - Sfuncflex[0]) + kpflex[-1] * (1 - ctou) / (1 + ctrend / 100) + + xiflex[0] = exp((csigma - 1) / (1 + csigl) * labflex[0] ^ (1 + csigl)) * (cflex[0] - cflex[-1] * chabb / (1 + ctrend / 100)) ^ (-csigma) + + 1 = qs[0] * pkflex[0] * (1 - Sfuncflex[0] - (1 + ctrend / 100) * inveflex[0] * SfuncDflex[0] / inveflex[-1]) + SfuncDflex[1] * qsaux[0] * xiflex[1] / xiflex[0] * pkflex[1] * ((1 + ctrend / 100) * inveflex[1] / inveflex[0]) ^ 2 * 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (-csigma) + + xiflex[0] = xiflex[1] * b[0] * rrflex[0] * 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (-csigma) + + rkflex[0] = afuncDflex[0] + + pkflex[0] = (rkflex[1] * zcapflex[1] - afuncflex[1] + (1 - ctou) * pkflex[1]) * xiflex[1] * 1 / (1 + constebeta / 100) * (1 + ctrend / 100) ^ (-csigma) / xiflex[0] + + kflex[0] = labflex[0] * calfa / (1 - calfa) * wflex[0] / rkflex[0] + + mcflex = wflex[0] ^ (1 - calfa) * rkflex[0] ^ calfa / (a[0] * calfa ^ calfa * (1 - calfa) ^ (1 - calfa)) + + wflex[0] * (1 + curvw * (1 - clandaw)) / (1 + curvw * (1 - clandaw) / clandaw) = sw[ss] * (labflex[0] ^ csigl * clandaw * (cflex[0] - cflex[-1] * chabb / (1 + ctrend / 100)) + wflex[0] * curvw * (1 - clandaw) / clandaw * (clandaw - 1) / (1 + curvw * (1 - clandaw) / clandaw)) + + afuncflex[0] = rkflex[ss] * 1 / (czcap / (1 - czcap)) * (exp(czcap / (1 - czcap) * (zcapflex[0] - 1)) - 1) + + afuncDflex[0] = rkflex[ss] * exp(czcap / (1 - czcap) * (zcapflex[0] - 1)) + + Sfuncflex[0] = csadjcost / 2 * ((1 + ctrend / 100) * inveflex[0] / inveflex[-1] - (1 + ctrend / 100)) ^ 2 + + SfuncDflex[0] = csadjcost * ((1 + ctrend / 100) * inveflex[0] / inveflex[-1] - (1 + ctrend / 100)) + + ygap[0] = 100 * log(y[0] / yflex[0]) + + dy[0] = ctrend + 100 * (y[0] / y[-1] - 1) + + dc[0] = ctrend + 100 * (c[0] / c[-1] - 1) + + dinve[0] = ctrend + 100 * (inve[0] / inve[-1] - 1) + + pinfobs[0] = 100 * (pinf[0] - pinf[ss]) + constepinf + + robs[0] = 100 * (r[0] - 1) + + dwobs[0] = ctrend + 100 * (w[0] / w[-1] - 1) + + labobs[0] = 100 * (lab[0] / lab[ss] - 1) + +end + + +@parameters SW07_nonlinear begin + mcflex = mc[ss] | mcflex + + pinf[ss] = 1 + constepinf / 100 | pinfss + + ctou = 0.025 + + cg = 0.18 + + clandaw = 1.5 + + curvw = 10 + + crhoa = 0.95827 + + crhob = 0.22137 + + crhog = 0.97391 + + crhoqs = 0.70524 + + crhoms = 0.11421 + + crhopinf = 0.83954 + + crhow = 0.9745 + + cmap = 0.69414 + + cmaw = 0.93617 + + csadjcost = 5.5811 + + csigma = 1.4103 + + chabb = 0.68049 + + cprobw = 0.80501 + + csigl = 2.2061 + + cindw = 0.56351 + + cindp = 0.24165 + + czcap = 0.49552 + + cfc = 1.3443 + + crpi = 1.931 + + crr = 0.82512 + + cry = 0.097844 + + crdy = 0.25114 + + constepinf = 0.8731 + + constebeta = 0.12575 + + ctrend = 0.4419 + + cgy = 0.53817 + + calfa = 0.18003 + + curvp = 64.5595 + + cprobp = 0.667 + +end + diff --git a/test/runtests.jl b/test/runtests.jl index 3774f19a..4907b942 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -17,6 +17,20 @@ include("functionality_tests.jl") # @test format(MacroModelling; verbose=true, overwrite=true) # end +# if test_set == "solver0" +# transform = 0 +# include("optim_solver_params.jl") +# elseif test_set == "solver1" +# transform = 1 +# include("optim_solver_params.jl") +# elseif test_set == "solver2" +# transform = 2 +# include("optim_solver_params.jl") +# elseif test_set == "solver3" +# transform = 3 +# include("optim_solver_params.jl") +# end + if test_set == "estimation" include("test_estimation.jl") end @@ -156,14 +170,19 @@ if test_set == "plots" FS2000 = nothing GC.gc() - - @testset verbose = true "SW07 with calibration equations" begin - include("../models/SW07.jl") - functionality_test(SW07, plots = plots) + @testset verbose = true "Smets and Wouters (2007) linear" begin + include("../models/Smets_Wouters_2007_linear.jl") + functionality_test(Smets_Wouters_2007_linear, plots = plots) end - SW07 = nothing + Smets_Wouters_2007_linear = nothing GC.gc() + @testset verbose = true "Smets and Wouters (2007) nonlinear" begin + include("../models/Smets_Wouters_2007.jl") + functionality_test(Smets_Wouters_2007, plots = plots) + end + Smets_Wouters_2007 = nothing + GC.gc() @testset verbose = true "RBC_CME with calibration equations, parameter definitions, special functions, variables in steady state, and leads/lag > 1 on endogenous and exogenous variables" begin include("models/RBC_CME_calibration_equations_and_parameter_definitions_lead_lags.jl") @@ -214,11 +233,11 @@ if test_set == "plots" - @testset verbose = true "SW03 with calibration equations" begin - include("../models/SW03.jl") - functionality_test(SW03, plots = plots) + @testset verbose = true "Smets_Wouters_2003 with calibration equations" begin + include("../models/Smets_Wouters_2003.jl") + functionality_test(Smets_Wouters_2003, plots = plots) end - SW03 = nothing + Smets_Wouters_2003 = nothing GC.gc() end @@ -287,6 +306,74 @@ if test_set == "basic" end m = nothing + + + @testset verbose = true "Non-stochastic steady state guess" begin + @model RBC_CME begin + y[0]=A[0]*k[-1]^alpha + 1/c[0]=beta*1/c[1]*(alpha*A[1]*k[0]^(alpha-1)+(1-delta)) + 1/c[0]=beta*1/c[1]*(R[0]/Pi[+1]) + R[0] * beta =(Pi[0]/Pibar)^phi_pi + # A[0]*k[-1]^alpha=c[0]+k[0]-(1-delta)*k[-1] + A[0]*k[-1]^alpha=c[0]+k[0]-(1-delta*z_delta[0])*k[-1] + z_delta[0] = 1 - rho_z_delta + rho_z_delta * z_delta[-1] + std_z_delta * delta_eps[x] + # z[0]=rhoz*z[-1]+std_eps*eps_z[x] + # A[0]=exp(z[0]) + A[0] = 1 - rhoz + rhoz * A[-1] + std_eps * eps_z[x] + # log(A[0]) = rhoz * log(A[-1]) + std_eps * eps_z[x] + end + + + @parameters RBC_CME verbose = true guess = Dict(:alpha => .2, :beta => .99) begin + alpha | k[ss] / (4 * y[ss]) = cap_share + cap_share = 1.66 + # alpha = .157 + + beta | R[ss] = R_ss # beta needs to enter into function: block in order to solve + R_ss = 1.0035 + # beta = .999 + + # delta | c[ss]/y[ss] = 1 - I_K_ratio + delta | delta * k[ss] / y[ss] = I_K_ratio #check why this doesnt solve for y; because delta is not recognised as a free parameter here. + I_K_ratio = .15 + # delta = .0226 + + Pibar | Pi[ss] = Pi_ss + Pi_ss = 1.0025 + # Pibar = 1.0008 + + phi_pi = 1.5 + rhoz = .9 + std_eps = .0068 + rho_z_delta = .9 + std_z_delta = .005 + + + # cap_share > 0 + # R_ss > 0 + # Pi_ss > 0 + # I_K_ratio > 0 + + # 0 < alpha < 1 + # 0 < beta < 1 + # 0 < delta < 1 + # 0 < Pibar + # 0 <= rhoz < 1 + # phi_pi > 0 + + # 0 < A < 1 + # 0 < k < 50 + # 0 < y < 10 + # 0 < c < 10 + end + + @test RBC_CME.guess == Dict(:alpha => .2, :beta => .99) + + @test get_steady_state(RBC_CME, verbose = true)(RBC_CME.var,:Steady_state) ≈ [1.0, 1.0025, 1.0035, 1.2081023824176236, 9.437411552284384, 1.4212969205027686, 1.0] + + RBC_CME = nothing + end + @testset verbose = true "Distribution functions, general and SS" begin @model RBC_CME begin @@ -1516,9 +1603,9 @@ if test_set == "basic" # using MacroModelling: @model, @parameters, get_steady_state, solve! - @testset verbose = true "Steady state SW03 model" begin + @testset verbose = true "Steady state Smets_Wouters_2003 model" begin - @model SW03 begin + @model Smets_Wouters_2003 begin -q[0] + beta * ((1 - tau) * q[1] + epsilon_b[1] * (r_k[1] * z[1] - psi^-1 * r_k[ss] * (-1 + exp(psi * (-1 + z[1])))) * (C[1] - h * C[0])^(-sigma_c)) = 0 -q_f[0] + beta * ((1 - tau) * q_f[1] + epsilon_b[1] * (r_k_f[1] * z_f[1] - psi^-1 * r_k_f[ss] * (-1 + exp(psi * (-1 + z_f[1])))) * (C_f[1] - h * C_f[0])^(-sigma_c)) = 0 -r_k[0] + alpha * epsilon_a[0] * mc[0] * L[0]^(1 - alpha) * (K[-1] * z[0])^(-1 + alpha) = 0 @@ -1576,7 +1663,7 @@ if test_set == "basic" end - @parameters SW03 verbose = true begin + @parameters Smets_Wouters_2003 verbose = true begin calibr_pi_obj | 1 = pi_obj[ss] calibr_pi | pi[ss] = pi_obj[ss] # Phi | Y_s[ss] * .408 = Phi @@ -1637,10 +1724,10 @@ if test_set == "basic" end - # solve!(SW03, verbose = true) + # solve!(Smets_Wouters_2003, verbose = true) - @test isapprox(get_steady_state(SW03, verbose = true)(SW03.timings.var), + @test isapprox(get_steady_state(Smets_Wouters_2003, verbose = true)(Smets_Wouters_2003.timings.var), [ 1.2043777509278788 1.2043777484127967 0.362 @@ -1698,13 +1785,13 @@ if test_set == "basic" rtol = eps(Float32) ) - SW03 = nothing + Smets_Wouters_2003 = nothing # # x = 1 - # # SW03 = nothing + # # Smets_Wouters_2003 = nothing - # # @model SW03 begin + # # @model Smets_Wouters_2003 begin # # -q[0] + beta * ((1 - tau) * q[1] + epsilon_b[1] * (r_k[1] * z[1] - psi^-1 * r_k[ss] * (-1 + exp(psi * (-1 + z[1])))) * (C[1] - h * C[0])^(-sigma_c)) = 0 # # -q_f[0] + beta * ((1 - tau) * q_f[1] + epsilon_b[1] * (r_k_f[1] * z_f[1] - psi^-1 * r_k_f[ss] * (-1 + exp(psi * (-1 + z_f[1])))) * (C_f[1] - h * C_f[0])^(-sigma_c)) = 0 # # -r_k[0] + alpha * epsilon_a[0] * mc[0] * L[0]^(1 - alpha) * (K[-1] * z[0])^(-1 + alpha) = 0 @@ -1762,7 +1849,7 @@ if test_set == "basic" # # end - # # @parameters SW03 begin + # # @parameters Smets_Wouters_2003 begin # # calibr_pi_obj | 1 = pi_obj[ss] # # calibr_pi | pi[ss] = pi_obj[ss] # # Phi | (Y_s[ss] + Phi) / Y_s[ss] = 1.408 @@ -1803,11 +1890,11 @@ if test_set == "basic" # # end - # # solve!(SW03, symbolic_SS = false) + # # solve!(Smets_Wouters_2003, symbolic_SS = false) - # # # get_steady_state(SW03) + # # # get_steady_state(Smets_Wouters_2003) - # # @test get_steady_state(SW03)[1] ≈ [ 1.20465991441435 + # # @test get_steady_state(Smets_Wouters_2003)[1] ≈ [ 1.20465991441435 # # 1.204659917151701 # # 0.3613478048030788 # # 0.3613478048030788 diff --git a/test/test_1st_order_inversion_filter_estimation.jl b/test/test_1st_order_inversion_filter_estimation.jl index a864bdf5..f484e25d 100644 --- a/test/test_1st_order_inversion_filter_estimation.jl +++ b/test/test_1st_order_inversion_filter_estimation.jl @@ -19,31 +19,58 @@ observables = sort(Symbol.("log_".*names(dat))) # subset observables in data data = data(observables,:) +dists = [ + Beta(0.356, 0.02, μσ = true), # alp + Beta(0.993, 0.002, μσ = true), # bet + Normal(0.0085, 0.003), # gam + Normal(1.0002, 0.007), # mst + Beta(0.129, 0.223, μσ = true), # rho + Beta(0.65, 0.05, μσ = true), # psi + Beta(0.01, 0.005, μσ = true), # del + InverseGamma(0.035449, Inf, μσ = true), # z_e_a + InverseGamma(0.008862, Inf, μσ = true) # z_e_m +] Turing.@model function FS2000_loglikelihood_function(data, m) - alp ~ Beta(0.356, 0.02, μσ = true) - bet ~ Beta(0.993, 0.002, μσ = true) - gam ~ Normal(0.0085, 0.003) - mst ~ Normal(1.0002, 0.007) - rho ~ Beta(0.129, 0.223, μσ = true) - psi ~ Beta(0.65, 0.05, μσ = true) - del ~ Beta(0.01, 0.005, μσ = true) - z_e_a ~ InverseGamma(0.035449, Inf, μσ = true) - z_e_m ~ InverseGamma(0.008862, Inf, μσ = true) - # println([alp, bet, gam, mst, rho, psi, del, z_e_a, z_e_m]) - Turing.@addlogprob! get_loglikelihood(m, data, [alp, bet, gam, mst, rho, psi, del, z_e_a, z_e_m], filter = :inversion) -end + all_params ~ Turing.arraydist(dists) + Turing.@addlogprob! get_loglikelihood(m, data, all_params, filter = :inversion) +end Random.seed!(30) -pt = @time Pigeons.pigeons(target = Pigeons.TuringLogPotential(FS2000_loglikelihood_function(data, FS2000)), +# generate a Pigeons log potential +FS2000_lp = Pigeons.TuringLogPotential(FS2000_loglikelihood_function(data, FS2000)) + +# find a feasible starting point +pt = Pigeons.pigeons(target = FS2000_lp, n_rounds = 0, n_chains = 1) + +replica = pt.replicas[end] +XMAX = deepcopy(replica.state) +LPmax = FS2000_lp(XMAX) + +i = 0 + +while !isfinite(LPmax) && i < 1000 + Pigeons.sample_iid!(FS2000_lp, replica, pt.shared) + new_LP = FS2000_lp(replica.state) + if new_LP > LPmax + LPmax = new_LP + XMAX = deepcopy(replica.state) + end + i += 1 +end + +# define a specific initialization for this model +Pigeons.initialization(::Pigeons.TuringLogPotential{typeof(FS2000_loglikelihood_function)}, ::AbstractRNG, ::Int64) = deepcopy(XMAX) + +pt = @time Pigeons.pigeons(target = FS2000_lp, record = [Pigeons.traces; Pigeons.round_trip; Pigeons.record_default()], n_chains = 1, n_rounds = 10, multithreaded = true) -samps = MCMCChains.Chains(Pigeons.get_sample(pt)) +samps = MCMCChains.Chains(pt) println(mean(samps).nt.mean) diff --git a/test/test_2nd_order_estimation.jl b/test/test_2nd_order_estimation.jl index 0cce1646..14a5b436 100644 --- a/test/test_2nd_order_estimation.jl +++ b/test/test_2nd_order_estimation.jl @@ -20,30 +20,59 @@ observables = sort(Symbol.("log_".*names(dat))) data = data(observables,:) +dists = [ + Beta(0.356, 0.02, μσ = true), # alp + Beta(0.993, 0.002, μσ = true), # bet + Normal(0.0085, 0.003), # gam + Normal(1.0002, 0.007), # mst + Beta(0.129, 0.223, μσ = true), # rho + Beta(0.65, 0.05, μσ = true), # psi + Beta(0.01, 0.005, μσ = true), # del + InverseGamma(0.035449, Inf, μσ = true), # z_e_a + InverseGamma(0.008862, Inf, μσ = true) # z_e_m +] + Turing.@model function FS2000_loglikelihood_function(data, m) - alp ~ Beta(0.356, 0.02, μσ = true) - bet ~ Beta(0.993, 0.002, μσ = true) - gam ~ Normal(0.0085, 0.003) - mst ~ Normal(1.0002, 0.007) - rho ~ Beta(0.129, 0.223, μσ = true) - psi ~ Beta(0.65, 0.05, μσ = true) - del ~ Beta(0.01, 0.005, μσ = true) - z_e_a ~ InverseGamma(0.035449, Inf, μσ = true) - z_e_m ~ InverseGamma(0.008862, Inf, μσ = true) - # println([alp, bet, gam, mst, rho, psi, del, z_e_a, z_e_m]) - Turing.@addlogprob! get_loglikelihood(m, data, [alp, bet, gam, mst, rho, psi, del, z_e_a, z_e_m], algorithm = :pruned_second_order) + all_params ~ Turing.arraydist(dists) + + Turing.@addlogprob! get_loglikelihood(m, data, all_params, algorithm = :pruned_second_order) end Random.seed!(30) -pt = @time Pigeons.pigeons(target = Pigeons.TuringLogPotential(FS2000_loglikelihood_function(data, FS2000)), +# generate a Pigeons log potential +FS2000_lp = Pigeons.TuringLogPotential(FS2000_loglikelihood_function(data, FS2000)) + +# find a feasible starting point +pt = Pigeons.pigeons(target = FS2000_lp, n_rounds = 0, n_chains = 1) + +replica = pt.replicas[end] +XMAX = deepcopy(replica.state) +LPmax = FS2000_lp(XMAX) + +i = 0 + +while !isfinite(LPmax) && i < 1000 + Pigeons.sample_iid!(FS2000_lp, replica, pt.shared) + new_LP = FS2000_lp(replica.state) + if new_LP > LPmax + LPmax = new_LP + XMAX = deepcopy(replica.state) + end + i += 1 +end + +# define a specific initialization for this model +Pigeons.initialization(::Pigeons.TuringLogPotential{typeof(FS2000_loglikelihood_function)}, ::AbstractRNG, ::Int64) = deepcopy(XMAX) + +pt = @time Pigeons.pigeons(target = FS2000_lp, record = [Pigeons.traces; Pigeons.round_trip; Pigeons.record_default()], n_chains = 2, n_rounds = 9, multithreaded = true) -samps = MCMCChains.Chains(Pigeons.get_sample(pt)) +samps = MCMCChains.Chains(pt) println(mean(samps).nt.mean) diff --git a/test/test_3rd_order_estimation.jl b/test/test_3rd_order_estimation.jl index 99bb8d1e..89116ddb 100644 --- a/test/test_3rd_order_estimation.jl +++ b/test/test_3rd_order_estimation.jl @@ -1,7 +1,7 @@ using MacroModelling import Turing import Pigeons -import Turing: NUTS, sample, logpdf +import Turing: NUTS, sample, logpdf, PG, IS import Optim, LineSearches using Random, CSV, DataFrames, MCMCChains, AxisKeys import DynamicPPL: logjoint @@ -30,31 +30,68 @@ include("models/Caldara_et_al_2012_estim.jl") # get_parameters(Caldara_et_al_2012_estim, values = true) +# Handling distributions with varying parameters using arraydist +dists = [ + Normal(0, 1), # dȳ + Normal(0, 1), # dc̄ + Beta(0.95, 0.005, μσ = true), # β + Beta(0.33, 0.05, μσ = true), # ζ + Beta(0.02, 0.01, μσ = true), # δ + Beta(0.75, 0.01, μσ = true), # λ + Normal(1, .25)#, μσ = true), # ψ + InverseGamma(0.021, Inf, μσ = true), # σ̄ + InverseGamma(0.1, Inf, μσ = true), # η + Beta(0.75, 0.02, μσ = true) # ρ +] + Turing.@model function Caldara_et_al_2012_loglikelihood_function(data, m) - dȳ ~ Normal(0, 1) - dc̄ ~ Normal(0, 1) - β ~ Beta(0.95, 0.005, μσ = true) - ζ ~ Beta(0.33, 0.05, μσ = true) - δ ~ Beta(0.02, 0.01, μσ = true) - λ ~ Beta(0.75, 0.01, μσ = true) - ψ ~ Normal(1, .25)#, μσ = true) - σ̄ ~ InverseGamma(0.021, Inf, μσ = true) - η ~ InverseGamma(0.1, Inf, μσ = true) - ρ ~ Beta(0.75, 0.02, μσ = true) - - Turing.@addlogprob! get_loglikelihood(m, data, [dȳ, dc̄, β, ζ, δ, λ, ψ, σ̄, η, ρ], algorithm = :pruned_third_order) + all_params ~ Turing.arraydist(dists) + + Turing.@addlogprob! get_loglikelihood(m, data, all_params, algorithm = :pruned_third_order) end Random.seed!(3) -pt = @time Pigeons.pigeons(target = Pigeons.TuringLogPotential(Caldara_et_al_2012_loglikelihood_function(data, Caldara_et_al_2012_estim)), +# Caldara_et_al_2012_loglikelihood = Caldara_et_al_2012_loglikelihood_function(data, Caldara_et_al_2012_estim) + +# samps = @time sample(Caldara_et_al_2012_loglikelihood, PG(100), 10, progress = true)#, init_params = sol) + +# samps = sample(Caldara_et_al_2012_loglikelihood, IS(), 1000, progress = true)#, init_params = sol) + + +# generate a Pigeons log potential +Caldara_lp = Pigeons.TuringLogPotential(Caldara_et_al_2012_loglikelihood_function(data, Caldara_et_al_2012_estim)) + +# find a feasible starting point +pt = Pigeons.pigeons(target = Caldara_lp, n_rounds = 0, n_chains = 1) + +replica = pt.replicas[end] +XMAX = deepcopy(replica.state) +LPmax = Caldara_lp(XMAX) + +i = 0 + +while !isfinite(LPmax) && i < 1000 + Pigeons.sample_iid!(Caldara_lp, replica, pt.shared) + new_LP = Caldara_lp(replica.state) + if new_LP > LPmax + LPmax = new_LP + XMAX = deepcopy(replica.state) + end + i += 1 +end + +# define a specific initialization for this model +Pigeons.initialization(::Pigeons.TuringLogPotential{typeof(Caldara_et_al_2012_loglikelihood_function)}, ::AbstractRNG, ::Int64) = deepcopy(XMAX) + +pt = @time Pigeons.pigeons(target = Caldara_lp, record = [Pigeons.traces; Pigeons.round_trip; Pigeons.record_default()], n_chains = 1, n_rounds = 6, multithreaded = true) -samps = MCMCChains.Chains(Pigeons.get_sample(pt)) +samps = MCMCChains.Chains(pt) println(mean(samps).nt.mean) diff --git a/test/test_estimation.jl b/test/test_estimation.jl index 10c97010..b70d44ad 100644 --- a/test/test_estimation.jl +++ b/test/test_estimation.jl @@ -19,18 +19,23 @@ observables = sort(Symbol.("log_".*names(dat))) data = data(observables,:) +# Handling distributions with varying parameters using arraydist +dists = [ + Beta(0.356, 0.02, μσ = true), # alp + Beta(0.993, 0.002, μσ = true), # bet + Normal(0.0085, 0.003), # gam + Normal(1.0002, 0.007), # mst + Beta(0.129, 0.223, μσ = true), # rho + Beta(0.65, 0.05, μσ = true), # psi + Beta(0.01, 0.005, μσ = true), # del + InverseGamma(0.035449, Inf, μσ = true), # z_e_a + InverseGamma(0.008862, Inf, μσ = true) # z_e_m +] + Turing.@model function FS2000_loglikelihood_function(data, m) - alp ~ Beta(0.356, 0.02, μσ = true) - bet ~ Beta(0.993, 0.002, μσ = true) - gam ~ Normal(0.0085, 0.003) - mst ~ Normal(1.0002, 0.007) - rho ~ Beta(0.129, 0.223, μσ = true) - psi ~ Beta(0.65, 0.05, μσ = true) - del ~ Beta(0.01, 0.005, μσ = true) - z_e_a ~ InverseGamma(0.035449, Inf, μσ = true) - z_e_m ~ InverseGamma(0.008862, Inf, μσ = true) - # println([alp, bet, gam, mst, rho, psi, del, z_e_a, z_e_m]) - Turing.@addlogprob! get_loglikelihood(m, data, [alp, bet, gam, mst, rho, psi, del, z_e_a, z_e_m]) + all_params ~ Turing.arraydist(dists) + + Turing.@addlogprob! get_loglikelihood(m, data, all_params) end FS2000_loglikelihood = FS2000_loglikelihood_function(data, FS2000) @@ -46,13 +51,38 @@ println(mean(samps).nt.mean) sample_nuts = mean(samps).nt.mean -pt = @time Pigeons.pigeons(target = Pigeons.TuringLogPotential(FS2000_loglikelihood_function(data, FS2000)), +# generate a Pigeons log potential +FS2000_lp = Pigeons.TuringLogPotential(FS2000_loglikelihood_function(data, FS2000)) + +# find a feasible starting point +pt = Pigeons.pigeons(target = FS2000_lp, n_rounds = 0, n_chains = 1) + +replica = pt.replicas[end] +XMAX = deepcopy(replica.state) +LPmax = FS2000_lp(XMAX) + +i = 0 + +while !isfinite(LPmax) && i < 1000 + Pigeons.sample_iid!(FS2000_lp, replica, pt.shared) + new_LP = FS2000_lp(replica.state) + if new_LP > LPmax + LPmax = new_LP + XMAX = deepcopy(replica.state) + end + i += 1 +end + +# define a specific initialization for this model +Pigeons.initialization(::Pigeons.TuringLogPotential{typeof(FS2000_loglikelihood_function)}, ::AbstractRNG, ::Int64) = deepcopy(XMAX) + +pt = @time Pigeons.pigeons(target = FS2000_lp, record = [Pigeons.traces; Pigeons.round_trip; Pigeons.record_default()], n_chains = 1, n_rounds = 10, multithreaded = true) -samps = MCMCChains.Chains(Pigeons.get_sample(pt)) +samps = MCMCChains.Chains(pt) println(mean(samps).nt.mean) @@ -61,23 +91,20 @@ sample_pigeons = mean(samps).nt.mean Random.seed!(30) -function calculate_posterior_loglikelihood(parameters) - alp, bet, gam, mst, rho, psi, del, z_e_a, z_e_m = parameters + +function calculate_posterior_loglikelihood(parameters, prior_distribuions) log_lik = 0 + + for (dist, val) in zip(prior_distribuions, parameters) + log_lik -= logpdf(dist, val) + end + log_lik -= get_loglikelihood(FS2000, data, parameters) - log_lik -= logpdf(Beta(0.356, 0.02, μσ = true),alp) - log_lik -= logpdf(Beta(0.993, 0.002, μσ = true),bet) - log_lik -= logpdf(Normal(0.0085, 0.003),gam) - log_lik -= logpdf(Normal(1.0002, 0.007),mst) - log_lik -= logpdf(Beta(0.129, 0.223, μσ = true),rho) - log_lik -= logpdf(Beta(0.65, 0.05, μσ = true),psi) - log_lik -= logpdf(Beta(0.01, 0.005, μσ = true),del) - log_lik -= logpdf(InverseGamma(0.035449, Inf, μσ = true),z_e_a) - log_lik -= logpdf(InverseGamma(0.008862, Inf, μσ = true),z_e_m) + return log_lik end -sol = Optim.optimize(calculate_posterior_loglikelihood, +sol = Optim.optimize(x -> calculate_posterior_loglikelihood(x, dists), [0,0,-10,-10,0,0,0,0,0], [1,1,10,10,1,1,1,100,100] ,FS2000.parameter_values, Optim.Fminbox(Optim.LBFGS(linesearch = LineSearches.BackTracking(order = 3))); autodiff = :forward) diff --git a/test/test_models.jl b/test/test_models.jl index 91dc2bb4..56088e20 100644 --- a/test/test_models.jl +++ b/test/test_models.jl @@ -1,8 +1,42 @@ if !test_higher_order + include("../models/Guerrieri_Iacoviello_2017.jl") + SSvals = get_SS(Guerrieri_Iacoviello_2017) + + @test isapprox(SSvals([:b,:c,:k,:r]),[3.7449, 1.01054, 16.5337, 1.01005],rtol = 1e-4) + + var_dec = get_var_decomp(Guerrieri_Iacoviello_2017) + + @test isapprox(var_dec([:dw,:k,:b],:eps_j) * 100, [0.38, 1.66, 83.52],rtol = 1e-3) + @test isapprox(var_dec([:y,:r,:c],:eps_r) * 100, [7.35, 31.93, 0.59],rtol = 1e-3) + + write_to_dynare_file(Guerrieri_Iacoviello_2017) + translate_dynare_file("Guerrieri_Iacoviello_2017.mod") + include("Guerrieri_Iacoviello_2017.jl") + # get_solution(Guerrieri_Iacoviello_2017) + Guerrieri_Iacoviello_2017 = nothing + + + include("models/SW07_nonlinear.jl") + SSvals = get_SS(SW07_nonlinear) + + @test isapprox(SSvals([:robs, :y, :kflex, :ygap]),[1.62996, 1.36422, 7.55624, 0],rtol = 1e-4) + + var_dec = get_var_decomp(SW07_nonlinear) + + @test isapprox(var_dec([:y,:yflex,:labobs],:ea) * 100, [10.10, 89.47, 0.53],rtol = 1e-3) + @test isapprox(var_dec([:y,:r,:c],:epinf) * 100, [36.42, 29.30, 22.62],rtol = 1e-3) + + write_to_dynare_file(SW07_nonlinear) + translate_dynare_file("SW07_nonlinear.mod") + include("SW07_nonlinear.jl") + get_solution(SW07_nonlinear) + SW07_nonlinear = nothing + + include("models/Backus_Kehoe_Kydland_1992.jl") - SS = get_SS(Backus_Kehoe_Kydland_1992) + SSvals = get_SS(Backus_Kehoe_Kydland_1992) - @test isapprox(SS(["A{F}","K{H}","L{F}","LGM"]),[0.606436, 11.0148, 0.696782, 0.278732],rtol = 1e-4) + @test isapprox(SSvals(["A{F}","K{H}","L{F}","LGM"]),[0.606436, 11.0148, 0.696782, 0.278732],rtol = 1e-4) var_dec = get_var_decomp(Backus_Kehoe_Kydland_1992) @@ -17,9 +51,9 @@ if !test_higher_order include("../models/NAWM_EAUS_2008.jl") - SS = get_SS(NAWM_EAUS_2008) + SSvals = get_SS(NAWM_EAUS_2008) - @test isapprox(SS([:EAUS_RER,:EA_Y,:EA_K,:EA_C,:US_Y,:US_K]),[0.937577, 3.62701, 33.4238, 2.18955, 3.92449, 33.6712],rtol = 1e-5) + @test isapprox(SSvals([:EAUS_RER,:EA_Y,:EA_K,:EA_C,:US_Y,:US_K]),[0.937577, 3.62701, 33.4238, 2.18955, 3.92449, 33.6712],rtol = 1e-5) var_dec = get_var_decomp(NAWM_EAUS_2008)