Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP - Onepass #132

Merged
merged 15 commits into from
May 23, 2024
73 changes: 49 additions & 24 deletions src/model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 ])
```
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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
```
"""
Expand Down Expand Up @@ -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)
```
"""
Expand Down Expand Up @@ -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)
```
"""
Expand All @@ -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;
Expand Down
133 changes: 91 additions & 42 deletions src/onepass.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,64 +73,101 @@ parse!(p, ocp, e; log=false) = begin
e = subs(e, a, p.aliases[a])
end
@match e begin
:( $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
:( $t ∈ [ $t0, $tf ], time ) => p_time!(p, ocp, t, t0, tf; log)
:( $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
:( $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)
:( ∂($x)($t) == $e1 ) => p_dynamics!(p, ocp, x, t, e1 ; log)
:( ∂($x)($t) == $e1, $label ) => p_dynamics!(p, ocp, x, t, e1, 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)
:( ∫($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_mayer!(p, ocp, e1, :min; log)
:( $e1 → max ) => p_mayer!(p, ocp, e1, :max; log)
#
:( $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
:( ($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)
# lagrange cost
:( ∫($e1) → min ) => p_lagrange!(p, ocp, e1, :min; log)
:( $e1 * ∫($e2) → min ) => p_lagrange!(p, ocp, :( $e1 * $e2 ), :min; log)
Copy link
Member

@jbcaillau jbcaillau May 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ocots convenient but: this kind of expression only makes sense if e1 does not contain references to state or control (variable allowed, though). Otherwise we would allow something like

x(t) * (u(t))  min # nonsense

as equivalent to

(x(t) * u(t))  min # ... becomes meaningful 

etc.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ocots I am taking care of the changes suggested in the review above before merging.

:( ∫($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)
# mayer cost
:( $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
e
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
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
vv = QuoteNode(v)
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
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
end

p_alias!(p, ocp, a, e; log=false) = begin
Expand Down Expand Up @@ -177,7 +214,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
Expand All @@ -186,18 +223,30 @@ 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
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
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
uu = QuoteNode(u)
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
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
end

p_constraint!(p, ocp, e1, e2, e3, label=gensym(); log=false) = begin
Expand Down
Loading
Loading