diff --git a/benchmark/benchmark.jl b/benchmark/benchmark.jl index a8cafa8d..7f7fbc5c 100644 --- a/benchmark/benchmark.jl +++ b/benchmark/benchmark.jl @@ -21,7 +21,7 @@ function bench(; precompile = true, display = false, verbose = true, - discretization = :trapeze + discretization = :trapeze, ) ####################################################### @@ -67,7 +67,7 @@ function bench(; linear_solver = linear_solver, max_iter = 0, display = display, - discretization = discretization + discretization = discretization, ) t_precomp += t end @@ -86,7 +86,7 @@ function bench(; linear_solver = linear_solver, grid_size = grid_size, tol = tol, - discretization = discretization + discretization = discretization, ) if !isnothing(problem[:obj]) && !isapprox(sol.objective, problem[:obj], rtol = 5e-2) error( diff --git a/benchmark/prof.jl b/benchmark/prof.jl index 68987f60..9d69d57c 100644 --- a/benchmark/prof.jl +++ b/benchmark/prof.jl @@ -39,7 +39,11 @@ if precompile CTDirect.DOCP_objective(CTDirect.DOCP_initial_guess(docp), docp) end if test_constraints - CTDirect.DOCP_constraints!(zeros(docp.dim_NLP_constraints), CTDirect.DOCP_initial_guess(docp), docp) + CTDirect.DOCP_constraints!( + zeros(docp.dim_NLP_constraints), + CTDirect.DOCP_initial_guess(docp), + docp, + ) end end @@ -49,8 +53,12 @@ if test_objective @btime CTDirect.DOCP_objective(CTDirect.DOCP_initial_guess(docp), docp) end if test_constraints - println("Timed constraints") - @btime CTDirect.DOCP_constraints!(zeros(docp.dim_NLP_constraints), CTDirect.DOCP_initial_guess(docp), docp) + println("Timed constraints") + @btime CTDirect.DOCP_constraints!( + zeros(docp.dim_NLP_constraints), + CTDirect.DOCP_initial_guess(docp), + docp, + ) end # transcription @@ -62,10 +70,9 @@ end # full solve if test_solve println("Timed full solve") - @btime sol = direct_solve(ocp, grid_size = grid_size, display=false) + @btime sol = direct_solve(ocp, grid_size = grid_size, display = false) end - if test_code_warntype if test_objective # NB. Pb with the mayer part: obj is type unstable (Any) because ocp.mayer is Union(Mayer,nothing), even for mayer problems (also, we should not even enter this code part for lagrange problems since has_mayer us defined as const in DOCP oO ...). diff --git a/src/gauss.jl b/src/gauss.jl index 6ddb02d4..cbc891c1 100644 --- a/src/gauss.jl +++ b/src/gauss.jl @@ -18,5 +18,11 @@ struct GaussLegendre2 <: Discretization butcher_a::Matrix{Float64} butcher_b::Vector{Float64} butcher_c::Vector{Float64} - GaussLegendre2() = new(2, 0, [0.25 (0.25 - sqrt(3)/6); (0.25 + sqrt(3)/6) 0.25], [0.5, 0.5], [(0.5 - sqrt(3)/6), (0.5 + sqrt(3)/6)]) + GaussLegendre2() = new( + 2, + 0, + [0.25 (0.25-sqrt(3) / 6); (0.25+sqrt(3) / 6) 0.25], + [0.5, 0.5], + [(0.5 - sqrt(3) / 6), (0.5 + sqrt(3) / 6)], + ) end diff --git a/src/midpoint.jl b/src/midpoint.jl index c5b56187..0ce639d5 100644 --- a/src/midpoint.jl +++ b/src/midpoint.jl @@ -12,19 +12,17 @@ struct Midpoint <: Discretization Midpoint() = new(1, 0) end - """ $(TYPEDSIGNATURES) Retrieve state and control variables at given time step from the NLP variables. """ function get_variables_at_time_step(xu, docp::DOCP{Midpoint}, i) - nx = docp.dim_NLP_x n = docp.dim_OCP_x m = docp.dim_NLP_u N = docp.dim_NLP_steps - offset = (nx*(1+docp.discretization.stage) + m) * i + offset = (nx * (1 + docp.discretization.stage) + m) * i # retrieve scalar/vector OCP state (w/o lagrange state) if n == 1 @@ -42,7 +40,7 @@ function get_variables_at_time_step(xu, docp::DOCP{Midpoint}, i) if i < N offset_u = offset else - offset_u = (nx*2 + m) * (i-1) + offset_u = (nx * 2 + m) * (i - 1) end if m == 1 ui = xu[offset_u + nx + 1] @@ -52,7 +50,7 @@ function get_variables_at_time_step(xu, docp::DOCP{Midpoint}, i) # retrieve vector stage variable (except at final time) if i < N - ki = xu[(offset + nx + m + 1):(offset + nx + m + nx) ] + ki = xu[(offset + nx + m + 1):(offset + nx + m + nx)] else ki = nothing end @@ -60,17 +58,15 @@ function get_variables_at_time_step(xu, docp::DOCP{Midpoint}, i) return xi, ui, xli, ki end - # internal NLP version for solution parsing # could be fused with one above if # - using extended dynamics that include lagrange cost # - scalar case is handled at OCP level function get_NLP_variables_at_time_step(xu, docp, i, disc::Midpoint) - nx = docp.dim_NLP_x m = docp.dim_NLP_u N = docp.dim_NLP_steps - offset = (nx*2 + m) * i + offset = (nx * 2 + m) * i # state xi = xu[(offset + 1):(offset + nx)] @@ -78,12 +74,12 @@ function get_NLP_variables_at_time_step(xu, docp, i, disc::Midpoint) if i < N offset_u = offset else - offset_u = (nx*2 + m) * (i-1) - end + offset_u = (nx * 2 + m) * (i - 1) + end ui = xu[(offset_u + nx + 1):(offset_u + nx + m)] # stage if i < N - ki = xu[(offset + nx + m + 1):(offset + nx + m + nx) ] + ki = xu[(offset + nx + m + 1):(offset + nx + m + nx)] else ki = nothing end @@ -91,14 +87,12 @@ function get_NLP_variables_at_time_step(xu, docp, i, disc::Midpoint) return xi, ui, ki end - function set_variables_at_time_step!(xu, x_init, u_init, docp, i, disc::Midpoint) - nx = docp.dim_NLP_x n = docp.dim_OCP_x m = docp.dim_NLP_u N = docp.dim_NLP_steps - offset = (nx*2 + m) * i + offset = (nx * 2 + m) * i # NB. only set the actual state variables from the OCP # - skip the possible additional state for lagrange cost @@ -111,7 +105,6 @@ function set_variables_at_time_step!(xu, x_init, u_init, docp, i, disc::Midpoint end end - # trivial version for now... # +++multiple dispatch here seems to cause more allocations ! # +++? use abstract type for all Args ? @@ -129,20 +122,19 @@ struct ArgsAtTimeStep_Midpoint next_time::Any next_state::Any next_lagrange_state::Any - - function ArgsAtTimeStep_Midpoint(xu, docp::DOCP{Midpoint}, v, time_grid, i::Int) + function ArgsAtTimeStep_Midpoint(xu, docp::DOCP{Midpoint}, v, time_grid, i::Int) disc = docp.discretization # variables - ti = time_grid[i+1] + ti = time_grid[i + 1] xi, ui, xli, ki = get_variables_at_time_step(xu, docp, i) - + if i == docp.dim_NLP_steps return new(ti, xi, ui, xli, ki, disc) else - tip1 = time_grid[i+2] - xip1, uip1, xlip1 = get_variables_at_time_step(xu, docp, i+1) + tip1 = time_grid[i + 2] + xip1, uip1, xlip1 = get_variables_at_time_step(xu, docp, i + 1) return new(ti, xi, ui, xli, ki, tip1, xip1, xlip1) end end @@ -151,20 +143,18 @@ function initArgs(xu, docp::DOCP{Midpoint}, time_grid) v = Float64[] docp.has_variable && (v = get_optim_variable(xu, docp)) args = ArgsAtTimeStep_Midpoint(xu, docp, v, time_grid, 0) - return args, v + return args, v end function updateArgs(args, xu, docp::DOCP{Midpoint}, v, time_grid, i::Int) - return ArgsAtTimeStep_Midpoint(xu, docp, v, time_grid, i+1) + return ArgsAtTimeStep_Midpoint(xu, docp, v, time_grid, i + 1) end - """ $(TYPEDSIGNATURES) Set the constraints corresponding to the state equation """ function setStateEquation!(docp::DOCP{Midpoint}, c, index::Int, args, v, i) - ocp = docp.ocp # +++ later use butcher table in struct ? @@ -181,36 +171,32 @@ function setStateEquation!(docp::DOCP{Midpoint}, c, index::Int, args, v, i) hi = tip1 - ti # midpoint rule - @. c[index:(index + docp.dim_OCP_x - 1)] = - xip1 - (xi + hi * ki[1:docp.dim_OCP_x]) + @. c[index:(index + docp.dim_OCP_x - 1)] = xip1 - (xi + hi * ki[1:(docp.dim_OCP_x)]) # +++ just define extended dynamics ! if docp.has_lagrange c[index + docp.dim_OCP_x] = xlip1 - (xli + hi * ki[end]) end index += docp.dim_NLP_x - + # stage equation at mid-step t_s = 0.5 * (ti + tip1) x_s = 0.5 * (xi + xip1) - c[index:(index + docp.dim_OCP_x - 1)] .= - ki[1:docp.dim_OCP_x] .- ocp.dynamics(t_s, x_s, ui, v) + c[index:(index + docp.dim_OCP_x - 1)] .= ki[1:(docp.dim_OCP_x)] .- ocp.dynamics(t_s, x_s, ui, v) # +++ just define extended dynamics ! if docp.has_lagrange - c[index + docp.dim_OCP_x] = ki[end] - ocp.lagrange(t_s, x_s, ui, v) + c[index + docp.dim_OCP_x] = ki[end] - ocp.lagrange(t_s, x_s, ui, v) end index += docp.dim_NLP_x return index end - """ $(TYPEDSIGNATURES) Set the path constraints at given time step """ function setPathConstraints!(docp::DOCP{Midpoint}, c, index::Int, args, v, i::Int) - ocp = docp.ocp ti = args.time xi = args.state diff --git a/src/problem.jl b/src/problem.jl index a55d26bb..825cc8f4 100644 --- a/src/problem.jl +++ b/src/problem.jl @@ -5,7 +5,6 @@ # later we can add an option for control discretization: step or stage # (meaningful only for schemes with more than 1 stage, at least I will be able to compare the two ! further options may include CVP -control vector parametrization-, and maybe even pseudo-spectral ?) - # generic discretization struct # NB. can we mutualize common fields at the abstract level ? abstract type Discretization end @@ -70,7 +69,12 @@ struct DOCP{T <: Discretization} discretization::T # constructor - function DOCP(ocp::OptimalControlModel, grid_size::Integer, time_grid, discretization::Discretization) + function DOCP( + ocp::OptimalControlModel, + grid_size::Integer, + time_grid, + discretization::Discretization, + ) # time grid if time_grid == nothing @@ -120,7 +124,11 @@ struct DOCP{T <: Discretization} dim_stage = discretization.stage # NLP unknown (state + control + variable [+ stage]) - dim_NLP_variables = (N + 1) * dim_NLP_x + (N + discretization.additional_controls) * dim_NLP_u + dim_NLP_v + N * dim_NLP_x * dim_stage + dim_NLP_variables = + (N + 1) * dim_NLP_x + + (N + discretization.additional_controls) * dim_NLP_u + + dim_NLP_v + + N * dim_NLP_x * dim_stage # NLP constraints # parse NLP constraints (and initialize dimensions) @@ -145,7 +153,10 @@ struct DOCP{T <: Discretization} # constraints (dynamics, stage, path, boundary, variable) dim_NLP_constraints = - N * (dim_NLP_x + (dim_NLP_x * dim_stage) + dim_path_cons) + dim_path_cons + dim_boundary_cons + dim_v_cons + N * (dim_NLP_x + (dim_NLP_x * dim_stage) + dim_path_cons) + + dim_path_cons + + dim_boundary_cons + + dim_v_cons if has_lagrange # add initial condition for lagrange state dim_NLP_constraints += 1 @@ -189,14 +200,13 @@ struct DOCP{T <: Discretization} Inf * ones(dim_NLP_variables), zeros(dim_NLP_constraints), zeros(dim_NLP_constraints), - discretization + discretization, ) return docp end end - """ $(TYPEDSIGNATURES) @@ -207,14 +217,12 @@ function is_solvable(ocp) return solvable end - """ $(TYPEDSIGNATURES) Build upper and lower bounds vectors for the DOCP nonlinear constraints. """ function constraints_bounds!(docp::DOCP) - lb = docp.con_l ub = docp.con_u @@ -237,7 +245,6 @@ function constraints_bounds!(docp::DOCP) return lb, ub end - """ $(TYPEDSIGNATURES) @@ -270,14 +277,12 @@ function variables_bounds!(docp::DOCP) return var_l, var_u end - """ $(TYPEDSIGNATURES) Compute the objective for the DOCP problem. """ function DOCP_objective(xu, docp::DOCP) - obj = 0.0 N = docp.dim_NLP_steps ocp = docp.ocp @@ -308,7 +313,6 @@ function DOCP_objective(xu, docp::DOCP) return obj end - """ $(TYPEDSIGNATURES) @@ -331,7 +335,6 @@ function DOCP_constraints!(c, xu, docp::DOCP) index = setPathConstraints!(docp, c, index, args, v, i) # update args = updateArgs(args, xu, docp, v, time_grid, i) - end # path constraints at final time @@ -345,14 +348,12 @@ function DOCP_constraints!(c, xu, docp::DOCP) return c end - """ $(TYPEDSIGNATURES) Set bounds for the path constraints at given time step """ function setPathBounds!(docp::DOCP, index::Int, lb, ub) - ocp = docp.ocp # pure control constraints @@ -379,14 +380,12 @@ function setPathBounds!(docp::DOCP, index::Int, lb, ub) return index end - """ $(TYPEDSIGNATURES) Set the boundary and variable constraints """ function setPointConstraints!(docp::DOCP, c, index::Int, xu, v) - ocp = docp.ocp x0, u0, xl0 = get_variables_at_time_step(xu, docp, 0) @@ -413,14 +412,12 @@ function setPointConstraints!(docp::DOCP, c, index::Int, xu, v) return index end - """ $(TYPEDSIGNATURES) Set bounds for the boundary and variable constraints """ function setPointBounds!(docp::DOCP, index::Int, lb, ub) - ocp = docp.ocp # boundary constraints @@ -447,7 +444,6 @@ function setPointBounds!(docp::DOCP, index::Int, lb, ub) return index end - """ $(TYPEDSIGNATURES) @@ -466,8 +462,15 @@ function DOCP_initial_guess(docp::DOCP, init::OptimalControlInit = OptimalContro # set state / control variables if provided time_grid = get_time_grid(NLP_X, docp) for i = 0:(docp.dim_NLP_steps) - ti = time_grid[i+1] - set_variables_at_time_step!(NLP_X, init.state_init(ti), init.control_init(ti), docp, i, docp.discretization) + ti = time_grid[i + 1] + set_variables_at_time_step!( + NLP_X, + init.state_init(ti), + init.control_init(ti), + docp, + i, + docp.discretization, + ) end return NLP_X diff --git a/src/solution.jl b/src/solution.jl index 9bbd7ff7..46f0cbaf 100644 --- a/src/solution.jl +++ b/src/solution.jl @@ -188,7 +188,7 @@ function parse_DOCP_solution_dual(docp, multipliers, constraints) if i < N + 1 P[i, :] = multipliers[i_m:(i_m + docp.dim_NLP_x - 1)] # skip dynamics constraints - i_c += docp.dim_NLP_x + i_c += docp.dim_NLP_x i_m += docp.dim_NLP_x # skip stage constraints i_c += docp.dim_NLP_x * docp.discretization.stage @@ -464,4 +464,3 @@ function set_box_block(T, mults, dim) end return t -> m_l(t), t -> m_u(t) end - diff --git a/src/solve.jl b/src/solve.jl index 811d5c4e..8f7943a7 100644 --- a/src/solve.jl +++ b/src/solve.jl @@ -24,7 +24,7 @@ function direct_transcription( init = CTBase.__ocp_init(), grid_size = __grid_size(), time_grid = __time_grid(), - discretization = __discretization() + discretization = __discretization(), ) # build DOCP @@ -110,7 +110,7 @@ function direct_solve( init = init, grid_size = grid_size, time_grid = time_grid, - discretization = discretization + discretization = discretization, ) # solve DOCP @@ -136,4 +136,4 @@ weakdeps = Dict(IpoptBackend => :NLPModelsIpopt, MadNLPBackend => :MadNLP) function solve_docp(solver_backend::T, args...; kwargs...) where {T <: AbstractSolverBackend} throw(ExtensionError(weakdeps[T])) -end \ No newline at end of file +end diff --git a/src/trapeze.jl b/src/trapeze.jl index e15db82e..18878300 100644 --- a/src/trapeze.jl +++ b/src/trapeze.jl @@ -3,7 +3,6 @@ Internal layout for NLP variables: [X_0,U_0, X_1,U_1, .., X_N,U_N, V] =# - struct Trapeze <: Discretization stage::Int additional_controls::Int @@ -11,14 +10,12 @@ struct Trapeze <: Discretization Trapeze() = new(0, 1) end - """ $(TYPEDSIGNATURES) Retrieve state and control variables at given time step from the NLP variables. """ function get_variables_at_time_step(xu, docp::DOCP{Trapeze}, i) - nx = docp.dim_NLP_x n = docp.dim_OCP_x m = docp.dim_NLP_u @@ -46,13 +43,11 @@ function get_variables_at_time_step(xu, docp::DOCP{Trapeze}, i) return xi, ui, xli end - # internal NLP version for solution parsing # could be fused with one above if # - using extended dynamics that include lagrange cost # - scalar case is handled at OCP level function get_NLP_variables_at_time_step(xu, docp, i, disc::Trapeze) - nx = docp.dim_NLP_x m = docp.dim_NLP_u offset = (nx + m) * i @@ -65,9 +60,7 @@ function get_NLP_variables_at_time_step(xu, docp, i, disc::Trapeze) return xi, ui end - function set_variables_at_time_step!(xu, x_init, u_init, docp, i, disc::Trapeze) - nx = docp.dim_NLP_x n = docp.dim_OCP_x m = docp.dim_NLP_u @@ -84,7 +77,6 @@ function set_variables_at_time_step!(xu, x_init, u_init, docp, i, disc::Trapeze) end end - # ? use abstract type for args ? """ $(TYPEDSIGNATURES) @@ -102,7 +94,7 @@ struct ArgsAtTimeStep_Trapeze function ArgsAtTimeStep_Trapeze(xu, docp::DOCP{Trapeze}, v, time_grid, i::Int) # variables - ti = time_grid[i+1] + ti = time_grid[i + 1] xi, ui, xli = get_variables_at_time_step(xu, docp, i) # dynamics and lagrange cost @@ -131,13 +123,12 @@ function updateArgs(args, xu, docp::DOCP{Trapeze}, v, time_grid, i) args_i, args_ip1 = args if i < docp.dim_NLP_steps - 1 # are we allocating more than one args here ? - return (args_ip1, ArgsAtTimeStep_Trapeze(xu, docp, v, time_grid, i+2)) + return (args_ip1, ArgsAtTimeStep_Trapeze(xu, docp, v, time_grid, i + 2)) else return (args_ip1, args_ip1) end end - """ $(TYPEDSIGNATURES) @@ -164,7 +155,6 @@ function setStateEquation!(docp::DOCP{Trapeze}, c, index::Int, args, v, i) return index end - """ $(TYPEDSIGNATURES) diff --git a/src/utils.jl b/src/utils.jl index e2844322..f4095b7d 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -5,14 +5,12 @@ Internal layout for NLP variables: with the convention u([t_i,t_i+1[) = U_i and u(tf) = U_N-1 =# - """ $(TYPEDSIGNATURES) Retrieve optimization variables from the NLP variables. """ function get_optim_variable(xu, docp) - if docp.has_variable if docp.dim_NLP_v == 1 return xu[end] @@ -24,7 +22,6 @@ function get_optim_variable(xu, docp) end end - """ $(TYPEDSIGNATURES) @@ -38,7 +35,6 @@ function get_initial_time(xu, docp) end end - """ $(TYPEDSIGNATURES) @@ -52,7 +48,6 @@ function get_final_time(xu, docp) end end - """ $(TYPEDSIGNATURES) @@ -64,7 +59,6 @@ function get_time_grid(xu, docp) return @. t0 + docp.NLP_normalized_time_grid * (tf - t0) end - """ $(TYPEDSIGNATURES) @@ -74,14 +68,12 @@ function set_optim_variable!(xu, v_init, docp) xu[(end - docp.dim_NLP_v + 1):end] .= v_init end - """ $(TYPEDSIGNATURES) Build full, ordered sets of bounds for state, control or optimization variables """ function build_bounds(dim_var, dim_box, box_triplet) - x_lb = -Inf * ones(dim_var) x_ub = Inf * ones(dim_var) for j = 1:(dim_box) @@ -93,7 +85,6 @@ function build_bounds(dim_var, dim_box, box_triplet) return x_lb, x_ub end - # placeholders (see CTDirectExt) function export_ocp_solution end function import_ocp_solution end diff --git a/test/suite/test_discretization.jl b/test/suite/test_discretization.jl index 24961a2d..831a4c8a 100644 --- a/test/suite/test_discretization.jl +++ b/test/suite/test_discretization.jl @@ -1,6 +1,5 @@ println("Test: discretization options") - normalize_grid(t) = return (t .- t[1]) ./ (t[end] - t[1]) # 1. simple integrator min energy (dual control for test) @@ -64,13 +63,12 @@ end ocp = simple_integrator().ocp sol_t = direct_solve(ocp, display = false) sol_m = direct_solve(ocp, display = false, discretization = "midpoint") - @test sol_m.objective ≈ sol_t.objective rtol = 1e-2 + @test sol_m.objective ≈ sol_t.objective rtol = 1e-2 end @testset verbose = true showtiming = true ":implicit_midpoint" begin ocp = double_integrator_freet0tf().ocp sol_t = direct_solve(ocp, display = false) sol_m = direct_solve(ocp, display = false, discretization = :midpoint) - @test sol_m.objective ≈ sol_t.objective rtol = 1e-2 + @test sol_m.objective ≈ sol_t.objective rtol = 1e-2 end - diff --git a/test/suite/test_initial_guess.jl b/test/suite/test_initial_guess.jl index 951a28fa..3884a1d8 100644 --- a/test/suite/test_initial_guess.jl +++ b/test/suite/test_initial_guess.jl @@ -29,22 +29,22 @@ u_vec = [0, 0.3, 0.1] @testset verbose = true showtiming = true ":default_init_no_arg" begin sol = direct_solve(ocp, display = false, max_iter = maxiter) T = sol.time_grid - @test isapprox(sol.state.(T), (t->[0.1,0.1]).(T), rtol = 1e-2) - @test isapprox(sol.control.(T), (t->0.1).(T), rtol = 1e-2) + @test isapprox(sol.state.(T), (t -> [0.1, 0.1]).(T), rtol = 1e-2) + @test isapprox(sol.control.(T), (t -> 0.1).(T), rtol = 1e-2) @test isapprox(sol.variable, 0.1, rtol = 1e-2) end @testset verbose = true showtiming = true ":default_init_()" begin sol = direct_solve(ocp, display = false, init = (), max_iter = maxiter) T = sol.time_grid - @test isapprox(sol.state.(T), (t->[0.1,0.1]).(T), rtol = 1e-2) - @test isapprox(sol.control.(T), (t->0.1).(T), rtol = 1e-2) + @test isapprox(sol.state.(T), (t -> [0.1, 0.1]).(T), rtol = 1e-2) + @test isapprox(sol.control.(T), (t -> 0.1).(T), rtol = 1e-2) @test isapprox(sol.variable, 0.1, rtol = 1e-2) end @testset verbose = true showtiming = true ":default_init_nothing" begin sol = direct_solve(ocp, display = false, init = nothing, max_iter = maxiter) T = sol.time_grid - @test isapprox(sol.state.(T), (t->[0.1,0.1]).(T), rtol = 1e-2) - @test isapprox(sol.control.(T), (t->0.1).(T), rtol = 1e-2) + @test isapprox(sol.state.(T), (t -> [0.1, 0.1]).(T), rtol = 1e-2) + @test isapprox(sol.control.(T), (t -> 0.1).(T), rtol = 1e-2) @test sol.variable == 0.1 end @@ -52,12 +52,12 @@ end @testset verbose = true showtiming = true ":constant_x" begin sol = direct_solve(ocp, display = false, init = (state = x_const,), max_iter = maxiter) T = sol.time_grid - @test isapprox(sol.state.(T), (t->x_const).(T), rtol = 1e-2) + @test isapprox(sol.state.(T), (t -> x_const).(T), rtol = 1e-2) end @testset verbose = true showtiming = true ":constant_u" begin sol = direct_solve(ocp, display = false, init = (control = u_const,), max_iter = maxiter) T = sol.time_grid - @test isapprox(sol.control.(T), (t->u_const).(T), rtol = 1e-2) + @test isapprox(sol.control.(T), (t -> u_const).(T), rtol = 1e-2) end @testset verbose = true showtiming = true ":constant_v" begin sol = direct_solve(ocp, display = false, init = (variable = v_const,), max_iter = maxiter) @@ -71,8 +71,8 @@ end max_iter = maxiter, ) T = sol.time_grid - @test isapprox(sol.state.(T), (t->x_const).(T), rtol = 1e-2) - @test isapprox(sol.control.(T), (t->u_const).(T), rtol = 1e-2) + @test isapprox(sol.state.(T), (t -> x_const).(T), rtol = 1e-2) + @test isapprox(sol.control.(T), (t -> u_const).(T), rtol = 1e-2) end @testset verbose = true showtiming = true ":constant_xv" begin sol = direct_solve( @@ -82,7 +82,7 @@ end max_iter = maxiter, ) T = sol.time_grid - @test isapprox(sol.state.(T), (t->x_const).(T), rtol = 1e-2) + @test isapprox(sol.state.(T), (t -> x_const).(T), rtol = 1e-2) @test sol.variable == v_const end @testset verbose = true showtiming = true ":constant_uv" begin @@ -93,7 +93,7 @@ end max_iter = maxiter, ) T = sol.time_grid - @test isapprox(sol.control.(T), (t->u_const).(T), rtol = 1e-2) + @test isapprox(sol.control.(T), (t -> u_const).(T), rtol = 1e-2) @test sol.variable == v_const end @testset verbose = true showtiming = true ":constant_xuv" begin @@ -104,8 +104,8 @@ end max_iter = maxiter, ) T = sol.time_grid - @test isapprox(sol.state.(T), (t->x_const).(T), rtol = 1e-2) - @test isapprox(sol.control.(T), (t->u_const).(T), rtol = 1e-2) + @test isapprox(sol.state.(T), (t -> x_const).(T), rtol = 1e-2) + @test isapprox(sol.control.(T), (t -> u_const).(T), rtol = 1e-2) @test sol.variable == v_const end @@ -164,7 +164,7 @@ end init = (time = t_vec, state = x_matrix, control = u_vec, variable = v_const), max_iter = maxiter, ) - @test isapprox(stack(sol.state.(t_matrix),dims=1), x_matrix, rtol = 1e-2) + @test isapprox(stack(sol.state.(t_matrix), dims = 1), x_matrix, rtol = 1e-2) @test isapprox(sol.control.(t_vec), u_vec, rtol = 1e-2) @test sol.variable == v_const end