Skip to content

Commit 2c8376e

Browse files
Thore KockerolsThore Kockerols
authored andcommitted
Refactor optimization test script to streamline steady state calculations and enhance residual function compatibility with NonlinearSolve.jl
1 parent 2c4b8cf commit 2c8376e

File tree

1 file changed

+62
-93
lines changed

1 file changed

+62
-93
lines changed

test_dynamic_equations_optimization.jl

Lines changed: 62 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -30,87 +30,50 @@ end
3030
β = 0.95
3131
end
3232

33-
println("Solving model...")
34-
solve!(RBC)
3533

36-
# Get steady states
37-
println("Computing steady states...")
38-
SS_non_stochastic = get_steady_state(RBC, stochastic = false)
39-
SS_stochastic = get_steady_state(RBC, stochastic = true)
40-
41-
println("Non-stochastic steady state:")
42-
println(SS_non_stochastic)
43-
println("\nStochastic steady state:")
44-
println(SS_stochastic)
45-
46-
# Get auxiliary indices for the steady state input
47-
aux_idx = RBC.solution.perturbation.auxiliary_indices
48-
SS_for_func = SS_non_stochastic[aux_idx.dyn_ss_idx]
49-
50-
# Number of variables and shocks
51-
n_vars = length(RBC.var)
52-
n_shocks = length(RBC.exo)
53-
n_dyn_eqs = length(RBC.dyn_equations)
54-
n_calib_eqs = length(RBC.calibration_equations)
55-
n_total_eqs = n_dyn_eqs + n_calib_eqs
56-
57-
println("\nModel dimensions:")
58-
println(" Variables: ", n_vars)
59-
println(" Shocks: ", n_shocks)
60-
println(" Dynamic equations: ", n_dyn_eqs)
61-
println(" Calibration equations: ", n_calib_eqs)
62-
println(" Total equations: ", n_total_eqs)
63-
64-
# Generate Sobol sequence for shocks
65-
n_draws = 100
66-
println("\nGenerating ", n_draws, " Sobol draws for shocks...")
67-
68-
# Generate Sobol sequence in [0,1]
69-
shock_draws_uniform = QuasiMonteCarlo.sample(n_draws, n_shocks, SobolSample())
34+
include("./models/Gali_2015_chapter_3_nonlinear.jl")
7035

71-
# Convert to normal distribution using inverse error function
72-
normal_draws = @. sqrt(2) * erfinv(2 * shock_draws_uniform - 1)
36+
m = Gali_2015_chapter_3_nonlinear
7337

74-
# Standardize to zero mean and unit variance
75-
normal_draws .-= mean(normal_draws, dims=2)
76-
normal_draws ./= Statistics.std(normal_draws, dims=2)
38+
# Get steady states
39+
SS_non_stochastic = get_steady_state(m, stochastic = false, derivatives = false) |> collect
40+
SS_stochastic = get_steady_state(m, stochastic = true, derivatives = false) |> collect
7741

78-
println("Shock draws shape: ", size(normal_draws))
79-
println("Shock draws mean: ", mean(normal_draws, dims=2))
80-
println("Shock draws std: ", Statistics.std(normal_draws, dims=2))
8142

8243
# Calibration parameters
83-
calib_params = zeros(length(RBC.calibration_equations_parameters))
44+
calib_params = zeros(length(m.calibration_equations_parameters))
8445

8546
# Define residual function that returns per-equation average residuals
8647
# This is compatible with NonlinearSolve.jl
48+
# function residual_function(vars_flat, p)
8749
function residual_function!(residual_avg, vars_flat, p)
88-
shock_draws, model, SS_for_func, calib_params = p
50+
shock_draws, model, SS_non_stochastic, calib_params = p
8951

9052
n_draws = size(shock_draws, 2)
91-
n_vars = length(model.var)
53+
# n_vars = length(model.var)
9254

9355
# Unpack variables: [past; present; future]
94-
past = vars_flat[1:n_vars]
95-
present = vars_flat[n_vars+1:2*n_vars]
96-
future = vars_flat[2*n_vars+1:3*n_vars]
56+
past = vars_flat#[1:n_vars]
57+
present = vars_flat#[n_vars+1:2*n_vars]
58+
future = vars_flat#[2*n_vars+1:3*n_vars]
9759

9860
n_eqs = length(model.dyn_equations) + length(model.calibration_equations)
99-
residual_temp = zeros(n_eqs)
61+
residual_temp = zeros(eltype(vars_flat), n_eqs)
10062

10163
# Initialize average residuals to zero
10264
fill!(residual_avg, 0.0)
65+
# residual_avg = zeros(eltype(vars_flat), n_eqs)
10366

10467
# Sum residuals across all shock draws
10568
for i in 1:n_draws
10669
shocks = shock_draws[:, i]
10770

10871
# Evaluate dynamic equations
10972
get_dynamic_residuals(residual_temp, model.parameter_values, calib_params,
110-
past, present, future, SS_for_func, shocks, model)
111-
73+
past, present, future, SS_non_stochastic, shocks, model)
74+
11275
# Accumulate residuals
113-
residual_avg .+= residual_temp
76+
residual_avg .+= abs.(residual_temp)
11477
end
11578

11679
# Average over draws
@@ -119,75 +82,81 @@ function residual_function!(residual_avg, vars_flat, p)
11982
return nothing
12083
end
12184

