|
| 1 | +using ModelingToolkit |
| 2 | +import JuMP, InfiniteOpt |
| 3 | +using DiffEqDevTools, DiffEqBase |
| 4 | +using SimpleDiffEq |
| 5 | +using OrdinaryDiffEqSDIRK, OrdinaryDiffEqVerner, OrdinaryDiffEqTsit5, OrdinaryDiffEqFIRK |
| 6 | +using Ipopt |
| 7 | +using DataInterpolations |
| 8 | +using CasADi |
| 9 | + |
| 10 | +const M = ModelingToolkit |
| 11 | + |
| 12 | +probtypes = [JuMPDynamicOptProblem, InfiniteOptDynamicOptProblem, CasADiDynamicOptProblem] |
| 13 | +solvers = [Ipopt.Optimizer, Ipopt.Optimizer, "opti"] |
| 14 | + |
| 15 | +function test_dynamic_opt_probs(tableaus, true_sol, args...; kwargs...) |
| 16 | + for (probtype, solver, tableau) in zip(probtypes, solvers tableaus) |
| 17 | + prob = probtype(args...; kwargs...) |
| 18 | + sol = solve(prob, solver, tableau, silent = true) |
| 19 | + end |
| 20 | +end |
| 21 | + |
| 22 | +@testset "ODE Solution, no cost" begin |
| 23 | + # Test solving without anything attached. |
| 24 | + @parameters α=1.5 β=1.0 γ=3.0 δ=1.0 |
| 25 | + @variables x(..) y(..) |
| 26 | + t = M.t_nounits |
| 27 | + D = M.D_nounits |
| 28 | + |
| 29 | + eqs = [D(x(t)) ~ α * x(t) - β * x(t) * y(t), |
| 30 | + D(y(t)) ~ -γ * y(t) + δ * x(t) * y(t)] |
| 31 | + |
| 32 | + @mtkbuild sys = ODESystem(eqs, t) |
| 33 | + tspan = (0.0, 1.0) |
| 34 | + u0map = [x(t) => 4.0, y(t) => 2.0] |
| 35 | + parammap = [α => 1.5, β => 1.0, γ => 3.0, δ => 1.0] |
| 36 | + |
| 37 | + # Test explicit method. |
| 38 | + jprob = JuMPDynamicOptProblem(sys, u0map, tspan, parammap, dt = 0.01) |
| 39 | + @test JuMP.num_constraints(jprob.model) == 2 # initials |
| 40 | + jsol = solve(jprob, Ipopt.Optimizer, constructRK4, silent = true) |
| 41 | + oprob = ODEProblem(sys, u0map, tspan, parammap) |
| 42 | + osol = solve(oprob, SimpleRK4(), dt = 0.01) |
| 43 | + cprob = CasADiDynamicOptProblem(sys, u0map, tspan, parammap, dt = 0.01) |
| 44 | + csol = solve(oprob, "ipopt", constructRK4) |
| 45 | + @test jsol.sol.u ≈ osol.u |
| 46 | + @test csol.sol.u ≈ osol.u |
| 47 | + |
| 48 | + # Implicit method. |
| 49 | + jsol2 = solve(jprob, Ipopt.Optimizer, constructImplicitEuler, silent = true) # 63.031 ms, 26.49 MiB |
| 50 | + osol2 = solve(oprob, ImplicitEuler(), dt = 0.01, adaptive = false) # 129.375 μs, 61.91 KiB |
| 51 | + jsol2 = solve(jprob, Ipopt.Optimizer, constructImplicitEuler, silent = true) # 63.031 ms, 26.49 MiB |
| 52 | + @test ≈(jsol2.sol.u, osol2.u, rtol = 0.001) |
| 53 | + iprob = InfiniteOptDynamicOptProblem(sys, u0map, tspan, parammap, dt = 0.01) |
| 54 | + isol = solve(iprob, Ipopt.Optimizer, |
| 55 | + derivative_method = InfiniteOpt.FiniteDifference(InfiniteOpt.Backward()), |
| 56 | + silent = true) # 11.540 ms, 4.00 MiB |
| 57 | + @test ≈(isol2.sol.u, osol2.u, rtol = 0.001) |
| 58 | + csol2 = solve(cprob, "ipopt", constructImplicitEuler, silent = true) |
| 59 | + @test ≈(csol2.sol.u, osol2.u, rtol = 0.001) |
| 60 | + |
| 61 | + # With a constraint |
| 62 | + u0map = Pair[] |
| 63 | + guess = [x(t) => 4.0, y(t) => 2.0] |
| 64 | + constr = [x(0.6) ~ 3.5, x(0.3) ~ 7.0] |
| 65 | + @mtkbuild lksys = ODESystem(eqs, t; constraints = constr) |
| 66 | + |
| 67 | + jprob = JuMPDynamicOptProblem(lksys, u0map, tspan, parammap; guesses = guess, dt = 0.01) |
| 68 | + @test JuMP.num_constraints(jprob.model) == 2 |
| 69 | + jsol = solve(jprob, Ipopt.Optimizer, constructTsitouras5, silent = true) # 12.190 s, 9.68 GiB |
| 70 | + @test jsol.sol(0.6)[1] ≈ 3.5 |
| 71 | + @test jsol.sol(0.3)[1] ≈ 7.0 |
| 72 | + |
| 73 | + cprob = CasADiDynamicOptProblem(lksys, u0map, tspan, parammap; guesses = guess, dt = 0.01) |
| 74 | + csol = solve(cprob, "ipopt", constructTsitouras5, silent = true) |
| 75 | + @test csol.sol(0.6)[1] ≈ 3.5 |
| 76 | + @test csol.sol(0.3)[1] ≈ 7.0 |
| 77 | + |
| 78 | + iprob = InfiniteOptDynamicOptProblem( |
| 79 | + lksys, u0map, tspan, parammap; guesses = guess, dt = 0.01) |
| 80 | + isol = solve(iprob, Ipopt.Optimizer, |
| 81 | + derivative_method = InfiniteOpt.OrthogonalCollocation(3), silent = true) # 48.564 ms, 9.58 MiB |
| 82 | + sol = isol.sol |
| 83 | + @test sol(0.6)[1] ≈ 3.5 |
| 84 | + @test sol(0.3)[1] ≈ 7.0 |
| 85 | + |
| 86 | + # Test whole-interval constraints |
| 87 | + constr = [x(t) ≳ 1, y(t) ≳ 1] |
| 88 | + @mtkbuild lksys = ODESystem(eqs, t; constraints = constr) |
| 89 | + iprob = InfiniteOptDynamicOptProblem( |
| 90 | + lksys, u0map, tspan, parammap; guesses = guess, dt = 0.01) |
| 91 | + isol = solve(iprob, Ipopt.Optimizer, |
| 92 | + derivative_method = InfiniteOpt.OrthogonalCollocation(3), silent = true) |
| 93 | + @test all(u -> u > [1, 1], isol.sol.u) |
| 94 | + |
| 95 | + jprob = JuMPDynamicOptProblem(lksys, u0map, tspan, parammap; guesses = guess, dt = 0.01) |
| 96 | + jsol = solve(jprob, Ipopt.Optimizer, constructRadauIA3, silent = true) # 12.190 s, 9.68 GiB |
| 97 | + @test all(u -> u > [1, 1], jsol.sol.u) |
| 98 | + |
| 99 | + cprob = CasADiDynamicOptProblem(lksys, u0map, tspan, parammap; guesses = guess, dt = 0.01) |
| 100 | + csol = solve(cprob, "ipopt", constructRadauIA3, silent = true) |
| 101 | + @test all(u -> u > [1, 1], csol.sol.u) |
| 102 | +end |
| 103 | + |
| 104 | +function is_bangbang(input_sol, lbounds, ubounds, rtol = 1e-4) |
| 105 | + for v in 1:(length(input_sol.u[1]) - 1) |
| 106 | + all(i -> ≈(i[v], bounds[v]; rtol) || ≈(i[v], bounds[u]; rtol), input_sol.u) || |
| 107 | + return false |
| 108 | + end |
| 109 | + true |
| 110 | +end |
| 111 | + |
| 112 | +function ctrl_to_spline(inputsol, splineType) |
| 113 | + us = reduce(vcat, inputsol.u) |
| 114 | + ts = reduce(vcat, inputsol.t) |
| 115 | + splineType(us, ts) |
| 116 | +end |
| 117 | + |
| 118 | +@testset "Linear systems" begin |
| 119 | + # Double integrator |
| 120 | + t = M.t_nounits |
| 121 | + D = M.D_nounits |
| 122 | + @variables x(..) [bounds = (0.0, 0.25)] v(..) |
| 123 | + @variables u(..) [bounds = (-1.0, 1.0), input = true] |
| 124 | + constr = [v(1.0) ~ 0.0] |
| 125 | + cost = [-x(1.0)] # Maximize the final distance. |
| 126 | + @named block = ODESystem( |
| 127 | + [D(x(t)) ~ v(t), D(v(t)) ~ u(t)], t; costs = cost, constraints = constr) |
| 128 | + block, input_idxs = structural_simplify(block, ([u(t)], [])) |
| 129 | + |
| 130 | + u0map = [x(t) => 0.0, v(t) => 0.0] |
| 131 | + tspan = (0.0, 1.0) |
| 132 | + parammap = [u(t) => 0.0] |
| 133 | + jprob = JuMPDynamicOptProblem(block, u0map, tspan, parammap; dt = 0.01) |
| 134 | + jsol = solve(jprob, Ipopt.Optimizer, constructVerner8, silent = true) |
| 135 | + # Linear systems have bang-bang controls |
| 136 | + @test is_bangbang(jsol.input_sol, [-1.0], [1.0]) |
| 137 | + # Test reached final position. |
| 138 | + @test ≈(jsol.sol.u[end][2], 0.25, rtol = 1e-5) |
| 139 | + |
| 140 | + cprob = CasADiDynamicOptProblem(block, u0map, tspan, parammap; dt = 0.01) |
| 141 | + csol = solve(cprob, "ipopt", constructVerner8, silent = true) |
| 142 | + # Linear systems have bang-bang controls |
| 143 | + @test is_bangbang(csol.input_sol, [-1.0], [1.0]) |
| 144 | + # Test reached final position. |
| 145 | + @test ≈(csol.sol.u[end][2], 0.25, rtol = 1e-5) |
| 146 | + |
| 147 | + # Test dynamics |
| 148 | + @parameters (u_interp::ConstantInterpolation)(..) |
| 149 | + @mtkbuild block_ode = ODESystem([D(x(t)) ~ v(t), D(v(t)) ~ u_interp(t)], t) |
| 150 | + spline = ctrl_to_spline(jsol.input_sol, ConstantInterpolation) |
| 151 | + oprob = ODEProblem(block_ode, u0map, tspan, [u_interp => spline]) |
| 152 | + osol = solve(oprob, Vern8(), dt = 0.01, adaptive = false) |
| 153 | + @test ≈(jsol.sol.u, osol.u, rtol = 0.05) |
| 154 | + @test ≈(csol.sol.u, osol.u, rtol = 0.05) |
| 155 | + |
| 156 | + iprob = InfiniteOptDynamicOptProblem(block, u0map, tspan, parammap; dt = 0.01) |
| 157 | + isol = solve(iprob, Ipopt.Optimizer; silent = true) |
| 158 | + @test is_bangbang(isol.input_sol, [-1.0], [1.0]) |
| 159 | + @test ≈(isol.sol.u[end][2], 0.25, rtol = 1e-5) |
| 160 | + osol = solve(oprob, ImplicitEuler(); dt = 0.01, adaptive = false) |
| 161 | + @test ≈(isol.sol.u, osol.u, rtol = 0.05) |
| 162 | + |
| 163 | + ################### |
| 164 | + ### Bee example ### |
| 165 | + ################### |
| 166 | + # From Lawrence Evans' notes |
| 167 | + @variables w(..) q(..) α(t) [input = true, bounds = (0, 1)] |
| 168 | + @parameters b c μ s ν |
| 169 | + |
| 170 | + tspan = (0, 4) |
| 171 | + eqs = [D(w(t)) ~ -μ * w(t) + b * s * α * w(t), |
| 172 | + D(q(t)) ~ -ν * q(t) + c * (1 - α) * s * w(t)] |
| 173 | + costs = [-q(tspan[2])] |
| 174 | + |
| 175 | + @named beesys = ODESystem(eqs, t; costs) |
| 176 | + beesys, input_idxs = structural_simplify(beesys, ([α], [])) |
| 177 | + u0map = [w(t) => 40, q(t) => 2] |
| 178 | + pmap = [b => 1, c => 1, μ => 1, s => 1, ν => 1, α => 1] |
| 179 | + |
| 180 | + jprob = JuMPDynamicOptProblem(beesys, u0map, tspan, pmap, dt = 0.01) |
| 181 | + jsol = solve(jprob, Ipopt.Optimizer, constructTsitouras5, silent = true) |
| 182 | + @test is_bangbang(jsol.input_sol, [0.0], [1.0]) |
| 183 | + iprob = InfiniteOptDynamicOptProblem(beesys, u0map, tspan, pmap, dt = 0.01) |
| 184 | + isol = solve(iprob, Ipopt.Optimizer; silent = true) |
| 185 | + @test is_bangbang(isol.input_sol, [0.0], [1.0]) |
| 186 | + cprob = CasADiDynamicOptProblem(beesys, u0map, tspan, pmap; dt = 0.01) |
| 187 | + csol = solve(cprob, "ipopt", constructTsitouras5, silent = true) |
| 188 | + @test is_bangbang(csol.input_sol, [0.0], [1.0]) |
| 189 | + |
| 190 | + @parameters (α_interp::LinearInterpolation)(..) |
| 191 | + eqs = [D(w(t)) ~ -μ * w(t) + b * s * α_interp(t) * w(t), |
| 192 | + D(q(t)) ~ -ν * q(t) + c * (1 - α_interp(t)) * s * w(t)] |
| 193 | + @mtkbuild beesys_ode = ODESystem(eqs, t) |
| 194 | + oprob = ODEProblem(beesys_ode, |
| 195 | + u0map, |
| 196 | + tspan, |
| 197 | + merge(Dict(pmap), |
| 198 | + Dict(α_interp => ctrl_to_spline(jsol.input_sol, LinearInterpolation)))) |
| 199 | + osol = solve(oprob, Tsit5(); dt = 0.01, adaptive = false) |
| 200 | + @test ≈(osol.u, jsol.sol.u, rtol = 0.01) |
| 201 | + @test ≈(osol.u, csol.sol.u, rtol = 0.01) |
| 202 | + osol2 = solve(oprob, ImplicitEuler(); dt = 0.01, adaptive = false) |
| 203 | + @test ≈(osol2.u, isol.sol.u, rtol = 0.01) |
| 204 | +end |
| 205 | + |
| 206 | +@testset "Rocket launch" begin |
| 207 | + t = M.t_nounits |
| 208 | + D = M.D_nounits |
| 209 | + |
| 210 | + @parameters h_c m₀ h₀ g₀ D_c c Tₘ m_c |
| 211 | + @variables h(..) v(..) m(..) [bounds = (m_c, 1)] T(..) [input = true, bounds = (0, Tₘ)] |
| 212 | + drag(h, v) = D_c * v^2 * exp(-h_c * (h - h₀) / h₀) |
| 213 | + gravity(h) = g₀ * (h₀ / h) |
| 214 | + |
| 215 | + eqs = [D(h(t)) ~ v(t), |
| 216 | + D(v(t)) ~ (T(t) - drag(h(t), v(t))) / m(t) - gravity(h(t)), |
| 217 | + D(m(t)) ~ -T(t) / c] |
| 218 | + |
| 219 | + (ts, te) = (0.0, 0.2) |
| 220 | + costs = [-h(te)] |
| 221 | + cons = [T(te) ~ 0, m(te) ~ m_c] |
| 222 | + @named rocket = ODESystem(eqs, t; costs, constraints = cons) |
| 223 | + rocket, input_idxs = structural_simplify(rocket, ([T(t)], [])) |
| 224 | + |
| 225 | + u0map = [h(t) => h₀, m(t) => m₀, v(t) => 0] |
| 226 | + pmap = [ |
| 227 | + g₀ => 1, m₀ => 1.0, h_c => 500, c => 0.5 * √(g₀ * h₀), D_c => 0.5 * 620 * m₀ / g₀, |
| 228 | + Tₘ => 3.5 * g₀ * m₀, T(t) => 0.0, h₀ => 1, m_c => 0.6] |
| 229 | + jprob = JuMPDynamicOptProblem(rocket, u0map, (ts, te), pmap; dt = 0.001, cse = false) |
| 230 | + jsol = solve(jprob, Ipopt.Optimizer, constructRadauIIA5, silent = true) |
| 231 | + @test jsol.sol.u[end][1] > 1.012 |
| 232 | + |
| 233 | + cprob = CasADiDynamicOptProblem(rocket, u0map, (ts, te), pmap; dt = 0.001, cse = false) |
| 234 | + csol = solve(cprob, "ipopt"; silent = true) |
| 235 | + @test csol.sol.u[end][1] > 1.012 |
| 236 | + |
| 237 | + iprob = InfiniteOptDynamicOptProblem( |
| 238 | + rocket, u0map, (ts, te), pmap; dt = 0.001) |
| 239 | + isol = solve(iprob, Ipopt.Optimizer, silent = true) |
| 240 | + @test isol.sol.u[end][1] > 1.012 |
| 241 | + |
| 242 | + # Test solution |
| 243 | + @parameters (T_interp::CubicSpline)(..) |
| 244 | + eqs = [D(h(t)) ~ v(t), |
| 245 | + D(v(t)) ~ (T_interp(t) - drag(h(t), v(t))) / m(t) - gravity(h(t)), |
| 246 | + D(m(t)) ~ -T_interp(t) / c] |
| 247 | + @mtkbuild rocket_ode = ODESystem(eqs, t) |
| 248 | + interpmap = Dict(T_interp => ctrl_to_spline(jsol.input_sol, CubicSpline)) |
| 249 | + oprob = ODEProblem(rocket_ode, u0map, (ts, te), merge(Dict(pmap), interpmap)) |
| 250 | + osol = solve(oprob, RadauIIA5(); adaptive = false, dt = 0.001) |
| 251 | + @test ≈(jsol.sol.u, osol.u, rtol = 0.02) |
| 252 | + @test ≈(csol.sol.u, osol.u, rtol = 0.02) |
| 253 | + |
| 254 | + interpmap1 = Dict(T_interp => ctrl_to_spline(isol.input_sol, CubicSpline)) |
| 255 | + oprob1 = ODEProblem(rocket_ode, u0map, (ts, te), merge(Dict(pmap), interpmap1)) |
| 256 | + osol1 = solve(oprob1, ImplicitEuler(); adaptive = false, dt = 0.001) |
| 257 | + @test ≈(isol.sol.u, osol1.u, rtol = 0.01) |
| 258 | +end |
| 259 | + |
| 260 | +@testset "Free final time problems" begin |
| 261 | + t = M.t_nounits |
| 262 | + D = M.D_nounits |
| 263 | + |
| 264 | + @variables x(..) u(..) [input = true, bounds = (0, 1)] |
| 265 | + @parameters tf |
| 266 | + eqs = [D(x(t)) ~ -2 + 0.5 * u(t)] |
| 267 | + # Integral cost function |
| 268 | + costs = [-Symbolics.Integral(t in (0, tf))(x(t) - u(t)), -x(tf)] |
| 269 | + consolidate(u) = u[1] + u[2] |
| 270 | + @named rocket = ODESystem(eqs, t; costs, consolidate) |
| 271 | + rocket, input_idxs = structural_simplify(rocket, ([u(t)], [])) |
| 272 | + |
| 273 | + u0map = [x(t) => 17.5] |
| 274 | + pmap = [u(t) => 0.0, tf => 8] |
| 275 | + jprob = JuMPDynamicOptProblem(rocket, u0map, (0, tf), pmap; steps = 201) |
| 276 | + jsol = solve(jprob, Ipopt.Optimizer, constructTsitouras5, silent = true) |
| 277 | + @test isapprox(jsol.sol.t[end], 10.0, rtol = 1e-3) |
| 278 | + |
| 279 | + cprob = CasADiDynamicOptProblem(rocket, u0map, (0, tf), pmap; steps = 201) |
| 280 | + csol = solve(cprob, "ipopt", constructTsitouras5, silent = true) |
| 281 | + @test isapprox(csol.sol.t[end], 10.0, rtol = 1e-3) |
| 282 | + |
| 283 | + iprob = InfiniteOptDynamicOptProblem(rocket, u0map, (0, tf), pmap; steps = 200) |
| 284 | + isol = solve(iprob, Ipopt.Optimizer, silent = true) |
| 285 | + @test isapprox(isol.sol.t[end], 10.0, rtol = 1e-3) |
| 286 | + |
| 287 | + @variables x(..) v(..) |
| 288 | + @variables u(..) [bounds = (-1.0, 1.0), input = true] |
| 289 | + @parameters tf |
| 290 | + constr = [v(tf) ~ 0, x(tf) ~ 0] |
| 291 | + cost = [tf] # Minimize time |
| 292 | + |
| 293 | + @named block = ODESystem( |
| 294 | + [D(x(t)) ~ v(t), D(v(t)) ~ u(t)], t; costs = cost, constraints = constr) |
| 295 | + block, input_idxs = structural_simplify(block, ([u(t)], [])) |
| 296 | + |
| 297 | + u0map = [x(t) => 1.0, v(t) => 0.0] |
| 298 | + tspan = (0.0, tf) |
| 299 | + parammap = [u(t) => 0.0, tf => 1.0] |
| 300 | + jprob = JuMPDynamicOptProblem(block, u0map, tspan, parammap; steps = 51) |
| 301 | + jsol = solve(jprob, Ipopt.Optimizer, constructVerner8, silent = true) |
| 302 | + @test isapprox(jsol.sol.t[end], 2.0, atol = 1e-5) |
| 303 | + |
| 304 | + cprob = CasADiDynamicOptProblem(block, u0map, (0, tf), parammap; steps = 51) |
| 305 | + csol = solve(cprob, "ipopt", constructVerner8, silent = true) |
| 306 | + @test isapprox(csol.sol.t[end], 2.0, atol = 1e-5) |
| 307 | + |
| 308 | + iprob = InfiniteOptDynamicOptProblem(block, u0map, tspan, parammap; steps = 51) |
| 309 | + isol = solve(iprob, Ipopt.Optimizer, silent = true) |
| 310 | + @test isapprox(isol.sol.t[end], 2.0, atol = 1e-5) |
| 311 | +end |
| 312 | + |
| 313 | +@testset "Cart-pole problem" begin |
| 314 | + t = M.t_nounits |
| 315 | + D = M.D_nounits |
| 316 | + # gravity, length, moment of Inertia, drag coeff |
| 317 | + @parameters g l mₚ mₖ |
| 318 | + @variables x(..) θ(..) u(t) [input = true, bounds = (-10, 10)] |
| 319 | + |
| 320 | + s = sin(θ(t)) |
| 321 | + c = cos(θ(t)) |
| 322 | + H = [mₖ+mₚ mₚ*l*c |
| 323 | + mₚ*l*c mₚ*l^2] |
| 324 | + C = [0 -mₚ*D(θ(t))*l*s |
| 325 | + 0 0] |
| 326 | + qd = [D(x(t)), D(θ(t))] |
| 327 | + G = [0, mₚ * g * l * s] |
| 328 | + B = [1, 0] |
| 329 | + |
| 330 | + tf = 5 |
| 331 | + rhss = -H \ Vector(C * qd + G - B * u) |
| 332 | + eqs = [D(D(x(t))) ~ rhss[1], D(D(θ(t))) ~ rhss[2]] |
| 333 | + cons = [θ(tf) ~ π, x(tf) ~ 0, D(θ(tf)) ~ 0, D(x(tf)) ~ 0] |
| 334 | + costs = [Symbolics.Integral(t in (0, tf))(u^2)] |
| 335 | + tspan = (0, tf) |
| 336 | + |
| 337 | + @named cartpole = ODESystem(eqs, t; costs, constraints = cons) |
| 338 | + cartpole, input_idxs = structural_simplify(cartpole, ([u], [])) |
| 339 | + |
| 340 | + u0map = [D(x(t)) => 0.0, D(θ(t)) => 0.0, θ(t) => 0.0, x(t) => 0.0] |
| 341 | + pmap = [mₖ => 1.0, mₚ => 0.2, l => 0.5, g => 9.81, u => 0] |
| 342 | + jprob = JuMPDynamicOptProblem(cartpole, u0map, tspan, pmap; dt = 0.04) |
| 343 | + jsol = solve(jprob, Ipopt.Optimizer, constructRK4, silent = true) |
| 344 | + @test jsol.sol.u[end] ≈ [π, 0, 0, 0] |
| 345 | + |
| 346 | + cprob = CasADiDynamicOptProblem(cartpole, u0map, tspan, pmap; dt = 0.04) |
| 347 | + csol = solve(cprob, "ipopt", constructRK4, silent = true) |
| 348 | + @test csol.sol.u[end] ≈ [π, 0, 0, 0] |
| 349 | + |
| 350 | + iprob = InfiniteOptDynamicOptProblem(cartpole, u0map, tspan, pmap; dt = 0.04) |
| 351 | + isol = solve(iprob, Ipopt.Optimizer, silent = true) |
| 352 | + @test isol.sol.u[end] ≈ [π, 0, 0, 0] |
| 353 | +end |
0 commit comments