Constraints
constraint! adds one constraint at a time to the pre-model. The first positional argument is the kind; the keywords give the bounds, the function or range, and a label used later to read back the constraint and its dual.
| Kind | Form | Keywords |
|---|---|---|
:path | nonlinear $\ell \le c(t,x,u,v) \le u$ | f, lb, ub, label |
:boundary | nonlinear $\ell \le b(x_0,x_f,v) \le u$ | f, lb, ub, label |
:state | box on state components | rg, lb, ub, label |
:control | box on control components | rg, lb, ub, label |
:variable | box on variable components | rg, lb, ub, label |
Nonlinear constraint functions are written in place like the dynamics: f(r, t, x, u, v) for :path, f(r, x0, xf, v) for :boundary.
using CTModels
pre = CTModels.PreModel()
CTModels.variable!(pre, 2, "v")
CTModels.time!(pre; t0=0.0, tf=1.0)
CTModels.state!(pre, 2)
CTModels.control!(pre, 1)
CTModels.dynamics!(pre, (r, t, x, u, v) -> (r[1] = x[2]; r[2] = u[1]; nothing))
CTModels.objective!(pre, :min; lagrange=(t, x, u, v) -> u[1]^2)
# Nonlinear path and boundary constraints
CTModels.constraint!(pre, :path;
f=(r, t, x, u, v) -> (r[1] = x[1] + u[1]; nothing), lb=[0.0], ub=[1.0], label=:p)
CTModels.constraint!(pre, :boundary;
f=(r, x0, xf, v) -> (r[1] = x0[1]; r[2] = xf[1]; nothing),
lb=[0.0, 0.0], ub=[0.0, 0.0], label=:bc)
# Box constraints on state, control and variable components
CTModels.constraint!(pre, :state; rg=1:1, lb=[-1.0], ub=[1.0], label=:x1)
CTModels.constraint!(pre, :control; rg=1:1, lb=[-10.0], ub=[10.0], label=:u)
CTModels.constraint!(pre, :variable; rg=1:2, lb=[0.0, 0.0], ub=[1.0, 1.0], label=:vbox)
CTModels.time_dependence!(pre; autonomous=true)
ocp = CTModels.build(pre)The (autonomous) optimal control problem is of the form:
minimize J(x, u, v) = ∫ f⁰(x(t), u(t), v) dt, over [0.0, 1.0]
subject to
ẋ(t) = f(x(t), u(t), v), t in [0.0, 1.0] a.e.,
ψ₋ ≤ ψ(x(t), u(t), v) ≤ ψ₊,
ϕ₋ ≤ ϕ(x(0.0), x(1.0), v) ≤ ϕ₊,
x₋ ≤ x(t) ≤ x₊,
u₋ ≤ u(t) ≤ u₊,
v₋ ≤ v ≤ v₊,
where x(t) ∈ R², u(t) ∈ R and v ∈ R².
Reading constraints back
On the built Model, the constraints are grouped in a ConstraintsModel and queried by dimension or by label:
(CTModels.dim_path_constraints_nl(ocp),
CTModels.dim_boundary_constraints_nl(ocp),
CTModels.dim_state_constraints_box(ocp),
CTModels.dim_control_constraints_box(ocp),
CTModels.dim_variable_constraints_box(ocp))(1, 2, 1, 1, 2)Labels and aliases
Before building, constraints live in a ConstraintsDictType keyed by label. Box constraints obey a per-component uniqueness invariant: if several declarations touch the same component, their bounds are intersected and all their labels are kept as aliases. This is what lets constraint and dual resolve any of the original labels to the merged component — see the Duals guide.