122-
# Initial guess: use stochastic steady state for all time periods
123-
println("\nSetting up nonlinear problem...")
124-
initial_vars = vcat(SS_stochastic, SS_stochastic, SS_stochastic)
85+
86+
# Number of variables and shocks
87+
n_shocks = length(m.exo)
88+
89+
# Generate Sobol sequence for shocks
90+
n_draws = 1000
91+
92+
# Generate Sobol sequence in [0,1]
93+
shock_draws_uniform = QuasiMonteCarlo.sample(n_draws, n_shocks, SobolSample())
94+
95+
# Convert to normal distribution using inverse error function
96+
normal_draws = @. sqrt(2) * erfinv(2 * shock_draws_uniform - 1)
97+
98+
# Standardize to zero mean and unit variance
99+
normal_draws .-= mean(normal_draws, dims=2)
100+
normal_draws ./= Statistics.std(normal_draws, dims=2)
125101

126102
# Package parameters for the residual function
127-
params = (normal_draws, RBC, SS_for_func, calib_params)
103+
params = (normal_draws, m, SS_non_stochastic, calib_params)
104+
105+
# Initial guess: use stochastic steady state for all time periods
106+
initial_vars = copy(SS_stochastic)
128107

129108
# Test initial residuals
130-
residual_test = zeros(n_total_eqs)
109+
residual_test = zeros(length(m.dyn_equations) + length(m.calibration_equations))
131110
residual_function!(residual_test, initial_vars, params)
132-
println("Initial residual norm: ", norm(residual_test))
111+
println("Initial residual norm: ", sum(abs2, residual_test))
133112
println("Initial max|residual|: ", maximum(abs.(residual_test)))
134113

135114
# Set up nonlinear problem
136-
println("\nSolving nonlinear system...")
137-
println("This may take a moment...")
138-
139115
prob = NonlinearProblem(residual_function!, initial_vars, params)
140116

141117
# Solve using Newton-Raphson with automatic differentiation
142-
sol = solve(prob, NewtonRaphson(; autodiff = AutoFiniteDiff()))
118+
solLM = solve(prob, LevenbergMarquardt(), show_trace = Val(true))
119+
solTR = solve(prob, TrustRegion(), show_trace = Val(true))
120+
# sol = solve(prob, show_trace = Val(true))
121+
122+
sum(abs, solTR.u - SS_stochastic)
123+
sum(abs, solLM.u - SS_stochastic)
124+
125+
sum(abs2, solLM.resid)
126+
sum(abs2, solTR.resid)
127+
128+
residual_function!(residual_test, solLM.u, params)
129+
sum(abs2, residual_test)
130+
143131

144132
println("\nSolution complete!")
145133
println("Solution return code: ", sol.retcode)
146-
println("Final residual norm: ", norm(sol.resid))
134+
println("Final residual norm: ", sum(abs2, sol.resid))
147135
println("Final max|residual|: ", maximum(abs.(sol.resid)))
148136

149137
# Extract solved variables
150-
solved_past = sol.u[1:n_vars]
151-
solved_present = sol.u[n_vars+1:2*n_vars]
152-
solved_future = sol.u[2*n_vars+1:3*n_vars]
153-
154-
println("\nSolved variables:")
155-
println("Past: ", solved_past)
156-
println("Present: ", solved_present)
157-
println("Future: ", solved_future)
138+
println("\nSolved variables:", sol.u)
158139

159140
println("\nComparison with steady states:")
160-
for (i, var) in enumerate(RBC.var)
141+
for (i, var) in enumerate(m.var)
161142
println(" ", var, ":")
162143
println(" Non-stochastic SS: ", SS_non_stochastic[i])
163144
println(" Stochastic SS: ", SS_stochastic[i])
164-
println(" Solved (past): ", solved_past[i])
165-
println(" Solved (present): ", solved_present[i])
166-
println(" Solved (future): ", solved_future[i])
145+
println(" Solved: ", sol.u[i])
167146
end
168147

148+
n_eqs = length(m.dyn_equations) + length(m.calibration_equations)
149+
169150
# Evaluate residuals at the solution for a few shock draws
170151
println("\nPer-draw residuals at solution for first 5 shock draws:")
171-
residual = zeros(n_total_eqs)
152+
residual = zeros(n_eqs)
172153
for i in 1:min(5, n_draws)
173154
shocks = normal_draws[:, i]
174-
get_dynamic_residuals(residual, RBC.parameter_values, calib_params,
175-
solved_past, solved_present, solved_future, SS_for_func, shocks, RBC)
155+
get_dynamic_residuals(residual, m.parameter_values, calib_params,
156+
sol.u, sol.u, sol.u, SS_non_stochastic, shocks, m)
176157
println("Draw ", i, ": max|residual| = ", maximum(abs.(residual)),
177158
", mean|residual| = ", sum(abs.(residual))/length(residual))
178159
end
179160

180-
println("\nScript completed successfully!")
181-
182-
# Evaluate residuals at the optimal point for a few shock draws
183-
println("\nResiduals at optimal point for first 5 shock draws:")
184-
residual = zeros(n_total_eqs)
185-
for i in 1:min(5, n_draws)
186-
shocks = shock_draws[:, i]
187-
get_dynamic_residuals(residual, RBC.parameter_values, calib_params,
188-
opt_past, opt_present, opt_future, SS_for_func, shocks, RBC)
189-
println("Draw ", i, ": max|residual| = ", maximum(abs.(residual)),
190-
", mean|residual| = ", sum(abs.(residual))/length(residual))
191-
end
192161

193-
println("\nScript completed successfully!")
162+
m.dyn_equations_func

0 commit comments

Comments
 (0)