From 46386cd95e0482103c9defa98c20ef6080f798e8 Mon Sep 17 00:00:00 2001 From: Baptiste Combelles Date: Mon, 31 Jul 2023 11:07:28 +0200 Subject: [PATCH 1/6] change functional constraint functions --- bench/bench_nlp_constraints.md | 238 +++++++++++++++++++-------------- src/ctparser_utils.jl | 20 +-- src/model.jl | 176 ++---------------------- test/test_ctparser_utils.jl | 10 +- test/test_model.jl | 133 +++++++++--------- test/test_print.jl | 12 +- 6 files changed, 232 insertions(+), 357 deletions(-) diff --git a/bench/bench_nlp_constraints.md b/bench/bench_nlp_constraints.md index 6aee2ff7..f0f90403 100644 --- a/bench/bench_nlp_constraints.md +++ b/bench/bench_nlp_constraints.md @@ -4,6 +4,7 @@ using BenchmarkTools using CTBase using MLStyle +using StaticArrays rg(i::Integer, j::Integer) = begin if i == j i @@ -11,22 +12,22 @@ rg(i::Integer, j::Integer) = begin i:j end end -$(Expr(:toplevel, :(ocp = Model()), :(time!(ocp, 0, 1)), :(state!(ocp, 2)), :(control!(ocp, 1)))) +$(Expr(:toplevel, :(ocp = Model()), :(time!(ocp, 0, 1)), :(state!(ocp, 2)), :(control!(ocp, 2)))) constraint!(ocp, :initial, Index(2), 10, :ci) constraint!(ocp, :final, Index(1), 1, :cf) -constraint!(ocp, :control, 0, 1, :cu) +constraint!(ocp, :control, [0, 0], [1, 1], :cu) constraint!(ocp, :state, [0, 1], [1, 2], :cs) constraint!(ocp, :boundary, ((x0, xf)->begin x0[2] + xf[2] end), 0, 1, :cb) constraint!(ocp, :control, (u->begin u - end), 0, 1, :cuu) + end), [0, 0], [1, 1], :cuu) constraint!(ocp, :state, (x->begin x end), [0, 1], [1, 2], :css) constraint!(ocp, :mixed, ((x, u)->begin - x[1] + u + x[1] + u[1] end), 1, 1, :cm) function nlp_constraints_original(ocp::OptimalControlModel) CTBase.__check_all_set(ocp) @@ -147,42 +148,52 @@ function nlp_constraints_original(ocp::OptimalControlModel) end return ((ξl, ξ, ξu), (ηl, η, ηu), (ψl, ψ, ψu), (ϕl, ϕ, ϕu), (θl, θ, θu), (ul, uind, uu), (xl, xind, xu), (vl, vind, vu)) end -function test_alloc_bad(ocp) - function get_state(XU, i, n, m) - return XU[rg((i - 1) * (n + m) + 1, (i - 1) * (n + m) + n)] - end - function get_control(XU, i, n, m) - return XU[rg((i - 1) * (n + m) + n + 1, (i - 1) * (n + m) + n + m)] - end - function set_control_constraint!(C, i, ξ, nξ, nc) - C[(i - 1) * nc + 1:(i - 1) * nc + nξ] = ξ - end - function set_state_constraint!(C, i, η, nη, nξ, nc) - C[(i - 1) * nc + nξ + 1:(i - 1) * nc + nξ + nη] = η - end - function set_mixed_constraint!(C, i, ψ, nψ, nξ, nη, nc) - C[(i - 1) * nc + nξ + nη + 1:(i - 1) * nc + nξ + nη + nψ] = ψ +function test_alloc_bad(ocp, N) + println(" getters and setters") + begin + function get_state(XU, i, n, m) + return XU[rg((i - 1) * (n + m) + 1, (i - 1) * (n + m) + n)] + end + function get_control(XU, i, n, m) + return XU[rg((i - 1) * (n + m) + n + 1, (i - 1) * (n + m) + n + m)] + end + function set_control_constraint!(C, i, ξ, nξ, nc) + C[(i - 1) * nc + 1:(i - 1) * nc + nξ] = ξ + end + function set_state_constraint!(C, i, η, nη, nξ, nc) + C[(i - 1) * nc + nξ + 1:(i - 1) * nc + nξ + nη] = η + end + function set_mixed_constraint!(C, i, ψ, nψ, nξ, nη, nc) + C[(i - 1) * nc + nξ + nη + 1:(i - 1) * nc + nξ + nη + nψ] = ψ + end end + println(" call nlp_constraints_original") ((ξl, ξ, ξu), (ηl, η, ηu), (ψl, ψ, ψu), (ϕl, ϕ, ϕu), (θl, θ, θu), (ul, uind, uu), (xl, xind, xu), (vl, vind, vu)) = nlp_constraints_original(ocp) - v = Real[] - n = 2 - m = 1 - N = 200 - times = LinRange(0, 1, N) - XU = ones(N * (n + m)) - nξ = length(ξl) - nη = length(ηl) - nψ = length(ψl) - nc = nξ + nη + nψ - C = zeros(N * nc) - for i = 1:N - t = times[i] - x = get_state(XU, i, n, m) - u = get_control(XU, i, n, m) - set_control_constraint!(C, i, ξ(t, u, v), nξ, nc) - set_state_constraint!(C, i, η(t, x, v), nη, nξ, nc) - set_mixed_constraint!(C, i, ψ(t, x, u, v), nψ, nξ, nη, nc) + println(" declare variables") + begin + v = Real[] + n = ocp.state_dimension + m = ocp.control_dimension + times = LinRange(0, 1, N) + XU = ones(N * (n + m)) + nξ = length(ξl) + nη = length(ηl) + nψ = length(ψl) + nc = nξ + nη + nψ + C = zeros(N * nc) + end + println(" start for loop") + begin + for i = 1:N + t = times[i] + x = get_state(XU, i, n, m) + u = get_control(XU, i, n, m) + set_control_constraint!(C, i, ξ(t, u, v), nξ, nc) + set_state_constraint!(C, i, η(t, x, v), nη, nξ, nc) + set_mixed_constraint!(C, i, ψ(t, x, u, v), nψ, nξ, nη, nc) + end end + println(" end for loop") nothing end function nlp_constraints_optimized(ocp::OptimalControlModel) @@ -284,101 +295,122 @@ function nlp_constraints_optimized(ocp::OptimalControlModel) ψfn = length(ψf) ϕfn = length(ϕf) θfn = length(θf) - function ξ!(val, t, u, v) + function ξ!(val, t, u, v, N = ξfn) offset = 0 - for i = 1:ξfn - val[1 + offset:(ξn[i] + offset) - 1] = (ξf[i])(t, u, v) + for i = 1:N + z = ((ξf[i])(t, u, v))[:] + val[rg(1 + offset, ξn[i] + offset)] = z offset += ξn[i] end nothing end - function η!(val, t, x, v) + function η!(val, t, x, v, N = ηfn) offset = 0 - for i = 1:ηfn - val[1 + offset:(ηn[i] + offset) - 1] = (ηf[i])(t, x, v) + for i = 1:N + val[rg(1 + offset, ηn[i] + offset)] = (ηf[i])(t, x, v) offset += ηn[i] end nothing end - function ψ!(val, t, x, u, v) + function ψ!(val, t, x, u, v, N = ψfn) offset = 0 - for i = 1:ψfn - val[1 + offset:(ψn[i] + offset) - 1] = (ψf[i])(t, x, u, v) + for i = 1:N + val[rg(1 + offset, ψn[i] + offset)] = (ψf[i])(t, x, u, v) offset += ψn[i] end nothing end - function ϕ!(val, x0, xf, v) + function ϕ!(val, x0, xf, v, N = ϕfn) offset = 0 - for i = 1:ϕfn - val[1 + offset:(ϕn[i] + offset) - 1] = (ϕf[i])(x0, xf, v) + for i = 1:N + val[rg(1 + offset, ϕn[i] + offset)] = (ϕf[i])(x0, xf, v) offset += ϕn[i] end nothing end - function θ!(val, v) + function θ!(val, v, N = θfn) offset = 0 - for i = 1:θfn - val[1 + offset:(θn[i] + offset) - 1] = (θf[i])(v) + for i = 1:N + val[rg(1 + offset, θn[i] + offset)] = (θf[i])(v) offset += θn[i] end nothing end return ((ξl, ξ!, ξu), (ηl, η!, ηu), (ψl, ψ!, ψu), (ϕl, ϕ!, ϕu), (θl, θ!, θu), (uind, ul, uu), (xind, xl, xu), (vind, vl, vu)) end -function test_alloc_good(ocp) - function get_state(XU, i, n, m) - if n == 1 - return XU[(i - 1) * (n + m) + 1] - else - return @view(XU[rg((i - 1) * (n + m) + 1, (i - 1) * (n + m) + n)]) +function test_alloc_good(ocp, N) + begin + println(" getters and setters") + begin + function get_state(XU, i, n, m) + if n == 1 + return XU[(i - 1) * (n + m) + 1] + else + return @view(XU[(i - 1) * (n + m) + 1:(i - 1) * (n + m) + n]) + end + end + function get_control(XU, i, n, m) + if m == 1 + return XU[(i - 1) * (n + m) + n + 1] + else + return @view(XU[(i - 1) * (n + m) + n + 1:(i - 1) * (n + m) + n + m]) + end + end + function set_control_constraint!(C, i, valξ, nξ, nc) + C[(i - 1) * nc + 1:(i - 1) * nc + nξ] = valξ + end + function set_state_constraint!(C, i, valη, nη, nξ, nc) + C[(i - 1) * nc + nξ + 1:(i - 1) * nc + nξ + nη] = valη + end + function set_mixed_constraint!(C, i, valψ, nψ, nξ, nη, nc) + C[(i - 1) * nc + nξ + nη + 1:(i - 1) * nc + nξ + nη + nψ] = valψ + end end - end - function get_control(XU, i, n, m) - if m == 1 - return XU[(i - 1) * (n + m) + n + 1] - else - return @view(XU[rg((i - 1) * (n + m) + n + 1, (i - 1) * (n + m) + n + m)]) + println(" call nlp_constraints_optimized") + begin + ((ξl, ξ!, ξu), (ηl, η!, ηu), (ψl, ψ!, ψu), (ϕl, ϕ!, ϕu), (θl, θ!, θu), (ul, uind, uu), (xl, xind, xu), (vl, vind, vu)) = nlp_constraints_optimized(ocp) end + println(" declare variables") + begin + v = Real[] + n = ocp.state_dimension + m = ocp.control_dimension + times = LinRange(0, 1, N) + XU = zeros(N * (n + m)) + nξ = length(ξl) + nη = length(ηl) + nψ = length(ψl) + nc = nξ + nη + nψ + C = zeros(N * nc) + valξ = SizedVector{nξ}(zeros(nξ)) + valη = SizedVector{nη}(zeros(nη)) + valψ = SizedVector{nψ}(zeros(nψ)) + x = SizedVector{n}(zeros(n)) + u = SizedVector{m}(zeros(m)) + end + t = 0 + println(" start for loop") + for i = 1:N + t = times[i] + x[:] = XU[(i - 1) * (n + m) + 1:(i - 1) * (n + m) + n] + u[:] = @view(XU[(i - 1) * (n + m) + n + 1:(i - 1) * (n + m) + n + m]) + ξ!(valξ, t, u, v) + η!(valη, t, x, v) + ψ!(valψ, t, x, u, v) + C[(i - 1) * nc + 1:(i - 1) * nc + nξ] = valξ + C[(i - 1) * nc + nξ + 1:(i - 1) * nc + nξ + nη] = valη + C[(i - 1) * nc + nξ + nη + 1:(i - 1) * nc + nξ + nη + nψ] = valψ + end + println(" end for loop") + nothing end - function set_control_constraint!(C, i, valξ, nξ, nc) - C[(i - 1) * nc + 1:(i - 1) * nc + nξ] = valξ - end - function set_state_constraint!(C, i, valη, nη, nξ, nc) - C[(i - 1) * nc + nξ + 1:(i - 1) * nc + nξ + nη] = valη - end - function set_mixed_constraint!(C, i, valψ, nψ, nξ, nη, nc) - C[(i - 1) * nc + nξ + nη + 1:(i - 1) * nc + nξ + nη + nψ] = valψ - end - ((ξl, ξ!, ξu), (ηl, η!, ηu), (ψl, ψ!, ψu), (ϕl, ϕ!, ϕu), (θl, θ!, θu), (ul, uind, uu), (xl, xind, xu), (vl, vind, vu)) = nlp_constraints_optimized(ocp) - v = Real[] - n = 2 - m = 1 - N = 100 - times = LinRange(0, 1, N) - XU = ones(N * (n + m)) - nξ = length(ξl) - nη = length(ηl) - nψ = length(ψl) - nc = nξ + nη + nψ - C = zeros(N * nc) - valξ = zeros(nξ) - valη = zeros(nη) - valψ = zeros(nψ) - for i = 1:N - t = times[i] - x = get_state(XU, i, n, m) - u = get_control(XU, i, n, m) - ξ!(valξ, t, u, v) - η!(valη, t, x, v) - ψ!(valψ, t, x, u, v) - set_control_constraint!(C, i, valξ, nξ, nc) - set_state_constraint!(C, i, valη, nη, nξ, nc) - set_mixed_constraint!(C, i, valψ, nψ, nξ, nη, nc) - end - nothing end -println("Allocations and times for good and bad code") -println() +N = 10000 +$(Expr(:toplevel, :(test_alloc_good(ocp, N)))) +$(Expr(:toplevel, :(test_alloc_bad(ocp, N)))) +println("----------------------------------------") println("good code") -t_good = @benchmark(test_alloc_good(ocp)) +@time test_alloc_good(ocp, N) +println() +println("bad code") +@time test_alloc_bad(ocp, N) diff --git a/src/ctparser_utils.jl b/src/ctparser_utils.jl index c2ac2825..ac3f6698 100644 --- a/src/ctparser_utils.jl +++ b/src/ctparser_utils.jl @@ -249,7 +249,7 @@ julia> constraint_type(:( x[1:2](0) ), t, t0, tf, x, u, v) (:initial, 1:2) julia> constraint_type(:( x[1](0) ), t, t0, tf, x, u, v) -(:initial, Index(1)) +(:initial, 1) julia> constraint_type(:( 2x[1](0)^2 ), t, t0, tf, x, u, v) :boundary @@ -264,7 +264,7 @@ julia> constraint_type(:( x[1:2](tf) ), t, t0, tf, x, u, v) (:final, 1:2) julia> constraint_type(:( x[1](tf) ), t, t0, tf, x, u, v) -(:final, Index(1)) +(:final, 1) julia> constraint_type(:( 2x[1](tf)^2 ), t, t0, tf, x, u, v) :boundary @@ -279,7 +279,7 @@ julia> constraint_type(:( u[1:2](t) ), t, t0, tf, x, u, v) (:control_range, 1:2) julia> constraint_type(:( u[1](t) ), t, t0, tf, x, u, v) -(:control_range, Index(1)) +(:control_range, 1) julia> constraint_type(:( u(t) ), t, t0, tf, x, u, v) (:control_range, nothing) @@ -294,7 +294,7 @@ julia> constraint_type(:( x[1:2](t) ), t, t0, tf, x, u, v) (:state_range, 1:2) julia> constraint_type(:( x[1](t) ), t, t0, tf, x, u, v) -(:state_range, Index(1)) +(:state_range, 1) julia> constraint_type(:( x(t) ), t, t0, tf, x, u, v) (:state_range, nothing) @@ -321,7 +321,7 @@ julia> constraint_type(:( v[1:10] ), t, t0, tf, x, u, v) (:variable_range, 1:10) julia> constraint_type(:( v[2] ), t, t0, tf, x, u, v) -(:variable_range, Index(2)) +(:variable_range, 2) julia> constraint_type(:( v ), t, t0, tf, x, u, v) (:variable_range, nothing) @@ -338,33 +338,33 @@ constraint_type(e, t, t0, tf, x, u, v) = begin [ true , false, false, false, false, false, _ ] => @match e begin :( $y[$i:$p:$j]($s) ) && if (y == x && s == t0) end => (:initial , i:p:j ) :( $y[$i:$j ]($s) ) && if (y == x && s == t0) end => (:initial , i:j ) - :( $y[$i ]($s) ) && if (y == x && s == t0) end => (:initial , Index(i)) + :( $y[$i ]($s) ) && if (y == x && s == t0) end => (:initial , i) :( $y($s) ) && if (y == x && s == t0) end => (:initial , nothing ) _ => :boundary end [ false, true , false, false, false, false, _ ] => @match e begin :( $y[$i:$p:$j]($s) ) && if (y == x && s == tf) end => (:final , i:p:j ) :( $y[$i:$j ]($s) ) && if (y == x && s == tf) end => (:final , i:j ) - :( $y[$i ]($s) ) && if (y == x && s == tf) end => (:final , Index(i)) + :( $y[$i ]($s) ) && if (y == x && s == tf) end => (:final , i) :( $y($s) ) && if (y == x && s == tf) end => (:final , nothing ) _ => :boundary end [ true , true , false, false, false, false, _ ] => :boundary [ false, false, true , false, false, false, _ ] => @match e begin :( $c[$i:$p:$j]($s) ) && if (c == u && s == t) end => (:control_range, i:p:j ) :( $c[$i:$j ]($s) ) && if (c == u && s == t) end => (:control_range, i:j ) - :( $c[$i ]($s) ) && if (c == u && s == t) end => (:control_range, Index(i)) + :( $c[$i ]($s) ) && if (c == u && s == t) end => (:control_range, i) :( $c($s) ) && if (c == u && s == t) end => (:control_range, nothing ) _ => :control_fun end [ false, false, false, true , false, false, _ ] => @match e begin :( $y[$i:$p:$j]($s) ) && if (y == x && s == t) end => (:state_range, i:p:j ) :( $y[$i:$j ]($s) ) && if (y == x && s == t) end => (:state_range, i:j ) - :( $y[$i ]($s) ) && if (y == x && s == t) end => (:state_range, Index(i)) + :( $y[$i ]($s) ) && if (y == x && s == t) end => (:state_range, i) :( $y($s) ) && if (y == x && s == t) end => (:state_range, nothing ) _ => :state_fun end [ false, false, true , true , false, false, _ ] => :mixed [ false, false, false, false, false, false, true ] => @match e begin :( $w[$i:$p:$j] ) && if (w == v) end => (:variable_range, i:p:j ) :( $w[$i:$j ] ) && if (w == v) end => (:variable_range, i:j ) - :( $w[$i ] ) && if (w == v) end => (:variable_range, Index(i)) + :( $w[$i ] ) && if (w == v) end => (:variable_range, i) _ && if (e == v) end => (:variable_range, nothing ) _ => :variable_fun end _ => :other diff --git a/src/model.jl b/src/model.jl index d9ffaaf4..1580ed96 100644 --- a/src/model.jl +++ b/src/model.jl @@ -500,113 +500,6 @@ end """ $(TYPEDSIGNATURES) -Add an `:initial` or `:final` value constraint on a range of the state, or a value constraint on a range of the -`:variable`. - -!!! note - - - The range of the constraint must be contained in 1:n if the constraint is on the state, or 1:q if the constraint is on the variable. - - The state, control and variable dimensions must be set before. Use state!, control! and variable!. - - The times must be set before. Use time!. - -# Examples - -```jldoctest -julia> constraint!(ocp, :initial, 1:2:5, [ 0, 0, 0 ]) -julia> constraint!(ocp, :initial, 2:3, [ 0, 0 ]) -julia> constraint!(ocp, :final, Index(2), 0) -julia> constraint!(ocp, :variable, 2:3, [ 0, 3 ]) -``` -""" -function constraint!(ocp::OptimalControlModel, type::Symbol, rg::RangeConstraint, val::ctVector, label::Symbol=__constraint_label()) - - # we check if the dimensions and times have been set just to force the user to set them before - __check_all_set(ocp) - type == :variable && is_variable_independent(ocp) && throw(UnauthorizedCall("the ocp is variable independent" * - ", you cannot use constraint! function with type=:variable.")) - - # check if the constraint named label already exists - if label ∈ constraints_labels(ocp) - throw(UnauthorizedCall("the constraint named " * String(label) * " already exists.")) - end - - # check if rg and val are consistent - (length(rg) != length(val)) && throw(IncorrectArgument("the range `rg`` and the value `val` must have the same dimension")) - - # dimensions - n = ocp.state_dimension - q = ocp.variable_dimension - - # check if the range is valid - if type == :initial - !all(1 .≤ rg .≤ n) && throw(IncorrectArgument("the range $rg of the initial state constraint must be contained in 1:$n")) - elseif type == :final - !all(1 .≤ rg .≤ n) && throw(IncorrectArgument("the range $rg of the final state constraint must be contained in 1:$n")) - elseif type == :variable - !all(1 .≤ rg .≤ q) && throw(IncorrectArgument("the range $rg of the variable constraint must be contained in 1:$q")) - end - - # - constraint!(ocp, type, rg, val, val, label) - -end - -""" -$(TYPEDSIGNATURES) - -Add an `:initial` or `:final` value constraint on the state, or a `:variable` value. Can also be used with -`:state` and `:control`. - -!!! note - - - The state, control and variable dimensions must be set before. Use state!, control! and variable!. - - The times must be set before. Use time!. - - When an element is of dimension 1, consider it as a scalar. - -# Examples - -```jldoctest -julia> constraint!(ocp, :initial, [ 0, 0 ]) -julia> constraint!(ocp, :final, 2) # if the state is of dimension 1 -julia> constraint!(ocp, :variable, [ 3, 0, 1 ]) -``` -""" -function constraint!(ocp::OptimalControlModel, type::Symbol, val::ctVector, label::Symbol=__constraint_label()) - # we use the constraint! defined before - - # we check if the dimensions and times have been set - __check_all_set(ocp) - type == :variable && is_variable_independent(ocp) && throw(UnauthorizedCall("the ocp is variable independent" * - ", you cannot use constraint! function with type=:variable.")) - - # - rg = nothing - - # dimensions - n = ocp.state_dimension - q = ocp.variable_dimension - - # - if type ∈ [:initial, :final, :state, :control ] # also allowed for :control and :state to treat uniformly eq and ineq - rg = n == 1 ? Index(1) : 1:n - # check if rg and val are consistent - (length(rg) != length(val)) && throw(IncorrectArgument("`val` must be of dimension $n")) - elseif type == :variable - rg = q == 1 ? Index(1) : 1:q - (length(rg) != length(val)) && throw(IncorrectArgument("`val` must be of dimension $q")) - else - throw(IncorrectArgument("the following type of constraint is not valid: " * String(type) * - ". Please choose in [ :initial, :final, :state, :control, :variable ] or check the arguments of the constraint! method.")) - end - - # - constraint!(ocp, type, rg, val, label) - -end - -""" -$(TYPEDSIGNATURES) - Add an `:initial`, `:final`, `:control`, `:state` or `:variable` box constraint (whole range). !!! note @@ -739,53 +632,6 @@ function constraint!(ocp::OptimalControlModel{T, V}, type::Symbol, f::Function, end -""" -$(TYPEDSIGNATURES) - -Add a `:boundary`, `:control`, `:state`, `:mixed` or `:variable` value functional constraint. - -!!! note - - - The state, control and variable dimensions must be set before. Use state!, control! and variable!. - - The times must be set before. Use time!. - - When an element is of dimension 1, consider it as a scalar. - -# Examples - -```@example -# variable independent ocp -julia> constraint!(ocp, :boundary, (x0, xf) -> x0[3]+xf[2], 0) - -# variable dependent ocp -julia> constraint!(ocp, :boundary, (x0, xf, v) -> x0[3]+xf[2]*v[1], 0) - -# time independent and variable independent ocp -julia> constraint!(ocp, :control, u -> 2u, 1) -julia> constraint!(ocp, :state, x -> x-1, [ 0, 0, 0 ]) -julia> constraint!(ocp, :mixed, (x, u) -> x[1]-u, 0) - -# time dependent and variable independent ocp -julia> constraint!(ocp, :control, (t, u) -> 2u, 1) -julia> constraint!(ocp, :state, (t, x) -> x-t, [ 0, 0, 0 ]) -julia> constraint!(ocp, :mixed, (t, x, u) -> x[1]-u, 0) - -# time independent and variable dependent ocp -julia> constraint!(ocp, :control, (u, v) -> 2u*v[1], 1) -julia> constraint!(ocp, :state, (x, v) -> x-v[2], [ 0, 0, 0 ]) -julia> constraint!(ocp, :mixed, (x, u) -> x[1]-u+v[1], 0) - -# time dependent and variable dependent ocp -julia> constraint!(ocp, :control, (t, u, v) -> 2u-t*v[2], 1) -julia> constraint!(ocp, :state, (t, x, v) -> x-t+v[1], [ 0, 0, 0 ]) -julia> constraint!(ocp, :mixed, (t, x, u, v) -> x[1]-u*v[1], 0) -``` -""" -function constraint!(ocp::OptimalControlModel, type::Symbol, f::Function, val::ctVector, - label::Symbol=__constraint_label()) # we use the constraint! defined before - constraint!(ocp, type, f, val, val, label) -end - - """ $(TYPEDSIGNATURES) @@ -801,29 +647,25 @@ Add an `:initial`, `:final`, `:control`, `:state` or `:variable` box constraint ```jldoctest julia> constraint!(ocp, :initial, rg=2:3, lb=[ 0, 0 ], ub=[ 1, 2 ]) -julia> constraint!(ocp, :final, val=Index(1), lb=0, ub=2) -julia> constraint!(ocp, :control, val=Index(1), lb=0, ub=2) +julia> constraint!(ocp, :final, rg=1, lb=0, ub=2) +julia> constraint!(ocp, :control, rg=1, lb=0, ub=2) julia> constraint!(ocp, :state, rg=2:3, lb=[ 0, 0 ], ub=[ 1, 2 ]) julia> constraint!(ocp, :initial, rg=1:2:5, lb=[ 0, 0, 0 ], ub=[ 1, 2, 1 ]) julia> constraint!(ocp, :variable, rg=1:2, lb=[ 0, 0 ], ub=[ 1, 2 ]) ``` """ function constraint!(ocp::OptimalControlModel{<: TimeDependence, <: VariableDependence}, type::Symbol; - rg::Union{RangeConstraint,Nothing}=nothing, f::Union{Function,Nothing}=nothing, - val::Union{ctVector,Nothing}=nothing, lb::Union{ctVector,Nothing}=nothing, ub::Union{ctVector,Nothing}=nothing, + rg::Union{OrdinalRange{<:Integer},Integer,Nothing}=nothing, f::Union{Function,Nothing}=nothing, lb::Union{ctVector,Nothing}=nothing, ub::Union{ctVector,Nothing}=nothing, label::Symbol=__constraint_label()) - (lb ≢ nothing && ub === nothing) && (ub = Inf*(size(lb,1) == 1 ? 1 : ones(eltype(ub), size(ub,1)))) (lb === nothing && ub ≢ nothing) && (lb = -Inf*(size(ub,1) == 1 ? 1 : ones(eltype(ub), size(ub,1)))) - - @match (rg,f,val,lb,ub) begin - (::Nothing,::Nothing,::ctVector,::Nothing,::Nothing) => return constraint!(ocp, type, val, label) # - (::Nothing,::Nothing,::Nothing,::ctVector,::ctVector) => return constraint!(ocp, type, lb, ub, label) # - (::Nothing,::Function,::ctVector,::Nothing,::Nothing) => return constraint!(ocp, type, f, val, label) # - (::Nothing,::Function,::Nothing,::ctVector,::ctVector) => return constraint!(ocp, type, f, lb, ub, label) # - (::RangeConstraint,::Nothing,::ctVector,::Nothing,::Nothing) => return constraint!(ocp, type, rg, val, label) # - (::RangeConstraint,::Nothing,::Nothing,::ctVector,::ctVector) => return constraint!(ocp, type, rg, lb, ub, label) # + (typeof(rg) <: Int) && (rg = Index(rg)) + + @match (rg,f,lb,ub) begin + (::Nothing,::Nothing,::ctVector,::ctVector) => return constraint!(ocp, type, lb, ub, label) # + (::Nothing,::Function,::ctVector,::ctVector) => return constraint!(ocp, type, f, lb, ub, label) # + (::RangeConstraint,::Nothing,::ctVector,::ctVector) => return constraint!(ocp, type, rg, lb, ub, label) # _ => throw(IncorrectArgument("Provided arguments are inconsistent")) end diff --git a/test/test_ctparser_utils.jl b/test/test_ctparser_utils.jl index aeb1454b..9acf7e11 100644 --- a/test/test_ctparser_utils.jl +++ b/test/test_ctparser_utils.jl @@ -64,24 +64,24 @@ t = :t; t0 = 0; tf = :tf; x = :x; u = :u; v = :v @test constraint_type(:( x(0) ), t, t0, tf, x, u, v) == (:initial, nothing) @test constraint_type(:( x[1:2:5](0) ), t, t0, tf, x, u, v) == (:initial, 1:2:5) @test constraint_type(:( x[1:2](0) ), t, t0, tf, x, u, v) == (:initial, 1:2) -@test constraint_type(:( x[1](0) ), t, t0, tf, x, u, v) == (:initial, Index(1)) +@test constraint_type(:( x[1](0) ), t, t0, tf, x, u, v) == (:initial, 1) @test constraint_type(:( x[1:2](0) ), t, t0, tf, x, u, v) == (:initial, 1:2) @test constraint_type(:( 2x[1](0)^2 ), t, t0, tf, x, u, v) == :boundary @test constraint_type(:( x(tf) ), t, t0, tf, x, u, v) == (:final, nothing) @test constraint_type(:( x[1:2:5](tf) ), t, t0, tf, x, u, v) == (:final, 1:2:5) @test constraint_type(:( x[1:2](tf) ), t, t0, tf, x, u, v) == (:final, 1:2) -@test constraint_type(:( x[1](tf) ), t, t0, tf, x, u, v) == (:final, Index(1)) +@test constraint_type(:( x[1](tf) ), t, t0, tf, x, u, v) == (:final, 1) @test constraint_type(:( x[1:2](tf) ), t, t0, tf, x, u, v) == (:final, 1:2) @test constraint_type(:( x[1](tf) - x[2](0) ), t, t0, tf, x, u, v) == :boundary @test constraint_type(:( 2x[1](tf)^2 ), t, t0, tf, x, u, v) == :boundary @test constraint_type(:( u[1:2:5](t) ), t, t0, tf, x, u, v) == (:control_range, 1:2:5) @test constraint_type(:( u[1:2](t) ), t, t0, tf, x, u, v) == (:control_range, 1:2) -@test constraint_type(:( u[1](t) ), t, t0, tf, x, u, v) == (:control_range, Index(1)) +@test constraint_type(:( u[1](t) ), t, t0, tf, x, u, v) == (:control_range, 1) @test constraint_type(:( u(t) ), t, t0, tf, x, u, v) == (:control_range, nothing) @test constraint_type(:( 2u[1](t)^2 ), t, t0, tf, x, u, v) == :control_fun @test constraint_type(:( x[1:2:5](t) ), t, t0, tf, x, u, v) == (:state_range, 1:2:5) @test constraint_type(:( x[1:2](t) ), t, t0, tf, x, u, v) == (:state_range, 1:2) -@test constraint_type(:( x[1](t) ), t, t0, tf, x, u, v) == (:state_range, Index(1)) +@test constraint_type(:( x[1](t) ), t, t0, tf, x, u, v) == (:state_range, 1) @test constraint_type(:( x(t) ), t, t0, tf, x, u, v) == (:state_range, nothing) @test constraint_type(:( 2x[1](t)^2 ), t, t0, tf, x, u, v) == :state_fun @test constraint_type(:( 2u[1](t)^2 * x(t) ), t, t0, tf, x, u, v) == :mixed @@ -89,7 +89,7 @@ t = :t; t0 = 0; tf = :tf; x = :x; u = :u; v = :v @test constraint_type(:( 2u[1](t)^2 * x(t) + v ), t, t0, tf, x, u, v) == :mixed @test constraint_type(:( v[1:2:10] ), t, t0, tf, x, u, v) == (:variable_range, 1:2:9) @test constraint_type(:( v[1:10] ), t, t0, tf, x, u, v) == (:variable_range, 1:10) -@test constraint_type(:( v[2] ), t, t0, tf, x, u, v) == (:variable_range, Index(2)) +@test constraint_type(:( v[2] ), t, t0, tf, x, u, v) == (:variable_range, 2) @test constraint_type(:( v ), t, t0, tf, x, u, v) == (:variable_range, nothing) @test constraint_type(:( v^2 + 1 ), t, t0, tf, x, u, v) == :variable_fun @test constraint_type(:( v[2]^2 + 1 ), t, t0, tf, x, u, v) == :variable_fun diff --git a/test/test_model.jl b/test/test_model.jl index 744431d1..b5d4b1c2 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -5,10 +5,10 @@ function test_model() # 30 55 185 @testset "variable!" begin ocp = Model(variable=false) @test_throws UnauthorizedCall variable!(ocp, 1) - @test_throws UnauthorizedCall constraint!(ocp, :variable, 2:3, [ 0, 3 ]) + @test_throws UnauthorizedCall constraint!(ocp, :variable, 2:3, [ 0, 3 ], [ 0, 3 ]) @test_throws UnauthorizedCall constraint!(ocp, :variable, 0, 1) # the variable here is of dimension 1 @test_throws UnauthorizedCall constraint!(ocp, :variable, 1:2, [ 0, 0 ], [ 1, 2 ]) - @test_throws UnauthorizedCall constraint!(ocp, :variable, [ 3, 0, 1 ]) + @test_throws UnauthorizedCall constraint!(ocp, :variable, [ 3, 0, 1 ], [ 3, 0, 1 ]) ocp = Model(variable=true) variable!(ocp, 1) @@ -59,13 +59,13 @@ end i == 7 && begin state!(ocp, 2); control!(ocp, 1) end # constraint! 1 - @test_throws UnauthorizedCall constraint!(ocp, :initial, 1:2:5, [ 0, 0, 0 ]) - @test_throws UnauthorizedCall constraint!(ocp, :initial, 2:3, [ 0, 0 ]) - @test_throws UnauthorizedCall constraint!(ocp, :final, Index(2), 0) + @test_throws UnauthorizedCall constraint!(ocp, :initial, 1:2:5, [ 0, 0, 0 ], [ 0, 0, 0 ]) + @test_throws UnauthorizedCall constraint!(ocp, :initial, 2:3, [ 0, 0 ], [ 0, 0 ]) + @test_throws UnauthorizedCall constraint!(ocp, :final, Index(2), 0, 0) # constraint! 2 - @test_throws UnauthorizedCall constraint!(ocp, :initial, [ 0, 0 ]) - @test_throws UnauthorizedCall constraint!(ocp, :final, 2) # if the state is of dimension 1 + @test_throws UnauthorizedCall constraint!(ocp, :initial, [ 0, 0 ], [ 0, 0 ]) + @test_throws UnauthorizedCall constraint!(ocp, :final, 2, 2) # if the state is of dimension 1 # constraint! 3 @test_throws UnauthorizedCall constraint!(ocp, :initial, 2:3, [ 0, 0 ], [ 1, 2 ]) @@ -109,30 +109,30 @@ end # constraint! 6 # variable independent ocp - @test_throws UnauthorizedCall constraint!(ocp, :boundary, (x0, xf) -> x0[3]+xf[2], 0) + @test_throws UnauthorizedCall constraint!(ocp, :boundary, (x0, xf) -> x0[3]+xf[2], 0, 0) # variable dependent ocp - @test_throws UnauthorizedCall constraint!(ocp, :boundary, (x0, xf, v) -> x0[3]+xf[2]*v[1], 0) + @test_throws UnauthorizedCall constraint!(ocp, :boundary, (x0, xf, v) -> x0[3]+xf[2]*v[1], 0, 0) # time independent and variable independent ocp - @test_throws UnauthorizedCall constraint!(ocp, :control, u -> 2u, 1) - @test_throws UnauthorizedCall constraint!(ocp, :state, x -> x-1, [ 0, 0, 0 ]) - @test_throws UnauthorizedCall constraint!(ocp, :mixed, (x, u) -> x[1]-u, 0) + @test_throws UnauthorizedCall constraint!(ocp, :control, u -> 2u, 1, 1) + @test_throws UnauthorizedCall constraint!(ocp, :state, x -> x-1, [ 0, 0, 0 ], [ 0, 0, 0 ]) + @test_throws UnauthorizedCall constraint!(ocp, :mixed, (x, u) -> x[1]-u, 0, 0) # time dependent and variable independent ocp - @test_throws UnauthorizedCall constraint!(ocp, :control, (t, u) -> 2u, 1) - @test_throws UnauthorizedCall constraint!(ocp, :state, (t, x) -> x-t, [ 0, 0, 0 ]) - @test_throws UnauthorizedCall constraint!(ocp, :mixed, (t, x, u) -> x[1]-u, 0) + @test_throws UnauthorizedCall constraint!(ocp, :control, (t, u) -> 2u, 1, 1) + @test_throws UnauthorizedCall constraint!(ocp, :state, (t, x) -> x-t, [ 0, 0, 0 ], [ 0, 0, 0 ]) + @test_throws UnauthorizedCall constraint!(ocp, :mixed, (t, x, u) -> x[1]-u, 0, 0) # time independent and variable dependent ocp - @test_throws UnauthorizedCall constraint!(ocp, :control, (u, v) -> 2u*v[1], 1) - @test_throws UnauthorizedCall constraint!(ocp, :state, (x, v) -> x-v[2], [ 0, 0, 0 ]) - @test_throws UnauthorizedCall constraint!(ocp, :mixed, (x, u) -> x[1]-u+v[1], 0) + @test_throws UnauthorizedCall constraint!(ocp, :control, (u, v) -> 2u*v[1], 1, 1) + @test_throws UnauthorizedCall constraint!(ocp, :state, (x, v) -> x-v[2], [ 0, 0, 0 ], [ 0, 0, 0 ]) + @test_throws UnauthorizedCall constraint!(ocp, :mixed, (x, u) -> x[1]-u+v[1], 0, 0) # time dependent and variable dependent ocp - @test_throws UnauthorizedCall constraint!(ocp, :control, (t, u, v) -> 2u-t*v[2], 1) - @test_throws UnauthorizedCall constraint!(ocp, :state, (t, x, v) -> x-t+v[1], [ 0, 0, 0 ]) - @test_throws UnauthorizedCall constraint!(ocp, :mixed, (t, x, u, v) -> x[1]-u*v[1], 0) + @test_throws UnauthorizedCall constraint!(ocp, :control, (t, u, v) -> 2u-t*v[2], 1, 1) + @test_throws UnauthorizedCall constraint!(ocp, :state, (t, x, v) -> x-t+v[1], [ 0, 0, 0 ], [ 0, 0, 0 ]) + @test_throws UnauthorizedCall constraint!(ocp, :mixed, (t, x, u, v) -> x[1]-u*v[1], 0, 0) end @@ -514,22 +514,22 @@ end @testset "constraint! 1" begin ocp = Model(); time!(ocp, 0, 1); state!(ocp, 1); control!(ocp, 1) - @test_throws IncorrectArgument constraint!(ocp, :initial, [0, 1], :c0) - constraint!(ocp, :initial, 0, :c0) - constraint!(ocp, :final, 1, :cf) + @test_throws IncorrectArgument constraint!(ocp, :initial, [0, 1], [0, 1], :c0) + constraint!(ocp, :initial, 0, 0, :c0) + constraint!(ocp, :final, 1, 1, :cf) @test constraint(ocp, :c0)(12, ∅) == 12 @test constraint(ocp, :cf)(∅, 12) == 12 ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 1) - constraint!(ocp, :initial, [0, 1], :c0) - constraint!(ocp, :final, [1, 2], :cf) + constraint!(ocp, :initial, [0, 1], [0, 1], :c0) + constraint!(ocp, :final, [1, 2], [1, 2], :cf) @test constraint(ocp, :c0)([12, 13], ∅) == [12, 13] @test constraint(ocp, :cf)(∅, [12, 13]) == [12, 13] # constraint already exists ocp = Model(); time!(ocp, 0, 1); state!(ocp, 1); control!(ocp, 1) - constraint!(ocp, :initial, 0, :c) - @test_throws UnauthorizedCall constraint!(ocp, :final, 0, :c) + constraint!(ocp, :initial, 0, 0, :c) + @test_throws UnauthorizedCall constraint!(ocp, :final, 0, 0, :c) end @@ -539,8 +539,8 @@ end x = 12 x0 = 0 xf = 1 - constraint!(ocp, :initial, Index(1), x0, :c0) - constraint!(ocp, :final, Index(1), xf, :cf) + constraint!(ocp, :initial, Index(1), x0, x0, :c0) + constraint!(ocp, :final, Index(1), xf, xf, :cf) @test constraint(ocp, :c0)(x, ∅) == x @test constraint(ocp, :cf)(∅, x) == x @@ -548,22 +548,22 @@ end x = [12, 13] x0 = [0, 1] xf = [1, 2] - @test_throws IncorrectArgument constraint!(ocp, :initial, Index(2), x0, :c0) - @test_throws IncorrectArgument constraint!(ocp, :final, Index(2), xf, :cf) + @test_throws IncorrectArgument constraint!(ocp, :initial, Index(2), x0, x0, :c0) + @test_throws IncorrectArgument constraint!(ocp, :final, Index(2), xf, xf, :cf) ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 1) x = [12, 13] x0 = [0, 1] xf = [1, 2] - constraint!(ocp, :initial, 1:2, x0, :c0) - constraint!(ocp, :final, 1:2, xf, :cf) + constraint!(ocp, :initial, 1:2, x0, x0, :c0) + constraint!(ocp, :final, 1:2, xf, xf, :cf) @test constraint(ocp, :c0)(x, ∅) == x[1:2] @test constraint(ocp, :cf)(∅, x) == x[1:2] # constraint already exists ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 1) - constraint!(ocp, :initial, Index(1), 0, :c) - @test_throws UnauthorizedCall constraint!(ocp, :final, Index(1), 0, :c) + constraint!(ocp, :initial, Index(1), 0, 0, :c) + @test_throws UnauthorizedCall constraint!(ocp, :final, Index(1), 0, 0, :c) end @@ -634,30 +634,30 @@ end @testset "constraint! 5" begin ocp = Model(); time!(ocp, 0, 1); state!(ocp, 1); control!(ocp, 1) - constraint!(ocp, :boundary, (x0, xf) -> x0+xf, 0, :cb) - constraint!(ocp, :control, u->u, 0, :cu) - constraint!(ocp, :state, x->x, 0, :cs) - constraint!(ocp, :mixed, (x,u)->x+u, 1, :cm) + constraint!(ocp, :boundary, (x0, xf) -> x0+xf, 0, 0, :cb) + constraint!(ocp, :control, u->u, 0, 0, :cu) + constraint!(ocp, :state, x->x, 0, 0, :cs) + constraint!(ocp, :mixed, (x,u)->x+u, 1, 1, :cm) @test constraint(ocp, :cb)(12, 13) == 12+13 @test constraint(ocp, :cu)(12) == 12 @test constraint(ocp, :cs)(12) == 12 @test constraint(ocp, :cm)(12, 13) == 12+13 ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 2) - constraint!(ocp, :boundary, (x0, xf) -> x0[1]+xf[1], 0, :cb) - constraint!(ocp, :control, u->u[1], 0, :cu) - constraint!(ocp, :state, x->x[1], 0, :cs) - constraint!(ocp, :mixed, (x,u)->x[1]+u[1], 1, :cm) + constraint!(ocp, :boundary, (x0, xf) -> x0[1]+xf[1], 0, 0, :cb) + constraint!(ocp, :control, u->u[1], 0, 0, :cu) + constraint!(ocp, :state, x->x[1], 0, 0, :cs) + constraint!(ocp, :mixed, (x,u)->x[1]+u[1], 1, 1, :cm) @test constraint(ocp, :cb)([13, 14], [16, 17]) == 13+16 @test constraint(ocp, :cu)([12, 13]) == 12 @test constraint(ocp, :cs)([12, 13]) == 12 @test constraint(ocp, :cm)([12, 13], [14, 15]) == 12+14 ocp = Model(); time!(ocp, 0, 1); state!(ocp, 3); control!(ocp, 3) - constraint!(ocp, :boundary, (x0, xf) -> [x0[1]+xf[1], x0[2]+xf[2]], [0, 0], :cb) - constraint!(ocp, :control, u->u[1:2], [0, 0], :cu) - constraint!(ocp, :state, x->x[1:2], [0, 0], :cs) - constraint!(ocp, :mixed, (x,u)->[x[1]+u[1], x[2]+u[2]], [0, 0], :cm) + constraint!(ocp, :boundary, (x0, xf) -> [x0[1]+xf[1], x0[2]+xf[2]], [0, 0], [0, 0], :cb) + constraint!(ocp, :control, u->u[1:2], [0, 0], [0, 0], :cu) + constraint!(ocp, :state, x->x[1:2], [0, 0], [0, 0], :cs) + constraint!(ocp, :mixed, (x,u)->[x[1]+u[1], x[2]+u[2]], [0, 0], [0, 0], :cm) @test constraint(ocp, :cb)([13, 14, 15], [17, 18, 19]) == [13+17, 14+18] @test constraint(ocp, :cu)([12, 13, 14]) == [12, 13] @test constraint(ocp, :cs)([12, 13, 14]) == [12, 13] @@ -745,11 +745,11 @@ end constraint!(ocp, :control, (u, v) -> u + v[1], 0, 1, :cu) constraint!(ocp, :state, (x, v) -> x + v[1], 0, 1, :cs) constraint!(ocp, :mixed, (x, u, v) -> x + u + v[1], 1, 1, :cm) - constraint!(ocp, :variable, [ 0, 0, 0, 0 ], :eq1) - constraint!(ocp, :variable, Index(1), 0, :eq2) - constraint!(ocp, :variable, 1:2, [ 0, 0 ], :eq3) - constraint!(ocp, :variable, 1:2:4, [ 0, 0 ], :eq4) - constraint!(ocp, :variable, v -> v.^2, [ 0, 0, 0, 0 ], :eq5) + constraint!(ocp, :variable, [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], :eq1) + constraint!(ocp, :variable, Index(1), 0, 0, :eq2) + constraint!(ocp, :variable, 1:2, [ 0, 0 ], [ 0, 0 ], :eq3) + constraint!(ocp, :variable, 1:2:4, [ 0, 0 ], [ 0, 0 ], :eq4) + constraint!(ocp, :variable, v -> v.^2, [ 0, 0, 0, 0 ], [ 0, 0, 0, 0], :eq5) @test constraint(ocp, :cb)(x0, xf, v) == x0 + xf + v[1] @test constraint(ocp, :cu)(u, v) == u + v[1] @test constraint(ocp, :cs)(x, v) == x + v[1] @@ -798,33 +798,34 @@ end ocp = Model(variable=true); time!(ocp, 0, 1); state!(ocp, 1); control!(ocp, 1); variable!(ocp,3) constraint!(ocp, :state, 0, 1, :c0) - constraint!(ocp, :control, dummy, 1, :c1) + constraint!(ocp, :control, dummy, 1, 1, :c1) constraint!(ocp, :variable, 1:2:3, [-Inf,-Inf], [0,0], :c2) ocp_bis = Model(variable=true); time!(ocp_bis, 0, 1); state!(ocp_bis, 1); control!(ocp_bis, 1); variable!(ocp_bis,3) constraint!(ocp_bis, :state, lb=0, ub=1, label=:c0) - constraint!(ocp_bis, :control, f=dummy, val=1, label=:c1) + constraint!(ocp_bis, :control, f=dummy, ub=1, lb=1, label=:c1) constraint!(ocp_bis, :variable, rg=1:2:3, ub=[0,0], label=:c2) @test ocp.constraints == ocp_bis.constraints ocp_ter = Model(variable=true); time!(ocp_ter, 0, 1); state!(ocp_ter, 3); control!(ocp_ter, 1); variable!(ocp_ter,1) - constraint!(ocp_ter, :variable, 1, :c0) + constraint!(ocp_ter, :variable, 1, 1, :c0) constraint!(ocp_ter, :control, dummy, 1, Inf, :c1) - constraint!(ocp_ter, :state, 1:2:3, [0,0], :c2) + constraint!(ocp_ter, :state, 1:2:3, [0,0], [0,0], :c2) ocp_quad = Model(variable=true); time!(ocp_quad, 0, 1); state!(ocp_quad, 3); control!(ocp_quad, 1); variable!(ocp_quad,1) - constraint!(ocp_quad, :variable, val=1, label=:c0) + constraint!(ocp_quad, :variable, lb=1, ub=1, label=:c0) constraint!(ocp_quad, :control, f=dummy, lb=1, label=:c1) - constraint!(ocp_quad, :state, rg=1:2:3, val=[0,0], label=:c2) + constraint!(ocp_quad, :state, rg=1:2:3, lb=[0,0],ub=[0,0], label=:c2) @test ocp_ter.constraints == ocp_quad.constraints ocp_error = ocp_error = Model(variable=true); time!(ocp_error, 0, 1); state!(ocp_error, 3); control!(ocp_error, 1); variable!(ocp_error,1) @test_throws IncorrectArgument constraint!(ocp_error, :variable) - @test_throws IncorrectArgument constraint!(ocp_error, :control, f=dummy, val=1, lb=1, label=:c1) - @test_throws IncorrectArgument constraint!(ocp_error, :state, rg=1:2:3, f=dummy, val=[0,0], label=:c2) - + @test_throws IncorrectArgument constraint!(ocp_error, :control, f=dummy, label=:c1) + @test_throws IncorrectArgument constraint!(ocp_error, :state, rg=1:2:3, label=:c2) + @test_throws IncorrectArgument constraint!(ocp_error, :state, rg=1:2:3, f=dummy, lb=[0,0], ub=[0,0], label=:c3) + @test_throws IncorrectArgument constraint!(ocp_error, :state, f=dummy, rg=1:2:3, lb=[0,0], ub=[0,0], label=:c4) end @testset "remove_constraint! and constraints_labels" begin @@ -845,8 +846,8 @@ end @testset "nlp_constraints without variable" begin ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 1) - constraint!(ocp, :initial, Index(2), 10, :ci) - constraint!(ocp, :final, Index(1), 1, :cf) + constraint!(ocp, :initial, Index(2), 10, 10, :ci) + constraint!(ocp, :final, Index(1), 1, 1, :cf) constraint!(ocp, :control, 0, 1, :cu) constraint!(ocp, :state, [0, 1], [1, 2], :cs) constraint!(ocp, :boundary, (x0, xf) -> x0[2]+xf[2], 0, 1, :cb) @@ -904,8 +905,8 @@ end variable!(ocp, 4) state!(ocp, 2) control!(ocp, 1) - constraint!(ocp, :initial, Index(2), 10, :ci) - constraint!(ocp, :final, Index(1), 1, :cf) + constraint!(ocp, :initial, Index(2), 10, 10, :ci) + constraint!(ocp, :final, Index(1), 1, 1, :cf) constraint!(ocp, :control, 0, 1, :cu) constraint!(ocp, :state, [0, 1], [1, 2], :cs) constraint!(ocp, :boundary, (x0, xf, v) -> x0[2]+xf[2]+v[1], 0, 1, :cb) diff --git a/test/test_print.jl b/test/test_print.jl index da7f9adb..82cb22b4 100644 --- a/test/test_print.jl +++ b/test/test_print.jl @@ -8,8 +8,8 @@ function test_print() state!(ocp, 2, "state", ["r", "v"]) # dimension of the state with the names of the components control!(ocp, 1) # dimension of the control time!(ocp, 0, 1, "s") # initial and final time, with the name of the variable time - constraint!(ocp, :initial, [-1, 0]) - constraint!(ocp, :final , [ 0, 0]) + constraint!(ocp, :initial, [-1, 0], [-1, 0]) + constraint!(ocp, :final , [ 0, 0], [0, 0]) A = [ 0 1 0 0 ] B = [ 0 @@ -28,8 +28,8 @@ function test_print() state!(ocp, 1, "y") # dimension of the state with the names of the components control!(ocp, 1, "v") # dimension of the control time!(ocp, 0, 1, "s") # initial and final time, with the name of the variable time - constraint!(ocp, :initial, -1) - constraint!(ocp, :final , 0) + constraint!(ocp, :initial, -1, -1) + constraint!(ocp, :final , 0, 0) dynamics!(ocp, (t, x, u) -> x+u) constraint!(ocp, :state, (t, x) -> x, 0, 1) constraint!(ocp, :control, (t, u) -> u, -1, 1) @@ -45,8 +45,8 @@ function test_print() state!(ocp, 1, "y") # dimension of the state with the names of the components control!(ocp, 2) # dimension of the control time!(ocp, 0, Index(1), "s") # initial and final time, with the name of the variable time - constraint!(ocp, :initial, -1) - constraint!(ocp, :final , 0) + constraint!(ocp, :initial, -1, -1) + constraint!(ocp, :final , 0, 0) dynamics!(ocp, (t, x, u) -> x+u) objective!(ocp, :mayer, (t0, x0, tf, xf) -> tf) @test display(ocp) isa Nothing From 8d356e8db27c892510a0cbe8ceee8137fdf2ff8b Mon Sep 17 00:00:00 2001 From: BaptisteCbl Date: Thu, 2 Nov 2023 15:53:42 +0100 Subject: [PATCH 2/6] new constraints! working --- src/model.jl | 158 +++++++++++++++++++++++++-------------------------- 1 file changed, 76 insertions(+), 82 deletions(-) diff --git a/src/model.jl b/src/model.jl index 1580ed96..4072e4a2 100644 --- a/src/model.jl +++ b/src/model.jl @@ -446,53 +446,11 @@ julia> constraint!(ocp, :initial, 1:2:5, [ 0, 0, 0 ], [ 1, 2, 1 ]) julia> constraint!(ocp, :variable, 1:2, [ 0, 0 ], [ 1, 2 ]) ``` """ -function constraint!(ocp::OptimalControlModel{<: TimeDependence, V}, type::Symbol, rg::RangeConstraint, lb::ctVector, ub::ctVector, - label::Symbol=__constraint_label()) where {V <: VariableDependence} +function constraint!(ocp::OptimalControlModel{<: TimeDependence, V}, type::Symbol, rg::RangeConstraint, lb::Union{ctVector,Nothing}, ub::Union{ctVector,Nothing}, + label::Symbol=__constraint_label()) where {V <: VariableDependence} - # we check if the dimensions and times have been set - __check_all_set(ocp) - type == :variable && is_variable_independent(ocp) && throw(UnauthorizedCall("the ocp is variable independent" * - ", you cannot use constraint! function with type=:variable.")) - - # check if the constraint named label already exists - if label ∈ constraints_labels(ocp) - throw(UnauthorizedCall("the constraint named " * String(label) * " already exists.")) - end - - # check that rg, lb and ub are consistent - txt = "the range `rg`, the lower bound `lb` and the upper bound `ub` must have the same dimension" - (length(rg) != length(lb)) && throw(IncorrectArgument(txt)) - (length(rg) != length(ub)) && throw(IncorrectArgument(txt)) + constraint!(ocp, type, rg=rg, f=nothing, lb=lb, ub=ub, label=label) - # dimensions - n = ocp.state_dimension - m = ocp.control_dimension - q = ocp.variable_dimension - - # check if the range is valid - if type == :initial - !all(1 .≤ rg .≤ n) && throw(IncorrectArgument("the range of the initial state constraint must be contained in 1:$n")) - elseif type == :final - !all(1 .≤ rg .≤ n) && throw(IncorrectArgument("the range of the final state constraint must be contained in 1:$n")) - elseif type == :control - !all(1 .≤ rg .≤ m) && throw(IncorrectArgument("the range of the control constraint must be contained in 1:$m")) - elseif type == :state - !all(1 .≤ rg .≤ n) && throw(IncorrectArgument("the range of the state constraint must be contained in 1:$n")) - elseif type == :variable - !all(1 .≤ rg .≤ q) && throw(IncorrectArgument("the range of the variable constraint must be contained in 1:$q")) - end - - # set the constraint - fun_rg = @match type begin - :initial => V == Fixed ? BoundaryConstraint((x0, xf ) -> x0[rg], V) : - BoundaryConstraint((x0, xf, v) -> x0[rg], V) - :final => V == Fixed ? BoundaryConstraint((x0, xf ) -> xf[rg], V) : - BoundaryConstraint((x0, xf, v) -> xf[rg], V) - :control || :state || :variable => rg - _ => throw(IncorrectArgument("the following type of constraint is not valid: " * String(type) * - ". Please choose in [ :initial, :final, :control, :state, :variable ] or check the arguments of the constraint! method.")) - end - ocp.constraints[label] = (type, fun_rg, lb, ub) nothing # to force to return nothing end @@ -518,9 +476,8 @@ julia> constraint!(ocp, :state, [ 0, 0, 0 ], [ 1, 2, 1 ]) julia> constraint!(ocp, :variable, 0, 1) # the variable here is of dimension 1 ``` """ -function constraint!(ocp::OptimalControlModel, type::Symbol, lb::ctVector, ub::ctVector, - label::Symbol=__constraint_label()) # we use the constraint! defined before - +function constraint!(ocp::OptimalControlModel, type::Symbol, lb::Union{ctVector,Nothing}, ub::Union{ctVector,Nothing}, + label::Symbol=__constraint_label()) # we check if the dimensions and times have been set __check_all_set(ocp) type == :variable && is_variable_independent(ocp) && throw(UnauthorizedCall("the ocp is variable independent" * @@ -554,7 +511,7 @@ function constraint!(ocp::OptimalControlModel, type::Symbol, lb::ctVector, ub::c (length(rg) != length(ub)) && throw(IncorrectArgument(txt)) # - constraint!(ocp, type, rg, lb, ub, label) + constraint!(ocp, type, rg=rg, f=nothing, lb=lb, ub=ub, label=label) end @@ -600,33 +557,9 @@ julia> constraint!(ocp, :mixed, (t, x, u, v) -> x[1]*v[2]-u, 0, 1) ``` """ function constraint!(ocp::OptimalControlModel{T, V}, type::Symbol, f::Function, - lb::ctVector, ub::ctVector, label::Symbol=__constraint_label()) where {T, V} - - # we check if the dimensions and times have been set - __check_all_set(ocp) - type == :variable && is_variable_independent(ocp) && throw(UnauthorizedCall("the ocp is variable independent" * - ", you cannot use constraint! function with type=:variable.")) + lb::Union{ctVector,Nothing}, ub::Union{ctVector,Nothing}, label::Symbol=__constraint_label()) where {T, V} - # check if the constraint named label already exists - if label ∈ constraints_labels(ocp) - throw(UnauthorizedCall("the constraint named " * String(label) * " already exists.")) - end - - # set the constraint - if type == :boundary - ocp.constraints[label] = (type, BoundaryConstraint(f, V), lb, ub) - elseif type == :control - ocp.constraints[label] = (type, ControlConstraint(f, T, V), lb, ub) - elseif type == :state - ocp.constraints[label] = (type, StateConstraint(f, T, V), lb, ub) - elseif type == :mixed - ocp.constraints[label] = (type, MixedConstraint(f, T, V), lb, ub) - elseif type == :variable - ocp.constraints[label] = (type, VariableConstraint(f), lb, ub) - else - throw(IncorrectArgument("the following type of constraint is not valid: " * String(type) * - ". Please choose in [ :boundary, :control, :state, :mixed ] or check the arguments of the constraint! method.")) - end + constraint!(ocp, type, rg=nothing, f=f, lb=lb, ub=ub, label=label) nothing # to force to return nothing @@ -654,18 +587,79 @@ julia> constraint!(ocp, :initial, rg=1:2:5, lb=[ 0, 0, 0 ], ub=[ 1, 2, 1 ]) julia> constraint!(ocp, :variable, rg=1:2, lb=[ 0, 0 ], ub=[ 1, 2 ]) ``` """ -function constraint!(ocp::OptimalControlModel{<: TimeDependence, <: VariableDependence}, type::Symbol; - rg::Union{OrdinalRange{<:Integer},Integer,Nothing}=nothing, f::Union{Function,Nothing}=nothing, lb::Union{ctVector,Nothing}=nothing, ub::Union{ctVector,Nothing}=nothing, - label::Symbol=__constraint_label()) +function constraint!(ocp::OptimalControlModel{T, V}, type::Symbol; + rg::Union{OrdinalRange{<:Integer},Integer,Index,Nothing}=nothing, f::Union{Function,Nothing}=nothing, lb::W=nothing, ub::X=nothing, + label::Symbol=__constraint_label()) where {T <: TimeDependence, V <: VariableDependence, W <: Union{ctVector,Nothing}, X <: Union{ctVector,Nothing}} + + __check_all_set(ocp) + type == :variable && is_variable_independent(ocp) && throw(UnauthorizedCall("the ocp is variable independent" * ", you cannot use constraint! function with type=:variable.")) + + # dimensions + n = ocp.state_dimension + m = ocp.control_dimension + q = ocp.variable_dimension + + if label ∈ constraints_labels(ocp) + throw(UnauthorizedCall("the constraint named " * String(label) * " already exists.")) + end (lb ≢ nothing && ub === nothing) && (ub = Inf*(size(lb,1) == 1 ? 1 : ones(eltype(ub), size(ub,1)))) (lb === nothing && ub ≢ nothing) && (lb = -Inf*(size(ub,1) == 1 ? 1 : ones(eltype(ub), size(ub,1)))) (typeof(rg) <: Int) && (rg = Index(rg)) - + @match (rg,f,lb,ub) begin - (::Nothing,::Nothing,::ctVector,::ctVector) => return constraint!(ocp, type, lb, ub, label) # - (::Nothing,::Function,::ctVector,::ctVector) => return constraint!(ocp, type, f, lb, ub, label) # - (::RangeConstraint,::Nothing,::ctVector,::ctVector) => return constraint!(ocp, type, rg, lb, ub, label) # + (::Nothing,::Nothing,::ctVector,::ctVector) => begin + constraint!(ocp,type,lb,ub,label) + end + (::Nothing,::Function,::ctVector,::ctVector) => begin + # set the constraint + if type == :boundary + ocp.constraints[label] = (type, BoundaryConstraint(f, V), lb, ub) + elseif type == :control + ocp.constraints[label] = (type, ControlConstraint(f, T, V), lb, ub) + elseif type == :state + ocp.constraints[label] = (type, StateConstraint(f, T, V), lb, ub) + elseif type == :mixed + ocp.constraints[label] = (type, MixedConstraint(f, T, V), lb, ub) + elseif type == :variable + ocp.constraints[label] = (type, VariableConstraint(f), lb, ub) + else + throw(IncorrectArgument("the following type of constraint is not valid: " * String(type) * + ". Please choose in [ :boundary, :control, :state, :mixed ] or check the arguments of the constraint! method.")) + end + end # + (::RangeConstraint,::Nothing,::ctVector,::ctVector) => begin + + txt = "the range `rg`, the lower bound `lb` and the upper bound `ub` must have the same dimension" + (length(rg) != length(lb)) && throw(IncorrectArgument(txt)) + (length(rg) != length(ub)) && throw(IncorrectArgument(txt)) + + # check if the range is valid + if type == :initial + !all(1 .≤ rg .≤ n) && throw(IncorrectArgument("the range of the initial state constraint must be contained in 1:$n")) + elseif type == :final + !all(1 .≤ rg .≤ n) && throw(IncorrectArgument("the range of the final state constraint must be contained in 1:$n")) + elseif type == :control + !all(1 .≤ rg .≤ m) && throw(IncorrectArgument("the range of the control constraint must be contained in 1:$m")) + elseif type == :state + !all(1 .≤ rg .≤ n) && throw(IncorrectArgument("the range of the state constraint must be contained in 1:$n")) + elseif type == :variable + !all(1 .≤ rg .≤ q) && throw(IncorrectArgument("the range of the variable constraint must be contained in 1:$q")) + end + + # set the constraint + fun_rg = @match type begin + :initial => V == Fixed ? BoundaryConstraint((x0, xf ) -> x0[rg], V) : + BoundaryConstraint((x0, xf, v) -> x0[rg], V) + :final => V == Fixed ? BoundaryConstraint((x0, xf ) -> xf[rg], V) : + BoundaryConstraint((x0, xf, v) -> xf[rg], V) + :control || :state || :variable => rg + _ => throw(IncorrectArgument("the following type of constraint is not valid: " * String(type) * + ". Please choose in [ :initial, :final, :control, :state, :variable ] or check the arguments of the constraint! method.")) + end + ocp.constraints[label] = (type, fun_rg, lb, ub) + nothing # to force to return nothing + end # _ => throw(IncorrectArgument("Provided arguments are inconsistent")) end From 27507a6ab9f958325edda8498bb8f0bc6caf88a3 Mon Sep 17 00:00:00 2001 From: BaptisteCbl Date: Mon, 6 Nov 2023 13:03:09 +0100 Subject: [PATCH 3/6] constraint with unnamed arguments now only call the one with named args --- src/model.jl | 58 ++++++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/src/model.jl b/src/model.jl index 4072e4a2..a10ccc02 100644 --- a/src/model.jl +++ b/src/model.jl @@ -478,40 +478,10 @@ julia> constraint!(ocp, :variable, 0, 1) # the variable here is of dimension 1 """ function constraint!(ocp::OptimalControlModel, type::Symbol, lb::Union{ctVector,Nothing}, ub::Union{ctVector,Nothing}, label::Symbol=__constraint_label()) - # we check if the dimensions and times have been set - __check_all_set(ocp) - type == :variable && is_variable_independent(ocp) && throw(UnauthorizedCall("the ocp is variable independent" * - ", you cannot use constraint! function with type=:variable.")) - - # - rg = nothing - - # dimensions - n = ocp.state_dimension - m = ocp.control_dimension - q = ocp.variable_dimension - # - if type ∈ [:initial, :final, :state] - rg = n == 1 ? Index(1) : 1:n - txt = "the lower bound `lb` and the upper bound `ub` must be of dimension $n" - elseif type == :control - rg = m == 1 ? Index(1) : 1:m - txt = "the lower bound `lb` and the upper bound `ub` must be of dimension $m" - elseif type == :variable - rg = q == 1 ? Index(1) : 1:q - txt = "the lower bound `lb` and the upper bound `ub` must be of dimension $q" - else - throw(IncorrectArgument("the following type of constraint is not valid: " * String(type) * - ". Please choose in [ :initial, :final, :control, :state, :variable ] or check the arguments of the constraint! method.")) - end - - # - (length(rg) != length(lb)) && throw(IncorrectArgument(txt)) - (length(rg) != length(ub)) && throw(IncorrectArgument(txt)) + constraint!(ocp, type, rg=nothing, f=nothing, lb=lb, ub=ub, label=label) - # - constraint!(ocp, type, rg=rg, f=nothing, lb=lb, ub=ub, label=label) + nothing # to force to return nothing end @@ -609,7 +579,29 @@ function constraint!(ocp::OptimalControlModel{T, V}, type::Symbol; @match (rg,f,lb,ub) begin (::Nothing,::Nothing,::ctVector,::ctVector) => begin - constraint!(ocp,type,lb,ub,label) + # + rg = nothing + + # + if type ∈ [:initial, :final, :state] + rg = n == 1 ? Index(1) : 1:n + txt = "the lower bound `lb` and the upper bound `ub` must be of dimension $n" + elseif type == :control + rg = m == 1 ? Index(1) : 1:m + txt = "the lower bound `lb` and the upper bound `ub` must be of dimension $m" + elseif type == :variable + rg = q == 1 ? Index(1) : 1:q + txt = "the lower bound `lb` and the upper bound `ub` must be of dimension $q" + else + throw(IncorrectArgument("the following type of constraint is not valid: " * String(type) * + ". Please choose in [ :initial, :final, :control, :state, :variable ] or check the arguments of the constraint! method.")) + end + + # + (length(rg) != length(lb)) && throw(IncorrectArgument(txt)) + (length(rg) != length(ub)) && throw(IncorrectArgument(txt)) + + constraint!(ocp, type, rg=rg, lb=lb, ub=ub, label=label) end (::Nothing,::Function,::ctVector,::ctVector) => begin # set the constraint From 53798fd1cff081f50150d74be94a9dd352f4eac4 Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Sun, 9 Jun 2024 20:41:01 +0200 Subject: [PATCH 4/6] foo --- src/model.jl | 71 ++++++++++++++++++++++------------------------ src/onepass.jl | 20 ++++++------- test/test_model.jl | 23 ++++++++------- 3 files changed, 56 insertions(+), 58 deletions(-) diff --git a/src/model.jl b/src/model.jl index b769d59f..9d4280b5 100644 --- a/src/model.jl +++ b/src/model.jl @@ -463,19 +463,22 @@ Add an `:initial`, `:final`, `:control`, `:state` or `:variable` box constraint # Examples ```jldoctest +julia> constraint!(ocp, :initial, 1:2:5, [ 0, 0, 0 ], [ 1, 2, 1 ]) julia> constraint!(ocp, :initial, 2:3, [ 0, 0 ], [ 1, 2 ]) julia> constraint!(ocp, :final, Index(1), 0, 2) julia> constraint!(ocp, :control, Index(1), 0, 2) julia> constraint!(ocp, :state, 2:3, [ 0, 0 ], [ 1, 2 ]) -julia> constraint!(ocp, :initial, 1:2:5, [ 0, 0, 0 ], [ 1, 2, 1 ]) julia> constraint!(ocp, :variable, 1:2, [ 0, 0 ], [ 1, 2 ]) ``` """ -function constraint!(ocp::OptimalControlModel{<: TimeDependence, V}, type::Symbol, rg::RangeConstraint, lb::Union{ctVector,Nothing}, ub::Union{ctVector,Nothing}, - label::Symbol=__constraint_label()) where {V <: VariableDependence} - - constraint!(ocp, type, rg=rg, f=nothing, lb=lb, ub=ub, label=label) +function constraint!(ocp::OptimalControlModel{<: TimeDependence, V}, + type::Symbol, + rg::RangeConstraint, + lb::Union{ctVector,Nothing}, + ub::Union{ctVector,Nothing}, + label::Symbol=__constraint_label()) where {V <: VariableDependence} + __constraint!(ocp, type, rg=rg, f=nothing, lb=lb, ub=ub, label=label) nothing # to force to return nothing end @@ -494,17 +497,20 @@ Add an `:initial`, `:final`, `:control`, `:state` or `:variable` box constraint # Examples ```jldoctest -julia> constraint!(ocp, :initial, 1:2:5, [ 0, 0, 0 ]) -julia> constraint!(ocp, :initial, 2:3, [ 0, 0 ]) -julia> constraint!(ocp, :final, Index(2), 0) -julia> constraint!(ocp, :variable, 2:3, [ 0, 3 ]) +julia> constraint!(ocp, :initial, [ 0, 0, 0 ], [ 1, 2, 1 ]) # the state is of dim 3 +julia> constraint!(ocp, :final, -1, 1) # the state is of dim 1 +julia> constraint!(ocp, :control, 0, 2) +julia> constraint!(ocp, :state, [ 0, 0 ], [ 1, 2 ]) +julia> constraint!(ocp, :variable, [ 0, 0 ], [ 1, 2 ]) ``` """ -function constraint!(ocp::OptimalControlModel, type::Symbol, lb::Union{ctVector,Nothing}, ub::Union{ctVector,Nothing}, - label::Symbol=__constraint_label()) - - constraint!(ocp, type, rg=nothing, f=nothing, lb=lb, ub=ub, label=label) +function constraint!(ocp::OptimalControlModel, + type::Symbol, + lb::Union{ctVector,Nothing}, + ub::Union{ctVector,Nothing}, + label::Symbol=__constraint_label()) + __constraint!(ocp, type, rg=nothing, f=nothing, lb=lb, ub=ub, label=label) nothing # to force to return nothing end @@ -550,11 +556,14 @@ julia> constraint!(ocp, :state, (t, x, v) -> x-t*v[1], [ 0, 0, 0 ], [ 1, 2, 1 ]) julia> constraint!(ocp, :mixed, (t, x, u, v) -> x[1]*v[2]-u, 0, 1) ``` """ -function constraint!(ocp::OptimalControlModel{T, V}, type::Symbol, f::Function, - lb::Union{ctVector,Nothing}, ub::Union{ctVector,Nothing}, label::Symbol=__constraint_label()) where {T, V} - - constraint!(ocp, type, rg=nothing, f=f, lb=lb, ub=ub, label=label) +function constraint!(ocp::OptimalControlModel{T, V}, + type::Symbol, + f::Function, + lb::Union{ctVector,Nothing}, + ub::Union{ctVector,Nothing}, + label::Symbol=__constraint_label()) where {T, V} + __constraint!(ocp, type, rg=nothing, f=f, lb=lb, ub=ub, label=label) nothing # to force to return nothing end @@ -562,27 +571,15 @@ end """ $(TYPEDSIGNATURES) -Add an `:initial`, `:final`, `:control`, `:state` or `:variable` box constraint on a range. - -!!! note - - - The range of the constraint must be contained in 1:n if the constraint is on the state, or 1:m if the constraint is on the control, or 1:q if the constraint is on the variable. - - The state, control and variable dimensions must be set before. Use state!, control! and variable!. - - The times must be set before. Use time!. - -# Examples +General setter for constraints. -```jldoctest -julia> constraint!(ocp, :initial, rg=2:3, lb=[ 0, 0 ], ub=[ 1, 2 ]) -julia> constraint!(ocp, :final, rg=1, lb=0, ub=2) -julia> constraint!(ocp, :control, rg=1, lb=0, ub=2) -julia> constraint!(ocp, :state, rg=2:3, lb=[ 0, 0 ], ub=[ 1, 2 ]) -julia> constraint!(ocp, :initial, rg=1:2:5, lb=[ 0, 0, 0 ], ub=[ 1, 2, 1 ]) -julia> constraint!(ocp, :variable, rg=1:2, lb=[ 0, 0 ], ub=[ 1, 2 ]) -``` """ -function constraint!(ocp::OptimalControlModel{T, V}, type::Symbol; - rg::Union{OrdinalRange{<:Integer},Integer,Index,Nothing}=nothing, f::Union{Function,Nothing}=nothing, lb::W=nothing, ub::X=nothing, +function __constraint!(ocp::OptimalControlModel{T, V}, + type::Symbol; + rg::Union{OrdinalRange{<:Integer},Integer,Index,Nothing}=nothing, + f::Union{Function,Nothing}=nothing, + lb::W=nothing, + ub::X=nothing, label::Symbol=__constraint_label()) where {T <: TimeDependence, V <: VariableDependence, W <: Union{ctVector,Nothing}, X <: Union{ctVector,Nothing}} __check_all_set(ocp) @@ -625,7 +622,7 @@ function constraint!(ocp::OptimalControlModel{T, V}, type::Symbol; (length(rg) != length(lb)) && throw(IncorrectArgument(txt)) (length(rg) != length(ub)) && throw(IncorrectArgument(txt)) - constraint!(ocp, type, rg=rg, lb=lb, ub=ub, label=label) + __constraint!(ocp, type, rg=rg, lb=lb, ub=ub, label=label) end (::Nothing,::Function,::ctVector,::ctVector) => begin # set the constraint diff --git a/src/onepass.jl b/src/onepass.jl index e07f98ba..e87fc309 100644 --- a/src/onepass.jl +++ b/src/onepass.jl @@ -266,8 +266,8 @@ p_constraint!(p, ocp, e1, e2, e3, label=gensym(); log=false) = begin label isa Symbol || return __throw("forbidden label: $label", p.lnum, p.line) llabel = QuoteNode(label) code = @match c_type begin - (:initial, rg) => :( constraint!($ocp, :initial; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) - (:final , rg) => :( constraint!($ocp, :final ; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) + (:initial, rg) => :( CTBase.__constraint!($ocp, :initial; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) + (:final , rg) => :( CTBase.__constraint!($ocp, :final ; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) :boundary => begin gs = gensym() x0 = gensym() @@ -279,9 +279,9 @@ p_constraint!(p, ocp, e1, e2, e3, label=gensym(); log=false) = begin function $gs($(args...)) $ee2 end - constraint!($ocp, :boundary; f=$gs, lb=$e1, ub=$e3, label=$llabel) + CTBase.__constraint!($ocp, :boundary; f=$gs, lb=$e1, ub=$e3, label=$llabel) end end - (:control_range, rg) => :( constraint!($ocp, :control; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) + (:control_range, rg) => :( CTBase.__constraint!($ocp, :control; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) :control_fun => begin gs = gensym() ut = gensym() @@ -292,9 +292,9 @@ p_constraint!(p, ocp, e1, e2, e3, label=gensym(); log=false) = begin function $gs($(args...)) $ee2 end - constraint!($ocp, :control; f=$gs, lb=$e1, ub=$e3, label=$llabel) + CTBase.__constraint!($ocp, :control; f=$gs, lb=$e1, ub=$e3, label=$llabel) end end - (:state_range, rg) => :( constraint!($ocp, :state; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) + (:state_range, rg) => :( CTBase.__constraint!($ocp, :state; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) :state_fun => begin gs = gensym() xt = gensym() @@ -305,9 +305,9 @@ p_constraint!(p, ocp, e1, e2, e3, label=gensym(); log=false) = begin function $gs($(args...)) $ee2 end - constraint!($ocp, :state; f=$gs, lb=$e1, ub=$e3, label=$llabel) + CTBase.__constraint!($ocp, :state; f=$gs, lb=$e1, ub=$e3, label=$llabel) end end - (:variable_range, rg) => :( constraint!($ocp, :variable; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) + (:variable_range, rg) => :( CTBase.__constraint!($ocp, :variable; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) :variable_fun => begin gs = gensym() args = [ p.v ] @@ -315,7 +315,7 @@ p_constraint!(p, ocp, e1, e2, e3, label=gensym(); log=false) = begin function $gs($(args...)) $e2 end - constraint!($ocp, :variable; f=$gs, lb=$e1, ub=$e3, label=$llabel) + CTBase.__constraint!($ocp, :variable; f=$gs, lb=$e1, ub=$e3, label=$llabel) end end :mixed => begin gs = gensym() @@ -328,7 +328,7 @@ p_constraint!(p, ocp, e1, e2, e3, label=gensym(); log=false) = begin function $gs($(args...)) $ee2 end - constraint!($ocp, :mixed; f=$gs, lb=$e1, ub=$e3, label=$llabel) + CTBase.__constraint!($ocp, :mixed; f=$gs, lb=$e1, ub=$e3, label=$llabel) end end _ => return __throw("bad constraint declaration", p.lnum, p.line) end diff --git a/test/test_model.jl b/test/test_model.jl index 4b121471..713d74b4 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -816,9 +816,9 @@ end constraint!(ocp, :variable, 1:2:3, [-Inf,-Inf], [0,0], :c2) ocp_bis = Model(variable=true); time!(ocp_bis, 0, 1); state!(ocp_bis, 1); control!(ocp_bis, 1); variable!(ocp_bis,3) - constraint!(ocp_bis, :state, lb=0, ub=1, label=:c0) - constraint!(ocp_bis, :control, f=dummy, ub=1, lb=1, label=:c1) - constraint!(ocp_bis, :variable, rg=1:2:3, ub=[0,0], label=:c2) + CTBase.__constraint!(ocp_bis, :state, lb=0, ub=1, label=:c0) + CTBase.__constraint!(ocp_bis, :control, f=dummy, ub=1, lb=1, label=:c1) + CTBase.__constraint!(ocp_bis, :variable, rg=1:2:3, ub=[0,0], label=:c2) @test ocp.constraints == ocp_bis.constraints @@ -828,18 +828,19 @@ end constraint!(ocp_ter, :state, 1:2:3, [0,0], [0,0], :c2) ocp_quad = Model(variable=true); time!(ocp_quad, 0, 1); state!(ocp_quad, 3); control!(ocp_quad, 1); variable!(ocp_quad,1) - constraint!(ocp_quad, :variable, lb=1, ub=1, label=:c0) - constraint!(ocp_quad, :control, f=dummy, lb=1, label=:c1) - constraint!(ocp_quad, :state, rg=1:2:3, lb=[0,0],ub=[0,0], label=:c2) + CTBase.__constraint!(ocp_quad, :variable, lb=1, ub=1, label=:c0) + CTBase.__constraint!(ocp_quad, :control, f=dummy, lb=1, label=:c1) + CTBase.__constraint!(ocp_quad, :state, rg=1:2:3, lb=[0,0],ub=[0,0], label=:c2) @test ocp_ter.constraints == ocp_quad.constraints ocp_error = ocp_error = Model(variable=true); time!(ocp_error, 0, 1); state!(ocp_error, 3); control!(ocp_error, 1); variable!(ocp_error,1) - @test_throws IncorrectArgument constraint!(ocp_error, :variable) - @test_throws IncorrectArgument constraint!(ocp_error, :control, f=dummy, label=:c1) - @test_throws IncorrectArgument constraint!(ocp_error, :state, rg=1:2:3, label=:c2) - @test_throws IncorrectArgument constraint!(ocp_error, :state, rg=1:2:3, f=dummy, lb=[0,0], ub=[0,0], label=:c3) - @test_throws IncorrectArgument constraint!(ocp_error, :state, f=dummy, rg=1:2:3, lb=[0,0], ub=[0,0], label=:c4) + @test_throws IncorrectArgument CTBase.__constraint!(ocp_error, :variable) + @test_throws IncorrectArgument CTBase.__constraint!(ocp_error, :control, f=dummy, label=:c1) + @test_throws IncorrectArgument CTBase.__constraint!(ocp_error, :state, rg=1:2:3, label=:c2) + @test_throws IncorrectArgument CTBase.__constraint!(ocp_error, :state, rg=1:2:3, f=dummy, lb=[0,0], ub=[0,0], label=:c3) + @test_throws IncorrectArgument CTBase.__constraint!(ocp_error, :state, f=dummy, rg=1:2:3, lb=[0,0], ub=[0,0], label=:c4) + end @testset "remove_constraint! and constraints_labels" begin From a7e20237fa1a74990879ba067ca8b153f95138fb Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Caillau Date: Tue, 11 Jun 2024 19:06:45 +0200 Subject: [PATCH 5/6] quickfix --- src/CTBase.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CTBase.jl b/src/CTBase.jl index 605c4d9d..7f3e8b4b 100644 --- a/src/CTBase.jl +++ b/src/CTBase.jl @@ -246,7 +246,7 @@ export BoundaryConstraint, StateConstraint, ControlConstraint, MixedConstraint, # model export OptimalControlModel export Model -export __OCPModel # redirection to Model to avoir confusion with other Model functions from other packages. Due to @def macro +export __OCPModel # redirection to Model to avoid confusion with other Model functions from other packages. Due to @def macro export variable!, time!, constraint!, dynamics!, objective!, state!, control!, remove_constraint!, constraint export is_time_independent, is_time_dependent, is_min, is_max, is_variable_dependent, is_variable_independent export nlp_constraints, constraints_labels From 562291489cf83a311d6c1a643f9841f30620de00 Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Tue, 11 Jun 2024 19:41:37 +0200 Subject: [PATCH 6/6] only one constraint! method --- docs/src/api-print.md | 4 +- src/model.jl | 281 +++++++++++++++++++---------------- src/onepass.jl | 20 +-- test/runtests.jl | 50 +++++++ test/test_model.jl | 338 +++++++++++++++++++++--------------------- test/test_print.jl | 32 ++-- 6 files changed, 406 insertions(+), 319 deletions(-) diff --git a/docs/src/api-print.md b/docs/src/api-print.md index c7724cf3..970a5f72 100644 --- a/docs/src/api-print.md +++ b/docs/src/api-print.md @@ -44,8 +44,8 @@ state!(ocp, 2, "x", ["r", "v"]) # dimension of the state with the names of the c control!(ocp, 1) # dimension of the control time!(ocp, [0, 1], "s") # initial and final time, with the name of the variable time -constraint!(ocp, :initial, [-1, 0]) -constraint!(ocp, :final , [ 0, 0]) +constraint!(ocp, :initial, lb=[-1, 0], ub=[-1, 0]) +constraint!(ocp, :final , lb=[ 0, 0], ub=[ 0, 0]) A = [ 0 1 0 0 ] B = [ 0 diff --git a/src/model.jl b/src/model.jl index 9d4280b5..2a7f5862 100644 --- a/src/model.jl +++ b/src/model.jl @@ -21,10 +21,15 @@ julia> ocp = Model(autonomous=false, variable=true) - If the time dependence of the model is defined as nonautonomous, then, the dynamics function, the lagrange cost and the path constraints must be defined as functions of time and state, and possibly control. If the model is defined as autonomous, then, the dynamics function, the lagrange cost and the path constraints must be defined as functions of state, and possibly control. """ -function Model(; autonomous::Bool=true, variable::Bool=false) +function Model(; + autonomous::Bool=true, + variable::Bool=false) + time_dependence = autonomous ? Autonomous : NonAutonomous variable_dependence = variable ? NonFixed : Fixed + return OptimalControlModel{time_dependence, variable_dependence}() + end """ @@ -116,28 +121,47 @@ julia> variable!(ocp, 1, "v") julia> variable!(ocp, 2, "v", [ "v₁", "v₂" ]) ``` """ -function variable!(ocp::OptimalControlModel, q::Dimension, name::String=__variable_name(), +function variable!( + ocp::OptimalControlModel, + q::Dimension, + name::String=__variable_name(), components_names::Vector{String}=__variable_components_names(q, name)) + # checkings is_variable_independent(ocp) && throw(UnauthorizedCall("the ocp is variable independent, you cannot use variable! function.")) __is_variable_set(ocp) && throw(UnauthorizedCall("the variable has already been set. Use variable! once.")) (q > 1) && (size(components_names, 1) ≠ q) && throw(IncorrectArgument("the number of variable names must be equal to the variable dimension")) - # + ocp.variable_dimension = q ocp.variable_components_names = components_names ocp.variable_name = name nothing # to force to return nothing + end -function variable!(ocp::OptimalControlModel, q::Dimension, name::Symbol, components_names::Vector{Symbol}) +function variable!( + ocp::OptimalControlModel, + q::Dimension, + name::Symbol, + components_names::Vector{Symbol}) + variable!(ocp, q, string(name), string.(components_names)) end -function variable!(ocp::OptimalControlModel, q::Dimension, name::Symbol, components_names::Vector{String}) +function variable!( + ocp::OptimalControlModel, + q::Dimension, + name::Symbol, + components_names::Vector{String}) + variable!(ocp, q, string(name), components_names) end -function variable!(ocp::OptimalControlModel, q::Dimension, name::Symbol) +function variable!( + ocp::OptimalControlModel, + q::Dimension, + name::Symbol) + variable!(ocp, q, string(name)) end @@ -184,27 +208,46 @@ julia> ocp.state_components_names ["y₁", "y₂"] ``` """ -function state!(ocp::OptimalControlModel, n::Dimension, name::String=__state_name(), +function state!( + ocp::OptimalControlModel, + n::Dimension, + name::String=__state_name(), components_names::Vector{String}=__state_components_names(n, name)) + # checkings __is_state_set(ocp) && throw(UnauthorizedCall("the state has already been set. Use state! once.")) (n > 1) && (size(components_names, 1) ≠ n) && throw(IncorrectArgument("the number of state names must be equal to the state dimension")) - # + ocp.state_dimension = n ocp.state_components_names = components_names ocp.state_name = name nothing # to force to return nothing + end -function state!(ocp::OptimalControlModel, n::Dimension, name::Symbol, components_names::Vector{Symbol}) +function state!( + ocp::OptimalControlModel, + n::Dimension, + name::Symbol, + components_names::Vector{Symbol}) + state!(ocp, n, string(name), string.(components_names)) end -function state!(ocp::OptimalControlModel, n::Dimension, name::Symbol, components_names::Vector{String}) +function state!( + ocp::OptimalControlModel, + n::Dimension, + name::Symbol, + components_names::Vector{String}) + state!(ocp, n, string(name), components_names) end -function state!(ocp::OptimalControlModel, n::Dimension, name::Symbol) +function state!( + ocp::OptimalControlModel, + n::Dimension, + name::Symbol) + state!(ocp, n, string(name)) end @@ -251,27 +294,46 @@ julia> ocp.control_components_names ["v₁", "v₂"] ``` """ -function control!(ocp::OptimalControlModel, m::Dimension, name::String=__control_name(), +function control!( + ocp::OptimalControlModel, + m::Dimension, + name::String=__control_name(), components_names::Vector{String}=__control_components_names(m, name)) + # checkings __is_control_set(ocp) && throw(UnauthorizedCall("the control has already been set. Use control! once.")) (m > 1) && (size(components_names, 1) ≠ m) && throw(IncorrectArgument("the number of control names must be equal to the control dimension")) - # + ocp.control_dimension = m ocp.control_components_names = components_names ocp.control_name = name nothing # to force to return nothing + end -function control!(ocp::OptimalControlModel, m::Dimension, name::Symbol, components_names::Vector{Symbol}) +function control!( + ocp::OptimalControlModel, + m::Dimension, + name::Symbol, + components_names::Vector{Symbol}) + control!(ocp, m, string(name), string.(components_names)) end -function control!(ocp::OptimalControlModel, m::Dimension, name::Symbol, components_names::Vector{String}) +function control!( + ocp::OptimalControlModel, + m::Dimension, + name::Symbol, + components_names::Vector{String}) + control!(ocp, m, string(name), components_names) end -function control!(ocp::OptimalControlModel, m::Dimension, name::Symbol) +function control!( + ocp::OptimalControlModel, + m::Dimension, + name::Symbol) + control!(ocp, m, string(name)) end @@ -452,135 +514,90 @@ end """ $(TYPEDSIGNATURES) -Add an `:initial`, `:final`, `:control`, `:state` or `:variable` box constraint on a range. +Add a constraint to an optimal control problem, denoted `ocp`. !!! note - - The range of the constraint must be contained in 1:n if the constraint is on the state, or 1:m if the constraint is on the control, or 1:q if the constraint is on the variable. - The state, control and variable dimensions must be set before. Use state!, control! and variable!. - - The times must be set before. Use time!. - -# Examples - -```jldoctest -julia> constraint!(ocp, :initial, 1:2:5, [ 0, 0, 0 ], [ 1, 2, 1 ]) -julia> constraint!(ocp, :initial, 2:3, [ 0, 0 ], [ 1, 2 ]) -julia> constraint!(ocp, :final, Index(1), 0, 2) -julia> constraint!(ocp, :control, Index(1), 0, 2) -julia> constraint!(ocp, :state, 2:3, [ 0, 0 ], [ 1, 2 ]) -julia> constraint!(ocp, :variable, 1:2, [ 0, 0 ], [ 1, 2 ]) -``` -""" -function constraint!(ocp::OptimalControlModel{<: TimeDependence, V}, - type::Symbol, - rg::RangeConstraint, - lb::Union{ctVector,Nothing}, - ub::Union{ctVector,Nothing}, - label::Symbol=__constraint_label()) where {V <: VariableDependence} - - __constraint!(ocp, type, rg=rg, f=nothing, lb=lb, ub=ub, label=label) - nothing # to force to return nothing - -end - -""" -$(TYPEDSIGNATURES) - -Add an `:initial`, `:final`, `:control`, `:state` or `:variable` box constraint (whole range). + - The initial and final times must be set before. Use time!. + - When an element is of dimension 1, consider it as a scalar. -!!! note +# Box constraint on the state, control or variable - - The state, control and variable dimensions must be set before. Use state!, control! and variable!. - - The times must be set before. Use time!. - - When an element is of dimension 1, consider it as a scalar. +You can add an `:initial`, `:final`, `:control`, `:state` or `:variable` box constraint (whole range). +We denote by `x`, `u` and `v` respectively the state, control and variable. -# Examples +## Examples ```jldoctest -julia> constraint!(ocp, :initial, [ 0, 0, 0 ], [ 1, 2, 1 ]) # the state is of dim 3 -julia> constraint!(ocp, :final, -1, 1) # the state is of dim 1 -julia> constraint!(ocp, :control, 0, 2) -julia> constraint!(ocp, :state, [ 0, 0 ], [ 1, 2 ]) -julia> constraint!(ocp, :variable, [ 0, 0 ], [ 1, 2 ]) +julia> constraint!(ocp, :initial, lb=[ 0, 0, 0 ]) # [ 0, 0, 0 ] ≤ x(t0), dim(x) = 3 +julia> constraint!(ocp, :initial, lb=[ 0, 0, 0 ], ub=[ 1, 2, 1 ]) # [ 0, 0, 0 ] ≤ x(t0) ≤ [ 1, 2, 1 ], dim(x) = 3 +julia> constraint!(ocp, :final, lb=-1, ub=1) # -1 ≤ x(tf) ≤ 1, dim(x) = 1 +julia> constraint!(ocp, :control, lb=0, ub=2) # 0 ≤ u(t) ≤ 2, t ∈ [t0, tf], dim(u) = 1 +julia> constraint!(ocp, :state, lb=[ 0, 0 ], ub=[ 1, 2 ]) # [ 0, 0 ] ≤ x(t) ≤ [ 1, 2 ], t ∈ [t0, tf], dim(x) = 2 +julia> constraint!(ocp, :variable, lb=[ 0, 0 ], ub=[ 1, 2 ]) # [ 0, 0 ] ≤ v ≤ [ 1, 2 ], dim(v) = 2 ``` -""" -function constraint!(ocp::OptimalControlModel, - type::Symbol, - lb::Union{ctVector,Nothing}, - ub::Union{ctVector,Nothing}, - label::Symbol=__constraint_label()) - __constraint!(ocp, type, rg=nothing, f=nothing, lb=lb, ub=ub, label=label) - nothing # to force to return nothing +# Box constraint on the state, control or variable on some components -end +You can add an `:initial`, `:final`, `:control`, `:state` or `:variable` box constraint on a range of it, that is only on some components. +We denote by `n`, `m` and `q` respectively the dimension of the state, control and variable. +The range of the constraint must be contained in 1:n if the constraint is on the state, or 1:m if the constraint is on the control, or 1:q if the constraint is on the variable. -""" -$(TYPEDSIGNATURES) +## Examples -Add a `:boundary`, `:control`, `:state`, `:mixed` or `:variable` box functional constraint. +```jldoctest +julia> constraint!(ocp, :initial, rg=1:2:5, lb=[ 0, 0, 0 ], ub=[ 1, 2, 1 ]) +julia> constraint!(ocp, :initial, rg=2:3, lb=[ 0, 0 ], ub=[ 1, 2 ]) +julia> constraint!(ocp, :final, rg=1, lb=0, ub=2) +julia> constraint!(ocp, :control, rg=1, lb=0, ub=2) +julia> constraint!(ocp, :state, rg=2:3, lb=[ 0, 0 ], ub=[ 1, 2 ]) +julia> constraint!(ocp, :variable, rg=1:2, lb=[ 0, 0 ], ub=[ 1, 2 ]) +``` -!!! note +# Functional constraint - - The state, control and variable dimensions must be set before. Use state!, control! and variable!. - - The times must be set before. Use time!. - - When an element is of dimension 1, consider it as a scalar. +You can add a `:boundary`, `:control`, `:state`, `:mixed` or `:variable` box functional constraint. -# Examples +## Examples ```@example # variable independent ocp -julia> constraint!(ocp, :boundary, (x0, xf) -> x0[3]+xf[2], 0, 1) +julia> constraint!(ocp, :boundary, f = (x0, xf) -> x0[3]+xf[2], lb=0, ub=1) # variable dependent ocp -julia> constraint!(ocp, :boundary, (x0, xf, v) -> x0[3]+xf[2]*v[1], 0, 1) +julia> constraint!(ocp, :boundary, f = (x0, xf, v) -> x0[3]+xf[2]*v[1], lb=0, ub=1) # time independent and variable independent ocp -julia> constraint!(ocp, :control, u -> 2u, 0, 1) -julia> constraint!(ocp, :state, x -> x-1, [ 0, 0, 0 ], [ 1, 2, 1 ]) -julia> constraint!(ocp, :mixed, (x, u) -> x[1]-u, 0, 1) +julia> constraint!(ocp, :control, f = u -> 2u, lb=0, ub=1) +julia> constraint!(ocp, :state, f = x -> x-1, lb=[ 0, 0, 0 ], ub=[ 1, 2, 1 ]) +julia> constraint!(ocp, :mixed, f = (x, u) -> x[1]-u, lb=0, ub=1) # time dependent and variable independent ocp -julia> constraint!(ocp, :control, (t, u) -> 2u, 0, 1) -julia> constraint!(ocp, :state, (t, x) -> x-t, [ 0, 0, 0 ], [ 1, 2, 1 ]) -julia> constraint!(ocp, :mixed, (t, x, u) -> x[1]-u, 0, 1) +julia> constraint!(ocp, :control, f = (t, u) -> 2u, lb=0, ub=1) +julia> constraint!(ocp, :state, f = (t, x) -> x-t, lb=[ 0, 0, 0 ], ub=[ 1, 2, 1 ]) +julia> constraint!(ocp, :mixed, f = (t, x, u) -> x[1]-u, lb=0, ub=1) # time independent and variable dependent ocp -julia> constraint!(ocp, :control, (u, v) -> 2u*v[1], 0, 1) -julia> constraint!(ocp, :state, (x, v) -> x-v[1], [ 0, 0, 0 ], [ 1, 2, 1 ]) -julia> constraint!(ocp, :mixed, (x, u, v) -> x[1]-v[2]*u, 0, 1) +julia> constraint!(ocp, :control, f = (u, v) -> 2u*v[1], lb=0, ub=1) +julia> constraint!(ocp, :state, f = (x, v) -> x-v[1], lb=[ 0, 0, 0 ], ub=[ 1, 2, 1 ]) +julia> constraint!(ocp, :mixed, f = (x, u, v) -> x[1]-v[2]*u, lb=0, ub=1) # time dependent and variable dependent ocp -julia> constraint!(ocp, :control, (t, u, v) -> 2u+v[2], 0, 1) -julia> constraint!(ocp, :state, (t, x, v) -> x-t*v[1], [ 0, 0, 0 ], [ 1, 2, 1 ]) -julia> constraint!(ocp, :mixed, (t, x, u, v) -> x[1]*v[2]-u, 0, 1) +julia> constraint!(ocp, :control, f = (t, u, v) -> 2u+v[2], lb=0, ub=1) +julia> constraint!(ocp, :state, f = (t, x, v) -> x-t*v[1], lb=[ 0, 0, 0 ], ub=[ 1, 2, 1 ]) +julia> constraint!(ocp, :mixed, f = (t, x, u, v) -> x[1]*v[2]-u, lb=0, ub=1) ``` -""" -function constraint!(ocp::OptimalControlModel{T, V}, - type::Symbol, - f::Function, - lb::Union{ctVector,Nothing}, - ub::Union{ctVector,Nothing}, - label::Symbol=__constraint_label()) where {T, V} - - __constraint!(ocp, type, rg=nothing, f=f, lb=lb, ub=ub, label=label) - nothing # to force to return nothing - -end - -""" -$(TYPEDSIGNATURES) - -General setter for constraints. """ -function __constraint!(ocp::OptimalControlModel{T, V}, +function constraint!( + ocp::OptimalControlModel{T, V}, type::Symbol; - rg::Union{OrdinalRange{<:Integer},Integer,Index,Nothing}=nothing, - f::Union{Function,Nothing}=nothing, + rg::Union{OrdinalRange{<:Integer}, Index, Integer, Nothing}=nothing, + f::Union{Function, Nothing}=nothing, lb::W=nothing, ub::X=nothing, - label::Symbol=__constraint_label()) where {T <: TimeDependence, V <: VariableDependence, W <: Union{ctVector,Nothing}, X <: Union{ctVector,Nothing}} + label::Symbol=__constraint_label()) where {T <: TimeDependence, V <: VariableDependence, W <: Union{ctVector, Nothing}, X <: Union{ctVector, Nothing}} __check_all_set(ocp) type == :variable && is_variable_independent(ocp) && throw(UnauthorizedCall("the ocp is variable independent" * ", you cannot use constraint! function with type=:variable.")) @@ -594,16 +611,29 @@ function __constraint!(ocp::OptimalControlModel{T, V}, throw(UnauthorizedCall("the constraint named " * String(label) * " already exists.")) end - (lb ≢ nothing && ub === nothing) && (ub = Inf*(size(lb,1) == 1 ? 1 : ones(eltype(ub), size(ub,1)))) - (lb === nothing && ub ≢ nothing) && (lb = -Inf*(size(ub,1) == 1 ? 1 : ones(eltype(ub), size(ub,1)))) + # bounds + (!isnothing(lb) && isnothing(ub)) && (ub = Inf*(size(lb,1) == 1 ? 1 : ones(eltype(ub), size(ub,1)))) + ( isnothing(lb) && !isnothing(ub)) && (lb = -Inf*(size(ub,1) == 1 ? 1 : ones(eltype(ub), size(ub,1)))) + + # range (typeof(rg) <: Int) && (rg = Index(rg)) - @match (rg,f,lb,ub) begin - (::Nothing,::Nothing,::ctVector,::ctVector) => begin - # + # checkings + @match (rg, f) begin + (::RangeConstraint, ::Function) => throw(UnauthorizedCall("Providing a range (rg keyword) and a function (f keyword) is not authorized.")) + _ => nothing + end + @match (lb, ub) begin + (::Nothing, ::Nothing) => throw(UnauthorizedCall("Calling the constraint! function without any bounds is not authorized.")) + _ => nothing + end + + # core + @match (rg, f, lb, ub) begin + (::Nothing, ::Nothing, ::ctVector, ::ctVector) => begin + rg = nothing - # if type ∈ [:initial, :final, :state] rg = n == 1 ? Index(1) : 1:n txt = "the lower bound `lb` and the upper bound `ub` must be of dimension $n" @@ -618,13 +648,14 @@ function __constraint!(ocp::OptimalControlModel{T, V}, ". Please choose in [ :initial, :final, :control, :state, :variable ] or check the arguments of the constraint! method.")) end - # (length(rg) != length(lb)) && throw(IncorrectArgument(txt)) (length(rg) != length(ub)) && throw(IncorrectArgument(txt)) - __constraint!(ocp, type, rg=rg, lb=lb, ub=ub, label=label) + constraint!(ocp, type, rg=rg, lb=lb, ub=ub, label=label) + end - (::Nothing,::Function,::ctVector,::ctVector) => begin + (::Nothing, ::Function, ::ctVector, ::ctVector) => begin + # set the constraint if type == :boundary ocp.constraints[label] = (type, BoundaryConstraint(f, V), lb, ub) @@ -640,8 +671,9 @@ function __constraint!(ocp::OptimalControlModel{T, V}, throw(IncorrectArgument("the following type of constraint is not valid: " * String(type) * ". Please choose in [ :boundary, :control, :state, :mixed ] or check the arguments of the constraint! method.")) end - end # - (::RangeConstraint,::Nothing,::ctVector,::ctVector) => begin + + end + (::RangeConstraint, ::Nothing, ::ctVector, ::ctVector) => begin txt = "the range `rg`, the lower bound `lb` and the upper bound `ub` must have the same dimension" (length(rg) != length(lb)) && throw(IncorrectArgument(txt)) @@ -662,18 +694,17 @@ function __constraint!(ocp::OptimalControlModel{T, V}, # set the constraint fun_rg = @match type begin - :initial => V == Fixed ? BoundaryConstraint((x0, xf ) -> x0[rg], V) : - BoundaryConstraint((x0, xf, v) -> x0[rg], V) - :final => V == Fixed ? BoundaryConstraint((x0, xf ) -> xf[rg], V) : - BoundaryConstraint((x0, xf, v) -> xf[rg], V) + :initial => V == Fixed ? BoundaryConstraint((x0, xf ) -> x0[rg], V) : BoundaryConstraint((x0, xf, v) -> x0[rg], V) + :final => V == Fixed ? BoundaryConstraint((x0, xf ) -> xf[rg], V) : BoundaryConstraint((x0, xf, v) -> xf[rg], V) :control || :state || :variable => rg _ => throw(IncorrectArgument("the following type of constraint is not valid: " * String(type) * ". Please choose in [ :initial, :final, :control, :state, :variable ] or check the arguments of the constraint! method.")) end ocp.constraints[label] = (type, fun_rg, lb, ub) nothing # to force to return nothing + end # - _ => throw(IncorrectArgument("Provided arguments are inconsistent")) + _ => throw(IncorrectArgument("Provided arguments are inconsistent.")) end end diff --git a/src/onepass.jl b/src/onepass.jl index 3147fe68..37cf35d1 100644 --- a/src/onepass.jl +++ b/src/onepass.jl @@ -266,8 +266,8 @@ p_constraint!(p, ocp, e1, e2, e3, label=gensym(); log=false) = begin label isa Symbol || return __throw("forbidden label: $label", p.lnum, p.line) llabel = QuoteNode(label) code = @match c_type begin - (:initial, rg) => :( CTBase.__constraint!($ocp, :initial; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) - (:final , rg) => :( CTBase.__constraint!($ocp, :final ; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) + (:initial, rg) => :( constraint!($ocp, :initial; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) + (:final , rg) => :( constraint!($ocp, :final ; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) :boundary => begin gs = gensym() x0 = gensym() @@ -279,9 +279,9 @@ p_constraint!(p, ocp, e1, e2, e3, label=gensym(); log=false) = begin function $gs($(args...)) $ee2 end - CTBase.__constraint!($ocp, :boundary; f=$gs, lb=$e1, ub=$e3, label=$llabel) + constraint!($ocp, :boundary; f=$gs, lb=$e1, ub=$e3, label=$llabel) end end - (:control_range, rg) => :( CTBase.__constraint!($ocp, :control; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) + (:control_range, rg) => :( constraint!($ocp, :control; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) :control_fun => begin gs = gensym() ut = gensym() @@ -292,9 +292,9 @@ p_constraint!(p, ocp, e1, e2, e3, label=gensym(); log=false) = begin function $gs($(args...)) $ee2 end - CTBase.__constraint!($ocp, :control; f=$gs, lb=$e1, ub=$e3, label=$llabel) + constraint!($ocp, :control; f=$gs, lb=$e1, ub=$e3, label=$llabel) end end - (:state_range, rg) => :( CTBase.__constraint!($ocp, :state; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) + (:state_range, rg) => :( constraint!($ocp, :state; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) :state_fun => begin gs = gensym() xt = gensym() @@ -305,9 +305,9 @@ p_constraint!(p, ocp, e1, e2, e3, label=gensym(); log=false) = begin function $gs($(args...)) $ee2 end - CTBase.__constraint!($ocp, :state; f=$gs, lb=$e1, ub=$e3, label=$llabel) + constraint!($ocp, :state; f=$gs, lb=$e1, ub=$e3, label=$llabel) end end - (:variable_range, rg) => :( CTBase.__constraint!($ocp, :variable; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) + (:variable_range, rg) => :( constraint!($ocp, :variable; rg=$rg, lb=$e1, ub=$e3, label=$llabel) ) :variable_fun => begin gs = gensym() args = [ p.v ] @@ -315,7 +315,7 @@ p_constraint!(p, ocp, e1, e2, e3, label=gensym(); log=false) = begin function $gs($(args...)) $e2 end - CTBase.__constraint!($ocp, :variable; f=$gs, lb=$e1, ub=$e3, label=$llabel) + constraint!($ocp, :variable; f=$gs, lb=$e1, ub=$e3, label=$llabel) end end :mixed => begin gs = gensym() @@ -328,7 +328,7 @@ p_constraint!(p, ocp, e1, e2, e3, label=gensym(); log=false) = begin function $gs($(args...)) $ee2 end - CTBase.__constraint!($ocp, :mixed; f=$gs, lb=$e1, ub=$e3, label=$llabel) + constraint!($ocp, :mixed; f=$gs, lb=$e1, ub=$e3, label=$llabel) end end _ => return __throw("bad constraint declaration", p.lnum, p.line) end diff --git a/test/runtests.jl b/test/runtests.jl index 8eafe652..97ee2850 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -9,6 +9,56 @@ const has = CTBase.has const replace_call = CTBase.replace_call const constraint_type = CTBase.constraint_type +function __constraint!( + ocp::OptimalControlModel{<: TimeDependence, V}, + type::Symbol, + rg::Index, + lb::Union{ctVector,Nothing}, + ub::Union{ctVector,Nothing}, + label::Symbol=CTBase.__constraint_label()) where {V <: VariableDependence} + + constraint!(ocp, type, rg=rg.val, f=nothing, lb=lb, ub=ub, label=label) + nothing # to force to return nothing + +end + +function __constraint!( + ocp::OptimalControlModel{<: TimeDependence, V}, + type::Symbol, + rg::OrdinalRange{<:Integer}, + lb::Union{ctVector,Nothing}, + ub::Union{ctVector,Nothing}, + label::Symbol=CTBase.__constraint_label()) where {V <: VariableDependence} + + constraint!(ocp, type, rg=rg, f=nothing, lb=lb, ub=ub, label=label) + nothing # to force to return nothing + +end + +function __constraint!( + ocp::OptimalControlModel, + type::Symbol, + lb::Union{ctVector,Nothing}, + ub::Union{ctVector,Nothing}, + label::Symbol=CTBase.__constraint_label()) + + constraint!(ocp, type, rg=nothing, f=nothing, lb=lb, ub=ub, label=label) + nothing # to force to return nothing + +end + +function __constraint!( + ocp::OptimalControlModel{T, V}, + type::Symbol, + f::Function, + lb::Union{ctVector,Nothing}, + ub::Union{ctVector,Nothing}, + label::Symbol=CTBase.__constraint_label()) where {T, V} + + constraint!(ocp, type, rg=nothing, f=f, lb=lb, ub=ub, label=label) + nothing # to force to return nothing +end + # @testset verbose = true showtiming = true "Base" begin for name ∈ ( diff --git a/test/test_model.jl b/test/test_model.jl index 713d74b4..8e2f9a17 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -4,11 +4,12 @@ function test_model() # 30 55 185 @testset "variable!" begin ocp = Model(variable=false) + @test_throws UnauthorizedCall variable!(ocp, 1) - @test_throws UnauthorizedCall constraint!(ocp, :variable, 2:3, [ 0, 3 ], [ 0, 3 ]) - @test_throws UnauthorizedCall constraint!(ocp, :variable, 0, 1) # the variable here is of dimension 1 - @test_throws UnauthorizedCall constraint!(ocp, :variable, 1:2, [ 0, 0 ], [ 1, 2 ]) - @test_throws UnauthorizedCall constraint!(ocp, :variable, [ 3, 0, 1 ], [ 3, 0, 1 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :variable, 2:3, [ 0, 3 ], [ 0, 3 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :variable, 0, 1) # the variable here is of dimension 1 + @test_throws UnauthorizedCall __constraint!(ocp, :variable, 1:2, [ 0, 0 ], [ 1, 2 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :variable, [ 3, 0, 1 ], [ 3, 0, 1 ]) ocp = Model(variable=true) variable!(ocp, 1) @@ -63,80 +64,80 @@ end i == 7 && begin state!(ocp, 2); control!(ocp, 1) end # constraint! 1 - @test_throws UnauthorizedCall constraint!(ocp, :initial, 1:2:5, [ 0, 0, 0 ], [ 0, 0, 0 ]) - @test_throws UnauthorizedCall constraint!(ocp, :initial, 2:3, [ 0, 0 ], [ 0, 0 ]) - @test_throws UnauthorizedCall constraint!(ocp, :final, Index(2), 0, 0) + @test_throws UnauthorizedCall __constraint!(ocp, :initial, 1:2:5, [ 0, 0, 0 ], [ 0, 0, 0 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :initial, 2:3, [ 0, 0 ], [ 0, 0 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :final, Index(2), 0, 0) # constraint! 2 - @test_throws UnauthorizedCall constraint!(ocp, :initial, [ 0, 0 ], [ 0, 0 ]) - @test_throws UnauthorizedCall constraint!(ocp, :final, 2, 2) # if the state is of dimension 1 + @test_throws UnauthorizedCall __constraint!(ocp, :initial, [ 0, 0 ], [ 0, 0 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :final, 2, 2) # if the state is of dimension 1 # constraint! 3 - @test_throws UnauthorizedCall constraint!(ocp, :initial, 2:3, [ 0, 0 ], [ 1, 2 ]) - @test_throws UnauthorizedCall constraint!(ocp, :final, Index(1), 0, 2) - @test_throws UnauthorizedCall constraint!(ocp, :control, Index(1), 0, 2) - @test_throws UnauthorizedCall constraint!(ocp, :state, 2:3, [ 0, 0 ], [ 1, 2 ]) - @test_throws UnauthorizedCall constraint!(ocp, :initial, 1:2:5, [ 0, 0, 0 ], [ 1, 2, 1 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :initial, 2:3, [ 0, 0 ], [ 1, 2 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :final, Index(1), 0, 2) + @test_throws UnauthorizedCall __constraint!(ocp, :control, Index(1), 0, 2) + @test_throws UnauthorizedCall __constraint!(ocp, :state, 2:3, [ 0, 0 ], [ 1, 2 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :initial, 1:2:5, [ 0, 0, 0 ], [ 1, 2, 1 ]) # constraint! 4 - @test_throws UnauthorizedCall constraint!(ocp, :initial, [ 0, 0, 0 ], [ 1, 2, 1 ]) - @test_throws UnauthorizedCall constraint!(ocp, :final, [ 0, 0, 0 ], [ 1, 2, 1 ]) - @test_throws UnauthorizedCall constraint!(ocp, :control, [ 0, 0 ], [ 2, 3 ]) - @test_throws UnauthorizedCall constraint!(ocp, :state, [ 0, 0, 0 ], [ 1, 2, 1 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :initial, [ 0, 0, 0 ], [ 1, 2, 1 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :final, [ 0, 0, 0 ], [ 1, 2, 1 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :control, [ 0, 0 ], [ 2, 3 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :state, [ 0, 0, 0 ], [ 1, 2, 1 ]) # constraint! 5 # variable independent ocp - @test_throws UnauthorizedCall constraint!(ocp, :boundary, (x0, xf) -> x0[3]+xf[2], 0, 1) + @test_throws UnauthorizedCall __constraint!(ocp, :boundary, (x0, xf) -> x0[3]+xf[2], 0, 1) # variable dependent ocp - @test_throws UnauthorizedCall constraint!(ocp, :boundary, (x0, xf, v) -> x0[3]+xf[2]*v[1], 0, 1) + @test_throws UnauthorizedCall __constraint!(ocp, :boundary, (x0, xf, v) -> x0[3]+xf[2]*v[1], 0, 1) # time independent and variable independent ocp - @test_throws UnauthorizedCall constraint!(ocp, :control, u -> 2u, 0, 1) - @test_throws UnauthorizedCall constraint!(ocp, :state, x -> x-1, [ 0, 0, 0 ], [ 1, 2, 1 ]) - @test_throws UnauthorizedCall constraint!(ocp, :mixed, (x, u) -> x[1]-u, 0, 1) + @test_throws UnauthorizedCall __constraint!(ocp, :control, u -> 2u, 0, 1) + @test_throws UnauthorizedCall __constraint!(ocp, :state, x -> x-1, [ 0, 0, 0 ], [ 1, 2, 1 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :mixed, (x, u) -> x[1]-u, 0, 1) # time dependent and variable independent ocp - @test_throws UnauthorizedCall constraint!(ocp, :control, (t, u) -> 2u, 0, 1) - @test_throws UnauthorizedCall constraint!(ocp, :state, (t, x) -> x-t, [ 0, 0, 0 ], [ 1, 2, 1 ]) - @test_throws UnauthorizedCall constraint!(ocp, :mixed, (t, x, u) -> x[1]-u, 0, 1) + @test_throws UnauthorizedCall __constraint!(ocp, :control, (t, u) -> 2u, 0, 1) + @test_throws UnauthorizedCall __constraint!(ocp, :state, (t, x) -> x-t, [ 0, 0, 0 ], [ 1, 2, 1 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :mixed, (t, x, u) -> x[1]-u, 0, 1) # time independent and variable dependent ocp - @test_throws UnauthorizedCall constraint!(ocp, :control, (u, v) -> 2u*v[1], 0, 1) - @test_throws UnauthorizedCall constraint!(ocp, :state, (x, v) -> x-v[1], [ 0, 0, 0 ], [ 1, 2, 1 ]) - @test_throws UnauthorizedCall constraint!(ocp, :mixed, (x, u, v) -> x[1]-v[2]*u, 0, 1) + @test_throws UnauthorizedCall __constraint!(ocp, :control, (u, v) -> 2u*v[1], 0, 1) + @test_throws UnauthorizedCall __constraint!(ocp, :state, (x, v) -> x-v[1], [ 0, 0, 0 ], [ 1, 2, 1 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :mixed, (x, u, v) -> x[1]-v[2]*u, 0, 1) # time dependent and variable dependent ocp - @test_throws UnauthorizedCall constraint!(ocp, :control, (t, u, v) -> 2u+v[2], 0, 1) - @test_throws UnauthorizedCall constraint!(ocp, :state, (t, x, v) -> x-t*v[1], [ 0, 0, 0 ], [ 1, 2, 1 ]) - @test_throws UnauthorizedCall constraint!(ocp, :mixed, (t, x, u, v) -> x[1]*v[2]-u, 0, 1) + @test_throws UnauthorizedCall __constraint!(ocp, :control, (t, u, v) -> 2u+v[2], 0, 1) + @test_throws UnauthorizedCall __constraint!(ocp, :state, (t, x, v) -> x-t*v[1], [ 0, 0, 0 ], [ 1, 2, 1 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :mixed, (t, x, u, v) -> x[1]*v[2]-u, 0, 1) # constraint! 6 # variable independent ocp - @test_throws UnauthorizedCall constraint!(ocp, :boundary, (x0, xf) -> x0[3]+xf[2], 0, 0) + @test_throws UnauthorizedCall __constraint!(ocp, :boundary, (x0, xf) -> x0[3]+xf[2], 0, 0) # variable dependent ocp - @test_throws UnauthorizedCall constraint!(ocp, :boundary, (x0, xf, v) -> x0[3]+xf[2]*v[1], 0, 0) + @test_throws UnauthorizedCall __constraint!(ocp, :boundary, (x0, xf, v) -> x0[3]+xf[2]*v[1], 0, 0) # time independent and variable independent ocp - @test_throws UnauthorizedCall constraint!(ocp, :control, u -> 2u, 1, 1) - @test_throws UnauthorizedCall constraint!(ocp, :state, x -> x-1, [ 0, 0, 0 ], [ 0, 0, 0 ]) - @test_throws UnauthorizedCall constraint!(ocp, :mixed, (x, u) -> x[1]-u, 0, 0) + @test_throws UnauthorizedCall __constraint!(ocp, :control, u -> 2u, 1, 1) + @test_throws UnauthorizedCall __constraint!(ocp, :state, x -> x-1, [ 0, 0, 0 ], [ 0, 0, 0 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :mixed, (x, u) -> x[1]-u, 0, 0) # time dependent and variable independent ocp - @test_throws UnauthorizedCall constraint!(ocp, :control, (t, u) -> 2u, 1, 1) - @test_throws UnauthorizedCall constraint!(ocp, :state, (t, x) -> x-t, [ 0, 0, 0 ], [ 0, 0, 0 ]) - @test_throws UnauthorizedCall constraint!(ocp, :mixed, (t, x, u) -> x[1]-u, 0, 0) + @test_throws UnauthorizedCall __constraint!(ocp, :control, (t, u) -> 2u, 1, 1) + @test_throws UnauthorizedCall __constraint!(ocp, :state, (t, x) -> x-t, [ 0, 0, 0 ], [ 0, 0, 0 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :mixed, (t, x, u) -> x[1]-u, 0, 0) # time independent and variable dependent ocp - @test_throws UnauthorizedCall constraint!(ocp, :control, (u, v) -> 2u*v[1], 1, 1) - @test_throws UnauthorizedCall constraint!(ocp, :state, (x, v) -> x-v[2], [ 0, 0, 0 ], [ 0, 0, 0 ]) - @test_throws UnauthorizedCall constraint!(ocp, :mixed, (x, u) -> x[1]-u+v[1], 0, 0) + @test_throws UnauthorizedCall __constraint!(ocp, :control, (u, v) -> 2u*v[1], 1, 1) + @test_throws UnauthorizedCall __constraint!(ocp, :state, (x, v) -> x-v[2], [ 0, 0, 0 ], [ 0, 0, 0 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :mixed, (x, u) -> x[1]-u+v[1], 0, 0) # time dependent and variable dependent ocp - @test_throws UnauthorizedCall constraint!(ocp, :control, (t, u, v) -> 2u-t*v[2], 1, 1) - @test_throws UnauthorizedCall constraint!(ocp, :state, (t, x, v) -> x-t+v[1], [ 0, 0, 0 ], [ 0, 0, 0 ]) - @test_throws UnauthorizedCall constraint!(ocp, :mixed, (t, x, u, v) -> x[1]-u*v[1], 0, 0) + @test_throws UnauthorizedCall __constraint!(ocp, :control, (t, u, v) -> 2u-t*v[2], 1, 1) + @test_throws UnauthorizedCall __constraint!(ocp, :state, (t, x, v) -> x-t+v[1], [ 0, 0, 0 ], [ 0, 0, 0 ]) + @test_throws UnauthorizedCall __constraint!(ocp, :mixed, (t, x, u, v) -> x[1]-u*v[1], 0, 0) end @@ -528,22 +529,22 @@ end @testset "constraint! 1" begin ocp = Model(); time!(ocp, 0, 1); state!(ocp, 1); control!(ocp, 1) - @test_throws IncorrectArgument constraint!(ocp, :initial, [0, 1], [0, 1], :c0) - constraint!(ocp, :initial, 0, 0, :c0) - constraint!(ocp, :final, 1, 1, :cf) + @test_throws IncorrectArgument __constraint!(ocp, :initial, [0, 1], [0, 1], :c0) + __constraint!(ocp, :initial, 0, 0, :c0) + __constraint!(ocp, :final, 1, 1, :cf) @test constraint(ocp, :c0)(12, ∅) == 12 @test constraint(ocp, :cf)(∅, 12) == 12 ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 1) - constraint!(ocp, :initial, [0, 1], [0, 1], :c0) - constraint!(ocp, :final, [1, 2], [1, 2], :cf) + __constraint!(ocp, :initial, [0, 1], [0, 1], :c0) + __constraint!(ocp, :final, [1, 2], [1, 2], :cf) @test constraint(ocp, :c0)([12, 13], ∅) == [12, 13] @test constraint(ocp, :cf)(∅, [12, 13]) == [12, 13] # constraint already exists ocp = Model(); time!(ocp, 0, 1); state!(ocp, 1); control!(ocp, 1) - constraint!(ocp, :initial, 0, 0, :c) - @test_throws UnauthorizedCall constraint!(ocp, :final, 0, 0, :c) + __constraint!(ocp, :initial, 0, 0, :c) + @test_throws UnauthorizedCall __constraint!(ocp, :final, 0, 0, :c) end @@ -553,51 +554,56 @@ end x = 12 x0 = 0 xf = 1 - constraint!(ocp, :initial, Index(1), x0, x0, :c0) - constraint!(ocp, :final, Index(1), xf, xf, :cf) + __constraint!(ocp, :initial, Index(1), x0, x0, :c0) + __constraint!(ocp, :final, Index(1), xf, xf, :cf) @test constraint(ocp, :c0)(x, ∅) == x @test constraint(ocp, :cf)(∅, x) == x + constraint!(ocp, :initial, rg=1, lb=x0, ub=x0, label=:c00) + constraint!(ocp, :final, rg=1, lb=xf, ub=xf, label=:cff) + @test constraint(ocp, :c00)(x, ∅) == x + @test constraint(ocp, :cff)(∅, x) == x + ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 1) x = [12, 13] x0 = [0, 1] xf = [1, 2] - @test_throws IncorrectArgument constraint!(ocp, :initial, Index(2), x0, x0, :c0) - @test_throws IncorrectArgument constraint!(ocp, :final, Index(2), xf, xf, :cf) + @test_throws IncorrectArgument __constraint!(ocp, :initial, Index(2), x0, x0, :c0) + @test_throws IncorrectArgument __constraint!(ocp, :final, Index(2), xf, xf, :cf) ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 1) x = [12, 13] x0 = [0, 1] xf = [1, 2] - constraint!(ocp, :initial, 1:2, x0, x0, :c0) - constraint!(ocp, :final, 1:2, xf, xf, :cf) + __constraint!(ocp, :initial, 1:2, x0, x0, :c0) + __constraint!(ocp, :final, 1:2, xf, xf, :cf) @test constraint(ocp, :c0)(x, ∅) == x[1:2] @test constraint(ocp, :cf)(∅, x) == x[1:2] # constraint already exists ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 1) - constraint!(ocp, :initial, Index(1), 0, 0, :c) - @test_throws UnauthorizedCall constraint!(ocp, :final, Index(1), 0, 0, :c) + __constraint!(ocp, :initial, Index(1), 0, 0, :c) + @test_throws UnauthorizedCall __constraint!(ocp, :final, Index(1), 0, 0, :c) end @testset "constraint! 3" begin ocp = Model(); time!(ocp, 0, 1); state!(ocp, 1); control!(ocp, 1) - constraint!(ocp, :initial, 0, 1, :c0) - constraint!(ocp, :final, 1, 2, :cf) - constraint!(ocp, :control, 0, 1, :cu) - constraint!(ocp, :state, 0, 1, :cs) + __constraint!(ocp, :initial, 0, 1, :c0) + __constraint!(ocp, :final, 1, 2, :cf) + __constraint!(ocp, :control, 0, 1, :cu) + __constraint!(ocp, :state, 0, 1, :cs) @test constraint(ocp, :c0)(12, ∅) == 12 @test constraint(ocp, :cf)(∅ ,12) == 12 @test constraint(ocp, :cu)(12) == 12 @test constraint(ocp, :cs)(12) == 12 ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 2) - constraint!(ocp, :initial, [0, 1], [1, 2], :c0) - constraint!(ocp, :final, [1, 2], [2, 3], :cf) - constraint!(ocp, :control, [0, 1], [1, 2], :cu) - constraint!(ocp, :state, [0, 1], [1, 2], :cs) + __constraint!(ocp, :initial, [0, 1], [1, 2], :c0) + __constraint!(ocp, :final, [1, 2], [2, 3], :cf) + __constraint!(ocp, :control, [0, 1], [1, 2], :cu) + __constraint!(ocp, :state, [0, 1], [1, 2], :cs) @test constraint(ocp, :c0)([12, 13], ∅) == [12, 13] @test constraint(ocp, :cf)(∅, [12, 13]) == [12, 13] @test constraint(ocp, :cu)([12, 13]) == [12, 13] @@ -605,34 +611,34 @@ end # constraint already exists ocp = Model(); time!(ocp, 0, 1); state!(ocp, 1); control!(ocp, 1) - constraint!(ocp, :initial, 0, 1, :c) - @test_throws UnauthorizedCall constraint!(ocp, :final, 0, 1, :c) + __constraint!(ocp, :initial, 0, 1, :c) + @test_throws UnauthorizedCall __constraint!(ocp, :final, 0, 1, :c) end @testset "constraint! 4" begin ocp = Model(); time!(ocp, 0, 1); state!(ocp, 1); control!(ocp, 1) - constraint!(ocp, :initial, Index(1), 0, 1, :c0) - constraint!(ocp, :final, Index(1), 1, 2, :cf) - constraint!(ocp, :control, Index(1), 0, 1, :cu) - constraint!(ocp, :state, Index(1), 0, 1, :cs) + __constraint!(ocp, :initial, Index(1), 0, 1, :c0) + __constraint!(ocp, :final, Index(1), 1, 2, :cf) + __constraint!(ocp, :control, Index(1), 0, 1, :cu) + __constraint!(ocp, :state, Index(1), 0, 1, :cs) @test constraint(ocp, :c0)(12, ∅) == 12 @test constraint(ocp, :cf)(∅, 12) == 12 @test constraint(ocp, :cu)(12) == 12 @test constraint(ocp, :cs)(12) == 12 ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 2) - @test_throws IncorrectArgument constraint!(ocp, :initial, Index(2), [0, 1], [1, 2], :c0) - @test_throws IncorrectArgument constraint!(ocp, :final, Index(2), [1, 2], [2, 3], :cf) - @test_throws IncorrectArgument constraint!(ocp, :control, Index(2), [0, 1], [1, 2], :cu) - @test_throws IncorrectArgument constraint!(ocp, :state, Index(2), [0, 1], [1, 2], :cs) + @test_throws IncorrectArgument __constraint!(ocp, :initial, Index(2), [0, 1], [1, 2], :c0) + @test_throws IncorrectArgument __constraint!(ocp, :final, Index(2), [1, 2], [2, 3], :cf) + @test_throws IncorrectArgument __constraint!(ocp, :control, Index(2), [0, 1], [1, 2], :cu) + @test_throws IncorrectArgument __constraint!(ocp, :state, Index(2), [0, 1], [1, 2], :cs) ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 2) - constraint!(ocp, :initial, 1:2, [0, 1], [1, 2], :c0) - constraint!(ocp, :final, 1:2, [1, 2], [2, 3], :cf) - constraint!(ocp, :control, 1:2, [0, 1], [1, 2], :cu) - constraint!(ocp, :state, 1:2, [0, 1], [1, 2], :cs) + __constraint!(ocp, :initial, 1:2, [0, 1], [1, 2], :c0) + __constraint!(ocp, :final, 1:2, [1, 2], [2, 3], :cf) + __constraint!(ocp, :control, 1:2, [0, 1], [1, 2], :cu) + __constraint!(ocp, :state, 1:2, [0, 1], [1, 2], :cs) @test constraint(ocp, :c0)([12, 13], ∅) == [12, 13] @test constraint(ocp, :cf)(∅, [12, 13]) == [12, 13] @test constraint(ocp, :cu)([12, 13]) == [12, 13] @@ -640,38 +646,38 @@ end # constraint already exists ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 1) - constraint!(ocp, :initial, Index(1), 0, 1, :c) - @test_throws UnauthorizedCall constraint!(ocp, :final, Index(1), 0, 1, :c) + __constraint!(ocp, :initial, Index(1), 0, 1, :c) + @test_throws UnauthorizedCall __constraint!(ocp, :final, Index(1), 0, 1, :c) end @testset "constraint! 5" begin ocp = Model(); time!(ocp, 0, 1); state!(ocp, 1); control!(ocp, 1) - constraint!(ocp, :boundary, (x0, xf) -> x0+xf, 0, 0, :cb) - constraint!(ocp, :control, u->u, 0, 0, :cu) - constraint!(ocp, :state, x->x, 0, 0, :cs) - constraint!(ocp, :mixed, (x,u)->x+u, 1, 1, :cm) + __constraint!(ocp, :boundary, (x0, xf) -> x0+xf, 0, 0, :cb) + __constraint!(ocp, :control, u->u, 0, 0, :cu) + __constraint!(ocp, :state, x->x, 0, 0, :cs) + __constraint!(ocp, :mixed, (x,u)->x+u, 1, 1, :cm) @test constraint(ocp, :cb)(12, 13) == 12+13 @test constraint(ocp, :cu)(12) == 12 @test constraint(ocp, :cs)(12) == 12 @test constraint(ocp, :cm)(12, 13) == 12+13 ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 2) - constraint!(ocp, :boundary, (x0, xf) -> x0[1]+xf[1], 0, 0, :cb) - constraint!(ocp, :control, u->u[1], 0, 0, :cu) - constraint!(ocp, :state, x->x[1], 0, 0, :cs) - constraint!(ocp, :mixed, (x,u)->x[1]+u[1], 1, 1, :cm) + __constraint!(ocp, :boundary, (x0, xf) -> x0[1]+xf[1], 0, 0, :cb) + __constraint!(ocp, :control, u->u[1], 0, 0, :cu) + __constraint!(ocp, :state, x->x[1], 0, 0, :cs) + __constraint!(ocp, :mixed, (x,u)->x[1]+u[1], 1, 1, :cm) @test constraint(ocp, :cb)([13, 14], [16, 17]) == 13+16 @test constraint(ocp, :cu)([12, 13]) == 12 @test constraint(ocp, :cs)([12, 13]) == 12 @test constraint(ocp, :cm)([12, 13], [14, 15]) == 12+14 ocp = Model(); time!(ocp, 0, 1); state!(ocp, 3); control!(ocp, 3) - constraint!(ocp, :boundary, (x0, xf) -> [x0[1]+xf[1], x0[2]+xf[2]], [0, 0], [0, 0], :cb) - constraint!(ocp, :control, u->u[1:2], [0, 0], [0, 0], :cu) - constraint!(ocp, :state, x->x[1:2], [0, 0], [0, 0], :cs) - constraint!(ocp, :mixed, (x,u)->[x[1]+u[1], x[2]+u[2]], [0, 0], [0, 0], :cm) + __constraint!(ocp, :boundary, (x0, xf) -> [x0[1]+xf[1], x0[2]+xf[2]], [0, 0], [0, 0], :cb) + __constraint!(ocp, :control, u->u[1:2], [0, 0], [0, 0], :cu) + __constraint!(ocp, :state, x->x[1:2], [0, 0], [0, 0], :cs) + __constraint!(ocp, :mixed, (x,u)->[x[1]+u[1], x[2]+u[2]], [0, 0], [0, 0], :cm) @test constraint(ocp, :cb)([13, 14, 15], [17, 18, 19]) == [13+17, 14+18] @test constraint(ocp, :cu)([12, 13, 14]) == [12, 13] @test constraint(ocp, :cs)([12, 13, 14]) == [12, 13] @@ -679,38 +685,38 @@ end # constraint already exists ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 1) - constraint!(ocp, :control, u->u, 0, 1, :c) - @test_throws UnauthorizedCall constraint!(ocp, :control, u->u, 0, 1, :c) + __constraint!(ocp, :control, u->u, 0, 1, :c) + @test_throws UnauthorizedCall __constraint!(ocp, :control, u->u, 0, 1, :c) end @testset "constraint! 6" begin ocp = Model(); time!(ocp, 0, 1); state!(ocp, 1); control!(ocp, 1) - constraint!(ocp, :boundary, (x0, xf) -> x0+xf, 0, 1, :cb) - constraint!(ocp, :control, u->u, 0, 1, :cu) - constraint!(ocp, :state, x->x, 0, 1, :cs) - constraint!(ocp, :mixed, (x,u)->x+u, 1, 1, :cm) + __constraint!(ocp, :boundary, (x0, xf) -> x0+xf, 0, 1, :cb) + __constraint!(ocp, :control, u->u, 0, 1, :cu) + __constraint!(ocp, :state, x->x, 0, 1, :cs) + __constraint!(ocp, :mixed, (x,u)->x+u, 1, 1, :cm) @test constraint(ocp, :cb)(12, 13) == 12+13 @test constraint(ocp, :cu)(12) == 12 @test constraint(ocp, :cs)(12) == 12 @test constraint(ocp, :cm)(12, 13) == 12+13 ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 2) - constraint!(ocp, :boundary, (x0, xf) -> x0[1]+xf[1], 0, 1, :cb) - constraint!(ocp, :control, u->u[1], 0, 1, :cu) - constraint!(ocp, :state, x->x[1], 0, 1, :cs) - constraint!(ocp, :mixed, (x,u)->x[1]+u[1], 1, 1, :cm) + __constraint!(ocp, :boundary, (x0, xf) -> x0[1]+xf[1], 0, 1, :cb) + __constraint!(ocp, :control, u->u[1], 0, 1, :cu) + __constraint!(ocp, :state, x->x[1], 0, 1, :cs) + __constraint!(ocp, :mixed, (x,u)->x[1]+u[1], 1, 1, :cm) @test constraint(ocp, :cb)([13, 14], [16, 17]) == 13+16 @test constraint(ocp, :cu)([12, 13]) == 12 @test constraint(ocp, :cs)([12, 13]) == 12 @test constraint(ocp, :cm)([12, 13], [14, 15]) == 12+14 ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 1) - constraint!(ocp, :boundary, (x0, xf) -> [x0[1]+xf[1], x0[2]+xf[2]], [0, 0], [1, 1], :cb) - constraint!(ocp, :control, u->u[1:2], [0, 0], [1, 1], :cu) - constraint!(ocp, :state, x->x[1:2], [0, 0], [1, 1], :cs) - constraint!(ocp, :mixed, (x,u)->[x[1]+u[1], x[2]+u[2]], [0, 0], [1, 1], :cm) + __constraint!(ocp, :boundary, (x0, xf) -> [x0[1]+xf[1], x0[2]+xf[2]], [0, 0], [1, 1], :cb) + __constraint!(ocp, :control, u->u[1:2], [0, 0], [1, 1], :cu) + __constraint!(ocp, :state, x->x[1:2], [0, 0], [1, 1], :cs) + __constraint!(ocp, :mixed, (x,u)->[x[1]+u[1], x[2]+u[2]], [0, 0], [1, 1], :cm) @test constraint(ocp, :cb)([13, 14, 15], [17, 18, 19]) == [13+17, 14+18] @test constraint(ocp, :cu)([12, 13, 14]) == [12, 13] @test constraint(ocp, :cs)([12, 13, 14]) == [12, 13] @@ -730,11 +736,11 @@ end variable!(ocp, 4) state!(ocp, 1) control!(ocp, 1) - constraint!(ocp, :variable, [ 0, 0, 0, 0 ], [ 1, 1, 1, 1 ], :eq1) - constraint!(ocp, :variable, Index(1), 0, 1, :eq2) - constraint!(ocp, :variable, 1:2, [ 0, 0 ], [ 1, 2 ], :eq3) - constraint!(ocp, :variable, 1:2:4, [ 0, 0 ], [ -1, 1 ], :eq4) - constraint!(ocp, :variable, v -> v.^2, [ 0, 0, 0, 0 ], [ 1, 0, 1, 0 ], :eq5) + __constraint!(ocp, :variable, [ 0, 0, 0, 0 ], [ 1, 1, 1, 1 ], :eq1) + __constraint!(ocp, :variable, Index(1), 0, 1, :eq2) + __constraint!(ocp, :variable, 1:2, [ 0, 0 ], [ 1, 2 ], :eq3) + __constraint!(ocp, :variable, 1:2:4, [ 0, 0 ], [ -1, 1 ], :eq4) + __constraint!(ocp, :variable, v -> v.^2, [ 0, 0, 0, 0 ], [ 1, 0, 1, 0 ], :eq5) @test constraint(ocp, :eq1)(v) == v @test constraint(ocp, :eq2)(v) == v[1] @test constraint(ocp, :eq3)(v) == v[1:2] @@ -755,15 +761,15 @@ end variable!(ocp, 4) state!(ocp, 1) control!(ocp, 1) - constraint!(ocp, :boundary, (x0, xf, v) -> x0 + xf + v[1], 0, 1, :cb) - constraint!(ocp, :control, (u, v) -> u + v[1], 0, 1, :cu) - constraint!(ocp, :state, (x, v) -> x + v[1], 0, 1, :cs) - constraint!(ocp, :mixed, (x, u, v) -> x + u + v[1], 1, 1, :cm) - constraint!(ocp, :variable, [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], :eq1) - constraint!(ocp, :variable, Index(1), 0, 0, :eq2) - constraint!(ocp, :variable, 1:2, [ 0, 0 ], [ 0, 0 ], :eq3) - constraint!(ocp, :variable, 1:2:4, [ 0, 0 ], [ 0, 0 ], :eq4) - constraint!(ocp, :variable, v -> v.^2, [ 0, 0, 0, 0 ], [ 0, 0, 0, 0], :eq5) + __constraint!(ocp, :boundary, (x0, xf, v) -> x0 + xf + v[1], 0, 1, :cb) + __constraint!(ocp, :control, (u, v) -> u + v[1], 0, 1, :cu) + __constraint!(ocp, :state, (x, v) -> x + v[1], 0, 1, :cs) + __constraint!(ocp, :mixed, (x, u, v) -> x + u + v[1], 1, 1, :cm) + __constraint!(ocp, :variable, [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], :eq1) + __constraint!(ocp, :variable, Index(1), 0, 0, :eq2) + __constraint!(ocp, :variable, 1:2, [ 0, 0 ], [ 0, 0 ], :eq3) + __constraint!(ocp, :variable, 1:2:4, [ 0, 0 ], [ 0, 0 ], :eq4) + __constraint!(ocp, :variable, v -> v.^2, [ 0, 0, 0, 0 ], [ 0, 0, 0, 0], :eq5) @test constraint(ocp, :cb)(x0, xf, v) == x0 + xf + v[1] @test constraint(ocp, :cu)(u, v) == u + v[1] @test constraint(ocp, :cs)(x, v) == x + v[1] @@ -799,8 +805,8 @@ end @testset "constraint! 10" begin ocp = Model(autonomous=false); time!(ocp, 0, 1); state!(ocp, 1); control!(ocp, 1) - constraint!(ocp, :initial, 0, 1, :c0) - constraint!(ocp, :final, 1, 2, :cf) + __constraint!(ocp, :initial, 0, 1, :c0) + __constraint!(ocp, :final, 1, 2, :cf) @test constraint(ocp, :c0)(12, ∅) == 12 @test constraint(ocp, :cf)(∅ ,12) == 12 @@ -811,43 +817,43 @@ end dummy(u) = u^2 + u ocp = Model(variable=true); time!(ocp, 0, 1); state!(ocp, 1); control!(ocp, 1); variable!(ocp,3) - constraint!(ocp, :state, 0, 1, :c0) - constraint!(ocp, :control, dummy, 1, 1, :c1) - constraint!(ocp, :variable, 1:2:3, [-Inf,-Inf], [0,0], :c2) + __constraint!(ocp, :state, 0, 1, :c0) + __constraint!(ocp, :control, dummy, 1, 1, :c1) + __constraint!(ocp, :variable, 1:2:3, [-Inf,-Inf], [0,0], :c2) ocp_bis = Model(variable=true); time!(ocp_bis, 0, 1); state!(ocp_bis, 1); control!(ocp_bis, 1); variable!(ocp_bis,3) - CTBase.__constraint!(ocp_bis, :state, lb=0, ub=1, label=:c0) - CTBase.__constraint!(ocp_bis, :control, f=dummy, ub=1, lb=1, label=:c1) - CTBase.__constraint!(ocp_bis, :variable, rg=1:2:3, ub=[0,0], label=:c2) + constraint!(ocp_bis, :state, lb=0, ub=1, label=:c0) + constraint!(ocp_bis, :control, f=dummy, ub=1, lb=1, label=:c1) + constraint!(ocp_bis, :variable, rg=1:2:3, ub=[0,0], label=:c2) @test ocp.constraints == ocp_bis.constraints ocp_ter = Model(variable=true); time!(ocp_ter, 0, 1); state!(ocp_ter, 3); control!(ocp_ter, 1); variable!(ocp_ter,1) - constraint!(ocp_ter, :variable, 1, 1, :c0) - constraint!(ocp_ter, :control, dummy, 1, Inf, :c1) - constraint!(ocp_ter, :state, 1:2:3, [0,0], [0,0], :c2) + __constraint!(ocp_ter, :variable, 1, 1, :c0) + __constraint!(ocp_ter, :control, dummy, 1, Inf, :c1) + __constraint!(ocp_ter, :state, 1:2:3, [0,0], [0,0], :c2) ocp_quad = Model(variable=true); time!(ocp_quad, 0, 1); state!(ocp_quad, 3); control!(ocp_quad, 1); variable!(ocp_quad,1) - CTBase.__constraint!(ocp_quad, :variable, lb=1, ub=1, label=:c0) - CTBase.__constraint!(ocp_quad, :control, f=dummy, lb=1, label=:c1) - CTBase.__constraint!(ocp_quad, :state, rg=1:2:3, lb=[0,0],ub=[0,0], label=:c2) + constraint!(ocp_quad, :variable, lb=1, ub=1, label=:c0) + constraint!(ocp_quad, :control, f=dummy, lb=1, label=:c1) + constraint!(ocp_quad, :state, rg=1:2:3, lb=[0,0], ub=[0,0], label=:c2) @test ocp_ter.constraints == ocp_quad.constraints ocp_error = ocp_error = Model(variable=true); time!(ocp_error, 0, 1); state!(ocp_error, 3); control!(ocp_error, 1); variable!(ocp_error,1) - @test_throws IncorrectArgument CTBase.__constraint!(ocp_error, :variable) - @test_throws IncorrectArgument CTBase.__constraint!(ocp_error, :control, f=dummy, label=:c1) - @test_throws IncorrectArgument CTBase.__constraint!(ocp_error, :state, rg=1:2:3, label=:c2) - @test_throws IncorrectArgument CTBase.__constraint!(ocp_error, :state, rg=1:2:3, f=dummy, lb=[0,0], ub=[0,0], label=:c3) - @test_throws IncorrectArgument CTBase.__constraint!(ocp_error, :state, f=dummy, rg=1:2:3, lb=[0,0], ub=[0,0], label=:c4) + @test_throws UnauthorizedCall constraint!(ocp_error, :variable) + @test_throws UnauthorizedCall constraint!(ocp_error, :control, f=dummy, label=:c1) + @test_throws UnauthorizedCall constraint!(ocp_error, :state, rg=1:2:3, label=:c2) + @test_throws UnauthorizedCall constraint!(ocp_error, :state, rg=1:2:3, f=dummy, lb=[0,0], ub=[0,0], label=:c3) + @test_throws UnauthorizedCall constraint!(ocp_error, :state, f=dummy, rg=1:2:3, lb=[0,0], ub=[0,0], label=:c4) end @testset "remove_constraint! and constraints_labels" begin ocp = Model(); time!(ocp, 0, 1); state!(ocp, 1); control!(ocp, 1) - constraint!(ocp, :boundary, (x0, xf) -> x0+xf, 0, 1, :cb) - constraint!(ocp, :control, u->u, 0, 1, :cu) + __constraint!(ocp, :boundary, (x0, xf) -> x0+xf, 0, 1, :cb) + __constraint!(ocp, :control, u->u, 0, 1, :cu) k = constraints_labels(ocp) @test :cb ∈ k @test :cu ∈ k @@ -861,14 +867,14 @@ end @testset "nlp_constraints without variable" begin ocp = Model(); time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 1) - constraint!(ocp, :initial, Index(2), 10, 10, :ci) - constraint!(ocp, :final, Index(1), 1, 1, :cf) - constraint!(ocp, :control, 0, 1, :cu) - constraint!(ocp, :state, [0, 1], [1, 2], :cs) - constraint!(ocp, :boundary, (x0, xf) -> x0[2]+xf[2], 0, 1, :cb) - constraint!(ocp, :control, u->u, 0, 1, :cuu) - constraint!(ocp, :state, x->x, [0, 1], [1, 2], :css) - constraint!(ocp, :mixed, (x,u)->x[1]+u, 1, 1, :cm) + __constraint!(ocp, :initial, Index(2), 10, 10, :ci) + __constraint!(ocp, :final, Index(1), 1, 1, :cf) + __constraint!(ocp, :control, 0, 1, :cu) + __constraint!(ocp, :state, [0, 1], [1, 2], :cs) + __constraint!(ocp, :boundary, (x0, xf) -> x0[2]+xf[2], 0, 1, :cb) + __constraint!(ocp, :control, u->u, 0, 1, :cuu) + __constraint!(ocp, :state, x->x, [0, 1], [1, 2], :css) + __constraint!(ocp, :mixed, (x,u)->x[1]+u, 1, 1, :cm) (ξl, ξ, ξu), (ηl, η, ηu), (ψl, ψ, ψu), (ϕl, ϕ, ϕu), (θl, θ, θu), (ul, uind, uu), (xl, xind, xu), (vl, vind, vu) = nlp_constraints(ocp) @@ -920,18 +926,18 @@ end variable!(ocp, 4) state!(ocp, 2) control!(ocp, 1) - constraint!(ocp, :initial, Index(2), 10, 10, :ci) - constraint!(ocp, :final, Index(1), 1, 1, :cf) - constraint!(ocp, :control, 0, 1, :cu) - constraint!(ocp, :state, [0, 1], [1, 2], :cs) - constraint!(ocp, :boundary, (x0, xf, v) -> x0[2]+xf[2]+v[1], 0, 1, :cb) - constraint!(ocp, :control, (u, v) -> u+v[2], 0, 1, :cuu) - constraint!(ocp, :state, (x, v) -> x+v[1:2], [0, 1], [1, 2], :css) - constraint!(ocp, :mixed, (x, u, v) -> x[1]+u+v[2], 1, 1, :cm) - constraint!(ocp, :variable, [ 0, 0, 0, 0 ], [ 5, 5, 5, 5 ], :cv1) - constraint!(ocp, :variable, 1:2, [ 1, 2 ], [ 3, 4 ], :cv2) - constraint!(ocp, :variable, Index(3), 2, 3, :cv3) - constraint!(ocp, :variable, v -> v[3]^2, 0, 1, :cv4) + __constraint!(ocp, :initial, Index(2), 10, 10, :ci) + __constraint!(ocp, :final, Index(1), 1, 1, :cf) + __constraint!(ocp, :control, 0, 1, :cu) + __constraint!(ocp, :state, [0, 1], [1, 2], :cs) + __constraint!(ocp, :boundary, (x0, xf, v) -> x0[2]+xf[2]+v[1], 0, 1, :cb) + __constraint!(ocp, :control, (u, v) -> u+v[2], 0, 1, :cuu) + __constraint!(ocp, :state, (x, v) -> x+v[1:2], [0, 1], [1, 2], :css) + __constraint!(ocp, :mixed, (x, u, v) -> x[1]+u+v[2], 1, 1, :cm) + __constraint!(ocp, :variable, [ 0, 0, 0, 0 ], [ 5, 5, 5, 5 ], :cv1) + __constraint!(ocp, :variable, 1:2, [ 1, 2 ], [ 3, 4 ], :cv2) + __constraint!(ocp, :variable, Index(3), 2, 3, :cv3) + __constraint!(ocp, :variable, v -> v[3]^2, 0, 1, :cv4) (ξl, ξ, ξu), (ηl, η, ηu), (ψl, ψ, ψu), (ϕl, ϕ, ϕu), (θl, θ, θu), (ul, uind, uu), (xl, xind, xu), (vl, vind, vu) = nlp_constraints(ocp) diff --git a/test/test_print.jl b/test/test_print.jl index 82cb22b4..9d51cba1 100644 --- a/test/test_print.jl +++ b/test/test_print.jl @@ -8,18 +8,18 @@ function test_print() state!(ocp, 2, "state", ["r", "v"]) # dimension of the state with the names of the components control!(ocp, 1) # dimension of the control time!(ocp, 0, 1, "s") # initial and final time, with the name of the variable time - constraint!(ocp, :initial, [-1, 0], [-1, 0]) - constraint!(ocp, :final , [ 0, 0], [0, 0]) + __constraint!(ocp, :initial, [-1, 0], [-1, 0]) + __constraint!(ocp, :final , [ 0, 0], [0, 0]) A = [ 0 1 0 0 ] B = [ 0 1 ] dynamics!(ocp, (t, x, u) -> A*x + B*u) - constraint!(ocp, :state, (t, x) -> x[2], 0, 1) - constraint!(ocp, :control, (t, u) -> u, -1, 1) - constraint!(ocp, :mixed, (t, x, u) -> x[1]+u, 2, 3) - constraint!(ocp, :state, Index(1), -10, 10) - constraint!(ocp, :control, -2, 2) + __constraint!(ocp, :state, (t, x) -> x[2], 0, 1) + __constraint!(ocp, :control, (t, u) -> u, -1, 1) + __constraint!(ocp, :mixed, (t, x, u) -> x[1]+u, 2, 3) + __constraint!(ocp, :state, Index(1), -10, 10) + __constraint!(ocp, :control, -2, 2) objective!(ocp, :bolza, (t0, x0, tf, xf) -> tf, (t, x, u) -> 0.5u^2) @test display(ocp) isa Nothing @@ -28,14 +28,14 @@ function test_print() state!(ocp, 1, "y") # dimension of the state with the names of the components control!(ocp, 1, "v") # dimension of the control time!(ocp, 0, 1, "s") # initial and final time, with the name of the variable time - constraint!(ocp, :initial, -1, -1) - constraint!(ocp, :final , 0, 0) + __constraint!(ocp, :initial, -1, -1) + __constraint!(ocp, :final , 0, 0) dynamics!(ocp, (t, x, u) -> x+u) - constraint!(ocp, :state, (t, x) -> x, 0, 1) - constraint!(ocp, :control, (t, u) -> u, -1, 1) - constraint!(ocp, :mixed, (t, x, u) -> x+u, 2, 3) - constraint!(ocp, :state, -10, 10) - constraint!(ocp, :control, -2, 2) + __constraint!(ocp, :state, (t, x) -> x, 0, 1) + __constraint!(ocp, :control, (t, u) -> u, -1, 1) + __constraint!(ocp, :mixed, (t, x, u) -> x+u, 2, 3) + __constraint!(ocp, :state, -10, 10) + __constraint!(ocp, :control, -2, 2) objective!(ocp, :mayer, (t0, x0, tf, xf) -> tf) @test display(ocp) isa Nothing @@ -45,8 +45,8 @@ function test_print() state!(ocp, 1, "y") # dimension of the state with the names of the components control!(ocp, 2) # dimension of the control time!(ocp, 0, Index(1), "s") # initial and final time, with the name of the variable time - constraint!(ocp, :initial, -1, -1) - constraint!(ocp, :final , 0, 0) + __constraint!(ocp, :initial, -1, -1) + __constraint!(ocp, :final , 0, 0) dynamics!(ocp, (t, x, u) -> x+u) objective!(ocp, :mayer, (t0, x0, tf, xf) -> tf) @test display(ocp) isa Nothing