From 0eff660ba8b7e02bcc077b8de328b43b227837bf Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Caillau Date: Sun, 8 Sep 2024 00:04:24 +0200 Subject: [PATCH] added in place tests in test_model --- src/optimal_control_model-getters.jl | 2 +- test/test_model.jl | 418 +++++++++++++++++++++++++++ 2 files changed, 419 insertions(+), 1 deletion(-) diff --git a/src/optimal_control_model-getters.jl b/src/optimal_control_model-getters.jl index 1ff464c7..b8bae46f 100644 --- a/src/optimal_control_model-getters.jl +++ b/src/optimal_control_model-getters.jl @@ -339,7 +339,7 @@ function constraint( (:control, rg, _, _) => begin C = @match ocp begin ::OptimalControlModel{Autonomous, Fixed} => is_in_place(ocp) ? - ControlConstraint!((r, u) -> (r[:] .= __view(u, rg); nothing), T, V) : + ControlConstraint!((r, u) -> (r[:] .= __view(u, rg); nothing), T, V) : # todo: CC!{T, V}(fun) syntax? ControlConstraint(u -> u[rg], T, V) ::OptimalControlModel{Autonomous, NonFixed} => is_in_place(ocp) ? ControlConstraint!((r, u, v) -> (r[:] .= __view(u, rg); nothing), T, V) : diff --git a/test/test_model.jl b/test/test_model.jl index 29a34447..936bb355 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -1482,6 +1482,207 @@ function test_model() # 30 55 185 @test dim_variable_range(ocp) == 7 end + + @testset "nlp_constraints! without variable (in place)" begin + ocp = Model(; in_place = true) + time!(ocp; t0 = 0, tf = 1) + state!(ocp, 2) + control!(ocp, 1) + constraint!(ocp, :initial, rg = 2, lb = 10, ub = 10, label = :ci) + constraint!(ocp, :final, rg = 1, lb = 1, ub = 1, label = :cf) + constraint!(ocp, :control, lb = 0, ub = 1, label = :cu) + constraint!(ocp, :state, lb = [0, 1], ub = [1, 2], label = :cs) + constraint!(ocp, :boundary, f = (r, x0, xf) -> (r[:] = x0[2] + xf[2]; nothing), lb = 0, ub = 1, label = :cb) + constraint!(ocp, :control, f = (r, u) -> (r[:] = u; nothing), lb = 0, ub = 1, label = :cuu) + constraint!(ocp, :state, f = (r, x) -> (r[:] = x; nothing), lb = [0, 1], ub = [1, 2], label = :css) + constraint!(ocp, :mixed, f = (r, x, u) -> (r[:] = x[1] + u; nothing), lb = 1, ub = 1, label = :cm) + + # dimensions (not set yet) + @test dim_control_constraints(ocp) === nothing + @test dim_state_constraints(ocp) === nothing + @test dim_mixed_constraints(ocp) === nothing + @test dim_path_constraints(ocp) === nothing + @test dim_boundary_constraints(ocp) === nothing + @test dim_variable_constraints(ocp) === nothing + @test dim_control_range(ocp) === nothing + @test dim_state_range(ocp) === nothing + @test dim_variable_range(ocp) === nothing + + (ξl, ξ!, ξu), + (ηl, η!, ηu), + (ψl, ψ!, ψu), + (ϕl, ϕ!, ϕu), + (θl, θ!, θu), + (ul, uind, uu), + (xl, xind, xu), + (vl, vind, vu) = nlp_constraints!(ocp) + + v = Real[] + + # control + @test sort(ξl) == sort([0]) + @test sort(ξu) == sort([1]) + r = [0.] + ξ!(r, -1, 1, v) + @test sort(r) == sort([1]) + + # state + @test sort(ηl) == sort([0, 1]) + @test sort(ηu) == sort([1, 2]) + r = [0., 0.] + η!(r, -1, [1, 1], v) + @test r == sort([1, 1]) + + # mixed + @test sort(ψl) == sort([1]) + @test sort(ψu) == sort([1]) + r = [0.] + ψ!(r, -1, [1, 1], 2, v) + @test r == sort([3]) + + # boundary + @test sort(ϕl) == sort([10, 1, 0]) + @test sort(ϕu) == sort([10, 1, 1]) + r = [0., 0., 0.] + ϕ!(r, [1, 3], [4, 100], v) + @test r == sort([3, 4, 103]) + + # box constraint + @test sort(ul) == sort([0]) + @test sort(uind) == sort([1]) + @test sort(uu) == sort([1]) + @test sort(xl) == sort([0, 1]) + @test sort(xind) == sort([1, 2]) + @test sort(xu) == sort([1, 2]) + + # variable + @test sort(vl) == sort([]) + @test sort(vind) == sort([]) + @test sort(vu) == sort([]) + @test sort(θl) == sort([]) + @test sort(θu) == sort([]) + r = Real[] + θ!(r, v) + @test r == sort([]) + + # dimensions (set) + @test dim_control_constraints(ocp) == 1 + @test dim_state_constraints(ocp) == 2 + @test dim_mixed_constraints(ocp) == 1 + @test dim_path_constraints(ocp) == 4 + @test dim_boundary_constraints(ocp) == 3 + @test dim_variable_constraints(ocp) == 0 + @test dim_control_range(ocp) == 1 + @test dim_state_range(ocp) == 2 + @test dim_variable_range(ocp) == 0 + end + + @testset "nlp_constraints! with variable (in place)" begin + ocp = Model(; variable = true, in_place = true) + time!(ocp; t0 = 0, tf = 1) + variable!(ocp, 4) + state!(ocp, 2) + control!(ocp, 1) + constraint!(ocp, :initial, rg = 2, lb = 10, ub = 10, label = :ci) + constraint!(ocp, :final, rg = 1, lb = 1, ub = 1, label = :cf) + constraint!(ocp, :control, lb = 0, ub = 1, label = :cu) + constraint!(ocp, :state, lb = [0, 1], ub = [1, 2], label = :cs) + constraint!( + ocp, + :boundary, + f = (r, x0, xf, v) -> (r[:] = x0[2] + xf[2] + v[1]; nothing), + lb = 0, + ub = 1, + label = :cb, + ) + constraint!(ocp, :control, f = (r, u, v) -> (r[:] = u + v[2]; nothing), lb = 0, ub = 1, label = :cuu) + constraint!(ocp, :state, f = (r, x, v) -> (r[:] = x + v[1:2]; nothing), lb = [0, 1], ub = [1, 2], label = :css) + constraint!(ocp, :mixed, f = (r, x, u, v) -> (r[:] = x[1] + u + v[2]; nothing), lb = 1, ub = 1, label = :cm) + constraint!(ocp, :variable, lb = [0, 0, 0, 0], ub = [5, 5, 5, 5], label = :cv1) + constraint!(ocp, :variable, rg = 1:2, lb = [1, 2], ub = [3, 4], label = :cv2) + constraint!(ocp, :variable, rg = 3, lb = 2, ub = 3, label = :cv3) + constraint!(ocp, :variable, f = (r, v) -> (r[:] = v[3]^2; nothing), lb = 0, ub = 1, label = :cv4) + + # dimensions (not set yet) + @test dim_control_constraints(ocp) === nothing + @test dim_state_constraints(ocp) === nothing + @test dim_mixed_constraints(ocp) === nothing + @test dim_path_constraints(ocp) === nothing + @test dim_boundary_constraints(ocp) === nothing + @test dim_variable_constraints(ocp) === nothing + @test dim_control_range(ocp) === nothing + @test dim_state_range(ocp) === nothing + @test dim_variable_range(ocp) === nothing + + (ξl, ξ!, ξu), + (ηl, η!, ηu), + (ψl, ψ!, ψu), + (ϕl, ϕ!, ϕu), + (θl, θ!, θu), + (ul, uind, uu), + (xl, xind, xu), + (vl, vind, vu) = nlp_constraints!(ocp) + + v = [1, 2, 3, 4] + + # control + @test sort(ξl) == sort([0]) + @test sort(ξu) == sort([1]) + r = [0.] + ξ!(r, -1, 1, v) + @test r == sort([1 + v[2]]) + + # state + @test sort(ηl) == sort([0, 1]) + @test sort(ηu) == sort([1, 2]) + r = [0., 0.] + η!(r, -1, [1, 1], v) + @test r == sort([1, 1] + v[1:2]) + + # mixed + @test sort(ψl) == sort([1]) + @test sort(ψu) == sort([1]) + r = [0.] + ψ!(r, -1, [1, 1], 2, v) + @test r == sort([3 + v[2]]) + + # boundary + @test sort(ϕl) == sort([10, 1, 0]) + @test sort(ϕu) == sort([10, 1, 1]) + r = [0., 0., 0.] + ϕ!(r, [1, 3], [4, 100], v)) == sort([3, 4, 103 + v[1]]) + @test r == sort([3, 4, 103 + v[1]]) + + # variable + @test sort(θl) == sort([0]) + @test sort(θu) == sort([1]) + r = [0.] + θ!(r, v) + @test r == sort([v[3]^2]) + + # box constraint + @test sort(ul) == sort([0]) + @test sort(uind) == sort([1]) + @test sort(uu) == sort([1]) + @test sort(xl) == sort([0, 1]) + @test sort(xind) == sort([1, 2]) + @test sort(xu) == sort([1, 2]) + @test sort(vl) == sort([0, 0, 0, 0, 1, 2, 2]) + @test sort(vind) == sort([1, 2, 3, 4, 1, 2, 3]) + @test sort(vu) == sort([5, 5, 5, 5, 3, 4, 3]) + + # dimensions + @test dim_control_constraints(ocp) == 1 + @test dim_state_constraints(ocp) == 2 + @test dim_mixed_constraints(ocp) == 1 + @test dim_path_constraints(ocp) == 4 + @test dim_boundary_constraints(ocp) == 3 + @test dim_variable_constraints(ocp) == 1 + @test dim_control_range(ocp) == 1 + @test dim_state_range(ocp) == 2 + @test dim_variable_range(ocp) == 7 + end + @testset "val vs lb and ub, errors" begin ocp = Model(variable = true) @@ -1872,6 +2073,223 @@ function test_model() # 30 55 185 @test dim_variable_range(ocp) == 7 end + + @testset "val vs lb and ub, 1/2 (in place)" begin + ocp = Model(variable = true, in_place = true) + + time!(ocp; t0 = 0, tf = 1) + variable!(ocp, 4) + state!(ocp, 2) + control!(ocp, 1) + + constraint!(ocp, :initial; rg = Index(2), lb = 10, ub = 10, label = :ci) + constraint!(ocp, :final; rg = Index(1), lb = 1, ub = 1, label = :cf) + constraint!(ocp, :control; lb = 0, ub = 0, label = :cu) + constraint!(ocp, :state; lb = [0, 1], ub = [0, 1], label = :cs) + constraint!( + ocp, + :boundary; + f = (r, x0, xf, v) -> (r[:] = x0[2] + xf[2] + v[1]; nothing), + lb = 2, + ub = 2, + label = :cb, + ) + constraint!(ocp, :control; f = (r, u, v) -> (r[:] = u + v[2]; nothing), lb = 20, ub = 20, label = :cuu) + constraint!( + ocp, + :state; + f = (r, x, v) -> (r[:] = x + v[1:2]; nothing), + lb = [100, 101], + ub = [100, 101], + label = :css, + ) + constraint!(ocp, :mixed; f = (r, x, u, v) -> (r[:] = x[1] + u + v[2]; nothing), lb = -1, ub = -1, label = :cm) + constraint!(ocp, :variable; lb = [5, 5, 5, 5], ub = [5, 5, 5, 5], label = :cv1) + constraint!(ocp, :variable; rg = 1:2, lb = [10, 20], ub = [10, 20], label = :cv2) + constraint!(ocp, :variable; rg = Index(3), lb = 1000, ub = 1000, label = :cv3) + constraint!(ocp, :variable; f = (r, v) -> (r[:] = v[3]^2; nothing), lb = -10, ub = -10, label = :cv4) + + # dimensions (not set yet) + @test dim_control_constraints(ocp) === nothing + @test dim_state_constraints(ocp) === nothing + @test dim_mixed_constraints(ocp) === nothing + @test dim_path_constraints(ocp) === nothing + @test dim_boundary_constraints(ocp) === nothing + @test dim_variable_constraints(ocp) === nothing + @test dim_control_range(ocp) === nothing + @test dim_state_range(ocp) === nothing + @test dim_variable_range(ocp) === nothing + + (ξl, ξ!, ξu), + (ηl, η!, ηu), + (ψl, ψ!, ψu), + (ϕl, ϕ!, ϕu), + (θl, θ!, θu), + (ul, uind, uu), + (xl, xind, xu), + (vl, vind, vu) = nlp_constraints!(ocp) + + v = [1, 2, 3, 4] + + # control + @test sort(ξl) == sort([20]) + @test sort(ξu) == sort([20]) + r = [0.] + ξ!(r, -1, 1, v) + @test r == sort([1 + v[2]]) + + # state + @test sort(ηl) == sort([100, 101]) + @test sort(ηu) == sort([100, 101]) + r = [0., 0.] + η!(r, -1, [1, 1], v)) + @test r == sort([1, 1] + v[1:2]) + + # mixed + @test sort(ψl) == sort([-1]) + @test sort(ψu) == sort([-1]) + r = [0.] + ψ!(r, -1, [1, 1], 2, v) + @test r == sort([3 + v[2]]) + + # boundary + @test sort(ϕl) == sort([10, 1, 2]) + @test sort(ϕu) == sort([10, 1, 2]) + r = [0., 0., 0.] + ϕ!(r, [1, 3], [4, 100], v)) + @test r == sort([3, 4, 103 + v[1]]) + + # variable + @test sort(θl) == sort([-10]) + @test sort(θu) == sort([-10]) + r = [0.] + θ!(r, v) + @test r == sort([v[3]^2]) + + # box constraint + @test sort(ul) == sort([0]) + @test sort(uind) == sort([1]) + @test sort(uu) == sort([0]) + @test sort(xl) == sort([0, 1]) + @test sort(xind) == sort([1, 2]) + @test sort(xu) == sort([0, 1]) + @test sort(vl) == sort([5, 5, 5, 5, 10, 20, 1000]) + @test sort(vind) == sort([1, 2, 3, 4, 1, 2, 3]) + @test sort(vu) == sort([5, 5, 5, 5, 10, 20, 1000]) + + # dimensions + @test dim_control_constraints(ocp) == 1 + @test dim_state_constraints(ocp) == 2 + @test dim_mixed_constraints(ocp) == 1 + @test dim_path_constraints(ocp) == 4 + @test dim_boundary_constraints(ocp) == 3 + @test dim_variable_constraints(ocp) == 1 + @test dim_control_range(ocp) == 1 + @test dim_state_range(ocp) == 2 + @test dim_variable_range(ocp) == 7 + end + + @testset "val vs lb and ub, 2/2 (in place)" begin + ocp = Model(variable = true, in_place = true) + + time!(ocp; t0 = 0, tf = 1) + variable!(ocp, 4) + state!(ocp, 2) + control!(ocp, 1) + + constraint!(ocp, :initial; rg = Index(2), val = 10, label = :ci) + constraint!(ocp, :final; rg = Index(1), val = 1, label = :cf) + constraint!(ocp, :control; val = 0, label = :cu) + constraint!(ocp, :state; val = [0, 1], label = :cs) + constraint!(ocp, :boundary; f = (r, x0, xf, v) -> (r[:] = x0[2] + xf[2] + v[1]; nothing), val = 2, label = :cb) + constraint!(ocp, :control; f = (r, u, v) -> (r[:] = u + v[2]; nothing), val = 20, label = :cuu) + constraint!(ocp, :state; f = (r, x, v) -> (r[:] = x + v[1:2]; nothing), val = [100, 101], label = :css) + constraint!(ocp, :mixed; f = (r, x, u, v) -> (r[:] = x[1] + u + v[2]; nothing), val = -1, label = :cm) + constraint!(ocp, :variable; val = [5, 5, 5, 5], label = :cv1) + constraint!(ocp, :variable; rg = 1:2, val = [10, 20], label = :cv2) + constraint!(ocp, :variable; rg = Index(3), val = 1000, label = :cv3) + constraint!(ocp, :variable; f = (r, v) -> (r[:] = v[3]^2; nothing), val = -10, label = :cv4) + + # dimensions (not set yet) + @test dim_control_constraints(ocp) === nothing + @test dim_state_constraints(ocp) === nothing + @test dim_mixed_constraints(ocp) === nothing + @test dim_path_constraints(ocp) === nothing + @test dim_boundary_constraints(ocp) === nothing + @test dim_variable_constraints(ocp) === nothing + @test dim_control_range(ocp) === nothing + @test dim_state_range(ocp) === nothing + @test dim_variable_range(ocp) === nothing + + (ξl, ξ!, ξu), + (ηl, η!, ηu), + (ψl, ψ!, ψu), + (ϕl, ϕ!, ϕu), + (θl, θ!, θu), + (ul, uind, uu), + (xl, xind, xu), + (vl, vind, vu) = nlp_constraints!(ocp) + + v = [1, 2, 3, 4] + + # control + @test sort(ξl) == sort([20]) + @test sort(ξu) == sort([20]) + r = [0.] + ξ!(r, -1, 1, v) + @test r == sort([1 + v[2]]) + + # state + @test sort(ηl) == sort([100, 101]) + @test sort(ηu) == sort([100, 101]) + r = [0., 0.] + η!(r, -1, [1, 1], v) + @test r == sort([1, 1] + v[1:2]) + + # mixed + @test sort(ψl) == sort([-1]) + @test sort(ψu) == sort([-1]) + r = [0.] + ψ!(r, -1, [1, 1], 2, v) + @test r == sort([3 + v[2]]) + + # boundary + @test sort(ϕl) == sort([10, 1, 2]) + @test sort(ϕu) == sort([10, 1, 2]) + r = [0., 0., 0.] + ϕ!(r, [1, 3], [4, 100], v)) + @test r == sort([3, 4, 103 + v[1]]) + + # variable + @test sort(θl) == sort([-10]) + @test sort(θu) == sort([-10]) + r = [0.] + θ!(r, v) + @test r == sort([v[3]^2]) + + # box constraint + @test sort(ul) == sort([0]) + @test sort(uind) == sort([1]) + @test sort(uu) == sort([0]) + @test sort(xl) == sort([0, 1]) + @test sort(xind) == sort([1, 2]) + @test sort(xu) == sort([0, 1]) + @test sort(vl) == sort([5, 5, 5, 5, 10, 20, 1000]) + @test sort(vind) == sort([1, 2, 3, 4, 1, 2, 3]) + @test sort(vu) == sort([5, 5, 5, 5, 10, 20, 1000]) + + # dimensions + @test dim_control_constraints(ocp) == 1 + @test dim_state_constraints(ocp) == 2 + @test dim_mixed_constraints(ocp) == 1 + @test dim_path_constraints(ocp) == 4 + @test dim_boundary_constraints(ocp) == 3 + @test dim_variable_constraints(ocp) == 1 + @test dim_control_range(ocp) == 1 + @test dim_state_range(ocp) == 2 + @test dim_variable_range(ocp) == 7 + end + @testset "objective!" begin ocp = Model() @test_throws UnauthorizedCall objective!(ocp, :lagrange, (x, u) -> 0.5u^2)