From c3c5005902cc633c7c031532390d61ac3fbf8192 Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Sat, 27 Apr 2024 17:29:00 +0200 Subject: [PATCH 01/13] foo --- src/onepass.jl | 30 ++++++---- src/repl.jl | 77 +++++++++++++----------- test/test_onepass.jl | 137 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+), 45 deletions(-) diff --git a/src/onepass.jl b/src/onepass.jl index 5e12a464..bb154d87 100644 --- a/src/onepass.jl +++ b/src/onepass.jl @@ -96,16 +96,26 @@ parse!(p, ocp, e; log=false) = begin :( $e3 ≥ $e2 ≥ $e1, $label ) => p_constraint!(p, ocp, e1 , e2, e3 , label; log) :( $e2 ≥ $e1 ) => p_constraint!(p, ocp, e1 , e2, nothing ; log) :( $e2 ≥ $e1, $label ) => p_constraint!(p, ocp, e1 , e2, nothing, label; log) - :( ∫($e1) → min ) => p_lagrange!(p, ocp, e1, :min; log) - :( ∫($e1) → max ) => p_lagrange!(p, ocp, e1, :max; log) - :( $e1 + ∫($e2) → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) - :( $e1 - ∫($e2) → min ) => p_bolza!(p, ocp, e1, :( -$e2 ), :min; log) - :( $e1 + ∫($e2) → max ) => p_bolza!(p, ocp, e1, e2 , :max; log) - :( $e1 - ∫($e2) → max ) => p_bolza!(p, ocp, e1, :( -$e2 ), :max; log) - :( ∫($e2) + $e1 → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) - :( ∫($e2) - $e1 → min ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :min; log) - :( ∫($e2) + $e1 → max ) => p_bolza!(p, ocp, e1, e2 , :max; log) - :( ∫($e2) - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :max; log) + :( ∫($e1) → min ) => p_lagrange!(p, ocp, e1, :min; log) + :( $e1 * ∫($e2) → min ) => p_lagrange!(p, ocp, :( $e1 * $e2 ), :min; log) + :( ∫($e1) → max ) => p_lagrange!(p, ocp, e1, :max; log) + :( $e1 * ∫($e2) → max ) => p_lagrange!(p, ocp, :( $e1 * $e2 ), :max; log) + :( $e1 + ∫($e2) → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) + :( $e1 + $e2 * ∫($e3) → min ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :min; log) + :( $e1 - ∫($e2) → min ) => p_bolza!(p, ocp, e1, :( -$e2 ) , :min; log) + :( $e1 - $e2 * ∫($e3) → min ) => p_bolza!(p, ocp, e1, :( -$e2 * $e3 ), :min; log) + :( $e1 + ∫($e2) → max ) => p_bolza!(p, ocp, e1, e2 , :max; log) + :( $e1 + $e2 * ∫($e3) → max ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :max; log) + :( $e1 - ∫($e2) → max ) => p_bolza!(p, ocp, e1, :( -$e2 ) , :max; log) + :( $e1 - $e2 * ∫($e3) → max ) => p_bolza!(p, ocp, e1, :( -$e2 * $e3 ), :max; log) + :( ∫($e2) + $e1 → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) + :( $e2 * ∫($e3) + $e1 → min ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :min; log) + :( ∫($e2) - $e1 → min ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :min; log) + :( $e2 * ∫($e3) - $e1 → min ) => p_bolza!(p, ocp, :( -$e1 ), :( $e2 * $e3 ), :min; log) + :( ∫($e2) + $e1 → max ) => p_bolza!(p, ocp, e1, e2 , :max; log) + :( $e2 * ∫($e3) + $e1 → max ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :max; log) + :( ∫($e2) - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :max; log) + :( $e2 * ∫($e3) - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), :( $e2 * $e3 ), :max; log) :( $e1 → min ) => p_mayer!(p, ocp, e1, :min; log) :( $e1 → max ) => p_mayer!(p, ocp, e1, :max; log) _ => begin diff --git a/src/repl.jl b/src/repl.jl index 3ccb168b..c4d16c13 100644 --- a/src/repl.jl +++ b/src/repl.jl @@ -141,6 +141,47 @@ end # utils functions # ---------------------------------------------------------------- +function NAME_ACTION_FUNCTION(ct_repl_data::CTRepl, history::HistoryRepl) + println("") + println("Optimal control problem name: ", ct_repl_data.ocp_name) + println("Solution name: ", ct_repl_data.sol_name) +end + +function NAME_ACTION_FUNCTION(ct_repl_data::CTRepl, name::Union{Symbol, Expr}, history::HistoryRepl) + ocp_name = ct_repl_data.ocp_name + sol_name = ct_repl_data.sol_name + if isa(name, Symbol) + name = (name, Symbol(string(name, "_sol"))) + elseif isa(name, Expr) + name = (name.args[1], name.args[2]) + else + println("\nname error\n\nType HELP to see the list of commands or enter a valid expression to update the model.") + return nothing + end + ct_repl_data.ocp_name = name[1] + ct_repl_data.sol_name = name[2] + ct_repl_data.debug && println("debug> ocp name: ", ct_repl_data.ocp_name) + ct_repl_data.debug && println("debug> sol name: ", ct_repl_data.sol_name) + __add!(history, ct_repl_data) # update history + qo1 = ct_repl_data.ocp_name ≠ ocp_name ? :($(ct_repl_data.ocp_name) = "no optimal control") : :() + qs1 = ct_repl_data.sol_name ≠ sol_name ? :($(ct_repl_data.sol_name) = "no solution") : :() + qo2 = ct_repl_data.ocp_name ≠ ocp_name ? :($(ct_repl_data.ocp_name) = $(ocp_name)) : :() + qs2 = ct_repl_data.sol_name ≠ sol_name ? :($(ct_repl_data.sol_name) = $(sol_name)) : :() + name_q = (quote + $(qo1) + $(qs1) + try + $(qo2) + $(qs2) + nothing + catch e + nothing + end + end) + ct_repl_data.debug && println("debug> new name quote: ", name_q) + return name_q +end + # dict of actions associated to ct repl commands COMMANDS_ACTIONS = Dict{Symbol, Function}( :SHOW => (ct_repl_data::CTRepl, history::HistoryRepl) -> begin @@ -158,40 +199,7 @@ COMMANDS_ACTIONS = Dict{Symbol, Function}( __add!(history, ct_repl_data) # update history return nothing end, - :NAME => (ct_repl_data::CTRepl, name::Union{Symbol, Expr}, history::HistoryRepl) -> begin - ocp_name = ct_repl_data.ocp_name - sol_name = ct_repl_data.sol_name - if isa(name, Symbol) - name = (name, Symbol(string(name, "_sol"))) - elseif isa(name, Expr) - name = (name.args[1], name.args[2]) - else - println("\nname error\n\nType HELP to see the list of commands or enter a valid expression to update the model.") - return nothing - end - ct_repl_data.ocp_name = name[1] - ct_repl_data.sol_name = name[2] - ct_repl_data.debug && println("debug> ocp name: ", ct_repl_data.ocp_name) - ct_repl_data.debug && println("debug> sol name: ", ct_repl_data.sol_name) - __add!(history, ct_repl_data) # update history - qo1 = ct_repl_data.ocp_name ≠ ocp_name ? :($(ct_repl_data.ocp_name) = "no optimal control") : :() - qs1 = ct_repl_data.sol_name ≠ sol_name ? :($(ct_repl_data.sol_name) = "no solution") : :() - qo2 = ct_repl_data.ocp_name ≠ ocp_name ? :($(ct_repl_data.ocp_name) = $(ocp_name)) : :() - qs2 = ct_repl_data.sol_name ≠ sol_name ? :($(ct_repl_data.sol_name) = $(sol_name)) : :() - name_q = (quote - $(qo1) - $(qs1) - try - $(qo2) - $(qs2) - nothing - catch e - nothing - end - end) - ct_repl_data.debug && println("debug> new name quote: ", name_q) - return name_q - end, + :NAME => NAME_ACTION_FUNCTION, :UNDO => (ct_repl_data::CTRepl, history::HistoryRepl) -> begin ct_repl_data_ = __undo!(history) __copy!(ct_repl_data, ct_repl_data_) @@ -299,7 +307,6 @@ end # get code from model and an extra expression function __code(model::ModelRepl, e::Expr) - println("ici") model_ = deepcopy(model) # copy model __update!(model_, e) # update model_ return __code(model_) # get code diff --git a/test/test_onepass.jl b/test/test_onepass.jl index 8e4948be..c2a5a4d6 100644 --- a/test/test_onepass.jl +++ b/test/test_onepass.jl @@ -113,6 +113,30 @@ B = [ 0 @test o.lagrange(x, u) == 0.5u^2 @test o.criterion == :min +t0 = 0 +tf = 1 +@def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + 0.5 * ∫( u(t)^2 ) → min +end +x = [ 1, 2 ] +x0 = 2 * x +xf = 3 * x +u = -1 +A = [ 0 1 + 0 0 ] +B = [ 0 + 1 ] +@test constraint(o, :eq1)(x0, xf) == x0 +@test o.dynamics(x, u) == A * x + B * u +@test o.lagrange(x, u) == 0.5u^2 +@test o.criterion == :min + a = 1 f(b) = begin # closure of a, local c, and @def in function c = 3 @@ -573,6 +597,21 @@ xf = 4 @test o.lagrange(x, u) == x + u @test o.criterion == :min + +@def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + (x(0) + 2x(1)) + 1 * ∫(x(t) + u(t)) → min +end +x = 1 +u = 2 +x0 = 3 +xf = 4 +@test o.mayer(x0, xf) == x0 + 2xf +@test o.lagrange(x, u) == x + u +@test o.criterion == :min + @def o begin t ∈ [ 0, 1 ], time x, state @@ -587,6 +626,20 @@ xf = 4 @test o.lagrange(x, u) == -(x + u) @test o.criterion == :min +@def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + (x(0) + 2x(1)) - 1 * ∫(x(t) + u(t)) → min +end +x = 1 +u = 2 +x0 = 3 +xf = 4 +@test o.mayer(x0, xf) == x0 + 2xf +@test o.lagrange(x, u) == -(x + u) +@test o.criterion == :min + @def o begin t ∈ [ 0, 1 ], time x, state @@ -601,6 +654,20 @@ xf = 4 @test o.lagrange(x, u) == x + u @test o.criterion == :max +@def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + (x(0) + 2x(1)) + 1 * ∫(x(t) + u(t)) → max +end +x = 1 +u = 2 +x0 = 3 +xf = 4 +@test o.mayer(x0, xf) == x0 + 2xf +@test o.lagrange(x, u) == x + u +@test o.criterion == :max + @def o begin t ∈ [ 0, 1 ], time x, state @@ -615,6 +682,20 @@ xf = 4 @test o.lagrange(x, u) == -(x + u) @test o.criterion == :max +@def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + (x(0) + 2x(1)) - 1 * ∫(x(t) + u(t)) → max +end +x = 1 +u = 2 +x0 = 3 +xf = 4 +@test o.mayer(x0, xf) == x0 + 2xf +@test o.lagrange(x, u) == -(x + u) +@test o.criterion == :max + @def o begin t ∈ [ 0, 1 ], time x, state @@ -629,6 +710,20 @@ xf = 4 @test o.lagrange(x, u) == x + u @test o.criterion == :min +@def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + 1 * ∫(x(t) + u(t)) + (x(0) + 2x(1)) → min +end +x = 1 +u = 2 +x0 = 3 +xf = 4 +@test o.mayer(x0, xf) == x0 + 2xf +@test o.lagrange(x, u) == x + u +@test o.criterion == :min + @def o begin t ∈ [ 0, 1 ], time x, state @@ -643,6 +738,20 @@ xf = 4 @test o.lagrange(x, u) == x + u @test o.criterion == :min +@def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + 1 * ∫(x(t) + u(t)) - (x(0) + 2x(1)) → min +end +x = 1 +u = 2 +x0 = 3 +xf = 4 +@test o.mayer(x0, xf) == -(x0 + 2xf) +@test o.lagrange(x, u) == x + u +@test o.criterion == :min + @def o begin t ∈ [ 0, 1 ], time x, state @@ -657,6 +766,20 @@ xf = 4 @test o.lagrange(x, u) == x + u @test o.criterion == :max +@def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + 1 * ∫(x(t) + u(t)) + (x(0) + 2x(1)) → max +end +x = 1 +u = 2 +x0 = 3 +xf = 4 +@test o.mayer(x0, xf) == x0 + 2xf +@test o.lagrange(x, u) == x + u +@test o.criterion == :max + @def o begin t ∈ [ 0, 1 ], time x, state @@ -671,6 +794,20 @@ xf = 4 @test o.lagrange(x, u) == x + u @test o.criterion == :max +@def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + 1 * ∫(x(t) + u(t)) - (x(0) + 2x(1)) → max +end +x = 1 +u = 2 +x0 = 3 +xf = 4 +@test o.mayer(x0, xf) == -(x0 + 2xf) +@test o.lagrange(x, u) == x + u +@test o.criterion == :max + @def o begin t ∈ [ 0, 1 ], time x, state From 0decc95177f9ab33dc7213c83e189429596817a0 Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Sun, 5 May 2024 18:59:53 +0200 Subject: [PATCH 02/13] foo --- src/model.jl | 73 +++++++++++++++++++++++++++++--------------- src/onepass.jl | 46 +++++++++++++++++++++++----- test/test_model.jl | 60 ++++++++++++++++++++++-------------- test/test_onepass.jl | 33 ++++++++++++-------- 4 files changed, 146 insertions(+), 66 deletions(-) diff --git a/src/model.jl b/src/model.jl index d9ffaaf4..4c4bc551 100644 --- a/src/model.jl +++ b/src/model.jl @@ -113,7 +113,7 @@ Define the variable dimension and possibly the names of each component. # Examples ```jldoctest julia> variable!(ocp, 1, "v") -julia> variable!(ocp, 2, "v", [ "v₁", "v₂" ]) +julia> variable!(ocp, 2, "v", [ "v₁", "v₂" ]) ``` """ function variable!(ocp::OptimalControlModel, q::Dimension, name::String=__variable_name(), @@ -129,6 +129,14 @@ function variable!(ocp::OptimalControlModel, q::Dimension, name::String=__variab nothing # to force to return nothing end +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}) + variable!(ocp, q, string(name), components_names) +end + function variable!(ocp::OptimalControlModel, q::Dimension, name::Symbol) variable!(ocp, q, string(name)) end @@ -187,6 +195,15 @@ function state!(ocp::OptimalControlModel, n::Dimension, name::String=__state_nam ocp.state_name = name nothing # to force to return nothing end + +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}) + state!(ocp, n, string(name), components_names) +end + function state!(ocp::OptimalControlModel, n::Dimension, name::Symbol) state!(ocp, n, string(name)) end @@ -246,6 +263,14 @@ function control!(ocp::OptimalControlModel, m::Dimension, name::String=__control nothing # to force to return nothing end +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}) + control!(ocp, m, string(name), components_names) +end + function control!(ocp::OptimalControlModel, m::Dimension, name::Symbol) control!(ocp, m, string(name)) end @@ -438,12 +463,12 @@ Add an `:initial`, `:final`, `:control`, `:state` or `:variable` box constraint # Examples ```jldoctest -julia> constraint!(ocp, :initial, 2:3, [ 0, 0 ], [ 1, 2 ]) +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 ]) +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::ctVector, ub::ctVector, @@ -512,8 +537,8 @@ Add an `:initial` or `:final` value constraint on a range of the state, or a val # Examples ```jldoctest -julia> constraint!(ocp, :initial, 1:2:5, [ 0, 0, 0 ]) -julia> constraint!(ocp, :initial, 2:3, [ 0, 0 ]) +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 ]) ``` @@ -566,9 +591,9 @@ Add an `:initial` or `:final` value constraint on the state, or a `:variable` va # Examples ```jldoctest -julia> constraint!(ocp, :initial, [ 0, 0 ]) +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 ]) +julia> constraint!(ocp, :variable, [ 3, 0, 1 ]) ``` """ function constraint!(ocp::OptimalControlModel, type::Symbol, val::ctVector, label::Symbol=__constraint_label()) @@ -618,10 +643,10 @@ Add an `:initial`, `:final`, `:control`, `:state` or `:variable` box constraint # Examples ```jldoctest -julia> constraint!(ocp, :initial, [ 0, 0, 0 ], [ 1, 2, 1 ]) -julia> constraint!(ocp, :final, [ 0, 0, 0 ], [ 1, 2, 1 ]) +julia> constraint!(ocp, :initial, [ 0, 0, 0 ], [ 1, 2, 1 ]) +julia> constraint!(ocp, :final, [ 0, 0, 0 ], [ 1, 2, 1 ]) julia> constraint!(ocp, :control, [ 0, 0 ], [ 2, 3 ]) -julia> constraint!(ocp, :state, [ 0, 0, 0 ], [ 1, 2, 1 ]) +julia> constraint!(ocp, :state, [ 0, 0, 0 ], [ 1, 2, 1 ]) julia> constraint!(ocp, :variable, 0, 1) # the variable here is of dimension 1 ``` """ @@ -687,22 +712,22 @@ julia> constraint!(ocp, :boundary, (x0, xf, v) -> x0[3]+xf[2]*v[1], 0, 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, :state, x -> x-1, [ 0, 0, 0 ], [ 1, 2, 1 ]) julia> constraint!(ocp, :mixed, (x, u) -> x[1]-u, 0, 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, :state, (t, x) -> x-t, [ 0, 0, 0 ], [ 1, 2, 1 ]) julia> constraint!(ocp, :mixed, (t, x, u) -> x[1]-u, 0, 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, :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) # 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, :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) ``` """ @@ -761,22 +786,22 @@ 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, :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, :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, :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, :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) ``` """ @@ -800,12 +825,12 @@ Add an `:initial`, `:final`, `:control`, `:state` or `:variable` box constraint # Examples ```jldoctest -julia> constraint!(ocp, :initial, rg=2:3, lb=[ 0, 0 ], ub=[ 1, 2 ]) +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, :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 ]) +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; diff --git a/src/onepass.jl b/src/onepass.jl index bb154d87..7519a280 100644 --- a/src/onepass.jl +++ b/src/onepass.jl @@ -73,19 +73,33 @@ parse!(p, ocp, e; log=false) = begin e = subs(e, a, p.aliases[a]) end @match e begin + # + :( $a = $e1 ) => + @match e1 begin + :( ($names) ∈ R^$q, variable ) => p_variable!(p, ocp, a, q; components_names=names, log) + :( ($names) ∈ R^$n, state ) => p_state!(p, ocp, a, n; components_names=names, log) + :( ($names) ∈ R^$m, control ) => p_control!(p, ocp, a, m; components_names=names, log) + :( ($names) ∈ R, $dummy ) => return __throw("unknown syntax", p.lnum, p.line) + _ => p_alias!(p, ocp, a, e1; log) # alias + end + # variable :( $v ∈ R^$q, variable ) => p_variable!(p, ocp, v, q; log) :( $v ∈ R , variable ) => p_variable!(p, ocp, v ; log) :( $v , variable ) => p_variable!(p, ocp, v ; log) # todo: remove + # time :( $t ∈ [ $t0, $tf ], time ) => p_time!(p, ocp, t, t0, tf; log) + # state :( $x ∈ R^$n, state ) => p_state!(p, ocp, x, n; log) :( $x ∈ R , state ) => p_state!(p, ocp, x ; log) :( $x , state ) => p_state!(p, ocp, x ; log) # todo: remove + # control :( $u ∈ R^$m, control ) => p_control!(p, ocp, u, m; log) :( $u ∈ R , control ) => p_control!(p, ocp, u ; log) :( $u , control ) => p_control!(p, ocp, u ; log) # todo: remove - :( $a = $e1 ) => p_alias!(p, ocp, a, e1; log) + # dynamics :( ∂($x)($t) == $e1 ) => p_dynamics!(p, ocp, x, t, e1 ; log) :( ∂($x)($t) == $e1, $label ) => p_dynamics!(p, ocp, x, t, e1, label; log) + # constraints :( $e1 == $e2 ) => p_constraint!(p, ocp, e2 , e1, e2 ; log) :( $e1 == $e2, $label ) => p_constraint!(p, ocp, e2 , e1, e2, label; log) :( $e1 ≤ $e2 ≤ $e3 ) => p_constraint!(p, ocp, e1 , e2, e3 ; log) @@ -96,10 +110,12 @@ parse!(p, ocp, e; log=false) = begin :( $e3 ≥ $e2 ≥ $e1, $label ) => p_constraint!(p, ocp, e1 , e2, e3 , label; log) :( $e2 ≥ $e1 ) => p_constraint!(p, ocp, e1 , e2, nothing ; log) :( $e2 ≥ $e1, $label ) => p_constraint!(p, ocp, e1 , e2, nothing, label; log) + # lagrange cost :( ∫($e1) → min ) => p_lagrange!(p, ocp, e1, :min; log) :( $e1 * ∫($e2) → min ) => p_lagrange!(p, ocp, :( $e1 * $e2 ), :min; log) :( ∫($e1) → max ) => p_lagrange!(p, ocp, e1, :max; log) :( $e1 * ∫($e2) → max ) => p_lagrange!(p, ocp, :( $e1 * $e2 ), :max; log) + # bolza cost :( $e1 + ∫($e2) → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) :( $e1 + $e2 * ∫($e3) → min ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :min; log) :( $e1 - ∫($e2) → min ) => p_bolza!(p, ocp, e1, :( -$e2 ) , :min; log) @@ -116,6 +132,7 @@ parse!(p, ocp, e; log=false) = begin :( $e2 * ∫($e3) + $e1 → max ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :max; log) :( ∫($e2) - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :max; log) :( $e2 * ∫($e3) - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), :( $e2 * $e3 ), :max; log) + # mayer cost :( $e1 → min ) => p_mayer!(p, ocp, e1, :min; log) :( $e1 → max ) => p_mayer!(p, ocp, e1, :max; log) _ => begin @@ -132,7 +149,7 @@ parse!(p, ocp, e; log=false) = begin end end -p_variable!(p, ocp, v, q=1; log=false) = begin +p_variable!(p, ocp, v, q=1; components_names=nothing, log=false) = begin log && println("variable: $v, dim: $q") v isa Symbol || return __throw("forbidden variable name: $v", p.lnum, p.line) p.v = v @@ -140,7 +157,12 @@ p_variable!(p, ocp, v, q=1; log=false) = begin qq = q isa Integer ? q : 9 for i ∈ 1:qq p.aliases[Symbol(v, ctindices(i))] = :( $v[$i] ) end for i ∈ 1:9 p.aliases[Symbol(v, ctupperscripts(i))] = :( $v^$i ) end - __wrap(:( variable!($ocp, $q, $vv) ), p.lnum, p.line) + if (isnothing(components_names)) + __wrap(:( variable!($ocp, $q, $vv) ), p.lnum, p.line) + else + ss = QuoteNode(string.(components_names.args)) + __wrap(:( variable!($ocp, $q, $vv, $ss) ), p.lnum, p.line) + end end p_alias!(p, ocp, a, e; log=false) = begin @@ -187,7 +209,7 @@ p_time!(p, ocp, t, t0, tf; log=false) = begin __wrap(code, p.lnum, p.line) end -p_state!(p, ocp, x, n=1; log=false) = begin +p_state!(p, ocp, x, n=1; components_names=nothing, log=false) = begin log && println("state: $x, dim: $n") x isa Symbol || return __throw("forbidden state name: $x", p.lnum, p.line) p.x = x @@ -196,10 +218,15 @@ p_state!(p, ocp, x, n=1; log=false) = begin for i ∈ 1:nn p.aliases[Symbol(x, ctindices(i))] = :( $x[$i] ) end for i ∈ 1:9 p.aliases[Symbol(x, ctupperscripts(i))] = :( $x^$i ) end p.aliases[Symbol(Unicode.normalize(string(x,"̇")))] = :( ∂($x) ) - __wrap(:( state!($ocp, $n, $xx) ), p.lnum, p.line) + if (isnothing(components_names)) + __wrap(:( state!($ocp, $n, $xx) ), p.lnum, p.line) + else + ss = QuoteNode(string.(components_names.args)) + __wrap(:( state!($ocp, $n, $xx, $ss) ), p.lnum, p.line) + end end -p_control!(p, ocp, u, m=1; log=false) = begin +p_control!(p, ocp, u, m=1; components_names=nothing, log=false) = begin log && println("control: $u, dim: $m") u isa Symbol || return __throw("forbidden control name: $u", p.lnum, p.line) p.u = u @@ -207,7 +234,12 @@ p_control!(p, ocp, u, m=1; log=false) = begin mm = m isa Integer ? m : 9 for i ∈ 1:mm p.aliases[Symbol(u, ctindices(i))] = :( $u[$i] ) end for i ∈ 1:9 p.aliases[Symbol(u, ctupperscripts(i))] = :( $u^$i ) end - __wrap(:( control!($ocp, $m, $uu) ), p.lnum, p.line) + if (isnothing(components_names)) + __wrap(:( control!($ocp, $m, $uu) ), p.lnum, p.line) + else + ss = QuoteNode(string.(components_names.args)) + __wrap(:( control!($ocp, $m, $uu, $ss) ), p.lnum, p.line) + end end p_constraint!(p, ocp, e1, e2, e3, label=gensym(); log=false) = begin diff --git a/test/test_model.jl b/test/test_model.jl index 744431d1..18040be2 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -7,8 +7,8 @@ function test_model() # 30 55 185 @test_throws UnauthorizedCall variable!(ocp, 1) @test_throws UnauthorizedCall constraint!(ocp, :variable, 2: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, 1:2, [ 0, 0 ], [ 1, 2 ]) + @test_throws UnauthorizedCall constraint!(ocp, :variable, [ 3, 0, 1 ]) ocp = Model(variable=true) variable!(ocp, 1) @@ -34,6 +34,11 @@ function test_model() # 30 55 185 @test ocp.variable_dimension == 2 @test ocp.variable_components_names == [ "vv₁", "vv₂" ] + ocp = Model(variable=true) + variable!(ocp, 2, "uu", [ "vv₁", "vv₂" ]) + @test ocp.variable_dimension == 2 + @test ocp.variable_components_names == [ "vv₁", "vv₂" ] + ocp = Model(variable=true) @test_throws MethodError variable!(ocp, 2, [ "vv1", "vv2" ]) @@ -42,7 +47,6 @@ function test_model() # 30 55 185 @test ocp.variable_dimension == 2 @test ocp.variable_components_names == [ "vv₁", "vv₂" ] - end @testset "time, state and control set or not" begin @@ -59,26 +63,26 @@ 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, :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) # constraint! 2 - @test_throws UnauthorizedCall constraint!(ocp, :initial, [ 0, 0 ]) + @test_throws UnauthorizedCall constraint!(ocp, :initial, [ 0, 0 ]) @test_throws UnauthorizedCall constraint!(ocp, :final, 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, :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, :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, :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, :state, [ 0, 0, 0 ], [ 1, 2, 1 ]) # constraint! 5 # variable independent ocp @@ -89,22 +93,22 @@ end # 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, :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, :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, :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, :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 @@ -116,22 +120,22 @@ end # 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, :state, x -> x-1, [ 0, 0, 0 ]) @test_throws UnauthorizedCall constraint!(ocp, :mixed, (x, u) -> x[1]-u, 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, :state, (t, x) -> x-t, [ 0, 0, 0 ]) @test_throws UnauthorizedCall constraint!(ocp, :mixed, (t, x, u) -> x[1]-u, 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, :state, (x, v) -> x-v[2], [ 0, 0, 0 ]) @test_throws UnauthorizedCall constraint!(ocp, :mixed, (x, u) -> x[1]-u+v[1], 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, :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) end @@ -344,6 +348,11 @@ end state!(ocp, 2, "y") @test ocp.state_dimension == 2 @test ocp.state_components_names == ["y₁", "y₂"] + + ocp = Model() + state!(ocp, 2, "y", ["z₁", "z₂"]) + @test ocp.state_dimension == 2 + @test ocp.state_components_names == ["z₁", "z₂"] end @testset "control!" begin @@ -374,6 +383,11 @@ end control!(ocp, 2, "v") @test ocp.control_dimension == 2 @test ocp.control_components_names == ["v₁", "v₂"] + + ocp = Model() + control!(ocp, 2, "u", ["v₁", "v₂"]) + @test ocp.control_dimension == 2 + @test ocp.control_components_names == ["v₁", "v₂"] end @testset "time!" begin @@ -716,7 +730,7 @@ 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, [ 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) @@ -745,7 +759,7 @@ 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, [ 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) @@ -912,7 +926,7 @@ end 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, [ 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) diff --git a/test/test_onepass.jl b/test/test_onepass.jl index c2a5a4d6..1c22ede4 100644 --- a/test/test_onepass.jl +++ b/test/test_onepass.jl @@ -2,13 +2,22 @@ function test_onepass() +@def o begin + x = (y, z) ∈ R², state + u = (uu1, uu2, uu3) ∈ R³, control + v = (vv1, vv2) ∈ R², variable +end +@test o.state_components_names == [ "y", "z" ] +@test o.control_components_names == [ "uu1", "uu2", "uu3" ] +@test o.variable_components_names == [ "vv1", "vv2" ] + t0 = 0 @def o t ∈ [ t0, t0 + 4 ], time @test o.initial_time == t0 @test o.final_time == t0 + 4 @def o begin - λ ∈ R^2, variable + λ ∈ R^2, variable tf = λ₂ t ∈ [ 0, tf ], time end @@ -887,9 +896,9 @@ z = v[1] + 2v[2] x(1) ≤ 0 x(1) ≤ 0, (2) x³(0) ≤ 0 - x³(0) ≤ 0,   (3) + x³(0) ≤ 0, (3) x³(1) ≤ 0 - x³(1) ≤ 0,   (4) + x³(1) ≤ 0, (4) x(t) ≤ 0 x(t) ≤ 0, (5) x(t) ≤ 0 @@ -899,17 +908,17 @@ z = v[1] + 2v[2] u₁(t) ≤ 0 u₁(t) ≤ 0, (8) x³(t) ≤ 0 - x³(t) ≤ 0,   (9) + x³(t) ≤ 0, (9) x³(t) ≤ 0 - x³(t) ≤ 0,   (10) + x³(t) ≤ 0, (10) (u₁^3)(t) ≤ 0 (u₁^3)(t) ≤ 0, (11) (u₁^3)(t) ≤ 0 - (u₁^3)(t) ≤ 0,   (12) + (u₁^3)(t) ≤ 0, (12) x(t) + (u₁^3)(t) ≤ 0 x(t) + (u₁^3)(t) ≤ 0, (13) x(t) + (u₁^3)(t) ≤ 0 - x(t) + (u₁^3)(t) ≤ 0,   (14) + x(t) + (u₁^3)(t) ≤ 0, (14) v ≤ 0 v ≤ 0, (15) end @@ -955,9 +964,9 @@ end x(1) ≥ 0 x(1) ≥ 0, (2) x³(0) ≥ 0 - x³(0) ≥ 0,   (3) + x³(0) ≥ 0, (3) x³(1) ≥ 0 - x³(1) ≥ 0,   (4) + x³(1) ≥ 0, (4) x(t) ≥ 0 x(t) ≥ 0, (5) x(t) ≥ 0 @@ -967,13 +976,13 @@ end u₁(t) ≥ 0 u₁(t) ≥ 0, (8) x³(t) ≥ 0 - x³(t) ≥ 0,   (9) + x³(t) ≥ 0, (9) x³(t) ≥ 0 - x³(t) ≥ 0,   (10) + x³(t) ≥ 0, (10) (u₁^3)(t) ≥ 0 (u₁^3)(t) ≥ 0, (11) (u₁^3)(t) ≥ 0 - (u₁^3)(t) ≥ 0,   (12) + (u₁^3)(t) ≥ 0, (12) x(t) + (u₁^3)(t) ≥ 0 x(t) + (u₁^3)(t) ≥ 0, (13) x(t) + (u₁^3)(t) ≥ 0 From 677f2560c159c0c4eaf0c623eeae29910ef1504d Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Wed, 15 May 2024 14:57:59 +0200 Subject: [PATCH 03/13] add labeling state, control and variable from declaration --- src/onepass.jl | 97 ++++++++++++++++++++++++-------------------- test/test_onepass.jl | 52 +++++++++++++++++++++++- 2 files changed, 103 insertions(+), 46 deletions(-) diff --git a/src/onepass.jl b/src/onepass.jl index 7519a280..aeb42101 100644 --- a/src/onepass.jl +++ b/src/onepass.jl @@ -83,58 +83,62 @@ parse!(p, ocp, e; log=false) = begin _ => p_alias!(p, ocp, a, e1; log) # alias end # variable - :( $v ∈ R^$q, variable ) => p_variable!(p, ocp, v, q; log) - :( $v ∈ R , variable ) => p_variable!(p, ocp, v ; log) - :( $v , variable ) => p_variable!(p, ocp, v ; log) # todo: remove + :( ($e1, $e2) ∈ R^$q, variable ) => return __throw("unknown syntax: please provide a name to the variable", p.lnum, p.line) + :( $v ∈ R^$q, variable ) => p_variable!(p, ocp, v, q; log) + :( $v ∈ R , variable ) => p_variable!(p, ocp, v ; log) + :( $v , variable ) => p_variable!(p, ocp, v ; log) # todo: remove # time - :( $t ∈ [ $t0, $tf ], time ) => p_time!(p, ocp, t, t0, tf; log) + :( $t ∈ [ $t0, $tf ], time ) => p_time!(p, ocp, t, t0, tf; log) # state - :( $x ∈ R^$n, state ) => p_state!(p, ocp, x, n; log) - :( $x ∈ R , state ) => p_state!(p, ocp, x ; log) - :( $x , state ) => p_state!(p, ocp, x ; log) # todo: remove + :( ($e1, $e2) ∈ R^$n, state ) => return __throw("unknown syntax: please provide a name to the state", p.lnum, p.line) + :( $x ∈ R^$n, state ) => p_state!(p, ocp, x, n; log) + :( $x ∈ R , state ) => p_state!(p, ocp, x ; log) + :( $x , state ) => p_state!(p, ocp, x ; log) # todo: remove # control - :( $u ∈ R^$m, control ) => p_control!(p, ocp, u, m; log) - :( $u ∈ R , control ) => p_control!(p, ocp, u ; log) - :( $u , control ) => p_control!(p, ocp, u ; log) # todo: remove + :( ($e1, $e2) ∈ R^$m, control ) => return __throw("unknown syntax: please provide a name to the control", p.lnum, p.line) + :( $u ∈ R^$m, control ) => p_control!(p, ocp, u, m; log) + :( $u ∈ R , control ) => p_control!(p, ocp, u ; log) + :( $u , control ) => p_control!(p, ocp, u ; log) # todo: remove # dynamics - :( ∂($x)($t) == $e1 ) => p_dynamics!(p, ocp, x, t, e1 ; log) - :( ∂($x)($t) == $e1, $label ) => p_dynamics!(p, ocp, x, t, e1, label; log) + :( ∂($x)($t) == $e1 ) => p_dynamics!(p, ocp, x, t, e1 ; log) + :( ∂($x)($t) == $e1, $label ) => p_dynamics!(p, ocp, x, t, e1, label; log) # constraints - :( $e1 == $e2 ) => p_constraint!(p, ocp, e2 , e1, e2 ; log) - :( $e1 == $e2, $label ) => p_constraint!(p, ocp, e2 , e1, e2, label; log) - :( $e1 ≤ $e2 ≤ $e3 ) => p_constraint!(p, ocp, e1 , e2, e3 ; log) - :( $e1 ≤ $e2 ≤ $e3, $label ) => p_constraint!(p, ocp, e1 , e2, e3 , label; log) - :( $e2 ≤ $e3 ) => p_constraint!(p, ocp, nothing, e2, e3 ; log) - :( $e2 ≤ $e3, $label ) => p_constraint!(p, ocp, nothing, e2, e3 , label; log) - :( $e3 ≥ $e2 ≥ $e1 ) => p_constraint!(p, ocp, e1 , e2, e3 ; log) - :( $e3 ≥ $e2 ≥ $e1, $label ) => p_constraint!(p, ocp, e1 , e2, e3 , label; log) - :( $e2 ≥ $e1 ) => p_constraint!(p, ocp, e1 , e2, nothing ; log) - :( $e2 ≥ $e1, $label ) => p_constraint!(p, ocp, e1 , e2, nothing, label; log) + :( $e1 == $e2 ) => p_constraint!(p, ocp, e2 , e1, e2 ; log) + :( $e1 == $e2, $label ) => p_constraint!(p, ocp, e2 , e1, e2, label; log) + :( $e1 ≤ $e2 ≤ $e3 ) => p_constraint!(p, ocp, e1 , e2, e3 ; log) + :( $e1 ≤ $e2 ≤ $e3, $label ) => p_constraint!(p, ocp, e1 , e2, e3 , label; log) + :( $e2 ≤ $e3 ) => p_constraint!(p, ocp, nothing, e2, e3 ; log) + :( $e2 ≤ $e3, $label ) => p_constraint!(p, ocp, nothing, e2, e3 , label; log) + :( $e3 ≥ $e2 ≥ $e1 ) => p_constraint!(p, ocp, e1 , e2, e3 ; log) + :( $e3 ≥ $e2 ≥ $e1, $label ) => p_constraint!(p, ocp, e1 , e2, e3 , label; log) + :( $e2 ≥ $e1 ) => p_constraint!(p, ocp, e1 , e2, nothing ; log) + :( $e2 ≥ $e1, $label ) => p_constraint!(p, ocp, e1 , e2, nothing, label; log) # lagrange cost - :( ∫($e1) → min ) => p_lagrange!(p, ocp, e1, :min; log) - :( $e1 * ∫($e2) → min ) => p_lagrange!(p, ocp, :( $e1 * $e2 ), :min; log) - :( ∫($e1) → max ) => p_lagrange!(p, ocp, e1, :max; log) - :( $e1 * ∫($e2) → max ) => p_lagrange!(p, ocp, :( $e1 * $e2 ), :max; log) + :( ∫($e1) → min ) => p_lagrange!(p, ocp, e1, :min; log) + :( $e1 * ∫($e2) → min ) => p_lagrange!(p, ocp, :( $e1 * $e2 ), :min; log) + :( ∫($e1) → max ) => p_lagrange!(p, ocp, e1, :max; log) + :( $e1 * ∫($e2) → max ) => p_lagrange!(p, ocp, :( $e1 * $e2 ), :max; log) # bolza cost - :( $e1 + ∫($e2) → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) - :( $e1 + $e2 * ∫($e3) → min ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :min; log) - :( $e1 - ∫($e2) → min ) => p_bolza!(p, ocp, e1, :( -$e2 ) , :min; log) - :( $e1 - $e2 * ∫($e3) → min ) => p_bolza!(p, ocp, e1, :( -$e2 * $e3 ), :min; log) - :( $e1 + ∫($e2) → max ) => p_bolza!(p, ocp, e1, e2 , :max; log) - :( $e1 + $e2 * ∫($e3) → max ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :max; log) - :( $e1 - ∫($e2) → max ) => p_bolza!(p, ocp, e1, :( -$e2 ) , :max; log) - :( $e1 - $e2 * ∫($e3) → max ) => p_bolza!(p, ocp, e1, :( -$e2 * $e3 ), :max; log) - :( ∫($e2) + $e1 → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) - :( $e2 * ∫($e3) + $e1 → min ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :min; log) - :( ∫($e2) - $e1 → min ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :min; log) - :( $e2 * ∫($e3) - $e1 → min ) => p_bolza!(p, ocp, :( -$e1 ), :( $e2 * $e3 ), :min; log) - :( ∫($e2) + $e1 → max ) => p_bolza!(p, ocp, e1, e2 , :max; log) - :( $e2 * ∫($e3) + $e1 → max ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :max; log) - :( ∫($e2) - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :max; log) - :( $e2 * ∫($e3) - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), :( $e2 * $e3 ), :max; log) + :( $e1 + ∫($e2) → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) + :( $e1 + $e2 * ∫($e3) → min ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :min; log) + :( $e1 - ∫($e2) → min ) => p_bolza!(p, ocp, e1, :( -$e2 ) , :min; log) + :( $e1 - $e2 * ∫($e3) → min ) => p_bolza!(p, ocp, e1, :( -$e2 * $e3 ), :min; log) + :( $e1 + ∫($e2) → max ) => p_bolza!(p, ocp, e1, e2 , :max; log) + :( $e1 + $e2 * ∫($e3) → max ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :max; log) + :( $e1 - ∫($e2) → max ) => p_bolza!(p, ocp, e1, :( -$e2 ) , :max; log) + :( $e1 - $e2 * ∫($e3) → max ) => p_bolza!(p, ocp, e1, :( -$e2 * $e3 ), :max; log) + :( ∫($e2) + $e1 → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) + :( $e2 * ∫($e3) + $e1 → min ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :min; log) + :( ∫($e2) - $e1 → min ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :min; log) + :( $e2 * ∫($e3) - $e1 → min ) => p_bolza!(p, ocp, :( -$e1 ), :( $e2 * $e3 ), :min; log) + :( ∫($e2) + $e1 → max ) => p_bolza!(p, ocp, e1, e2 , :max; log) + :( $e2 * ∫($e3) + $e1 → max ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :max; log) + :( ∫($e2) - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :max; log) + :( $e2 * ∫($e3) - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), :( $e2 * $e3 ), :max; log) # mayer cost - :( $e1 → min ) => p_mayer!(p, ocp, e1, :min; log) - :( $e1 → max ) => p_mayer!(p, ocp, e1, :max; log) + :( $e1 → min ) => p_mayer!(p, ocp, e1, :min; log) + :( $e1 → max ) => p_mayer!(p, ocp, e1, :max; log) + # _ => begin if e isa LineNumberNode p.lnum = p.lnum - 1 @@ -142,7 +146,7 @@ parse!(p, ocp, e; log=false) = begin elseif e isa Expr && e.head == :block p.lnum = p.lnum - 1 Expr(:block, map(e -> parse!(p, ocp, e; log), e.args)...) - # !!! assumes that map is done sequentially for side effects on p + # !!! assumes that map is done sequentially for side effects on p else return __throw("unknown syntax", p.lnum, p.line) end end @@ -160,6 +164,7 @@ p_variable!(p, ocp, v, q=1; components_names=nothing, log=false) = begin if (isnothing(components_names)) __wrap(:( variable!($ocp, $q, $vv) ), p.lnum, p.line) else + for i ∈ 1:qq p.aliases[components_names.args[i]] = :( $v[$i] ) end ss = QuoteNode(string.(components_names.args)) __wrap(:( variable!($ocp, $q, $vv, $ss) ), p.lnum, p.line) end @@ -221,6 +226,7 @@ p_state!(p, ocp, x, n=1; components_names=nothing, log=false) = begin if (isnothing(components_names)) __wrap(:( state!($ocp, $n, $xx) ), p.lnum, p.line) else + for i ∈ 1:nn p.aliases[components_names.args[i]] = :( $x[$i] ) end ss = QuoteNode(string.(components_names.args)) __wrap(:( state!($ocp, $n, $xx, $ss) ), p.lnum, p.line) end @@ -237,6 +243,7 @@ p_control!(p, ocp, u, m=1; components_names=nothing, log=false) = begin if (isnothing(components_names)) __wrap(:( control!($ocp, $m, $uu) ), p.lnum, p.line) else + for i ∈ 1:mm p.aliases[components_names.args[i]] = :( $u[$i] ) end ss = QuoteNode(string.(components_names.args)) __wrap(:( control!($ocp, $m, $uu, $ss) ), p.lnum, p.line) end diff --git a/test/test_onepass.jl b/test/test_onepass.jl index 1c22ede4..776168da 100644 --- a/test/test_onepass.jl +++ b/test/test_onepass.jl @@ -11,6 +11,18 @@ end @test o.control_components_names == [ "uu1", "uu2", "uu3" ] @test o.variable_components_names == [ "vv1", "vv2" ] +@test_throws ParsingError @def o begin # a name must be provided + (y, z) ∈ R², state +end + +@test_throws ParsingError @def o begin # a name must be provided + (uu1, uu2, uu3) ∈ R³, control +end + +@test_throws ParsingError @def o begin # a name must be provided + (vv1, vv2) ∈ R², variable +end + t0 = 0 @def o t ∈ [ t0, t0 + 4 ], time @test o.initial_time == t0 @@ -24,6 +36,13 @@ end @test o.initial_time == 0 @test o.final_time == Index(2) +@def o begin + λ = (λ₁, tf) ∈ R^2, variable + t ∈ [ 0, tf ], time +end +@test o.initial_time == 0 +@test o.final_time == Index(2) + @def o begin t0 ∈ R, variable t ∈ [ t0, 1 ], time @@ -98,6 +117,18 @@ x = [ 1, 2, 3 ] u = [ -1, 2 ] @test o.dynamics(x, u) == [ x[1] + 2u[2], 2x[3], x[1] + u[2] ] +@def o begin + t ∈ [ 0, 1 ], time + x ∈ R^3, state + u = (u₁, v) ∈ R^2, control + ẋ(t) == [ x[1](t) + 2v(t), 2x[3](t), x[1](t) + v(t) ] +end +@test o.state_dimension == 3 +@test o.control_dimension == 2 +x = [ 1, 2, 3 ] +u = [ -1, 2 ] +@test o.dynamics(x, u) == [ x[1] + 2u[2], 2x[3], x[1] + u[2] ] + t0 = 0 tf = 1 @def o begin @@ -172,7 +203,7 @@ u = 20 v = x₂ w = r + 2v r(0) == 0, (1) -end + end v(0) == 1, (♡) ẋ(t) == [ v(t), w(t)^2 ] ∫( u(t)^2 + x₁(t) ) → min @@ -207,6 +238,25 @@ u = 3 @test o.dynamics(x, u) == [ x[2], (x[1] + 2x[2])^2 ] @test o.lagrange(x, u) == u^2 + x[1] +@def o begin + t ∈ [ 0, 1 ], time + x = (r, v) ∈ R², state + u ∈ R, control + w = r + 2v + r(0) == 0, (1) + v(0) == 1, (♡) + ẋ(t) == [ v(t), w(t)^2 ] + ∫( u(t)^2 + x₁(t) ) → min +end +x = [ 1, 2 ] +x0 = 2 * x +xf = 3 * x +u = 3 +@test constraint(o, :eq1)(x0, xf) == x0[1] +@test constraint(o, Symbol("♡"))(x0, xf) == x0[2] +@test o.dynamics(x, u) == [ x[2], (x[1] + 2x[2])^2 ] +@test o.lagrange(x, u) == u^2 + x[1] + @def o begin z ∈ R², variable t ∈ [ 0, 1 ], time From 41058d4e4313f9e12e39f5edd2c2e7eb63f4cf06 Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Wed, 22 May 2024 15:58:39 +0200 Subject: [PATCH 04/13] foo --- test/test_onepass.jl | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/test_onepass.jl b/test/test_onepass.jl index 776168da..bdb41056 100644 --- a/test/test_onepass.jl +++ b/test/test_onepass.jl @@ -177,6 +177,30 @@ B = [ 0 @test o.lagrange(x, u) == 0.5u^2 @test o.criterion == :min +t0 = 0 +tf = 1 +@def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + 0.5∫( u(t)^2 ) → min +end +x = [ 1, 2 ] +x0 = 2 * x +xf = 3 * x +u = -1 +A = [ 0 1 + 0 0 ] +B = [ 0 + 1 ] +@test constraint(o, :eq1)(x0, xf) == x0 +@test o.dynamics(x, u) == A * x + B * u +@test o.lagrange(x, u) == 0.5u^2 +@test o.criterion == :min + a = 1 f(b) = begin # closure of a, local c, and @def in function c = 3 From 3a433924c43a3c97fd0e0b91a4e9b05f26efc767 Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Wed, 22 May 2024 15:59:04 +0200 Subject: [PATCH 05/13] =?UTF-8?q?test=200.5=E2=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/test_onepass.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_onepass.jl b/test/test_onepass.jl index bdb41056..e26b6f8d 100644 --- a/test/test_onepass.jl +++ b/test/test_onepass.jl @@ -186,7 +186,7 @@ tf = 1 x(t0) == [ -1, 0 ], (1) x(tf) == [ 0, 0 ] ẋ(t) == A * x(t) + B * u(t) - 0.5∫( u(t)^2 ) → min + 0.5∫( u(t)^2 ) → min end x = [ 1, 2 ] x0 = 2 * x From e3812c73f319b5e40883b423c470bbba454381ed Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Wed, 22 May 2024 15:59:08 +0200 Subject: [PATCH 06/13] =?UTF-8?q?test=200.5=E2=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/test_onepass.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_onepass.jl b/test/test_onepass.jl index e26b6f8d..bdb41056 100644 --- a/test/test_onepass.jl +++ b/test/test_onepass.jl @@ -186,7 +186,7 @@ tf = 1 x(t0) == [ -1, 0 ], (1) x(tf) == [ 0, 0 ] ẋ(t) == A * x(t) + B * u(t) - 0.5∫( u(t)^2 ) → min + 0.5∫( u(t)^2 ) → min end x = [ 1, 2 ] x0 = 2 * x From 580498e4367cd897da9c9349bb1ce3db7a4c8c00 Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Wed, 22 May 2024 16:28:02 +0200 Subject: [PATCH 07/13] add square brackets --- src/onepass.jl | 4 +++ test/test_onepass.jl | 63 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/onepass.jl b/src/onepass.jl index aeb42101..42b01673 100644 --- a/src/onepass.jl +++ b/src/onepass.jl @@ -77,9 +77,13 @@ parse!(p, ocp, e; log=false) = begin :( $a = $e1 ) => @match e1 begin :( ($names) ∈ R^$q, variable ) => p_variable!(p, ocp, a, q; components_names=names, log) + :( [$names] ∈ R^$q, variable ) => p_variable!(p, ocp, a, q; components_names=names, log) :( ($names) ∈ R^$n, state ) => p_state!(p, ocp, a, n; components_names=names, log) + :( [$names] ∈ R^$n, state ) => p_state!(p, ocp, a, n; components_names=names, log) :( ($names) ∈ R^$m, control ) => p_control!(p, ocp, a, m; components_names=names, log) + :( [$names] ∈ R^$m, control ) => p_control!(p, ocp, a, m; components_names=names, log) :( ($names) ∈ R, $dummy ) => return __throw("unknown syntax", p.lnum, p.line) + :( [$names] ∈ R, $dummy ) => return __throw("unknown syntax", p.lnum, p.line) _ => p_alias!(p, ocp, a, e1; log) # alias end # variable diff --git a/test/test_onepass.jl b/test/test_onepass.jl index bdb41056..cdddf9d8 100644 --- a/test/test_onepass.jl +++ b/test/test_onepass.jl @@ -11,6 +11,15 @@ end @test o.control_components_names == [ "uu1", "uu2", "uu3" ] @test o.variable_components_names == [ "vv1", "vv2" ] +@def o begin + x = [y, z] ∈ R², state + u = [uu1, uu2, uu3] ∈ R³, control + v = [vv1, vv2] ∈ R², variable +end +@test o.state_components_names == [ "y", "z" ] +@test o.control_components_names == [ "uu1", "uu2", "uu3" ] +@test o.variable_components_names == [ "vv1", "vv2" ] + @test_throws ParsingError @def o begin # a name must be provided (y, z) ∈ R², state end @@ -23,6 +32,18 @@ end (vv1, vv2) ∈ R², variable end +@test_throws ParsingError @def o begin # a name must be provided + [y, z] ∈ R², state +end + +@test_throws ParsingError @def o begin # a name must be provided + [uu1, uu2, uu3] ∈ R³, control +end + +@test_throws ParsingError @def o begin # a name must be provided + [vv1, vv2] ∈ R², variable +end + t0 = 0 @def o t ∈ [ t0, t0 + 4 ], time @test o.initial_time == t0 @@ -264,7 +285,7 @@ u = 3 @def o begin t ∈ [ 0, 1 ], time - x = (r, v) ∈ R², state + x = ( r, v ) ∈ R², state u ∈ R, control w = r + 2v r(0) == 0, (1) @@ -281,6 +302,46 @@ u = 3 @test o.dynamics(x, u) == [ x[2], (x[1] + 2x[2])^2 ] @test o.lagrange(x, u) == u^2 + x[1] +@def o begin + t ∈ [ 0, 1 ], time + x = [ r, v ] ∈ R², state + u ∈ R, control + w = r + 2v + r(0) == 0, (1) + v(0) == 1, (♡) + ẋ(t) == [ v(t), w(t)^2 ] + ∫( u(t)^2 + x₁(t) ) → min +end +x = [ 1, 2 ] +x0 = 2 * x +xf = 3 * x +u = 3 +@test constraint(o, :eq1)(x0, xf) == x0[1] +@test constraint(o, Symbol("♡"))(x0, xf) == x0[2] +@test o.dynamics(x, u) == [ x[2], (x[1] + 2x[2])^2 ] +@test o.lagrange(x, u) == u^2 + x[1] + +@def o begin + t ∈ [ 0, 1 ], time + x = [ r, v ] ∈ R², state + c = [ u, b ] ∈ R², control + w = r + 2v + b(t) == 0 + r(0) == 0, (1) + v(0) == 1, (♡) + ẋ(t) == [ v(t), w(t)^2 ] + ∫( u(t)^2 + b(t)^2 + x₁(t) ) → min +end +x = [ 1, 2 ] +x0 = 2 * x +xf = 3 * x +u = 3 +c = [ u, 0 ] +@test constraint(o, :eq1)(x0, xf) == x0[1] +@test constraint(o, Symbol("♡"))(x0, xf) == x0[2] +@test o.dynamics(x, c) == [ x[2], (x[1] + 2x[2])^2 ] +@test o.lagrange(x, c) == u^2 + x[1] + @def o begin z ∈ R², variable t ∈ [ 0, 1 ], time From 9af75250cd44d473d349b40158e0cffdd603bfd2 Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Wed, 22 May 2024 23:13:19 +0200 Subject: [PATCH 08/13] add left x and right / --- src/onepass.jl | 64 +- test/test_onepass.jl | 2908 ++++++++++++++++++++++++------------------ 2 files changed, 1715 insertions(+), 1257 deletions(-) diff --git a/src/onepass.jl b/src/onepass.jl index 42b01673..ecd1350c 100644 --- a/src/onepass.jl +++ b/src/onepass.jl @@ -67,13 +67,15 @@ Foo ``` """ parse!(p, ocp, e; log=false) = begin + # p.lnum = p.lnum + 1 p.line = string(e) for a ∈ keys(p.aliases) e = subs(e, a, p.aliases[a]) end + # @match e begin - # + # aliases :( $a = $e1 ) => @match e1 begin :( ($names) ∈ R^$q, variable ) => p_variable!(p, ocp, a, q; components_names=names, log) @@ -84,7 +86,7 @@ parse!(p, ocp, e; log=false) = begin :( [$names] ∈ R^$m, control ) => p_control!(p, ocp, a, m; components_names=names, log) :( ($names) ∈ R, $dummy ) => return __throw("unknown syntax", p.lnum, p.line) :( [$names] ∈ R, $dummy ) => return __throw("unknown syntax", p.lnum, p.line) - _ => p_alias!(p, ocp, a, e1; log) # alias + _ => p_alias!(p, ocp, a, e1; log) # alias end # variable :( ($e1, $e2) ∈ R^$q, variable ) => return __throw("unknown syntax: please provide a name to the variable", p.lnum, p.line) @@ -118,27 +120,43 @@ parse!(p, ocp, e; log=false) = begin :( $e2 ≥ $e1 ) => p_constraint!(p, ocp, e1 , e2, nothing ; log) :( $e2 ≥ $e1, $label ) => p_constraint!(p, ocp, e1 , e2, nothing, label; log) # lagrange cost - :( ∫($e1) → min ) => p_lagrange!(p, ocp, e1, :min; log) - :( $e1 * ∫($e2) → min ) => p_lagrange!(p, ocp, :( $e1 * $e2 ), :min; log) - :( ∫($e1) → max ) => p_lagrange!(p, ocp, e1, :max; log) - :( $e1 * ∫($e2) → max ) => p_lagrange!(p, ocp, :( $e1 * $e2 ), :max; log) + :( ∫($e1) → min ) => p_lagrange!(p, ocp, e1 , :min; log) + :( - ∫($e1) → min ) => p_lagrange!(p, ocp, :( -$e1 ) , :min; log) + :( $e1 * ∫($e2) → min ) => p_lagrange!(p, ocp, :( $e1 * $e2 ), :min; log) + #:( - $e1 * ∫($e2) → min ) => p_lagrange!(p, ocp, :( -$e1 * $e2 ), :min; log) + :( ∫($e2) / $e1 → min ) => p_lagrange!(p, ocp, :( $e2 / $e1 ), :min; log) + :( - ∫($e2) / $e1 → min ) => p_lagrange!(p, ocp, :( -$e2 / $e1 ), :min; log) + :( ∫($e1) → max ) => p_lagrange!(p, ocp, e1 , :max; log) + :( - ∫($e1) → max ) => p_lagrange!(p, ocp, :( -$e1 ) , :max; log) + :( $e1 * ∫($e2) → max ) => p_lagrange!(p, ocp, :( $e1 * $e2 ), :max; log) + #:( - $e1 * ∫($e2) → max ) => p_lagrange!(p, ocp, :( -$e1 * $e2 ), :max; log) + :( ∫($e2) / $e1 → max ) => p_lagrange!(p, ocp, :( $e2 / $e1 ), :max; log) + :( - ∫($e2) / $e1 → max ) => p_lagrange!(p, ocp, :( -$e2 / $e1 ), :max; log) # bolza cost - :( $e1 + ∫($e2) → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) - :( $e1 + $e2 * ∫($e3) → min ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :min; log) - :( $e1 - ∫($e2) → min ) => p_bolza!(p, ocp, e1, :( -$e2 ) , :min; log) - :( $e1 - $e2 * ∫($e3) → min ) => p_bolza!(p, ocp, e1, :( -$e2 * $e3 ), :min; log) - :( $e1 + ∫($e2) → max ) => p_bolza!(p, ocp, e1, e2 , :max; log) - :( $e1 + $e2 * ∫($e3) → max ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :max; log) - :( $e1 - ∫($e2) → max ) => p_bolza!(p, ocp, e1, :( -$e2 ) , :max; log) - :( $e1 - $e2 * ∫($e3) → max ) => p_bolza!(p, ocp, e1, :( -$e2 * $e3 ), :max; log) - :( ∫($e2) + $e1 → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) - :( $e2 * ∫($e3) + $e1 → min ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :min; log) - :( ∫($e2) - $e1 → min ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :min; log) - :( $e2 * ∫($e3) - $e1 → min ) => p_bolza!(p, ocp, :( -$e1 ), :( $e2 * $e3 ), :min; log) - :( ∫($e2) + $e1 → max ) => p_bolza!(p, ocp, e1, e2 , :max; log) - :( $e2 * ∫($e3) + $e1 → max ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :max; log) - :( ∫($e2) - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :max; log) - :( $e2 * ∫($e3) - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), :( $e2 * $e3 ), :max; log) + :( $e1 + ∫($e2) → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) + :( $e1 + $e2 * ∫($e3) → min ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :min; log) + :( $e1 + ∫($e3) / $e2 → min ) => p_bolza!(p, ocp, e1, :( $e3 / $e2 ), :min; log) + :( $e1 - ∫($e2) → min ) => p_bolza!(p, ocp, e1, :( -$e2 ) , :min; log) + :( $e1 - $e2 * ∫($e3) → min ) => p_bolza!(p, ocp, e1, :( -$e2 * $e3 ), :min; log) + :( $e1 - ∫($e3) / $e2 → min ) => p_bolza!(p, ocp, e1, :( -$e3 / $e2 ), :min; log) + :( $e1 + ∫($e2) → max ) => p_bolza!(p, ocp, e1, e2 , :max; log) + :( $e1 + $e2 * ∫($e3) → max ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :max; log) + :( $e1 + ∫($e3) / $e2 → max ) => p_bolza!(p, ocp, e1, :( $e3 / $e2 ), :max; log) + :( $e1 - ∫($e2) → max ) => p_bolza!(p, ocp, e1, :( -$e2 ) , :max; log) + :( $e1 - $e2 * ∫($e3) → max ) => p_bolza!(p, ocp, e1, :( -$e2 * $e3 ), :max; log) + :( $e1 - ∫($e3) / $e2 → max ) => p_bolza!(p, ocp, e1, :( -$e3 / $e2 ), :max; log) + :( ∫($e2) + $e1 → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) + :( $e2 * ∫($e3) + $e1 → min ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :min; log) + :( ∫($e3) / $e2 + $e1 → min ) => p_bolza!(p, ocp, e1, :( $e3 / $e2 ), :min; log) + :( ∫($e2) - $e1 → min ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :min; log) + :( $e2 * ∫($e3) - $e1 → min ) => p_bolza!(p, ocp, :( -$e1 ), :( $e2 * $e3 ), :min; log) + :( ∫($e3) / $e2 - $e1 → min ) => p_bolza!(p, ocp, :( -$e1 ), :( $e3 / $e2 ), :min; log) + :( ∫($e2) + $e1 → max ) => p_bolza!(p, ocp, e1, e2 , :max; log) + :( $e2 * ∫($e3) + $e1 → max ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :max; log) + :( ∫($e3) / $e2 + $e1 → max ) => p_bolza!(p, ocp, e1, :( $e3 / $e2 ), :max; log) + :( ∫($e2) - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :max; log) + :( $e2 * ∫($e3) - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), :( $e2 * $e3 ), :max; log) + :( ∫($e3) / $e2 - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), :( $e3 / $e2 ), :max; log) # mayer cost :( $e1 → min ) => p_mayer!(p, ocp, e1, :min; log) :( $e1 → max ) => p_mayer!(p, ocp, e1, :max; log) @@ -150,7 +168,7 @@ parse!(p, ocp, e; log=false) = begin elseif e isa Expr && e.head == :block p.lnum = p.lnum - 1 Expr(:block, map(e -> parse!(p, ocp, e; log), e.args)...) - # !!! assumes that map is done sequentially for side effects on p + # !!! assumes that map is done sequentially for side effects on p else return __throw("unknown syntax", p.lnum, p.line) end end diff --git a/test/test_onepass.jl b/test/test_onepass.jl index cdddf9d8..18a51a63 100644 --- a/test/test_onepass.jl +++ b/test/test_onepass.jl @@ -2,1168 +2,249 @@ function test_onepass() -@def o begin - x = (y, z) ∈ R², state - u = (uu1, uu2, uu3) ∈ R³, control - v = (vv1, vv2) ∈ R², variable -end -@test o.state_components_names == [ "y", "z" ] -@test o.control_components_names == [ "uu1", "uu2", "uu3" ] -@test o.variable_components_names == [ "vv1", "vv2" ] - -@def o begin - x = [y, z] ∈ R², state - u = [uu1, uu2, uu3] ∈ R³, control - v = [vv1, vv2] ∈ R², variable -end -@test o.state_components_names == [ "y", "z" ] -@test o.control_components_names == [ "uu1", "uu2", "uu3" ] -@test o.variable_components_names == [ "vv1", "vv2" ] - -@test_throws ParsingError @def o begin # a name must be provided - (y, z) ∈ R², state -end +# --------------------------------------------------------------- +# --------------------------------------------------------------- +@testset "aliases" begin + + @def o begin + x = (y, z) ∈ R², state + u = (uu1, uu2, uu3) ∈ R³, control + v = (vv1, vv2) ∈ R², variable + end + @test o.state_components_names == [ "y", "z" ] + @test o.control_components_names == [ "uu1", "uu2", "uu3" ] + @test o.variable_components_names == [ "vv1", "vv2" ] + + @def o begin + x = [y, z] ∈ R², state + u = [uu1, uu2, uu3] ∈ R³, control + v = [vv1, vv2] ∈ R², variable + end + @test o.state_components_names == [ "y", "z" ] + @test o.control_components_names == [ "uu1", "uu2", "uu3" ] + @test o.variable_components_names == [ "vv1", "vv2" ] -@test_throws ParsingError @def o begin # a name must be provided - (uu1, uu2, uu3) ∈ R³, control -end + @test_throws ParsingError @def o begin # a name must be provided + (y, z) ∈ R², state + end -@test_throws ParsingError @def o begin # a name must be provided - (vv1, vv2) ∈ R², variable -end + @test_throws ParsingError @def o begin # a name must be provided + (uu1, uu2, uu3) ∈ R³, control + end -@test_throws ParsingError @def o begin # a name must be provided - [y, z] ∈ R², state -end + @test_throws ParsingError @def o begin # a name must be provided + (vv1, vv2) ∈ R², variable + end -@test_throws ParsingError @def o begin # a name must be provided - [uu1, uu2, uu3] ∈ R³, control -end + @test_throws ParsingError @def o begin # a name must be provided + [y, z] ∈ R², state + end -@test_throws ParsingError @def o begin # a name must be provided - [vv1, vv2] ∈ R², variable -end + @test_throws ParsingError @def o begin # a name must be provided + [uu1, uu2, uu3] ∈ R³, control + end -t0 = 0 -@def o t ∈ [ t0, t0 + 4 ], time -@test o.initial_time == t0 -@test o.final_time == t0 + 4 + @test_throws ParsingError @def o begin # a name must be provided + [vv1, vv2] ∈ R², variable + end -@def o begin - λ ∈ R^2, variable - tf = λ₂ - t ∈ [ 0, tf ], time -end -@test o.initial_time == 0 -@test o.final_time == Index(2) + @def o begin + t ∈ [ 0, 1 ], time + x = ( r, v ) ∈ R², state + u ∈ R, control + w = r + 2v + r(0) == 0, (1) + v(0) == 1, (♡) + ẋ(t) == [ v(t), w(t)^2 ] + ∫( u(t)^2 + x₁(t) ) → min + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = 3 + @test constraint(o, :eq1)(x0, xf) == x0[1] + @test constraint(o, Symbol("♡"))(x0, xf) == x0[2] + @test o.dynamics(x, u) == [ x[2], (x[1] + 2x[2])^2 ] + @test o.lagrange(x, u) == u^2 + x[1] + + @def o begin + t ∈ [ 0, 1 ], time + x = [ r, v ] ∈ R², state + u ∈ R, control + w = r + 2v + r(0) == 0, (1) + v(0) == 1, (♡) + ẋ(t) == [ v(t), w(t)^2 ] + ∫( u(t)^2 + x₁(t) ) → min + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = 3 + @test constraint(o, :eq1)(x0, xf) == x0[1] + @test constraint(o, Symbol("♡"))(x0, xf) == x0[2] + @test o.dynamics(x, u) == [ x[2], (x[1] + 2x[2])^2 ] + @test o.lagrange(x, u) == u^2 + x[1] + + @def o begin + t ∈ [ 0, 1 ], time + x = [ r, v ] ∈ R², state + c = [ u, b ] ∈ R², control + w = r + 2v + b(t) == 0 + r(0) == 0, (1) + v(0) == 1, (♡) + ẋ(t) == [ v(t), w(t)^2 ] + ∫( u(t)^2 + b(t)^2 + x₁(t) ) → min + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = 3 + c = [ u, 0 ] + @test constraint(o, :eq1)(x0, xf) == x0[1] + @test constraint(o, Symbol("♡"))(x0, xf) == x0[2] + @test o.dynamics(x, c) == [ x[2], (x[1] + 2x[2])^2 ] + @test o.lagrange(x, c) == u^2 + x[1] + + @def o begin + t ∈ [ 0, 1 ], time + x ∈ R^3, state + u = (u₁, v) ∈ R^2, control + ẋ(t) == [ x[1](t) + 2v(t), 2x[3](t), x[1](t) + v(t) ] + end + @test o.state_dimension == 3 + @test o.control_dimension == 2 + x = [ 1, 2, 3 ] + u = [ -1, 2 ] + @test o.dynamics(x, u) == [ x[1] + 2u[2], 2x[3], x[1] + u[2] ] -@def o begin - λ = (λ₁, tf) ∈ R^2, variable - t ∈ [ 0, tf ], time -end -@test o.initial_time == 0 -@test o.final_time == Index(2) + t0 = .0; tf = .1 + @def ocp begin + t ∈ [ t0, tf ], time + x ∈ R^3, state + u ∈ R^3, control -@def o begin - t0 ∈ R, variable - t ∈ [ t0, 1 ], time -end -@test o.initial_time == Index(1) -@test o.final_time == 1 + r = x[1] + v = x₂ + a = x₃ + end ; + @test ocp isa OptimalControlModel + @test ocp.time_name == "t" + @test ocp.initial_time == t0 + @test ocp.final_time == tf + @test ocp.control_name == "u" + @test ocp.control_dimension == 3 + @test ocp.state_name == "x" + @test ocp.state_dimension == 3 -@def o begin - tf ∈ R, variable - t ∈ [ 0, tf ], time end -@test o.initial_time == 0 -@test o.final_time == Index(1) -@def o begin - v ∈ R², variable - s ∈ [ v[1], v[2] ], time -end -@test o.initial_time == Index(1) -@test o.final_time == Index(2) - -@def o begin - v ∈ R², variable - s0 = v₁ - sf = v₂ - s ∈ [ s0, sf ], time -end -@test o.initial_time == Index(1) -@test o.final_time == Index(2) +# --------------------------------------------------------------- +# --------------------------------------------------------------- +@testset "variable" begin -@test_throws IncorrectArgument @def o begin - t0 ∈ R², variable - t ∈ [ t0, 1 ], time -end + @def o begin + λ ∈ R^2, variable + tf = λ₂ + t ∈ [ 0, tf ], time + end + @test o.initial_time == 0 + @test o.final_time == Index(2) + + @def o begin + λ = (λ₁, tf) ∈ R^2, variable + t ∈ [ 0, tf ], time + end + @test o.initial_time == 0 + @test o.final_time == Index(2) + + @def o begin + t0 ∈ R, variable + t ∈ [ t0, 1 ], time + end + @test o.initial_time == Index(1) + @test o.final_time == 1 + + @def o begin + tf ∈ R, variable + t ∈ [ 0, tf ], time + end + @test o.initial_time == 0 + @test o.final_time == Index(1) + + @def o begin + v ∈ R², variable + s ∈ [ v[1], v[2] ], time + end + @test o.initial_time == Index(1) + @test o.final_time == Index(2) + + @def o begin + v ∈ R², variable + s0 = v₁ + sf = v₂ + s ∈ [ s0, sf ], time + end + @test o.initial_time == Index(1) + @test o.final_time == Index(2) + + @test_throws IncorrectArgument @def o begin + t0 ∈ R², variable + t ∈ [ t0, 1 ], time + end + + @test_throws IncorrectArgument @def o begin + tf ∈ R², variable + t ∈ [ 0, tf ], time + end + + @test_throws ParsingError @def o begin + v, variable + t ∈ [ 0, tf[v] ], time + end + + @test_throws ParsingError @def o begin + v, variable + t ∈ [ t0[v], 1 ], time + end + + @test_throws ParsingError @def o begin + v, variable + t ∈ [ t0[v], tf[v+1] ], time + end -@test_throws IncorrectArgument @def o begin - tf ∈ R², variable - t ∈ [ 0, tf ], time -end + t0 = .0; tf = .1 + @def ocp begin + t ∈ [ t0, tf ], time + a, variable + end ; + @test ocp isa OptimalControlModel + @test ocp.variable_dimension == 1 + @test ocp.variable_name == "a" -@test_throws ParsingError @def o begin - v, variable - t ∈ [ 0, tf[v] ], time -end + t0 = .0; tf = .1 + @def ocp begin + t ∈ [ t0, tf ], time + a ∈ R³, variable + end ; + @test ocp isa OptimalControlModel + @test ocp.variable_dimension == 3 + @test ocp.variable_name == "a" -@test_throws ParsingError @def o begin - v, variable - t ∈ [ t0[v], 1 ], time end -@test_throws ParsingError @def o begin - v, variable - t ∈ [ t0[v], tf[v+1] ], time -end +# --------------------------------------------------------------- +# --------------------------------------------------------------- +@testset "time" begin -@def o begin - x ∈ R, state - u ∈ R, control -end -@test o.state_dimension == 1 -@test o.control_dimension == 1 - -@def o begin - t ∈ [ 0, 1 ], time - x ∈ R^3, state - u ∈ R^2, control - ẋ(t) == [ x[1](t) + 2u[2](t), 2x[3](t), x[1](t) + u[2](t) ] -end -@test o.state_dimension == 3 -@test o.control_dimension == 2 -x = [ 1, 2, 3 ] -u = [ -1, 2 ] -@test o.dynamics(x, u) == [ x[1] + 2u[2], 2x[3], x[1] + u[2] ] - -@def o begin - t ∈ [ 0, 1 ], time - x ∈ R^3, state - u = (u₁, v) ∈ R^2, control - ẋ(t) == [ x[1](t) + 2v(t), 2x[3](t), x[1](t) + v(t) ] -end -@test o.state_dimension == 3 -@test o.control_dimension == 2 -x = [ 1, 2, 3 ] -u = [ -1, 2 ] -@test o.dynamics(x, u) == [ x[1] + 2u[2], 2x[3], x[1] + u[2] ] - -t0 = 0 -tf = 1 -@def o begin - t ∈ [ t0, tf ], time - x ∈ R^2, state - u ∈ R, control - x(t0) == [ -1, 0 ], (1) - x(tf) == [ 0, 0 ] - ẋ(t) == A * x(t) + B * u(t) - ∫( 0.5u(t)^2 ) → min -end -x = [ 1, 2 ] -x0 = 2 * x -xf = 3 * x -u = -1 -A = [ 0 1 - 0 0 ] -B = [ 0 - 1 ] -@test constraint(o, :eq1)(x0, xf) == x0 -@test o.dynamics(x, u) == A * x + B * u -@test o.lagrange(x, u) == 0.5u^2 -@test o.criterion == :min - -t0 = 0 -tf = 1 -@def o begin - t ∈ [ t0, tf ], time - x ∈ R^2, state - u ∈ R, control - x(t0) == [ -1, 0 ], (1) - x(tf) == [ 0, 0 ] - ẋ(t) == A * x(t) + B * u(t) - 0.5 * ∫( u(t)^2 ) → min -end -x = [ 1, 2 ] -x0 = 2 * x -xf = 3 * x -u = -1 -A = [ 0 1 - 0 0 ] -B = [ 0 - 1 ] -@test constraint(o, :eq1)(x0, xf) == x0 -@test o.dynamics(x, u) == A * x + B * u -@test o.lagrange(x, u) == 0.5u^2 -@test o.criterion == :min - -t0 = 0 -tf = 1 -@def o begin - t ∈ [ t0, tf ], time - x ∈ R^2, state - u ∈ R, control - x(t0) == [ -1, 0 ], (1) - x(tf) == [ 0, 0 ] - ẋ(t) == A * x(t) + B * u(t) - 0.5∫( u(t)^2 ) → min -end -x = [ 1, 2 ] -x0 = 2 * x -xf = 3 * x -u = -1 -A = [ 0 1 - 0 0 ] -B = [ 0 - 1 ] -@test constraint(o, :eq1)(x0, xf) == x0 -@test o.dynamics(x, u) == A * x + B * u -@test o.lagrange(x, u) == 0.5u^2 -@test o.criterion == :min - -a = 1 -f(b) = begin # closure of a, local c, and @def in function - c = 3 - @def ocp begin - t ∈ [ a, b ], time - x ∈ R, state - u ∈ R, control - ẋ(t) == x(t) + u(t) + b + c + d -end - ocp -end -o = f(2) -d = 4 -x = 10 -u = 20 -@test o.dynamics(x, u) == x + u + 2 + 3 + 4 - -@def o begin - t ∈ [ 0, 1 ], time - x ∈ R², state - u ∈ R, control - begin - r = x₁ - v = x₂ - w = r + 2v - r(0) == 0, (1) - end - v(0) == 1, (♡) - ẋ(t) == [ v(t), w(t)^2 ] - ∫( u(t)^2 + x₁(t) ) → min -end -x = [ 1, 2 ] -x0 = 2 * x -xf = 3 * x -u = 3 -@test constraint(o, :eq1)(x0, xf) == x0[1] -@test constraint(o, Symbol("♡"))(x0, xf) == x0[2] -@test o.dynamics(x, u) == [ x[2], (x[1] + 2x[2])^2 ] -@test o.lagrange(x, u) == u^2 + x[1] - -@def o begin - t ∈ [ 0, 1 ], time - x ∈ R², state - u ∈ R, control - r = x₁ - v = x₂ - w = r + 2v - r(0) == 0, (1) - v(0) == 1, (♡) - ẋ(t) == [ v(t), w(t)^2 ] - ∫( u(t)^2 + x₁(t) ) → min -end -x = [ 1, 2 ] -x0 = 2 * x -xf = 3 * x -u = 3 -@test constraint(o, :eq1)(x0, xf) == x0[1] -@test constraint(o, Symbol("♡"))(x0, xf) == x0[2] -@test o.dynamics(x, u) == [ x[2], (x[1] + 2x[2])^2 ] -@test o.lagrange(x, u) == u^2 + x[1] - -@def o begin - t ∈ [ 0, 1 ], time - x = ( r, v ) ∈ R², state - u ∈ R, control - w = r + 2v - r(0) == 0, (1) - v(0) == 1, (♡) - ẋ(t) == [ v(t), w(t)^2 ] - ∫( u(t)^2 + x₁(t) ) → min -end -x = [ 1, 2 ] -x0 = 2 * x -xf = 3 * x -u = 3 -@test constraint(o, :eq1)(x0, xf) == x0[1] -@test constraint(o, Symbol("♡"))(x0, xf) == x0[2] -@test o.dynamics(x, u) == [ x[2], (x[1] + 2x[2])^2 ] -@test o.lagrange(x, u) == u^2 + x[1] - -@def o begin - t ∈ [ 0, 1 ], time - x = [ r, v ] ∈ R², state - u ∈ R, control - w = r + 2v - r(0) == 0, (1) - v(0) == 1, (♡) - ẋ(t) == [ v(t), w(t)^2 ] - ∫( u(t)^2 + x₁(t) ) → min -end -x = [ 1, 2 ] -x0 = 2 * x -xf = 3 * x -u = 3 -@test constraint(o, :eq1)(x0, xf) == x0[1] -@test constraint(o, Symbol("♡"))(x0, xf) == x0[2] -@test o.dynamics(x, u) == [ x[2], (x[1] + 2x[2])^2 ] -@test o.lagrange(x, u) == u^2 + x[1] - -@def o begin - t ∈ [ 0, 1 ], time - x = [ r, v ] ∈ R², state - c = [ u, b ] ∈ R², control - w = r + 2v - b(t) == 0 - r(0) == 0, (1) - v(0) == 1, (♡) - ẋ(t) == [ v(t), w(t)^2 ] - ∫( u(t)^2 + b(t)^2 + x₁(t) ) → min -end -x = [ 1, 2 ] -x0 = 2 * x -xf = 3 * x -u = 3 -c = [ u, 0 ] -@test constraint(o, :eq1)(x0, xf) == x0[1] -@test constraint(o, Symbol("♡"))(x0, xf) == x0[2] -@test o.dynamics(x, c) == [ x[2], (x[1] + 2x[2])^2 ] -@test o.lagrange(x, c) == u^2 + x[1] - -@def o begin - z ∈ R², variable - t ∈ [ 0, 1 ], time - x ∈ R², state - u ∈ R, control - r = x₁ - v = x₂ - w = r + 2v - r(0) == 0, (1) - v(0) == 1, (♡) - ẋ(t) == [ v(t), w(t)^2 + z₁ ] - ∫( u(t)^2 + z₂ * x₁(t) ) → min -end -x = [ 1, 2 ] -x0 = 2 * [ 1, 2 ] -xf = 3 * [ 1, 2 ] -u = 3 -z = [ 4, 5 ] -@test constraint(o, :eq1)(x0, xf, z) == x0[1] -@test constraint(o, Symbol("♡"))(x0, xf, z) == x0[2] -@test o.dynamics(x, u, z) == [ x[2], (x[1] + 2x[2])^2 + z[1] ] -@test o.lagrange(x, u, z) == u^2 + z[2] * x[1] - -@def o begin - tf, variable - t ∈ [ 0, tf ], time - x ∈ R², state - u ∈ R, control - r = x₁ - v = x₂ - w = r¹ + 2v³ - r(0) + w(tf) - tf² == 0, (1) -end -tf = 2 -x0 = [ 1, 2 ] -xf = [ 3, 4 ] -@test constraint(o, :eq1)(x0, xf, tf) == x0[1] + ( xf[1] + 2xf[2]^3 ) - tf^2 - -@def o begin - t ∈ [ 0, 1 ], time - x ∈ R², state - u ∈ R, control - r = x₁ - v = x₂ - r(0)^2 + v(1) == 0, (1) - v(0) == 1, (♡) - ẋ(t) == [ v(t), r(t)^2 ] - ∫( u(t)^2 + x₁(t) ) → min -end -x0 = [ 2, 3 ] -xf = [ 4, 5 ] -x = [ 1, 2 ] -u = 3 -@test constraint(o, :eq1)(x0, xf) == x0[1]^2 + xf[2] -@test constraint(o, Symbol("♡"))(x0, xf) == x0[2] -@test o.dynamics(x, u) == [ x[2], x[1]^2 ] -@test o.lagrange(x, u) == u^2 + x[1] - -@def o begin - z ∈ R, variable - t ∈ [ 0, 1 ], time - x ∈ R², state - u ∈ R, control - r = x₁ - v = x₂ - r(0) - z == 0, (1) - v(0) == 1, (♡) - ẋ(t) == [ v(t), r(t)^2 + z ] - ∫( u(t)^2 + z * x₁(t) ) → min -end -x0 = [ 2, 3 ] -xf = [ 4, 5 ] -x = [ 1, 2 ] -u = 3 -z = 4 -@test constraint(o, :eq1)(x0, xf, z) == x0[1] - z -@test constraint(o, Symbol("♡"))(x0, xf, z) == x0[2] -@test o.dynamics(x, u, z) == [ x[2], x[1]^2 + z ] -@test o.lagrange(x, u, z) == u^2 + z * x[1] - -@def o begin - z ∈ R, variable - t ∈ [ 0, 1 ], time - x ∈ R², state - u ∈ R, control - r = x₁ - v = x₂ - 0 ≤ r(0) - z ≤ 1, (1) - 0 ≤ v(1)^2 ≤ 1, (2) - [ 0, 0 ] ≤ x(0) ≤ [ 1, 1 ], (♡) - ẋ(t) == [ v(t), r(t)^2 + z ] - ∫( u(t)^2 + z * x₁(t) ) → min -end -x0 = [ 2, 3 ] -xf = [ 4, 5 ] -x = [ 1, 2 ] -u = 3 -z = 4 -@test constraint(o, :eq1)(x0, xf, z) == x0[1] - z -@test constraint(o, :eq2)(x0, xf, z) == xf[2]^2 -@test constraint(o, Symbol("♡"))(x0, xf, z) == x0 -@test o.dynamics(x, u, z) == [ x[2], x[1]^2 + z ] -@test o.lagrange(x, u, z) == u^2 + z * x[1] - -@def o begin - z ∈ R, variable - t ∈ [ 0, 1 ], time - x ∈ R², state - u ∈ R, control - r = x₁ - v = x₂ - 1 ≥ r(0) - z ≥ 0, (1) - 1 ≥ v(1)^2 ≥ 0, (2) - [ 1, 1 ] ≥ x(0) ≥ [ 0, 0 ], (3) - ẋ(t) == [ v(t), r(t)^2 + z ] - ∫( u(t)^2 + z * x₁(t) ) → min -end -x0 = [ 2, 3 ] -xf = [ 4, 5 ] -x = [ 1, 2 ] -u = 3 -z = 4 -@test constraint(o, :eq1)(x0, xf, z) == x0[1] - z -@test constraint(o, :eq2)(x0, xf, z) == xf[2]^2 -@test constraint(o, :eq3)(x0, xf, z) == x0 -@test o.dynamics(x, u, z) == [ x[2], x[1]^2 + z ] -@test o.lagrange(x, u, z) == u^2 + z * x[1] -@test o.constraints[:eq1][3] == 0 -@test o.constraints[:eq1][4] == 1 -@test o.constraints[:eq2][3] == 0 -@test o.constraints[:eq2][4] == 1 -@test o.constraints[:eq3][3] == [ 0, 0 ] -@test o.constraints[:eq3][4] == [ 1, 1 ] - -n = 11 -m = 6 -@def o begin - t ∈ [ 0, 1 ], time - x ∈ R^n, state - u ∈ R^m, control - r = x₁ - v = x₂ - 0 ≤ r(t) ≤ 1, (1) - zeros(n) ≤ x(t) ≤ ones(n), (2) - [ 0, 0 ] ≤ x[1:2](t) ≤ [ 1, 1 ], (3) - [ 0, 0 ] ≤ x[1:2:4](t) ≤ [ 1, 1 ], (4) - 0 ≤ v(t)^2 ≤ 1, (5) - zeros(m) ≤ u(t) ≤ ones(m), (6) - [ 0, 0 ] ≤ u[1:2](t) ≤ [ 1, 1 ], (7) - [ 0, 0 ] ≤ u[1:2:4](t) ≤ [ 1, 1 ], (8) - 0 ≤ u₂(t)^2 ≤ 1, (9) - u₁(t) * x[1:2](t) == 1, (10) - 0 ≤ u₁(t) * x[1:2](t).^3 ≤ 1, (11) -end -x = Vector{Float64}(1:n) -u = 2 * Vector{Float64}(1:m) -@test constraint(o, :eq1 )(x) == x[1] -@test constraint(o, :eq2 )(x) == x -@test constraint(o, :eq3 )(x) == x[1:2] -@test constraint(o, :eq4 )(x) == x[1:2:4] -@test constraint(o, :eq5 )(x) == x[2]^2 -@test constraint(o, :eq6 )(u) == u -@test constraint(o, :eq7 )(u) == u[1:2] -@test constraint(o, :eq8 )(u) == u[1:2:4] -@test constraint(o, :eq9 )(u) == u[2]^2 -@test constraint(o, :eq10)(x, u) == u[1] * x[1:2] -@test constraint(o, :eq11)(x, u) == u[1] * x[1:2].^3 - -n = 11 -m = 6 -@def o begin - z ∈ R^2, variable - t ∈ [ 0, 1 ], time - x ∈ R^n, state - u ∈ R^m, control - r = x₁ - v = x₂ - 0 ≤ r(t) ≤ 1, (1) - zeros(n) ≤ x(t) ≤ ones(n), (2) - [ 0, 0 ] ≤ x[1:2](t) - [ z₁, 1 ] ≤ [ 1, 1 ], (3) - [ 0, 0 ] ≤ x[1:2:4](t) ≤ [ 1, 1 ], (4) - 0 ≤ v(t)^2 ≤ 1, (5) - zeros(m) ≤ u(t) ≤ ones(m), (6) - [ 0, 0 ] ≤ u[1:2](t) ≤ [ 1, 1 ], (7) - [ 0, 0 ] ≤ u[1:2:4](t) ≤ [ 1, 1 ], (8) - 0 ≤ u₂(t)^2 ≤ 1, (9) - u₁(t) * x[1:2](t) + z + f() == 1, (10) - 0 ≤ u₁(t) * x[1:2](t).^3 + z ≤ 1, (11) -end -f() = [ 1, 1 ] -z = 3 * Vector{Float64}(1:2) -x = Vector{Float64}(1:n) -u = 2 * Vector{Float64}(1:m) -@test constraint(o, :eq1 )(x, z) == x[1] -@test constraint(o, :eq2 )(x, z) == x -@test constraint(o, :eq3 )(x, z) == x[1:2] - [ z[1], 1 ] -@test constraint(o, :eq4 )(x, z) == x[1:2:4] -@test constraint(o, :eq5 )(x, z) == x[2]^2 -@test constraint(o, :eq6 )(u, z) == u -@test constraint(o, :eq7 )(u, z) == u[1:2] -@test constraint(o, :eq8 )(u, z) == u[1:2:4] -@test constraint(o, :eq9 )(u, z) == u[2]^2 -@test constraint(o, :eq10)(x, u, z) == u[1] * x[1:2] + z + f() -@test constraint(o, :eq11)(x, u, z) == u[1] * x[1:2].^3 + z - -@def o begin - s ∈ [ 0, 1 ], time - y ∈ R^4, state - w ∈ R, control - r = y₃ - v = y₄ - r(0) + v(1) → min -end -y0 = [ 1, 2, 3, 4 ] -yf = 2 * [ 1, 2, 3, 4 ] -@test is_min(o) -@test o.mayer(y0, yf) == y0[3] + yf[4] - - -@def o begin - s ∈ [ 0, 1 ], time - y ∈ R^4, state - w ∈ R, control - r = y₃ - v = y₄ - r(0) + v(1) → max -end -y0 = [ 1, 2, 3, 4 ] -yf = 2 * [ 1, 2, 3, 4 ] -@test is_max(o) -@test o.mayer(y0, yf) == y0[3] + yf[4] - -@def o begin - z ∈ R^2, variable - s ∈ [ 0, z₁ ], time - y ∈ R^4, state - w ∈ R, control - r = y₃ - v = y₄ - r(0) + v(z₁) + z₂ → min -end -z = [ 5, 6 ] -y0 = [ 1, 2, 3, 4 ] -yf = 2 * [ 1, 2, 3, 4 ] -@test is_min(o) -@test o.mayer(y0, yf, z) == y0[3] + yf[4] + z[2] - -@def o begin - z ∈ R², variable - s ∈ [ 0, z₁ ], time - y ∈ R⁴, state - w ∈ R, control - r = y₃ - v = y₄ - aa = y₁ + w² + v³ + z₂ - ẏ(s) == [ aa(s), r²(s), 0, 0 ] - r(0) + v(z₁) + z₂ → min -end -z = [ 5, 6 ] -y = [ 1, 2, 3, 4 ] -y0 = y -yf = 3y0 -w = 7 -@test o.dynamics(y, w, z) == [ y[1] + w^2 + y[4]^3 + z[2], y[3]^2, 0, 0 ] -@test o.mayer(y0, yf, z) == y0[3] + yf[4] + z[2] - -@def o begin - z ∈ R², variable - s ∈ [ 0, z₁ ], time - y ∈ R⁴, state - w ∈ R, control - r = y₃ - v = y₄ - aa = y₁(s) + v³ + z₂ - ẏ(s) == [ aa(s) + (w^2)(s), r²(s), 0, 0 ] - r(0) + v(z₁) + z₂ → min -end -z = [ 5, 6 ] -y = [ 1, 2, 3, 4 ] -y0 = y -yf = 3y0 -w = 7 -@test o.dynamics(y, w, z) == [ y[1] + w^2 + y[4]^3 + z[2], y[3]^2, 0, 0 ] -@test o.mayer(y0, yf, z) == y0[3] + yf[4] + z[2] - -@def o begin - z ∈ R², variable - s ∈ [ 0, z₁ ], time - y ∈ R⁴, state - w ∈ R, control - r = y₃ - v = y₄ - aa = y₁ - ẏ(s) == [ aa(s), r²(s) + w(s) + z₁, 0, 0 ] -end -z = [ 5, 6 ] -y = [ 1, 2, 3, 4 ] -w = 9 -@test o.dynamics(y, w, z) == [ y[1], y[3]^2 + w + z[1], 0, 0 ] - -@def o begin - z ∈ R², variable - __s ∈ [ 0, z₁ ], time - y ∈ R⁴, state - w ∈ R, control - r = y₃ - v = y₄ - aa = y₁(__s) - ẏ(__s) == [ aa(__s), r²(__s) + w(__s) + z₁, 0, 0 ] -end -z = [ 5, 6 ] -y = [ 1, 2, 3, 4 ] -w = 9 -@test_throws MethodError o.dynamics(y, w, z) - -@def o begin - z ∈ R², variable - s ∈ [ 0, z₁ ], time - y ∈ R⁴, state - w ∈ R, control - r = y₃ - v = y₄ - aa = y₁(s) + v³ + z₂ - ẏ(s) == [ aa(s) + w(s)^2, r²(s), 0, 0 ] -end -z = [ 5, 6 ] -y = [ 1, 2, 3, 4 ] -y0 = y -yf = 3y0 -ww = 19 -@test o.dynamics(y, ww, z) == [ y[1] + ww^2 + y[4]^3 + z[2], y[3]^2, 0, 0 ] - -@def o begin - z ∈ R², variable - s ∈ [ 0, z₁ ], time - y ∈ R⁴, state - w, control - r = y₃ - v = y₄ - aa = y₁ + v³ + z₂ - aa(0) + y₂(z₁) → min -end -z = [ 5, 6 ] -y0 = y -yf = 3y0 -@test o.mayer(y0, yf, z) == y0[1] + y0[4]^3 + z[2] + yf[2] - -@def o begin - z ∈ R², variable - __t ∈ [ 0, z₁ ], time - y ∈ R⁴, state - w, control - r = y₃ - v = y₄ - aa = y₁(__t) + v³ + z₂ - ẏ(__t) == [ aa(__t) + (w^2)(__t), r²(__t), 0, 0 ] - aa(0) + y₂(z₁) → min -end -z = [ 5, 6 ] -y = [ 1, 2, 3, 4 ] -y0 = y -yf = 3y0 -w = 11 -@test o.dynamics(y, w, z) == [ y[1] + w^2 + y[4]^3 + z[2], y[3]^2, 0, 0 ] -@test_throws UndefVarError o.mayer(y0, yf, z) - -@def o begin - z ∈ R², variable - __t ∈ [ 0, z₁ ], time - y ∈ R⁴, state - w, control - r = y₃ - v = y₄ - aa = y₁(0) + v³ + z₂ - ẏ(__t) == [ aa(__t) + (w^2)(__t), r²(__t), 0, 0 ] - aa(0) + y₂(z₁) → min -end -z = [ 5, 6 ] -y = [ 1, 2, 3, 4 ] -y0 = y -yf = 3y0 -w = 11 -@test_throws MethodError o.dynamics(y, w, z) -@test o.mayer(y0, yf, z) == y0[1] + y0[4]^3 + z[2] + yf[2] - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - (x(0) + 2x(1)) + ∫(x(t) + u(t)) → min -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test o.mayer(x0, xf) == x0 + 2xf -@test o.lagrange(x, u) == x + u -@test o.criterion == :min - - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - (x(0) + 2x(1)) + 1 * ∫(x(t) + u(t)) → min -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test o.mayer(x0, xf) == x0 + 2xf -@test o.lagrange(x, u) == x + u -@test o.criterion == :min - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - (x(0) + 2x(1)) - ∫(x(t) + u(t)) → min -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test o.mayer(x0, xf) == x0 + 2xf -@test o.lagrange(x, u) == -(x + u) -@test o.criterion == :min - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - (x(0) + 2x(1)) - 1 * ∫(x(t) + u(t)) → min -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test o.mayer(x0, xf) == x0 + 2xf -@test o.lagrange(x, u) == -(x + u) -@test o.criterion == :min - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - (x(0) + 2x(1)) + ∫(x(t) + u(t)) → max -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test o.mayer(x0, xf) == x0 + 2xf -@test o.lagrange(x, u) == x + u -@test o.criterion == :max - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - (x(0) + 2x(1)) + 1 * ∫(x(t) + u(t)) → max -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test o.mayer(x0, xf) == x0 + 2xf -@test o.lagrange(x, u) == x + u -@test o.criterion == :max - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - (x(0) + 2x(1)) - ∫(x(t) + u(t)) → max -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test o.mayer(x0, xf) == x0 + 2xf -@test o.lagrange(x, u) == -(x + u) -@test o.criterion == :max - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - (x(0) + 2x(1)) - 1 * ∫(x(t) + u(t)) → max -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test o.mayer(x0, xf) == x0 + 2xf -@test o.lagrange(x, u) == -(x + u) -@test o.criterion == :max - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - ∫(x(t) + u(t)) + (x(0) + 2x(1)) → min -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test o.mayer(x0, xf) == x0 + 2xf -@test o.lagrange(x, u) == x + u -@test o.criterion == :min - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - 1 * ∫(x(t) + u(t)) + (x(0) + 2x(1)) → min -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test o.mayer(x0, xf) == x0 + 2xf -@test o.lagrange(x, u) == x + u -@test o.criterion == :min - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - ∫(x(t) + u(t)) - (x(0) + 2x(1)) → min -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test o.mayer(x0, xf) == -(x0 + 2xf) -@test o.lagrange(x, u) == x + u -@test o.criterion == :min - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - 1 * ∫(x(t) + u(t)) - (x(0) + 2x(1)) → min -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test o.mayer(x0, xf) == -(x0 + 2xf) -@test o.lagrange(x, u) == x + u -@test o.criterion == :min - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - ∫(x(t) + u(t)) + (x(0) + 2x(1)) → max -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test o.mayer(x0, xf) == x0 + 2xf -@test o.lagrange(x, u) == x + u -@test o.criterion == :max - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - 1 * ∫(x(t) + u(t)) + (x(0) + 2x(1)) → max -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test o.mayer(x0, xf) == x0 + 2xf -@test o.lagrange(x, u) == x + u -@test o.criterion == :max - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - ∫(x(t) + u(t)) - (x(0) + 2x(1)) → max -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test o.mayer(x0, xf) == -(x0 + 2xf) -@test o.lagrange(x, u) == x + u -@test o.criterion == :max - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - 1 * ∫(x(t) + u(t)) - (x(0) + 2x(1)) → max -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test o.mayer(x0, xf) == -(x0 + 2xf) -@test o.lagrange(x, u) == x + u -@test o.criterion == :max - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - x(0) + 2x(1) + ∫(x(t) + u(t)) → max -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test_throws UndefVarError o.mayer(x0, xf) - -@def o begin - t ∈ [ 0, 1 ], time - x, state - u, control - ∫(x(t) + u(t)) - x(0) + 2x(1) → max -end -x = 1 -u = 2 -x0 = 3 -xf = 4 -@test_throws UndefVarError o.mayer(x0, xf) - -@def o begin - v ∈ R², variable - t ∈ [ 0, 1 ], time - x ∈ R, state - u ∈ R, control - x(0) - v₁ == 0, (1) - x(1) - v₁ == 0, (2) - 0 ≤ x(0) - v₁ ≤ 1, (3) - 0 ≤ x(1) - v₁ ≤ 1, (4) - x(0) + x(1) - v₂ == 0, (5) - 0 ≤ x(0) + x(1) - v₂ ≤ 1, (6) - x(t) - v₁ == 0, (7) - u(t) - v₁ == 0, (8) - z = v₁ + 2v₂ - 0 ≤ x(t) - z ≤ 1, (9) - 0 ≤ u(t) - z ≤ 1, (10) - 0 ≤ x(t) + u(t) - z ≤ 1, (11) - ẋ(t) == z * x(t) + 2u(t) - v₁ == 1, (12) - 0 ≤ v₁ ≤ 1, (13) - z == 1, (14) - 0 ≤ z ≤ 1, (15) - z * x(1) → min -end -x = 1 -x0 = 2 -xf = 3 -u = 4 -v = [ 5, 6 ] -z = v[1] + 2v[2] -@test constraint(o, :eq1)(x0, xf, v) == x0 - v[1] -@test constraint(o, :eq2)(x0, xf, v) == xf - v[1] -@test constraint(o, :eq3)(x0, xf, v) == x0 - v[1] -@test constraint(o, :eq4)(x0, xf, v) == xf - v[1] -@test constraint(o, :eq5)(x0, xf, v) == x0 + xf - v[2] -@test constraint(o, :eq6)(x0, xf, v) == x0 + xf - v[2] -@test constraint(o, :eq7)(x, v) == x - v[1] -@test constraint(o, :eq9)(x, v) == x - z -@test constraint(o, :eq10)(u, v) == u - z -@test constraint(o, :eq11)(x, u, v) == x + u - z -@test constraint(o, :eq12)(v) == v[1] -@test constraint(o, :eq13)(v) == v[1] -@test constraint(o, :eq14)(v) == v[1] + 2v[2] -@test constraint(o, :eq15)(v) == v[1] + 2v[2] - -@def o begin - v ∈ R, variable - t ∈ [ 0, 1 ], time - x ∈ R, state - u ∈ R², control - x(0) ≤ 0 - x(0) ≤ 0, (1) - x(1) ≤ 0 - x(1) ≤ 0, (2) - x³(0) ≤ 0 - x³(0) ≤ 0, (3) - x³(1) ≤ 0 - x³(1) ≤ 0, (4) - x(t) ≤ 0 - x(t) ≤ 0, (5) - x(t) ≤ 0 - x(t) ≤ 0, (6) - u₁(t) ≤ 0 - u₁(t) ≤ 0, (7) - u₁(t) ≤ 0 - u₁(t) ≤ 0, (8) - x³(t) ≤ 0 - x³(t) ≤ 0, (9) - x³(t) ≤ 0 - x³(t) ≤ 0, (10) - (u₁^3)(t) ≤ 0 - (u₁^3)(t) ≤ 0, (11) - (u₁^3)(t) ≤ 0 - (u₁^3)(t) ≤ 0, (12) - x(t) + (u₁^3)(t) ≤ 0 - x(t) + (u₁^3)(t) ≤ 0, (13) - x(t) + (u₁^3)(t) ≤ 0 - x(t) + (u₁^3)(t) ≤ 0, (14) - v ≤ 0 - v ≤ 0, (15) -end + t0 = 0 + @def o t ∈ [ t0, t0 + 4 ], time + @test o.initial_time == t0 + @test o.final_time == t0 + 4 -@test o.constraints[:eq1 ][3] == -Inf -@test o.constraints[:eq2 ][3] == -Inf -@test o.constraints[:eq3 ][3] == -Inf -@test o.constraints[:eq4 ][3] == -Inf -@test o.constraints[:eq5 ][3] == -Inf -@test o.constraints[:eq6 ][3] == -Inf -@test o.constraints[:eq7 ][3] == -Inf -@test o.constraints[:eq8 ][3] == -Inf -@test o.constraints[:eq9 ][3] == -Inf -@test o.constraints[:eq10][3] == -Inf -@test o.constraints[:eq11][3] == -Inf -@test o.constraints[:eq12][3] == -Inf -@test o.constraints[:eq13][3] == -Inf -@test o.constraints[:eq14][3] == -Inf -@test o.constraints[:eq15][3] == -Inf -@test o.constraints[:eq1 ][4] == 0 -@test o.constraints[:eq2 ][4] == 0 -@test o.constraints[:eq3 ][4] == 0 -@test o.constraints[:eq4 ][4] == 0 -@test o.constraints[:eq5 ][4] == 0 -@test o.constraints[:eq6 ][4] == 0 -@test o.constraints[:eq7 ][4] == 0 -@test o.constraints[:eq8 ][4] == 0 -@test o.constraints[:eq9 ][4] == 0 -@test o.constraints[:eq10][4] == 0 -@test o.constraints[:eq11][4] == 0 -@test o.constraints[:eq12][4] == 0 -@test o.constraints[:eq13][4] == 0 -@test o.constraints[:eq14][4] == 0 -@test o.constraints[:eq15][4] == 0 - -@def o begin - v ∈ R, variable - t ∈ [ 0, 1 ], time - x ∈ R, state - u ∈ R², control - x(0) ≥ 0 - x(0) ≥ 0, (1) - x(1) ≥ 0 - x(1) ≥ 0, (2) - x³(0) ≥ 0 - x³(0) ≥ 0, (3) - x³(1) ≥ 0 - x³(1) ≥ 0, (4) - x(t) ≥ 0 - x(t) ≥ 0, (5) - x(t) ≥ 0 - x(t) ≥ 0, (6) - u₁(t) ≥ 0 - u₁(t) ≥ 0, (7) - u₁(t) ≥ 0 - u₁(t) ≥ 0, (8) - x³(t) ≥ 0 - x³(t) ≥ 0, (9) - x³(t) ≥ 0 - x³(t) ≥ 0, (10) - (u₁^3)(t) ≥ 0 - (u₁^3)(t) ≥ 0, (11) - (u₁^3)(t) ≥ 0 - (u₁^3)(t) ≥ 0, (12) - x(t) + (u₁^3)(t) ≥ 0 - x(t) + (u₁^3)(t) ≥ 0, (13) - x(t) + (u₁^3)(t) ≥ 0 - x(t) + (u₁^3)(t) ≥ 0, (14) - v ≥ 0 - v ≥ 0, (15) -end + @test_throws ParsingError @def o t ∈ 1 -@test o.constraints[:eq1 ][3] == 0 -@test o.constraints[:eq2 ][3] == 0 -@test o.constraints[:eq3 ][3] == 0 -@test o.constraints[:eq4 ][3] == 0 -@test o.constraints[:eq5 ][3] == 0 -@test o.constraints[:eq6 ][3] == 0 -@test o.constraints[:eq7 ][3] == 0 -@test o.constraints[:eq8 ][3] == 0 -@test o.constraints[:eq9 ][3] == 0 -@test o.constraints[:eq10][3] == 0 -@test o.constraints[:eq11][3] == 0 -@test o.constraints[:eq12][3] == 0 -@test o.constraints[:eq13][3] == 0 -@test o.constraints[:eq14][3] == 0 -@test o.constraints[:eq15][3] == 0 -@test o.constraints[:eq1 ][4] == Inf -@test o.constraints[:eq2 ][4] == Inf -@test o.constraints[:eq3 ][4] == Inf -@test o.constraints[:eq4 ][4] == Inf -@test o.constraints[:eq5 ][4] == Inf -@test o.constraints[:eq6 ][4] == Inf -@test o.constraints[:eq7 ][4] == Inf -@test o.constraints[:eq8 ][4] == Inf -@test o.constraints[:eq9 ][4] == Inf -@test o.constraints[:eq10][4] == Inf -@test o.constraints[:eq11][4] == Inf -@test o.constraints[:eq12][4] == Inf -@test o.constraints[:eq13][4] == Inf -@test o.constraints[:eq14][4] == Inf -@test o.constraints[:eq15][4] == Inf - -@test_throws ParsingError @def o t ∈ 1 - -# tests from ct_parser.jl - - # phase 1: minimal problems, to check all possible syntaxes - - # time @def ocp t ∈ [ 0.0 , 1.0 ], time; @test ocp isa OptimalControlModel @test ocp.time_name == "t" @@ -1190,6 +271,19 @@ end @test ocp.initial_time == Index(1) @test ocp.final_time == tf +end + +# --------------------------------------------------------------- +# --------------------------------------------------------------- +@testset "state / control" begin + + @def o begin + x ∈ R, state + u ∈ R, control + end + @test o.state_dimension == 1 + @test o.control_dimension == 1 + # state t0 = 1.0; tf = 1.1 @def ocp begin @@ -1239,7 +333,6 @@ end @test ocp.state_dimension == 1 @test ocp.state_name == "a" - t0 = 5.0; tf = 5.1 @def ocp begin t ∈ [ t0 , tf ], time @@ -1252,7 +345,6 @@ end @test ocp.state_dimension == 1 @test ocp.state_name == "b" - t0 = 6.0; tf = 6.1 @def ocp begin t ∈ [ t0 , tf ], time @@ -1265,7 +357,6 @@ end @test ocp.state_dimension == 9 @test ocp.state_name == "u" - n = 3 t0 = 7.0; tf = 7.1 @def ocp begin @@ -1279,7 +370,6 @@ end @test ocp.state_dimension == n @test ocp.state_name == "u" - # control t0 = 1.0; tf = 1.1 @def ocp begin @@ -1369,66 +459,525 @@ end @test ocp.control_dimension == n @test ocp.control_name == "u" +end - # variables - t0 = .0; tf = .1 - @def ocp begin - t ∈ [ t0, tf ], time - a, variable - end ; - @test ocp isa OptimalControlModel - @test ocp.variable_dimension == 1 - @test ocp.variable_name == "a" - - t0 = .0; tf = .1 - @def ocp begin - t ∈ [ t0, tf ], time - a ∈ R³, variable - end ; - @test ocp isa OptimalControlModel - @test ocp.variable_dimension == 3 - @test ocp.variable_name == "a" +# --------------------------------------------------------------- +# --------------------------------------------------------------- +@testset "dynamics" begin - # alias - t0 = .0; tf = .1 - @def ocp begin - t ∈ [ t0, tf ], time + @def o begin + t ∈ [ 0, 1 ], time x ∈ R^3, state - u ∈ R^3, control - - r = x[1] - v = x₂ - a = x₃ - end ; - @test ocp isa OptimalControlModel - @test ocp.time_name == "t" - @test ocp.initial_time == t0 - @test ocp.final_time == tf - @test ocp.control_name == "u" - @test ocp.control_dimension == 3 - @test ocp.state_name == "x" - @test ocp.state_dimension == 3 + u ∈ R^2, control + ẋ(t) == [ x[1](t) + 2u[2](t), 2x[3](t), x[1](t) + u[2](t) ] + end + @test o.state_dimension == 3 + @test o.control_dimension == 2 + x = [ 1, 2, 3 ] + u = [ -1, 2 ] + @test o.dynamics(x, u) == [ x[1] + 2u[2], 2x[3], x[1] + u[2] ] + @def o begin + z ∈ R², variable + s ∈ [ 0, z₁ ], time + y ∈ R⁴, state + w ∈ R, control + r = y₃ + v = y₄ + aa = y₁ + ẏ(s) == [ aa(s), r²(s) + w(s) + z₁, 0, 0 ] + end + z = [ 5, 6 ] + y = [ 1, 2, 3, 4 ] + w = 9 + @test o.dynamics(y, w, z) == [ y[1], y[3]^2 + w + z[1], 0, 0 ] + + @def o begin + z ∈ R², variable + __s ∈ [ 0, z₁ ], time + y ∈ R⁴, state + w ∈ R, control + r = y₃ + v = y₄ + aa = y₁(__s) + ẏ(__s) == [ aa(__s), r²(__s) + w(__s) + z₁, 0, 0 ] + end + z = [ 5, 6 ] + y = [ 1, 2, 3, 4 ] + w = 9 + @test_throws MethodError o.dynamics(y, w, z) + + @def o begin + z ∈ R², variable + s ∈ [ 0, z₁ ], time + y ∈ R⁴, state + w ∈ R, control + r = y₃ + v = y₄ + aa = y₁(s) + v³ + z₂ + ẏ(s) == [ aa(s) + w(s)^2, r²(s), 0, 0 ] + end + z = [ 5, 6 ] + y = [ 1, 2, 3, 4 ] + y0 = y + yf = 3y0 + ww = 19 + @test o.dynamics(y, ww, z) == [ y[1] + ww^2 + y[4]^3 + z[2], y[3]^2, 0, 0 ] + + @def o begin + z ∈ R², variable + __t ∈ [ 0, z₁ ], time + y ∈ R⁴, state + w, control + r = y₃ + v = y₄ + aa = y₁(0) + v³ + z₂ + ẏ(__t) == [ aa(__t) + (w^2)(__t), r²(__t), 0, 0 ] + aa(0) + y₂(z₁) → min + end + z = [ 5, 6 ] + y = [ 1, 2, 3, 4 ] + y0 = y + yf = 3y0 + w = 11 + @test_throws MethodError o.dynamics(y, w, z) + @test o.mayer(y0, yf, z) == y0[1] + y0[4]^3 + z[2] + yf[2] - # objectives - t0 = .0; tf = .1 - @def ocp begin - t ∈ [ t0, tf ], time - x ∈ R^3, state - u ∈ R^3, control - ∫( 0.5u(t)^2 ) → min - end ; - @test ocp isa OptimalControlModel +end - t0 = .0; tf = .1 - @def ocp begin - t ∈ [ t0, tf ], time - x ∈ R^3, state - u ∈ R^3, control - ∫( 0.5u(t)^2 ) → max - end ; - @test ocp isa OptimalControlModel +# --------------------------------------------------------------- +# --------------------------------------------------------------- +@testset "constraints" begin - # constraints + @def o begin + tf, variable + t ∈ [ 0, tf ], time + x ∈ R², state + u ∈ R, control + r = x₁ + v = x₂ + w = r¹ + 2v³ + r(0) + w(tf) - tf² == 0, (1) + end + tf = 2 + x0 = [ 1, 2 ] + xf = [ 3, 4 ] + @test constraint(o, :eq1)(x0, xf, tf) == x0[1] + ( xf[1] + 2xf[2]^3 ) - tf^2 + + n = 11 + m = 6 + @def o begin + t ∈ [ 0, 1 ], time + x ∈ R^n, state + u ∈ R^m, control + r = x₁ + v = x₂ + 0 ≤ r(t) ≤ 1, (1) + zeros(n) ≤ x(t) ≤ ones(n), (2) + [ 0, 0 ] ≤ x[1:2](t) ≤ [ 1, 1 ], (3) + [ 0, 0 ] ≤ x[1:2:4](t) ≤ [ 1, 1 ], (4) + 0 ≤ v(t)^2 ≤ 1, (5) + zeros(m) ≤ u(t) ≤ ones(m), (6) + [ 0, 0 ] ≤ u[1:2](t) ≤ [ 1, 1 ], (7) + [ 0, 0 ] ≤ u[1:2:4](t) ≤ [ 1, 1 ], (8) + 0 ≤ u₂(t)^2 ≤ 1, (9) + u₁(t) * x[1:2](t) == 1, (10) + 0 ≤ u₁(t) * x[1:2](t).^3 ≤ 1, (11) + end + x = Vector{Float64}(1:n) + u = 2 * Vector{Float64}(1:m) + @test constraint(o, :eq1 )(x) == x[1] + @test constraint(o, :eq2 )(x) == x + @test constraint(o, :eq3 )(x) == x[1:2] + @test constraint(o, :eq4 )(x) == x[1:2:4] + @test constraint(o, :eq5 )(x) == x[2]^2 + @test constraint(o, :eq6 )(u) == u + @test constraint(o, :eq7 )(u) == u[1:2] + @test constraint(o, :eq8 )(u) == u[1:2:4] + @test constraint(o, :eq9 )(u) == u[2]^2 + @test constraint(o, :eq10)(x, u) == u[1] * x[1:2] + @test constraint(o, :eq11)(x, u) == u[1] * x[1:2].^3 + + n = 11 + m = 6 + @def o begin + z ∈ R^2, variable + t ∈ [ 0, 1 ], time + x ∈ R^n, state + u ∈ R^m, control + r = x₁ + v = x₂ + 0 ≤ r(t) ≤ 1, (1) + zeros(n) ≤ x(t) ≤ ones(n), (2) + [ 0, 0 ] ≤ x[1:2](t) - [ z₁, 1 ] ≤ [ 1, 1 ], (3) + [ 0, 0 ] ≤ x[1:2:4](t) ≤ [ 1, 1 ], (4) + 0 ≤ v(t)^2 ≤ 1, (5) + zeros(m) ≤ u(t) ≤ ones(m), (6) + [ 0, 0 ] ≤ u[1:2](t) ≤ [ 1, 1 ], (7) + [ 0, 0 ] ≤ u[1:2:4](t) ≤ [ 1, 1 ], (8) + 0 ≤ u₂(t)^2 ≤ 1, (9) + u₁(t) * x[1:2](t) + z + f() == 1, (10) + 0 ≤ u₁(t) * x[1:2](t).^3 + z ≤ 1, (11) + end + f() = [ 1, 1 ] + z = 3 * Vector{Float64}(1:2) + x = Vector{Float64}(1:n) + u = 2 * Vector{Float64}(1:m) + @test constraint(o, :eq1 )(x, z) == x[1] + @test constraint(o, :eq2 )(x, z) == x + @test constraint(o, :eq3 )(x, z) == x[1:2] - [ z[1], 1 ] + @test constraint(o, :eq4 )(x, z) == x[1:2:4] + @test constraint(o, :eq5 )(x, z) == x[2]^2 + @test constraint(o, :eq6 )(u, z) == u + @test constraint(o, :eq7 )(u, z) == u[1:2] + @test constraint(o, :eq8 )(u, z) == u[1:2:4] + @test constraint(o, :eq9 )(u, z) == u[2]^2 + @test constraint(o, :eq10)(x, u, z) == u[1] * x[1:2] + z + f() + @test constraint(o, :eq11)(x, u, z) == u[1] * x[1:2].^3 + z + + + @def o begin + t ∈ [ 0, 1 ], time + x ∈ R², state + u ∈ R, control + begin + r = x₁ + v = x₂ + w = r + 2v + r(0) == 0, (1) + end + v(0) == 1, (♡) + ẋ(t) == [ v(t), w(t)^2 ] + ∫( u(t)^2 + x₁(t) ) → min + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = 3 + @test constraint(o, :eq1)(x0, xf) == x0[1] + @test constraint(o, Symbol("♡"))(x0, xf) == x0[2] + @test o.dynamics(x, u) == [ x[2], (x[1] + 2x[2])^2 ] + @test o.lagrange(x, u) == u^2 + x[1] + + @def o begin + t ∈ [ 0, 1 ], time + x ∈ R², state + u ∈ R, control + r = x₁ + v = x₂ + w = r + 2v + r(0) == 0, (1) + v(0) == 1, (♡) + ẋ(t) == [ v(t), w(t)^2 ] + ∫( u(t)^2 + x₁(t) ) → min + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = 3 + @test constraint(o, :eq1)(x0, xf) == x0[1] + @test constraint(o, Symbol("♡"))(x0, xf) == x0[2] + @test o.dynamics(x, u) == [ x[2], (x[1] + 2x[2])^2 ] + @test o.lagrange(x, u) == u^2 + x[1] + + @def o begin + z ∈ R², variable + t ∈ [ 0, 1 ], time + x ∈ R², state + u ∈ R, control + r = x₁ + v = x₂ + w = r + 2v + r(0) == 0, (1) + v(0) == 1, (♡) + ẋ(t) == [ v(t), w(t)^2 + z₁ ] + ∫( u(t)^2 + z₂ * x₁(t) ) → min + end + x = [ 1, 2 ] + x0 = 2 * [ 1, 2 ] + xf = 3 * [ 1, 2 ] + u = 3 + z = [ 4, 5 ] + @test constraint(o, :eq1)(x0, xf, z) == x0[1] + @test constraint(o, Symbol("♡"))(x0, xf, z) == x0[2] + @test o.dynamics(x, u, z) == [ x[2], (x[1] + 2x[2])^2 + z[1] ] + @test o.lagrange(x, u, z) == u^2 + z[2] * x[1] + + @def o begin + t ∈ [ 0, 1 ], time + x ∈ R², state + u ∈ R, control + r = x₁ + v = x₂ + r(0)^2 + v(1) == 0, (1) + v(0) == 1, (♡) + ẋ(t) == [ v(t), r(t)^2 ] + ∫( u(t)^2 + x₁(t) ) → min + end + x0 = [ 2, 3 ] + xf = [ 4, 5 ] + x = [ 1, 2 ] + u = 3 + @test constraint(o, :eq1)(x0, xf) == x0[1]^2 + xf[2] + @test constraint(o, Symbol("♡"))(x0, xf) == x0[2] + @test o.dynamics(x, u) == [ x[2], x[1]^2 ] + @test o.lagrange(x, u) == u^2 + x[1] + + @def o begin + z ∈ R, variable + t ∈ [ 0, 1 ], time + x ∈ R², state + u ∈ R, control + r = x₁ + v = x₂ + r(0) - z == 0, (1) + v(0) == 1, (♡) + ẋ(t) == [ v(t), r(t)^2 + z ] + ∫( u(t)^2 + z * x₁(t) ) → min + end + x0 = [ 2, 3 ] + xf = [ 4, 5 ] + x = [ 1, 2 ] + u = 3 + z = 4 + @test constraint(o, :eq1)(x0, xf, z) == x0[1] - z + @test constraint(o, Symbol("♡"))(x0, xf, z) == x0[2] + @test o.dynamics(x, u, z) == [ x[2], x[1]^2 + z ] + @test o.lagrange(x, u, z) == u^2 + z * x[1] + + @def o begin + z ∈ R, variable + t ∈ [ 0, 1 ], time + x ∈ R², state + u ∈ R, control + r = x₁ + v = x₂ + 0 ≤ r(0) - z ≤ 1, (1) + 0 ≤ v(1)^2 ≤ 1, (2) + [ 0, 0 ] ≤ x(0) ≤ [ 1, 1 ], (♡) + ẋ(t) == [ v(t), r(t)^2 + z ] + ∫( u(t)^2 + z * x₁(t) ) → min + end + x0 = [ 2, 3 ] + xf = [ 4, 5 ] + x = [ 1, 2 ] + u = 3 + z = 4 + @test constraint(o, :eq1)(x0, xf, z) == x0[1] - z + @test constraint(o, :eq2)(x0, xf, z) == xf[2]^2 + @test constraint(o, Symbol("♡"))(x0, xf, z) == x0 + @test o.dynamics(x, u, z) == [ x[2], x[1]^2 + z ] + @test o.lagrange(x, u, z) == u^2 + z * x[1] + + @def o begin + z ∈ R, variable + t ∈ [ 0, 1 ], time + x ∈ R², state + u ∈ R, control + r = x₁ + v = x₂ + 1 ≥ r(0) - z ≥ 0, (1) + 1 ≥ v(1)^2 ≥ 0, (2) + [ 1, 1 ] ≥ x(0) ≥ [ 0, 0 ], (3) + ẋ(t) == [ v(t), r(t)^2 + z ] + ∫( u(t)^2 + z * x₁(t) ) → min + end + x0 = [ 2, 3 ] + xf = [ 4, 5 ] + x = [ 1, 2 ] + u = 3 + z = 4 + @test constraint(o, :eq1)(x0, xf, z) == x0[1] - z + @test constraint(o, :eq2)(x0, xf, z) == xf[2]^2 + @test constraint(o, :eq3)(x0, xf, z) == x0 + @test o.dynamics(x, u, z) == [ x[2], x[1]^2 + z ] + @test o.lagrange(x, u, z) == u^2 + z * x[1] + @test o.constraints[:eq1][3] == 0 + @test o.constraints[:eq1][4] == 1 + @test o.constraints[:eq2][3] == 0 + @test o.constraints[:eq2][4] == 1 + @test o.constraints[:eq3][3] == [ 0, 0 ] + @test o.constraints[:eq3][4] == [ 1, 1 ] + + @def o begin + v ∈ R², variable + t ∈ [ 0, 1 ], time + x ∈ R, state + u ∈ R, control + x(0) - v₁ == 0, (1) + x(1) - v₁ == 0, (2) + 0 ≤ x(0) - v₁ ≤ 1, (3) + 0 ≤ x(1) - v₁ ≤ 1, (4) + x(0) + x(1) - v₂ == 0, (5) + 0 ≤ x(0) + x(1) - v₂ ≤ 1, (6) + x(t) - v₁ == 0, (7) + u(t) - v₁ == 0, (8) + z = v₁ + 2v₂ + 0 ≤ x(t) - z ≤ 1, (9) + 0 ≤ u(t) - z ≤ 1, (10) + 0 ≤ x(t) + u(t) - z ≤ 1, (11) + ẋ(t) == z * x(t) + 2u(t) + v₁ == 1, (12) + 0 ≤ v₁ ≤ 1, (13) + z == 1, (14) + 0 ≤ z ≤ 1, (15) + z * x(1) → min + end + x = 1 + x0 = 2 + xf = 3 + u = 4 + v = [ 5, 6 ] + z = v[1] + 2v[2] + @test constraint(o, :eq1)(x0, xf, v) == x0 - v[1] + @test constraint(o, :eq2)(x0, xf, v) == xf - v[1] + @test constraint(o, :eq3)(x0, xf, v) == x0 - v[1] + @test constraint(o, :eq4)(x0, xf, v) == xf - v[1] + @test constraint(o, :eq5)(x0, xf, v) == x0 + xf - v[2] + @test constraint(o, :eq6)(x0, xf, v) == x0 + xf - v[2] + @test constraint(o, :eq7)(x, v) == x - v[1] + @test constraint(o, :eq9)(x, v) == x - z + @test constraint(o, :eq10)(u, v) == u - z + @test constraint(o, :eq11)(x, u, v) == x + u - z + @test constraint(o, :eq12)(v) == v[1] + @test constraint(o, :eq13)(v) == v[1] + @test constraint(o, :eq14)(v) == v[1] + 2v[2] + @test constraint(o, :eq15)(v) == v[1] + 2v[2] + + @def o begin + v ∈ R, variable + t ∈ [ 0, 1 ], time + x ∈ R, state + u ∈ R², control + x(0) ≤ 0 + x(0) ≤ 0, (1) + x(1) ≤ 0 + x(1) ≤ 0, (2) + x³(0) ≤ 0 + x³(0) ≤ 0, (3) + x³(1) ≤ 0 + x³(1) ≤ 0, (4) + x(t) ≤ 0 + x(t) ≤ 0, (5) + x(t) ≤ 0 + x(t) ≤ 0, (6) + u₁(t) ≤ 0 + u₁(t) ≤ 0, (7) + u₁(t) ≤ 0 + u₁(t) ≤ 0, (8) + x³(t) ≤ 0 + x³(t) ≤ 0, (9) + x³(t) ≤ 0 + x³(t) ≤ 0, (10) + (u₁^3)(t) ≤ 0 + (u₁^3)(t) ≤ 0, (11) + (u₁^3)(t) ≤ 0 + (u₁^3)(t) ≤ 0, (12) + x(t) + (u₁^3)(t) ≤ 0 + x(t) + (u₁^3)(t) ≤ 0, (13) + x(t) + (u₁^3)(t) ≤ 0 + x(t) + (u₁^3)(t) ≤ 0, (14) + v ≤ 0 + v ≤ 0, (15) + end + + @test o.constraints[:eq1 ][3] == -Inf + @test o.constraints[:eq2 ][3] == -Inf + @test o.constraints[:eq3 ][3] == -Inf + @test o.constraints[:eq4 ][3] == -Inf + @test o.constraints[:eq5 ][3] == -Inf + @test o.constraints[:eq6 ][3] == -Inf + @test o.constraints[:eq7 ][3] == -Inf + @test o.constraints[:eq8 ][3] == -Inf + @test o.constraints[:eq9 ][3] == -Inf + @test o.constraints[:eq10][3] == -Inf + @test o.constraints[:eq11][3] == -Inf + @test o.constraints[:eq12][3] == -Inf + @test o.constraints[:eq13][3] == -Inf + @test o.constraints[:eq14][3] == -Inf + @test o.constraints[:eq15][3] == -Inf + @test o.constraints[:eq1 ][4] == 0 + @test o.constraints[:eq2 ][4] == 0 + @test o.constraints[:eq3 ][4] == 0 + @test o.constraints[:eq4 ][4] == 0 + @test o.constraints[:eq5 ][4] == 0 + @test o.constraints[:eq6 ][4] == 0 + @test o.constraints[:eq7 ][4] == 0 + @test o.constraints[:eq8 ][4] == 0 + @test o.constraints[:eq9 ][4] == 0 + @test o.constraints[:eq10][4] == 0 + @test o.constraints[:eq11][4] == 0 + @test o.constraints[:eq12][4] == 0 + @test o.constraints[:eq13][4] == 0 + @test o.constraints[:eq14][4] == 0 + @test o.constraints[:eq15][4] == 0 + + @def o begin + v ∈ R, variable + t ∈ [ 0, 1 ], time + x ∈ R, state + u ∈ R², control + x(0) ≥ 0 + x(0) ≥ 0, (1) + x(1) ≥ 0 + x(1) ≥ 0, (2) + x³(0) ≥ 0 + x³(0) ≥ 0, (3) + x³(1) ≥ 0 + x³(1) ≥ 0, (4) + x(t) ≥ 0 + x(t) ≥ 0, (5) + x(t) ≥ 0 + x(t) ≥ 0, (6) + u₁(t) ≥ 0 + u₁(t) ≥ 0, (7) + u₁(t) ≥ 0 + u₁(t) ≥ 0, (8) + x³(t) ≥ 0 + x³(t) ≥ 0, (9) + x³(t) ≥ 0 + x³(t) ≥ 0, (10) + (u₁^3)(t) ≥ 0 + (u₁^3)(t) ≥ 0, (11) + (u₁^3)(t) ≥ 0 + (u₁^3)(t) ≥ 0, (12) + x(t) + (u₁^3)(t) ≥ 0 + x(t) + (u₁^3)(t) ≥ 0, (13) + x(t) + (u₁^3)(t) ≥ 0 + x(t) + (u₁^3)(t) ≥ 0, (14) + v ≥ 0 + v ≥ 0, (15) + end + + @test o.constraints[:eq1 ][3] == 0 + @test o.constraints[:eq2 ][3] == 0 + @test o.constraints[:eq3 ][3] == 0 + @test o.constraints[:eq4 ][3] == 0 + @test o.constraints[:eq5 ][3] == 0 + @test o.constraints[:eq6 ][3] == 0 + @test o.constraints[:eq7 ][3] == 0 + @test o.constraints[:eq8 ][3] == 0 + @test o.constraints[:eq9 ][3] == 0 + @test o.constraints[:eq10][3] == 0 + @test o.constraints[:eq11][3] == 0 + @test o.constraints[:eq12][3] == 0 + @test o.constraints[:eq13][3] == 0 + @test o.constraints[:eq14][3] == 0 + @test o.constraints[:eq15][3] == 0 + @test o.constraints[:eq1 ][4] == Inf + @test o.constraints[:eq2 ][4] == Inf + @test o.constraints[:eq3 ][4] == Inf + @test o.constraints[:eq4 ][4] == Inf + @test o.constraints[:eq5 ][4] == Inf + @test o.constraints[:eq6 ][4] == Inf + @test o.constraints[:eq7 ][4] == Inf + @test o.constraints[:eq8 ][4] == Inf + @test o.constraints[:eq9 ][4] == Inf + @test o.constraints[:eq10][4] == Inf + @test o.constraints[:eq11][4] == Inf + @test o.constraints[:eq12][4] == Inf + @test o.constraints[:eq13][4] == Inf + @test o.constraints[:eq14][4] == Inf + @test o.constraints[:eq15][4] == Inf # minimal constraint tests # remark: constraint are heavily tested in test_ctparser_constraints.jl @@ -1508,41 +1057,6 @@ end @test ocp.state_name == "t" @test ocp.state_dimension == 3 - # error detections (this can be tricky -> need more work) - - # this one is detected by the generated code (and not the parser) - @test_throws CTException @def o begin - t ∈ [ t0, tf ], time - t ∈ [ t0, tf ], time - end - - # illegal constraint name (1bis), detected by the parser - t0 = 9.0; tf = 9.1 - r0 = 1.0; v0 = 2.0; m0 = 3.0 - @test_throws ParsingError @def o begin - t ∈ [ t0, tf ], time - x ∈ R^2, state - u ∈ R^2, control - - 0 ≤ u(t) ≤ 1 , (1bis) - end ; - - # t0 is unknown in the x(t0) constraint, detected by the parser - r0 = 1.0; v0 = 2.0; m0 = 3.0 - @test_throws ParsingError @def o begin - t ∈ [ 0, 1 ], time - x ∈ R^2, state - u ∈ R^2, control - - x(t0) == [ r0, v0, m0 ], (1) - 0 ≤ u(t) ≤ 1 , (1bis) - end ; - - # -#end - -# old tests from test_ctparser_constraints.jl - # # test all constraints on @def macro # @@ -1895,3 +1409,929 @@ end end end + +# --------------------------------------------------------------- +# --------------------------------------------------------------- +@testset "Lagrange cost" begin + + # -------------------------------- + # min + t0 = 0 + tf = 1 + @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + ∫( 0.5u(t)^2 ) → min + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = -1 + A = [ 0 1 + 0 0 ] + B = [ 0 + 1 ] + @test constraint(o, :eq1)(x0, xf) == x0 + @test o.dynamics(x, u) == A * x + B * u + @test o.lagrange(x, u) == 0.5u^2 + @test o.criterion == :min + + t0 = 0 + tf = 1 + @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + -∫( 0.5u(t)^2 ) → min + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = -1 + A = [ 0 1 + 0 0 ] + B = [ 0 + 1 ] + @test constraint(o, :eq1)(x0, xf) == x0 + @test o.dynamics(x, u) == A * x + B * u + @test o.lagrange(x, u) == -0.5u^2 + @test o.criterion == :min + + t0 = 0 + tf = 1 + @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + 0.5 * ∫( u(t)^2 ) → min + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = -1 + A = [ 0 1 + 0 0 ] + B = [ 0 + 1 ] + @test constraint(o, :eq1)(x0, xf) == x0 + @test o.dynamics(x, u) == A * x + B * u + @test o.lagrange(x, u) == 0.5u^2 + @test o.criterion == :min + + t0 = 0 + tf = 1 + @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + 0.5∫( u(t)^2 ) → min + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = -1 + A = [ 0 1 + 0 0 ] + B = [ 0 + 1 ] + @test constraint(o, :eq1)(x0, xf) == x0 + @test o.dynamics(x, u) == A * x + B * u + @test o.lagrange(x, u) == 0.5u^2 + @test o.criterion == :min + + t0 = 0 + tf = 1 + @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + -0.5 * ∫( u(t)^2 ) → min + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = -1 + A = [ 0 1 + 0 0 ] + B = [ 0 + 1 ] + @test constraint(o, :eq1)(x0, xf) == x0 + @test o.dynamics(x, u) == A * x + B * u + @test o.lagrange(x, u) == -0.5u^2 + @test o.criterion == :min + + t0 = 0 + tf = 1 + @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + ∫( u(t)^2 ) / 2 → min + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = -1 + A = [ 0 1 + 0 0 ] + B = [ 0 + 1 ] + @test constraint(o, :eq1)(x0, xf) == x0 + @test o.dynamics(x, u) == A * x + B * u + @test o.lagrange(x, u) == 0.5u^2 + @test o.criterion == :min + + t0 = 0 + tf = 1 + @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + -∫( u(t)^2 ) / 2 → min + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = -1 + A = [ 0 1 + 0 0 ] + B = [ 0 + 1 ] + @test constraint(o, :eq1)(x0, xf) == x0 + @test o.dynamics(x, u) == A * x + B * u + @test o.lagrange(x, u) == -0.5u^2 + @test o.criterion == :min + + # ----------------------------------- + # max + t0 = 0 + tf = 1 + @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + ∫( 0.5u(t)^2 ) → max + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = -1 + A = [ 0 1 + 0 0 ] + B = [ 0 + 1 ] + @test constraint(o, :eq1)(x0, xf) == x0 + @test o.dynamics(x, u) == A * x + B * u + @test o.lagrange(x, u) == 0.5u^2 + @test o.criterion == :max + + t0 = 0 + tf = 1 + @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + -∫( 0.5u(t)^2 ) → max + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = -1 + A = [ 0 1 + 0 0 ] + B = [ 0 + 1 ] + @test constraint(o, :eq1)(x0, xf) == x0 + @test o.dynamics(x, u) == A * x + B * u + @test o.lagrange(x, u) == -0.5u^2 + @test o.criterion == :max + + t0 = 0 + tf = 1 + @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + 0.5 * ∫( u(t)^2 ) → max + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = -1 + A = [ 0 1 + 0 0 ] + B = [ 0 + 1 ] + @test constraint(o, :eq1)(x0, xf) == x0 + @test o.dynamics(x, u) == A * x + B * u + @test o.lagrange(x, u) == 0.5u^2 + @test o.criterion == :max + + t0 = 0 + tf = 1 + @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + 0.5∫( u(t)^2 ) → max + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = -1 + A = [ 0 1 + 0 0 ] + B = [ 0 + 1 ] + @test constraint(o, :eq1)(x0, xf) == x0 + @test o.dynamics(x, u) == A * x + B * u + @test o.lagrange(x, u) == 0.5u^2 + @test o.criterion == :max + + t0 = 0 + tf = 1 + @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + -0.5 * ∫( u(t)^2 ) → max + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = -1 + A = [ 0 1 + 0 0 ] + B = [ 0 + 1 ] + @test constraint(o, :eq1)(x0, xf) == x0 + @test o.dynamics(x, u) == A * x + B * u + @test o.lagrange(x, u) == -0.5u^2 + @test o.criterion == :max + + t0 = 0 + tf = 1 + @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + ∫( u(t)^2 ) / 2 → max + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = -1 + A = [ 0 1 + 0 0 ] + B = [ 0 + 1 ] + @test constraint(o, :eq1)(x0, xf) == x0 + @test o.dynamics(x, u) == A * x + B * u + @test o.lagrange(x, u) == 0.5u^2 + @test o.criterion == :max + + t0 = 0 + tf = 1 + @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + -∫( u(t)^2 ) / 2 → max + end + x = [ 1, 2 ] + x0 = 2 * x + xf = 3 * x + u = -1 + A = [ 0 1 + 0 0 ] + B = [ 0 + 1 ] + @test constraint(o, :eq1)(x0, xf) == x0 + @test o.dynamics(x, u) == A * x + B * u + @test o.lagrange(x, u) == -0.5u^2 + @test o.criterion == :max + + # ----------------------------------- + t0 = .0; tf = .1 + @def ocp begin + t ∈ [ t0, tf ], time + x ∈ R^3, state + u ∈ R^3, control + ∫( 0.5u(t)^2 ) → min + end ; + @test ocp isa OptimalControlModel + + t0 = .0; tf = .1 + @def ocp begin + t ∈ [ t0, tf ], time + x ∈ R^3, state + u ∈ R^3, control + ∫( 0.5u(t)^2 ) → max + end ; + @test ocp isa OptimalControlModel + +end + +# --------------------------------------------------------------- +# --------------------------------------------------------------- +@testset "Bolza cost" begin + + # ------------------------------- + # min + # Mayer ± Lagrange + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + (x(0) + 2x(1)) + ∫(x(t) + u(t)) → min + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == x + u + @test o.criterion == :min + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + (x(0) + 2x(1)) + 2 * ∫(x(t) + u(t)) → min + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == 2(x + u) + @test o.criterion == :min + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + (x(0) + 2x(1)) + ∫(x(t) + u(t)) / 2 → min + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == (x + u)/2 + @test o.criterion == :min + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + (x(0) + 2x(1)) - ∫(x(t) + u(t)) → min + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == -(x + u) + @test o.criterion == :min + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + (x(0) + 2x(1)) - 2 * ∫(x(t) + u(t)) → min + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == -2(x + u) + @test o.criterion == :min + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + (x(0) + 2x(1)) - ∫(x(t) + u(t)) / 2 → min + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == -(x + u)/2 + @test o.criterion == :min + + # ------------------------------- + # max + # Mayer ± Lagrange + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + (x(0) + 2x(1)) + ∫(x(t) + u(t)) → max + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == x + u + @test o.criterion == :max + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + (x(0) + 2x(1)) + 2 * ∫(x(t) + u(t)) → max + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == 2(x + u) + @test o.criterion == :max + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + (x(0) + 2x(1)) + ∫(x(t) + u(t)) / 2 → max + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == (x + u)/2 + @test o.criterion == :max + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + (x(0) + 2x(1)) - ∫(x(t) + u(t)) → max + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == -(x + u) + @test o.criterion == :max + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + (x(0) + 2x(1)) - 2 * ∫(x(t) + u(t)) → max + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == -2(x + u) + @test o.criterion == :max + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + (x(0) + 2x(1)) - ∫(x(t) + u(t)) / 2 → max + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == -(x + u)/2 + @test o.criterion == :max + + # ------------------------------- + # min + # Lagrange ± Mayer + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + ∫(x(t) + u(t)) + (x(0) + 2x(1)) → min + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == x + u + @test o.criterion == :min + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + 2 * ∫(x(t) + u(t)) + (x(0) + 2x(1)) → min + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == 2(x + u) + @test o.criterion == :min + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + ∫(x(t) + u(t)) / 2 + (x(0) + 2x(1)) → min + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == (x + u)/2 + @test o.criterion == :min + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + ∫(x(t) + u(t)) - (x(0) + 2x(1)) → min + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == -(x0 + 2xf) + @test o.lagrange(x, u) == x + u + @test o.criterion == :min + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + 2 * ∫(x(t) + u(t)) - (x(0) + 2x(1)) → min + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == -(x0 + 2xf) + @test o.lagrange(x, u) == 2(x + u) + @test o.criterion == :min + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + ∫(x(t) + u(t)) / 2 - (x(0) + 2x(1)) → min + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == -(x0 + 2xf) + @test o.lagrange(x, u) == (x + u)/2 + @test o.criterion == :min + + # ------------------------------- + # max + # Lagrange ± Mayer + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + ∫(x(t) + u(t)) + (x(0) + 2x(1)) → max + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == x + u + @test o.criterion == :max + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + 2 * ∫(x(t) + u(t)) + (x(0) + 2x(1)) → max + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == 2(x + u) + @test o.criterion == :max + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + ∫(x(t) + u(t)) / 2 + (x(0) + 2x(1)) → max + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == x0 + 2xf + @test o.lagrange(x, u) == (x + u)/2 + @test o.criterion == :max + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + ∫(x(t) + u(t)) - (x(0) + 2x(1)) → max + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == -(x0 + 2xf) + @test o.lagrange(x, u) == x + u + @test o.criterion == :max + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + 2 * ∫(x(t) + u(t)) - (x(0) + 2x(1)) → max + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == -(x0 + 2xf) + @test o.lagrange(x, u) == 2(x + u) + @test o.criterion == :max + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + ∫(x(t) + u(t)) / 2 - (x(0) + 2x(1)) → max + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test o.mayer(x0, xf) == -(x0 + 2xf) + @test o.lagrange(x, u) == (x + u)/2 + @test o.criterion == :max + + # ------------------------------- + # error + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + x(0) + 2x(1) + ∫(x(t) + u(t)) → max + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test_throws UndefVarError o.mayer(x0, xf) + + @def o begin + t ∈ [ 0, 1 ], time + x, state + u, control + ∫(x(t) + u(t)) - x(0) + 2x(1) → max + end + x = 1 + u = 2 + x0 = 3 + xf = 4 + @test_throws UndefVarError o.mayer(x0, xf) + +end + +# --------------------------------------------------------------- +# --------------------------------------------------------------- +@testset "Mayer cost" begin + + @def o begin + s ∈ [ 0, 1 ], time + y ∈ R^4, state + w ∈ R, control + r = y₃ + v = y₄ + r(0) + v(1) → min + end + y0 = [ 1, 2, 3, 4 ] + yf = 2 * [ 1, 2, 3, 4 ] + @test is_min(o) + @test o.mayer(y0, yf) == y0[3] + yf[4] + + @def o begin + s ∈ [ 0, 1 ], time + y ∈ R^4, state + w ∈ R, control + r = y₃ + v = y₄ + r(0) + v(1) → max + end + y0 = [ 1, 2, 3, 4 ] + yf = 2 * [ 1, 2, 3, 4 ] + @test is_max(o) + @test o.mayer(y0, yf) == y0[3] + yf[4] + + @def o begin + z ∈ R^2, variable + s ∈ [ 0, z₁ ], time + y ∈ R^4, state + w ∈ R, control + r = y₃ + v = y₄ + r(0) + v(z₁) + z₂ → min + end + z = [ 5, 6 ] + y0 = [ 1, 2, 3, 4 ] + yf = 2 * [ 1, 2, 3, 4 ] + @test is_min(o) + @test o.mayer(y0, yf, z) == y0[3] + yf[4] + z[2] + + @def o begin + z ∈ R², variable + s ∈ [ 0, z₁ ], time + y ∈ R⁴, state + w ∈ R, control + r = y₃ + v = y₄ + aa = y₁ + w² + v³ + z₂ + ẏ(s) == [ aa(s), r²(s), 0, 0 ] + r(0) + v(z₁) + z₂ → min + end + z = [ 5, 6 ] + y = [ 1, 2, 3, 4 ] + y0 = y + yf = 3y0 + w = 7 + @test o.dynamics(y, w, z) == [ y[1] + w^2 + y[4]^3 + z[2], y[3]^2, 0, 0 ] + @test o.mayer(y0, yf, z) == y0[3] + yf[4] + z[2] + + @def o begin + z ∈ R², variable + s ∈ [ 0, z₁ ], time + y ∈ R⁴, state + w ∈ R, control + r = y₃ + v = y₄ + aa = y₁(s) + v³ + z₂ + ẏ(s) == [ aa(s) + (w^2)(s), r²(s), 0, 0 ] + r(0) + v(z₁) + z₂ → min + end + z = [ 5, 6 ] + y = [ 1, 2, 3, 4 ] + y0 = y + yf = 3y0 + w = 7 + @test o.dynamics(y, w, z) == [ y[1] + w^2 + y[4]^3 + z[2], y[3]^2, 0, 0 ] + @test o.mayer(y0, yf, z) == y0[3] + yf[4] + z[2] + + @def o begin + z ∈ R², variable + s ∈ [ 0, z₁ ], time + y ∈ R⁴, state + w, control + r = y₃ + v = y₄ + aa = y₁ + v³ + z₂ + aa(0) + y₂(z₁) → min + end + z = [ 5, 6 ] + y0 = y + yf = 3y0 + @test o.mayer(y0, yf, z) == y0[1] + y0[4]^3 + z[2] + yf[2] + + @def o begin + z ∈ R², variable + __t ∈ [ 0, z₁ ], time + y ∈ R⁴, state + w, control + r = y₃ + v = y₄ + aa = y₁(__t) + v³ + z₂ + ẏ(__t) == [ aa(__t) + (w^2)(__t), r²(__t), 0, 0 ] + aa(0) + y₂(z₁) → min + end + z = [ 5, 6 ] + y = [ 1, 2, 3, 4 ] + y0 = y + yf = 3y0 + w = 11 + @test o.dynamics(y, w, z) == [ y[1] + w^2 + y[4]^3 + z[2], y[3]^2, 0, 0 ] + @test_throws UndefVarError o.mayer(y0, yf, z) + +end + +# --------------------------------------------------------------- +# --------------------------------------------------------------- +@testset "closure" begin + + a = 1 + f(b) = begin # closure of a, local c, and @def in function + c = 3 + @def ocp begin + t ∈ [ a, b ], time + x ∈ R, state + u ∈ R, control + ẋ(t) == x(t) + u(t) + b + c + d + end + ocp + end + o = f(2) + d = 4 + x = 10 + u = 20 + @test o.dynamics(x, u) == x + u + 2 + 3 + 4 + +end + +# --------------------------------------------------------------- +# --------------------------------------------------------------- +@testset "error detection" begin + + # error detections (this can be tricky -> need more work) + + # this one is detected by the generated code (and not the parser) + t0 = 9.0; tf = 9.1 + @test_throws CTException @def o begin + t ∈ [ t0, tf ], time + t ∈ [ t0, tf ], time + end + + # illegal constraint name (1bis), detected by the parser + t0 = 9.0; tf = 9.1 + r0 = 1.0; v0 = 2.0; m0 = 3.0 + @test_throws ParsingError @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R^2, control + + 0 ≤ u(t) ≤ 1 , (1bis) + end + + # t0 is unknown in the x(t0) constraint, detected by the parser + r0 = 1.0; v0 = 2.0; m0 = 3.0 + @test_throws ParsingError @def o begin + t ∈ [ 0, 1 ], time + x ∈ R^2, state + u ∈ R^2, control + + x(t0) == [ r0, v0, m0 ], (1) + 0 ≤ u(t) ≤ 1 , (1bis) + end + +end + +end From fd062490a578e5ea7b300cb120c4361ddd9cd5c7 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Caillau Date: Thu, 23 May 2024 00:51:23 +0200 Subject: [PATCH 09/13] wip - onepass/ ctparser_utils update --- src/ctparser_utils.jl | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/ctparser_utils.jl b/src/ctparser_utils.jl index 65c992e3..2ecc1108 100644 --- a/src/ctparser_utils.jl +++ b/src/ctparser_utils.jl @@ -14,7 +14,7 @@ expr_it(e, _Expr, f) = if e isa Expr args = e.args n = length(args) - newargs = [ expr_it(e.args[i], _Expr, f) for i ∈ 1:n ] + newargs = [ expr_it(e.args[i], _Expr, f) for i ∈ 1:n ] return _Expr(e.head, newargs...) else return f(e) @@ -119,11 +119,11 @@ replace_call(e, x::Vector{Symbol}, t, y) = begin :( $eee($tt) ) && if tt == t end => let ch = false for i ∈ 1:length(x) - if has(eee, x[i]) - eee = subs(eee, x[i], y[i]) - ch = true + if has(eee, x[i]) + eee = subs(eee, x[i], y[i]) + ch = true # todo: unnecessary (as subs can be idempotent)? + end end - end ch ? eee : ee end _ => ee @@ -205,9 +205,9 @@ true has(e, x, t) = begin foo(x, t) = (h, args...) -> begin ee = Expr(h, args...) - if :yes ∈ args - :yes - else @match ee begin + if :yes ∈ args + :yes + else @match ee begin :( $eee($tt) ) => (tt == t && has(eee, x)) ? :yes : ee _ => ee end end @@ -215,6 +215,11 @@ has(e, x, t) = begin expr_it(e, foo(x, t), x -> x) == :yes end +# todo: has_call(e, t) == true if e = ...(t)... i.e. if e contains an evaluation (call) at t +# has_call(:( 2f(t) ), :t) == true +# slight update of has(e, x, t); intended to check expression to be incorporated into Lagrange integrand, see onepass.jl +# TBI + """ $(TYPEDSIGNATURES) From 8d9638b52d5e0a42ccbe7d642fdec8489544822b Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Caillau Date: Thu, 23 May 2024 11:27:01 +0200 Subject: [PATCH 10/13] has_call, for the record (useless) --- src/ctparser_utils.jl | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/ctparser_utils.jl b/src/ctparser_utils.jl index 2ecc1108..dc3725a9 100644 --- a/src/ctparser_utils.jl +++ b/src/ctparser_utils.jl @@ -188,7 +188,7 @@ end """ $(TYPEDSIGNATURES) -Return true if e contains an `(...x...)(t)` call. +Return true if e contains a `(...x...)(t)` call. # Example ```jldoctest @@ -202,7 +202,7 @@ julia> has(e, :u, :t) true ``` """ -has(e, x, t) = begin +has(e, x, t::Symbol) = begin foo(x, t) = (h, args...) -> begin ee = Expr(h, args...) if :yes ∈ args @@ -216,9 +216,37 @@ has(e, x, t) = begin end # todo: has_call(e, t) == true if e = ...(t)... i.e. if e contains an evaluation (call) at t -# has_call(:( 2f(t) ), :t) == true # slight update of has(e, x, t); intended to check expression to be incorporated into Lagrange integrand, see onepass.jl # TBI +""" +$(TYPEDSIGNATURES) + +Return true if e contains a `(...)(t)` call. + +# Example +```jldoctest +julia> e = :( ∫( x[1](t)^2 + 2*u(t) ) → min ) +:(∫((x[1])(t) ^ 2 + 2 * u(t)) → min) + +julia> has_call(e, :t) + +julia> has_call(e, :x) + +julia> has_call(:( 2f(t) ), :t) +``` +""" +has_call(e, t::Symbol) = begin + foo(t) = (h, args...) -> begin + ee = Expr(h, args...) + if :yes ∈ args + :yes + else @match ee begin + :( $eee($tt) ) => (tt == t) ? :yes : ee + _ => ee end + end + end + expr_it(e, foo(t), x -> x) == :yes +end """ $(TYPEDSIGNATURES) @@ -374,4 +402,4 @@ constraint_type(e, t, t0, tf, x, u, v) = begin _ => :variable_fun end _ => :other end -end +end \ No newline at end of file From 6c3a438b74455269aae3f01d2a6c7cea7b997851 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Caillau Date: Thu, 23 May 2024 14:08:24 +0200 Subject: [PATCH 11/13] check for expression before integral in Lagrange / Bolza cost --- src/ctparser_utils.jl | 36 +--------- src/onepass.jl | 149 ++++++++++++++++++++---------------------- 2 files changed, 72 insertions(+), 113 deletions(-) diff --git a/src/ctparser_utils.jl b/src/ctparser_utils.jl index dc3725a9..a770d24f 100644 --- a/src/ctparser_utils.jl +++ b/src/ctparser_utils.jl @@ -115,7 +115,7 @@ replace_call(e, x::Vector{Symbol}, t, y) = begin @assert length(x) == length(y) foo(x, t, y) = (h, args...) -> begin ee = Expr(h, args...) - @match ee begin + @match ee begin :( $eee($tt) ) && if tt == t end => let ch = false for i ∈ 1:length(x) @@ -202,7 +202,7 @@ julia> has(e, :u, :t) true ``` """ -has(e, x, t::Symbol) = begin +has(e, x, t::Union{Symbol, Real}) = begin foo(x, t) = (h, args...) -> begin ee = Expr(h, args...) if :yes ∈ args @@ -215,38 +215,6 @@ has(e, x, t::Symbol) = begin expr_it(e, foo(x, t), x -> x) == :yes end -# todo: has_call(e, t) == true if e = ...(t)... i.e. if e contains an evaluation (call) at t -# slight update of has(e, x, t); intended to check expression to be incorporated into Lagrange integrand, see onepass.jl -# TBI -""" -$(TYPEDSIGNATURES) - -Return true if e contains a `(...)(t)` call. - -# Example -```jldoctest -julia> e = :( ∫( x[1](t)^2 + 2*u(t) ) → min ) -:(∫((x[1])(t) ^ 2 + 2 * u(t)) → min) - -julia> has_call(e, :t) - -julia> has_call(e, :x) - -julia> has_call(:( 2f(t) ), :t) -``` -""" -has_call(e, t::Symbol) = begin - foo(t) = (h, args...) -> begin - ee = Expr(h, args...) - if :yes ∈ args - :yes - else @match ee begin - :( $eee($tt) ) => (tt == t) ? :yes : ee - _ => ee end - end - end - expr_it(e, foo(t), x -> x) == :yes -end """ $(TYPEDSIGNATURES) diff --git a/src/onepass.jl b/src/onepass.jl index ecd1350c..d5075605 100644 --- a/src/onepass.jl +++ b/src/onepass.jl @@ -78,88 +78,79 @@ parse!(p, ocp, e; log=false) = begin # aliases :( $a = $e1 ) => @match e1 begin - :( ($names) ∈ R^$q, variable ) => p_variable!(p, ocp, a, q; components_names=names, log) - :( [$names] ∈ R^$q, variable ) => p_variable!(p, ocp, a, q; components_names=names, log) - :( ($names) ∈ R^$n, state ) => p_state!(p, ocp, a, n; components_names=names, log) - :( [$names] ∈ R^$n, state ) => p_state!(p, ocp, a, n; components_names=names, log) - :( ($names) ∈ R^$m, control ) => p_control!(p, ocp, a, m; components_names=names, log) - :( [$names] ∈ R^$m, control ) => p_control!(p, ocp, a, m; components_names=names, log) - :( ($names) ∈ R, $dummy ) => return __throw("unknown syntax", p.lnum, p.line) - :( [$names] ∈ R, $dummy ) => return __throw("unknown syntax", p.lnum, p.line) - _ => p_alias!(p, ocp, a, e1; log) # alias - end - # variable - :( ($e1, $e2) ∈ R^$q, variable ) => return __throw("unknown syntax: please provide a name to the variable", p.lnum, p.line) - :( $v ∈ R^$q, variable ) => p_variable!(p, ocp, v, q; log) - :( $v ∈ R , variable ) => p_variable!(p, ocp, v ; log) - :( $v , variable ) => p_variable!(p, ocp, v ; log) # todo: remove - # time - :( $t ∈ [ $t0, $tf ], time ) => p_time!(p, ocp, t, t0, tf; log) - # state - :( ($e1, $e2) ∈ R^$n, state ) => return __throw("unknown syntax: please provide a name to the state", p.lnum, p.line) - :( $x ∈ R^$n, state ) => p_state!(p, ocp, x, n; log) - :( $x ∈ R , state ) => p_state!(p, ocp, x ; log) - :( $x , state ) => p_state!(p, ocp, x ; log) # todo: remove - # control - :( ($e1, $e2) ∈ R^$m, control ) => return __throw("unknown syntax: please provide a name to the control", p.lnum, p.line) - :( $u ∈ R^$m, control ) => p_control!(p, ocp, u, m; log) - :( $u ∈ R , control ) => p_control!(p, ocp, u ; log) - :( $u , control ) => p_control!(p, ocp, u ; log) # todo: remove - # dynamics - :( ∂($x)($t) == $e1 ) => p_dynamics!(p, ocp, x, t, e1 ; log) - :( ∂($x)($t) == $e1, $label ) => p_dynamics!(p, ocp, x, t, e1, label; log) - # constraints - :( $e1 == $e2 ) => p_constraint!(p, ocp, e2 , e1, e2 ; log) - :( $e1 == $e2, $label ) => p_constraint!(p, ocp, e2 , e1, e2, label; log) - :( $e1 ≤ $e2 ≤ $e3 ) => p_constraint!(p, ocp, e1 , e2, e3 ; log) - :( $e1 ≤ $e2 ≤ $e3, $label ) => p_constraint!(p, ocp, e1 , e2, e3 , label; log) - :( $e2 ≤ $e3 ) => p_constraint!(p, ocp, nothing, e2, e3 ; log) - :( $e2 ≤ $e3, $label ) => p_constraint!(p, ocp, nothing, e2, e3 , label; log) - :( $e3 ≥ $e2 ≥ $e1 ) => p_constraint!(p, ocp, e1 , e2, e3 ; log) - :( $e3 ≥ $e2 ≥ $e1, $label ) => p_constraint!(p, ocp, e1 , e2, e3 , label; log) - :( $e2 ≥ $e1 ) => p_constraint!(p, ocp, e1 , e2, nothing ; log) - :( $e2 ≥ $e1, $label ) => p_constraint!(p, ocp, e1 , e2, nothing, label; log) + :( ($names) ∈ R^$q, variable ) => p_variable!(p, ocp, a, q; components_names=names, log) + :( [$names] ∈ R^$q, variable ) => p_variable!(p, ocp, a, q; components_names=names, log) + :( ($names) ∈ R^$n, state ) => p_state!(p, ocp, a, n; components_names=names, log) + :( [$names] ∈ R^$n, state ) => p_state!(p, ocp, a, n; components_names=names, log) + :( ($names) ∈ R^$m, control ) => p_control!(p, ocp, a, m; components_names=names, log) + :( [$names] ∈ R^$m, control ) => p_control!(p, ocp, a, m; components_names=names, log) + _ => p_alias!(p, ocp, a, e1; log) # alias + end + # variable + :( $v ∈ R^$q, variable ) => p_variable!(p, ocp, v, q; log) + :( $v ∈ R , variable ) => p_variable!(p, ocp, v ; log) + :( $v , variable ) => p_variable!(p, ocp, v ; log) # todo: remove + # time + :( $t ∈ [ $t0, $tf ], time ) => p_time!(p, ocp, t, t0, tf; log) + # state + :( $x ∈ R^$n, state ) => p_state!(p, ocp, x, n; log) + :( $x ∈ R , state ) => p_state!(p, ocp, x ; log) + :( $x , state ) => p_state!(p, ocp, x ; log) # todo: remove + # control + :( $u ∈ R^$m, control ) => p_control!(p, ocp, u, m; log) + :( $u ∈ R , control ) => p_control!(p, ocp, u ; log) + :( $u , control ) => p_control!(p, ocp, u ; log) # todo: remove + # dynamics + :( ∂($x)($t) == $e1 ) => p_dynamics!(p, ocp, x, t, e1 ; log) + :( ∂($x)($t) == $e1, $label ) => p_dynamics!(p, ocp, x, t, e1, label; log) + # constraints + :( $e1 == $e2 ) => p_constraint!(p, ocp, e2 , e1, e2 ; log) + :( $e1 == $e2, $label ) => p_constraint!(p, ocp, e2 , e1, e2, label; log) + :( $e1 ≤ $e2 ≤ $e3 ) => p_constraint!(p, ocp, e1 , e2, e3 ; log) + :( $e1 ≤ $e2 ≤ $e3, $label ) => p_constraint!(p, ocp, e1 , e2, e3 , label; log) + :( $e2 ≤ $e3 ) => p_constraint!(p, ocp, nothing, e2, e3 ; log) + :( $e2 ≤ $e3, $label ) => p_constraint!(p, ocp, nothing, e2, e3 , label; log) + :( $e3 ≥ $e2 ≥ $e1 ) => p_constraint!(p, ocp, e1 , e2, e3 ; log) + :( $e3 ≥ $e2 ≥ $e1, $label ) => p_constraint!(p, ocp, e1 , e2, e3 , label; log) + :( $e2 ≥ $e1 ) => p_constraint!(p, ocp, e1 , e2, nothing ; log) + :( $e2 ≥ $e1, $label ) => p_constraint!(p, ocp, e1 , e2, nothing, label; log) # lagrange cost - :( ∫($e1) → min ) => p_lagrange!(p, ocp, e1 , :min; log) - :( - ∫($e1) → min ) => p_lagrange!(p, ocp, :( -$e1 ) , :min; log) - :( $e1 * ∫($e2) → min ) => p_lagrange!(p, ocp, :( $e1 * $e2 ), :min; log) - #:( - $e1 * ∫($e2) → min ) => p_lagrange!(p, ocp, :( -$e1 * $e2 ), :min; log) - :( ∫($e2) / $e1 → min ) => p_lagrange!(p, ocp, :( $e2 / $e1 ), :min; log) - :( - ∫($e2) / $e1 → min ) => p_lagrange!(p, ocp, :( -$e2 / $e1 ), :min; log) - :( ∫($e1) → max ) => p_lagrange!(p, ocp, e1 , :max; log) - :( - ∫($e1) → max ) => p_lagrange!(p, ocp, :( -$e1 ) , :max; log) - :( $e1 * ∫($e2) → max ) => p_lagrange!(p, ocp, :( $e1 * $e2 ), :max; log) - #:( - $e1 * ∫($e2) → max ) => p_lagrange!(p, ocp, :( -$e1 * $e2 ), :max; log) - :( ∫($e2) / $e1 → max ) => p_lagrange!(p, ocp, :( $e2 / $e1 ), :max; log) - :( - ∫($e2) / $e1 → max ) => p_lagrange!(p, ocp, :( -$e2 / $e1 ), :max; log) + :( ∫($e1) → min ) => p_lagrange!(p, ocp, e1 , :min; log) + :( - ∫($e1) → min ) => p_lagrange!(p, ocp, :( -$e1 ) , :min; log) + :( $e1 * ∫($e2) → min ) => has(e1, p.t) ? ( return __throw("time $(p.t) must not appear in $e1", p.lnum, p.line) ) : + p_lagrange!(p, ocp, :( $e1 * $e2 ), :min; log) + :( ∫($e1) → max ) => p_lagrange!(p, ocp, e1 , :max; log) + :( - ∫($e1) → max ) => p_lagrange!(p, ocp, :( -$e1 ) , :max; log) + :( $e1 * ∫($e2) → max ) => has(e1, p.t) ? ( return __throw("time $(p.t) must not appear in $e1", p.lnum, p.line) ) : + p_lagrange!(p, ocp, :( $e1 * $e2 ), :max; log) # bolza cost - :( $e1 + ∫($e2) → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) - :( $e1 + $e2 * ∫($e3) → min ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :min; log) - :( $e1 + ∫($e3) / $e2 → min ) => p_bolza!(p, ocp, e1, :( $e3 / $e2 ), :min; log) - :( $e1 - ∫($e2) → min ) => p_bolza!(p, ocp, e1, :( -$e2 ) , :min; log) - :( $e1 - $e2 * ∫($e3) → min ) => p_bolza!(p, ocp, e1, :( -$e2 * $e3 ), :min; log) - :( $e1 - ∫($e3) / $e2 → min ) => p_bolza!(p, ocp, e1, :( -$e3 / $e2 ), :min; log) - :( $e1 + ∫($e2) → max ) => p_bolza!(p, ocp, e1, e2 , :max; log) - :( $e1 + $e2 * ∫($e3) → max ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :max; log) - :( $e1 + ∫($e3) / $e2 → max ) => p_bolza!(p, ocp, e1, :( $e3 / $e2 ), :max; log) - :( $e1 - ∫($e2) → max ) => p_bolza!(p, ocp, e1, :( -$e2 ) , :max; log) - :( $e1 - $e2 * ∫($e3) → max ) => p_bolza!(p, ocp, e1, :( -$e2 * $e3 ), :max; log) - :( $e1 - ∫($e3) / $e2 → max ) => p_bolza!(p, ocp, e1, :( -$e3 / $e2 ), :max; log) - :( ∫($e2) + $e1 → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) - :( $e2 * ∫($e3) + $e1 → min ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :min; log) - :( ∫($e3) / $e2 + $e1 → min ) => p_bolza!(p, ocp, e1, :( $e3 / $e2 ), :min; log) - :( ∫($e2) - $e1 → min ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :min; log) - :( $e2 * ∫($e3) - $e1 → min ) => p_bolza!(p, ocp, :( -$e1 ), :( $e2 * $e3 ), :min; log) - :( ∫($e3) / $e2 - $e1 → min ) => p_bolza!(p, ocp, :( -$e1 ), :( $e3 / $e2 ), :min; log) - :( ∫($e2) + $e1 → max ) => p_bolza!(p, ocp, e1, e2 , :max; log) - :( $e2 * ∫($e3) + $e1 → max ) => p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :max; log) - :( ∫($e3) / $e2 + $e1 → max ) => p_bolza!(p, ocp, e1, :( $e3 / $e2 ), :max; log) - :( ∫($e2) - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :max; log) - :( $e2 * ∫($e3) - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), :( $e2 * $e3 ), :max; log) - :( ∫($e3) / $e2 - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), :( $e3 / $e2 ), :max; log) + :( $e1 + ∫($e2) → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) + :( $e1 + $e2 * ∫($e3) → min ) => has(e2, p.t) ? ( return __throw("time $(p.t) must not appear in $e2", p.lnum, p.line) ) : + p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :min; log) + :( $e1 - ∫($e2) → min ) => p_bolza!(p, ocp, e1, :( -$e2 ) , :min; log) + :( $e1 - $e2 * ∫($e3) → min ) => has(e2, p.t) ? ( return __throw("time $(p.t) must not appear in $e2", p.lnum, p.line) ) : + p_bolza!(p, ocp, e1, :( -$e2 * $e3 ), :min; log) + :( $e1 + ∫($e2) → max ) => p_bolza!(p, ocp, e1, e2 , :max; log) + :( $e1 + $e2 * ∫($e3) → max ) => has(e2, p.t) ? ( return __throw("time $(p.t) must not appear in $e2", p.lnum, p.line) ) : + p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :max; log) + :( $e1 - ∫($e2) → max ) => p_bolza!(p, ocp, e1, :( -$e2 ) , :max; log) + :( $e1 - $e2 * ∫($e3) → max ) => has(e2, p.t) ? ( return __throw("time $(p.t) must not appear in $e2", p.lnum, p.line) ) : + p_bolza!(p, ocp, e1, :( -$e2 * $e3 ), :max; log) + :( ∫($e2) + $e1 → min ) => p_bolza!(p, ocp, e1, e2 , :min; log) + :( $e2 * ∫($e3) + $e1 → min ) => has(e2, p.t) ? ( return __throw("time $(p.t) must not appear in $e2", p.lnum, p.line) ) : + p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :min; log) + :( ∫($e2) - $e1 → min ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :min; log) + :( $e2 * ∫($e3) - $e1 → min ) => has(e2, p.t) ? ( return __throw("time $(p.t) must not appear in $e2", p.lnum, p.line) ) : + p_bolza!(p, ocp, :( -$e1 ), :( $e2 * $e3 ), :min; log) + :( ∫($e2) + $e1 → max ) => p_bolza!(p, ocp, e1, e2 , :max; log) + :( $e2 * ∫($e3) + $e1 → max ) => has(e2, p.t) ? ( return __throw("time $(p.t) must not appear in $e2", p.lnum, p.line) ) : + p_bolza!(p, ocp, e1, :( $e2 * $e3 ), :max; log) + :( ∫($e2) - $e1 → max ) => p_bolza!(p, ocp, :( -$e1 ), e2 , :max; log) + :( $e2 * ∫($e3) - $e1 → max ) => has(e2, p.t) ? ( return __throw("time $(p.t) must not appear in $e2", p.lnum, p.line) ) : + p_bolza!(p, ocp, :( -$e1 ), :( $e2 * $e3 ), :max; log) # mayer cost - :( $e1 → min ) => p_mayer!(p, ocp, e1, :min; log) - :( $e1 → max ) => p_mayer!(p, ocp, e1, :max; log) + :( $e1 → min ) => p_mayer!(p, ocp, e1, :min; log) + :( $e1 → max ) => p_mayer!(p, ocp, e1, :max; log) # _ => begin if e isa LineNumberNode From acbeb23fda9489e36b6884fcbe8be98697a960ae Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Caillau Date: Thu, 23 May 2024 17:56:20 +0200 Subject: [PATCH 12/13] running tests... --- src/ctparser_utils.jl | 2 +- src/onepass.jl | 11 +- test/test_goddard.jl | 2 +- test/test_onepass.jl | 383 ++++++++++++++++-------------------------- 4 files changed, 149 insertions(+), 249 deletions(-) diff --git a/src/ctparser_utils.jl b/src/ctparser_utils.jl index a770d24f..f3af294a 100644 --- a/src/ctparser_utils.jl +++ b/src/ctparser_utils.jl @@ -202,7 +202,7 @@ julia> has(e, :u, :t) true ``` """ -has(e, x, t::Union{Symbol, Real}) = begin +has(e, x, t) = begin foo(x, t) = (h, args...) -> begin ee = Expr(h, args...) if :yes ∈ args diff --git a/src/onepass.jl b/src/onepass.jl index d5075605..aa247db9 100644 --- a/src/onepass.jl +++ b/src/onepass.jl @@ -10,6 +10,8 @@ # - tests exceptions (parsing and semantics/runtime) # - add assert for pre/post conditions and invariants # - add tests on ParsingError + run time errors (wrapped in try ... catch's - use string to be precise) +# - currently "t ∈ [ 0+0, 1 ], time" is allowed, and compels to declare "x(0+0) == ..." +# - add a waring (@warn) when Mayer part has ∫ (bad syntax usage, e.g. "1 + 2 + ∫(...)" instead of "(1 + 2) + ∫(...)") """ $(TYPEDEF) @@ -89,17 +91,14 @@ parse!(p, ocp, e; log=false) = begin # variable :( $v ∈ R^$q, variable ) => p_variable!(p, ocp, v, q; log) :( $v ∈ R , variable ) => p_variable!(p, ocp, v ; log) - :( $v , variable ) => p_variable!(p, ocp, v ; log) # todo: remove # time :( $t ∈ [ $t0, $tf ], time ) => p_time!(p, ocp, t, t0, tf; log) # state :( $x ∈ R^$n, state ) => p_state!(p, ocp, x, n; log) :( $x ∈ R , state ) => p_state!(p, ocp, x ; log) - :( $x , state ) => p_state!(p, ocp, x ; log) # todo: remove # control :( $u ∈ R^$m, control ) => p_control!(p, ocp, u, m; log) :( $u ∈ R , control ) => p_control!(p, ocp, u ; log) - :( $u , control ) => p_control!(p, ocp, u ; log) # todo: remove # dynamics :( ∂($x)($t) == $e1 ) => p_dynamics!(p, ocp, x, t, e1 ; log) :( ∂($x)($t) == $e1, $label ) => p_dynamics!(p, ocp, x, t, e1, label; log) @@ -361,7 +360,7 @@ p_dynamics!(p, ocp, x, t, e, label=nothing; log=false) = begin end p_lagrange!(p, ocp, e, type; log=false) = begin - log && println("objective: ∫($e) → $type") + log && println("objective (Lagrange): ∫($e) → $type") isnothing(p.x) && return __throw("state not yet declared", p.lnum, p.line) isnothing(p.u) && return __throw("control not yet declared", p.lnum, p.line) isnothing(p.t) && return __throw("time not yet declared", p.lnum, p.line) @@ -381,7 +380,7 @@ p_lagrange!(p, ocp, e, type; log=false) = begin end p_mayer!(p, ocp, e, type; log=false) = begin - log && println("objective: $e → $type") + log && println("objective (Mayer): $e → $type") isnothing(p.x) && return __throw("state not yet declared", p.lnum, p.line) isnothing(p.t0) && return __throw("time not yet declared", p.lnum, p.line) isnothing(p.tf) && return __throw("time not yet declared", p.lnum, p.line) @@ -401,7 +400,7 @@ p_mayer!(p, ocp, e, type; log=false) = begin end p_bolza!(p, ocp, e1, e2, type; log=false) = begin - log && println("objective: $e1 + ∫($e2) → $type") + log && println("objective (Bolza): $e1 + ∫($e2) → $type") isnothing(p.x) && return __throw("state not yet declared", p.lnum, p.line) isnothing(p.t0) && return __throw("time not yet declared", p.lnum, p.line) isnothing(p.tf) && return __throw("time not yet declared", p.lnum, p.line) diff --git a/test/test_goddard.jl b/test/test_goddard.jl index 1955b3a7..821fdf77 100644 --- a/test/test_goddard.jl +++ b/test/test_goddard.jl @@ -16,7 +16,7 @@ x0 = [ r0, v0, m0 ] # Abstract model @def ocp begin - tf, variable + tf ∈ R, variable t ∈ [ t0, tf ], time x ∈ R³, state u ∈ R, control diff --git a/test/test_onepass.jl b/test/test_onepass.jl index 18a51a63..5832e60b 100644 --- a/test/test_onepass.jl +++ b/test/test_onepass.jl @@ -124,7 +124,6 @@ function test_onepass() t ∈ [ t0, tf ], time x ∈ R^3, state u ∈ R^3, control - r = x[1] v = x₂ a = x₃ @@ -217,7 +216,7 @@ end t0 = .0; tf = .1 @def ocp begin t ∈ [ t0, tf ], time - a, variable + a ∈ R, variable end ; @test ocp isa OptimalControlModel @test ocp.variable_dimension == 1 @@ -288,7 +287,7 @@ end t0 = 1.0; tf = 1.1 @def ocp begin t ∈ [ t0, tf ], time - u, state + u ∈ R, state end ; @test ocp isa OptimalControlModel @test ocp.time_name == "t" @@ -374,7 +373,7 @@ end t0 = 1.0; tf = 1.1 @def ocp begin t ∈ [ t0, tf ], time - u, control + u ∈ R, control end ; @test ocp isa OptimalControlModel @test ocp.time_name == "t" @@ -432,7 +431,6 @@ end @test ocp.control_dimension == 1 @test ocp.control_name == "b" - t0 = 6.0; tf = 6.1 @def ocp begin t ∈ [ t0 , tf ], time @@ -445,7 +443,6 @@ end @test ocp.control_dimension == 9 @test ocp.control_name == "u" - n = 3 t0 = 7.0; tf = 7.1 @def ocp begin @@ -527,7 +524,7 @@ end z ∈ R², variable __t ∈ [ 0, z₁ ], time y ∈ R⁴, state - w, control + w ∈ R, control r = y₃ v = y₄ aa = y₁(0) + v³ + z₂ @@ -549,7 +546,7 @@ end @testset "constraints" begin @def o begin - tf, variable + tf ∈ R, variable t ∈ [ 0, tf ], time x ∈ R², state u ∈ R, control @@ -634,7 +631,6 @@ end @test constraint(o, :eq10)(x, u, z) == u[1] * x[1:2] + z + f() @test constraint(o, :eq11)(x, u, z) == u[1] * x[1:2].^3 + z - @def o begin t ∈ [ 0, 1 ], time x ∈ R², state @@ -1039,9 +1035,7 @@ end u ∈ [ u0, uf ], time t ∈ R^3, state x ∈ R^2, control - b = t₂ - t(u0) == [ z0, k0, b0 ] 0 ≤ x[2](u) ≤ 1 z0 ≤ t(u)[1] ≤ z1 @@ -1083,7 +1077,6 @@ end t ∈ [ t0, tf ], time x ∈ R^n, state u ∈ R^n, control - x(t0) == x0 x[2](t0) == x02 x[2:3](t0) == y0 @@ -1132,11 +1125,9 @@ end tf = 1.2 n = 4 @def ocp3 begin - t ∈ [ t0, tf ], time x ∈ R^n, state u ∈ R^n, control - x(tf) == xf xf_b ≤ x(tf) ≤ xf_u x[2](tf) == xf2 @@ -1165,7 +1156,6 @@ end t ∈ [ t0, tf ], time x ∈ R^n, state u ∈ R^n, control - x(tf) == xf , final_1 xf_b ≤ x(tf) ≤ xf_u , final_2 x[2](tf) == xf2 , final_3 @@ -1184,18 +1174,15 @@ end tf = 1.4 n = 2 @def ocp5 begin - t ∈ [ t0, tf ], time x ∈ R^n, state u ∈ R^n, control - x(tf) - tf*x(t0) == [ 0, 1 ] [ 0, 1 ] ≤ x(tf) - tf*x(t0) ≤ [ 1, 3 ] x[2](t0)^2 == 1 1 ≤ x[2](t0)^2 ≤ 2 x[2](tf)^2 == 1 1 ≤ x[2](tf)^2 ≤ 2 - end @test ocp5 isa OptimalControlModel @test ocp5.state_dimension == n @@ -1207,18 +1194,15 @@ end tf = 1.5 n = 2 @def ocp6 begin - t ∈ [ t0, tf ], time x ∈ R^n, state u ∈ R^n, control - x(tf) - tf*x(t0) == [ 0, 1 ] , boundary_1 [ 0, 1 ] ≤ x(tf) - tf*x(t0) ≤ [ 1, 3 ] , boundary_2 x[2](t0)^2 == 1 , boundary_3 1 ≤ x[2](t0)^2 ≤ 2 , boundary_4 x[2](tf)^2 == 1 , boundary_5 1 ≤ x[2](tf)^2 ≤ 2 , boundary_6 - end @test ocp6 isa OptimalControlModel @test ocp6.state_dimension == n @@ -1239,11 +1223,9 @@ end tf = 1.6 n = 2 @def ocp7 begin - t ∈ [ t0, tf ], time x ∈ R^n, state u ∈ R^n, control - u_b ≤ u[1](t) ≤ u_u u2_b ≤ u[1](t) ≤ u2_u v_b ≤ u[2](t) ≤ v_u @@ -1267,11 +1249,9 @@ end v_b = 5.0 v_u = 6.0 @def ocp8 begin - t ∈ [ t0, tf ], time x ∈ R^n, state u ∈ R^n, control - u_b ≤ u[2](t) ≤ u_u , control_1 u2_b ≤ u[1](t) ≤ u2_u , control_3 [ 1, v_b ] ≤ u[1:2](t) ≤ [ 2, v_u ], control_5 @@ -1284,7 +1264,6 @@ end @test ocp8.initial_time == t0 @test ocp8.final_time == tf - # more vars x_b = 10.0 x_u = 11.0 @@ -1298,11 +1277,9 @@ end tf = 1.8 n = 10 @def ocp9 begin - t ∈ [ t0, tf ], time x ∈ R^n, state u ∈ R^n, control - x_b ≤ x[3](t) ≤ x_u #x(t) == x_u x2_b ≤ x[2](t) ≤ x2_u @@ -1322,11 +1299,9 @@ end tf = 1.9 n = 11 @def ocp10 begin - t ∈ [ t0, tf ], time x ∈ R^n, state u ∈ R^n, control - x_b ≤ x[3](t) ≤ x_u , state_1 #x(t) == x_u , state_2 x2_b ≤ x[2](t) ≤ x2_u , state_3 @@ -1342,7 +1317,6 @@ end @test ocp10.initial_time == t0 @test ocp10.final_time == tf - # === mixed t0 = 0.111 tf = 1.111 @@ -1352,7 +1326,6 @@ end t ∈ [ t0, tf ], time x ∈ R^n, state u ∈ R^n, control - u[2](t) * x[1:2](t) == [ -1, 1 ] [ -1, 1 ] ≤ u[2](t) * x[1:2](t) ≤ [ 0, 2 ] end @@ -1363,11 +1336,9 @@ end @test ocp11.final_time == tf @def ocp12 begin - t ∈ [ t0, tf ], time x ∈ R^n, state u ∈ R^n, control - u[2](t) * x[1:2](t) == [ -1, 1 ] , mixed_1 [ -1, 1 ] ≤ u[2](t) * x[1:2](t) ≤ [ 0, 2 ] , mixed_2 end @@ -1377,17 +1348,14 @@ end @test ocp12.initial_time == t0 @test ocp12.final_time == tf - # === dynamics t0 = 0.112 tf = 1.112 @def ocp13 begin - t ∈ [ t0, tf ], time x ∈ R, state u ∈ R, control - ẋ(t) == 2x(t) + u(t)^2 end @test ocp13 isa OptimalControlModel @@ -1545,7 +1513,7 @@ end x(t0) == [ -1, 0 ], (1) x(tf) == [ 0, 0 ] ẋ(t) == A * x(t) + B * u(t) - ∫( u(t)^2 ) / 2 → min + (-0.5 + tf) * ∫( u(t)^2 ) → min end x = [ 1, 2 ] x0 = 2 * x @@ -1557,32 +1525,32 @@ end 1 ] @test constraint(o, :eq1)(x0, xf) == x0 @test o.dynamics(x, u) == A * x + B * u - @test o.lagrange(x, u) == 0.5u^2 + @test o.lagrange(x, u) == (-0.5 + tf) * u^2 @test o.criterion == :min t0 = 0 tf = 1 - @def o begin + @test_throws ParsingError @def o begin # a call to the time (t, here) must not appear before the integral t ∈ [ t0, tf ], time x ∈ R^2, state u ∈ R, control x(t0) == [ -1, 0 ], (1) x(tf) == [ 0, 0 ] ẋ(t) == A * x(t) + B * u(t) - -∫( u(t)^2 ) / 2 → min + (-0.5 + t) * ∫( u(t)^2 ) → min + end + + t0 = 0 + tf = 1 + @test_throws ParsingError @def o begin # a call to the time (t, here) must not appear before the integral + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + (-0.5 + x(t)) * ∫( u(t)^2 ) → min end - x = [ 1, 2 ] - x0 = 2 * x - xf = 3 * x - u = -1 - A = [ 0 1 - 0 0 ] - B = [ 0 - 1 ] - @test constraint(o, :eq1)(x0, xf) == x0 - @test o.dynamics(x, u) == A * x + B * u - @test o.lagrange(x, u) == -0.5u^2 - @test o.criterion == :min # ----------------------------------- # max @@ -1706,54 +1674,6 @@ end @test o.lagrange(x, u) == -0.5u^2 @test o.criterion == :max - t0 = 0 - tf = 1 - @def o begin - t ∈ [ t0, tf ], time - x ∈ R^2, state - u ∈ R, control - x(t0) == [ -1, 0 ], (1) - x(tf) == [ 0, 0 ] - ẋ(t) == A * x(t) + B * u(t) - ∫( u(t)^2 ) / 2 → max - end - x = [ 1, 2 ] - x0 = 2 * x - xf = 3 * x - u = -1 - A = [ 0 1 - 0 0 ] - B = [ 0 - 1 ] - @test constraint(o, :eq1)(x0, xf) == x0 - @test o.dynamics(x, u) == A * x + B * u - @test o.lagrange(x, u) == 0.5u^2 - @test o.criterion == :max - - t0 = 0 - tf = 1 - @def o begin - t ∈ [ t0, tf ], time - x ∈ R^2, state - u ∈ R, control - x(t0) == [ -1, 0 ], (1) - x(tf) == [ 0, 0 ] - ẋ(t) == A * x(t) + B * u(t) - -∫( u(t)^2 ) / 2 → max - end - x = [ 1, 2 ] - x0 = 2 * x - xf = 3 * x - u = -1 - A = [ 0 1 - 0 0 ] - B = [ 0 - 1 ] - @test constraint(o, :eq1)(x0, xf) == x0 - @test o.dynamics(x, u) == A * x + B * u - @test o.lagrange(x, u) == -0.5u^2 - @test o.criterion == :max - # ----------------------------------- t0 = .0; tf = .1 @def ocp begin @@ -1775,6 +1695,31 @@ end end + t0 = 0 + tf = 1 + @test_throws ParsingError @def o begin # a call to the time (t, here) must not appear before the integral + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + (-0.5 + t) * ∫( u(t)^2 ) → max + end + + t0 = 0 + tf = 1 + @test_throws ParsingError @def o begin # a call to the time (t, here) must not appear before the integral + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + (-0.5 + x(t)) * ∫( u(t)^2 ) → max + end + + # --------------------------------------------------------------- # --------------------------------------------------------------- @testset "Bolza cost" begin @@ -1784,8 +1729,8 @@ end # Mayer ± Lagrange @def o begin t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control (x(0) + 2x(1)) + ∫(x(t) + u(t)) → min end x = 1 @@ -1798,36 +1743,36 @@ end @def o begin t ∈ [ 0, 1 ], time - x, state - u, control - (x(0) + 2x(1)) + 2 * ∫(x(t) + u(t)) → min + x ∈ R, state + u ∈ R, control + (x(0) + 2x(1)) + ∫(x(t) + u(t)) → min end x = 1 u = 2 x0 = 3 xf = 4 @test o.mayer(x0, xf) == x0 + 2xf - @test o.lagrange(x, u) == 2(x + u) + @test o.lagrange(x, u) == x + u @test o.criterion == :min @def o begin t ∈ [ 0, 1 ], time - x, state - u, control - (x(0) + 2x(1)) + ∫(x(t) + u(t)) / 2 → min + x ∈ R, state + u ∈ R, control + (x(0) + 2x(1)) + 2 * ∫(x(t) + u(t)) → min end x = 1 u = 2 x0 = 3 xf = 4 @test o.mayer(x0, xf) == x0 + 2xf - @test o.lagrange(x, u) == (x + u)/2 + @test o.lagrange(x, u) == 2(x + u) @test o.criterion == :min - + @def o begin t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control (x(0) + 2x(1)) - ∫(x(t) + u(t)) → min end x = 1 @@ -1840,8 +1785,8 @@ end @def o begin t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control (x(0) + 2x(1)) - 2 * ∫(x(t) + u(t)) → min end x = 1 @@ -1851,28 +1796,28 @@ end @test o.mayer(x0, xf) == x0 + 2xf @test o.lagrange(x, u) == -2(x + u) @test o.criterion == :min - - @def o begin + + @test_throws ParsingError @def o begin t ∈ [ 0, 1 ], time - x, state - u, control - (x(0) + 2x(1)) - ∫(x(t) + u(t)) / 2 → min + x ∈ R, state + u ∈ R, control + (x(0) + 2x(1)) + t * ∫(x(t) + u(t)) → min end - x = 1 - u = 2 - x0 = 3 - xf = 4 - @test o.mayer(x0, xf) == x0 + 2xf - @test o.lagrange(x, u) == -(x + u)/2 - @test o.criterion == :min + @test_throws ParsingError @def o begin + t ∈ [ 0, 1 ], time + x ∈ R, state + u ∈ R, control + (x(0) + 2x(1)) - t * ∫(x(t) + u(t)) → min + end + # ------------------------------- # max # Mayer ± Lagrange @def o begin t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control (x(0) + 2x(1)) + ∫(x(t) + u(t)) → max end x = 1 @@ -1885,8 +1830,8 @@ end @def o begin t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control (x(0) + 2x(1)) + 2 * ∫(x(t) + u(t)) → max end x = 1 @@ -1899,22 +1844,8 @@ end @def o begin t ∈ [ 0, 1 ], time - x, state - u, control - (x(0) + 2x(1)) + ∫(x(t) + u(t)) / 2 → max - end - x = 1 - u = 2 - x0 = 3 - xf = 4 - @test o.mayer(x0, xf) == x0 + 2xf - @test o.lagrange(x, u) == (x + u)/2 - @test o.criterion == :max - - @def o begin - t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control (x(0) + 2x(1)) - ∫(x(t) + u(t)) → max end x = 1 @@ -1927,8 +1858,8 @@ end @def o begin t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control (x(0) + 2x(1)) - 2 * ∫(x(t) + u(t)) → max end x = 1 @@ -1938,28 +1869,28 @@ end @test o.mayer(x0, xf) == x0 + 2xf @test o.lagrange(x, u) == -2(x + u) @test o.criterion == :max - - @def o begin + + @test_throws ParsingError @def o begin t ∈ [ 0, 1 ], time - x, state - u, control - (x(0) + 2x(1)) - ∫(x(t) + u(t)) / 2 → max + x ∈ R, state + u ∈ R, control + (x(0) + 2x(1)) + t * ∫(x(t) + u(t)) → max end - x = 1 - u = 2 - x0 = 3 - xf = 4 - @test o.mayer(x0, xf) == x0 + 2xf - @test o.lagrange(x, u) == -(x + u)/2 - @test o.criterion == :max - + + @test_throws ParsingError @def o begin + t ∈ [ 0, 1 ], time + x ∈ R, state + u ∈ R, control + (x(0) + 2x(1)) - t * ∫(x(t) + u(t)) → max + end + # ------------------------------- # min # Lagrange ± Mayer @def o begin t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control ∫(x(t) + u(t)) + (x(0) + 2x(1)) → min end x = 1 @@ -1972,8 +1903,8 @@ end @def o begin t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control 2 * ∫(x(t) + u(t)) + (x(0) + 2x(1)) → min end x = 1 @@ -1986,22 +1917,8 @@ end @def o begin t ∈ [ 0, 1 ], time - x, state - u, control - ∫(x(t) + u(t)) / 2 + (x(0) + 2x(1)) → min - end - x = 1 - u = 2 - x0 = 3 - xf = 4 - @test o.mayer(x0, xf) == x0 + 2xf - @test o.lagrange(x, u) == (x + u)/2 - @test o.criterion == :min - - @def o begin - t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control ∫(x(t) + u(t)) - (x(0) + 2x(1)) → min end x = 1 @@ -2014,8 +1931,8 @@ end @def o begin t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control 2 * ∫(x(t) + u(t)) - (x(0) + 2x(1)) → min end x = 1 @@ -2025,28 +1942,28 @@ end @test o.mayer(x0, xf) == -(x0 + 2xf) @test o.lagrange(x, u) == 2(x + u) @test o.criterion == :min - - @def o begin + + @test_throws ParsingError @def o begin t ∈ [ 0, 1 ], time - x, state - u, control - ∫(x(t) + u(t)) / 2 - (x(0) + 2x(1)) → min + x ∈ R, state + u ∈ R, control + t * ∫(x(t) + u(t)) + 1 → min end - x = 1 - u = 2 - x0 = 3 - xf = 4 - @test o.mayer(x0, xf) == -(x0 + 2xf) - @test o.lagrange(x, u) == (x + u)/2 - @test o.criterion == :min - + + @test_throws ParsingError @def o begin + t ∈ [ 0, 1 ], time + x ∈ R, state + u ∈ R, control + t * ∫(x(t) + u(t)) - 1 → min + end + # ------------------------------- # max # Lagrange ± Mayer @def o begin t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control ∫(x(t) + u(t)) + (x(0) + 2x(1)) → max end x = 1 @@ -2059,8 +1976,8 @@ end @def o begin t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control 2 * ∫(x(t) + u(t)) + (x(0) + 2x(1)) → max end x = 1 @@ -2073,22 +1990,8 @@ end @def o begin t ∈ [ 0, 1 ], time - x, state - u, control - ∫(x(t) + u(t)) / 2 + (x(0) + 2x(1)) → max - end - x = 1 - u = 2 - x0 = 3 - xf = 4 - @test o.mayer(x0, xf) == x0 + 2xf - @test o.lagrange(x, u) == (x + u)/2 - @test o.criterion == :max - - @def o begin - t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control ∫(x(t) + u(t)) - (x(0) + 2x(1)) → max end x = 1 @@ -2101,8 +2004,8 @@ end @def o begin t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control 2 * ∫(x(t) + u(t)) - (x(0) + 2x(1)) → max end x = 1 @@ -2112,27 +2015,27 @@ end @test o.mayer(x0, xf) == -(x0 + 2xf) @test o.lagrange(x, u) == 2(x + u) @test o.criterion == :max - - @def o begin + + @test_throws ParsingError @def o begin t ∈ [ 0, 1 ], time - x, state - u, control - ∫(x(t) + u(t)) / 2 - (x(0) + 2x(1)) → max + x ∈ R, state + u ∈ R, control + t * ∫(x(t) + u(t)) + 1 → max + end + + @test_throws ParsingError @def o begin + t ∈ [ 0, 1 ], time + x ∈ R, state + u ∈ R, control + t * ∫(x(t) + u(t)) - 1 → max end - x = 1 - u = 2 - x0 = 3 - xf = 4 - @test o.mayer(x0, xf) == -(x0 + 2xf) - @test o.lagrange(x, u) == (x + u)/2 - @test o.criterion == :max # ------------------------------- # error @def o begin t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control x(0) + 2x(1) + ∫(x(t) + u(t)) → max end x = 1 @@ -2143,8 +2046,8 @@ end @def o begin t ∈ [ 0, 1 ], time - x, state - u, control + x ∈ R, state + u ∈ R, control ∫(x(t) + u(t)) - x(0) + 2x(1) → max end x = 1 @@ -2242,7 +2145,7 @@ end z ∈ R², variable s ∈ [ 0, z₁ ], time y ∈ R⁴, state - w, control + w ∈ R, control r = y₃ v = y₄ aa = y₁ + v³ + z₂ @@ -2257,7 +2160,7 @@ end z ∈ R², variable __t ∈ [ 0, z₁ ], time y ∈ R⁴, state - w, control + w ∈ R, control r = y₃ v = y₄ aa = y₁(__t) + v³ + z₂ @@ -2317,7 +2220,6 @@ end t ∈ [ t0, tf ], time x ∈ R^2, state u ∈ R^2, control - 0 ≤ u(t) ≤ 1 , (1bis) end @@ -2327,11 +2229,10 @@ end t ∈ [ 0, 1 ], time x ∈ R^2, state u ∈ R^2, control - x(t0) == [ r0, v0, m0 ], (1) 0 ≤ u(t) ≤ 1 , (1bis) end end -end +end \ No newline at end of file From 1b70320c4695e526ef3959b0cde19b0e10b27a28 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Caillau Date: Thu, 23 May 2024 19:01:51 +0200 Subject: [PATCH 13/13] tests passed --- src/onepass.jl | 2 +- test/test_onepass.jl | 66 ++++++++++++++++++++++++-------------------- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/onepass.jl b/src/onepass.jl index aa247db9..dfcc7fb7 100644 --- a/src/onepass.jl +++ b/src/onepass.jl @@ -11,7 +11,6 @@ # - add assert for pre/post conditions and invariants # - add tests on ParsingError + run time errors (wrapped in try ... catch's - use string to be precise) # - currently "t ∈ [ 0+0, 1 ], time" is allowed, and compels to declare "x(0+0) == ..." -# - add a waring (@warn) when Mayer part has ∫ (bad syntax usage, e.g. "1 + 2 + ∫(...)" instead of "(1 + 2) + ∫(...)") """ $(TYPEDEF) @@ -384,6 +383,7 @@ p_mayer!(p, ocp, e, type; log=false) = begin isnothing(p.x) && return __throw("state not yet declared", p.lnum, p.line) isnothing(p.t0) && return __throw("time not yet declared", p.lnum, p.line) isnothing(p.tf) && return __throw("time not yet declared", p.lnum, p.line) + has(e, :∫) && return __throw("bad objective declaration resulting in a Mayer term with trailing ∫", p.lnum, p.line) gs = gensym() x0 = gensym() xf = gensym() diff --git a/test/test_onepass.jl b/test/test_onepass.jl index 5832e60b..8bf4bb81 100644 --- a/test/test_onepass.jl +++ b/test/test_onepass.jl @@ -1731,13 +1731,13 @@ end t ∈ [ 0, 1 ], time x ∈ R, state u ∈ R, control - (x(0) + 2x(1)) + ∫(x(t) + u(t)) → min + (x(0) + 3x(1)) + ∫(x(t) + u(t)) → min end x = 1 u = 2 x0 = 3 xf = 4 - @test o.mayer(x0, xf) == x0 + 2xf + @test o.mayer(x0, xf) == x0 + 3xf @test o.lagrange(x, u) == x + u @test o.criterion == :min @@ -1818,13 +1818,13 @@ end t ∈ [ 0, 1 ], time x ∈ R, state u ∈ R, control - (x(0) + 2x(1)) + ∫(x(t) + u(t)) → max + (x(0) + 5x(1)) + ∫(x(t) + u(t)) → max end x = 1 u = 2 x0 = 3 xf = 4 - @test o.mayer(x0, xf) == x0 + 2xf + @test o.mayer(x0, xf) == x0 + 5xf @test o.lagrange(x, u) == x + u @test o.criterion == :max @@ -2030,32 +2030,6 @@ end t * ∫(x(t) + u(t)) - 1 → max end - # ------------------------------- - # error - @def o begin - t ∈ [ 0, 1 ], time - x ∈ R, state - u ∈ R, control - x(0) + 2x(1) + ∫(x(t) + u(t)) → max - end - x = 1 - u = 2 - x0 = 3 - xf = 4 - @test_throws UndefVarError o.mayer(x0, xf) - - @def o begin - t ∈ [ 0, 1 ], time - x ∈ R, state - u ∈ R, control - ∫(x(t) + u(t)) - x(0) + 2x(1) → max - end - x = 1 - u = 2 - x0 = 3 - xf = 4 - @test_throws UndefVarError o.mayer(x0, xf) - end # --------------------------------------------------------------- @@ -2233,6 +2207,38 @@ end 0 ≤ u(t) ≤ 1 , (1bis) end + # bad syntax for Bolza cost interpreted as a Mayer term with trailing ∫ + @test_throws ParsingError @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + 1 + 2 + ∫( u(t)^2 ) → min # should be ( 1 + 2 ) + ∫(...) + end + + @test_throws ParsingError @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + ∫( u(t)^2 ) + 1 + 2 → min # should be ∫(...) + ( 1 + 2 ) + end + + @test_throws ParsingError @def o begin + t ∈ [ t0, tf ], time + x ∈ R^2, state + u ∈ R, control + x(t0) == [ -1, 0 ], (1) + x(tf) == [ 0, 0 ] + ẋ(t) == A * x(t) + B * u(t) + ∫( u(t)^2 ) / 2 → min # forbidden + end + + end end \ No newline at end of file