Constraints and time¶
Every declared constraint enters the NLP. Redundant or inconsistent inequalities can make a feasible continuous problem infeasible after transcription.
Constraint tuples. t_0(...) or t_f(...) marks a boundary
condition; a bare expression is a path condition (the whole
horizon).
# Two-sided
(lb, "<=", expr, "<=", ub)
(lb, "<=", eco_opt.t_0(expr), "<=", ub)
(lb, "<=", eco_opt.t_f(expr), "<=", ub)
# Lower bound: lb <= expr
(lb, "<=", expr)
(lb, "<=", eco_opt.t_0(expr))
(lb, "<=", eco_opt.t_f(expr))
# Upper bound: ub >= expr (same as expr <= ub)
(ub, ">=", expr)
(ub, ">=", eco_opt.t_0(expr))
(ub, ">=", eco_opt.t_f(expr))
# Equality
(eq, "==", expr)
(eq, "==", eco_opt.t_0(expr))
(eq, "==", eco_opt.t_f(expr))
Read (ub, ">=", expr) left to right: the number is at least the
expression. Bryson (1.0/9.0, ">=", position) is \(x\le 1/9\), not
\(x\ge 1/9\). (expr, "<=", ub) is accepted as the same upper bound;
the form above is the one to write.
Taxonomy¶
| Kind | Syntax | Meaning |
|---|---|---|
| Box | bound on a bare sys.x[i], sys.u[i], sys.p[i], sys.t |
Bound on that decision variable |
| Path | bound on a derived expression, no t_0/t_f |
\(g(t,\mathbf{x},\mathbf{u})\le 0\) along the horizon |
| Initial / final | t_0(expr) / t_f(expr) |
Point condition at \(t_0\) or \(T\) |
| Integral (isoperimetric) | auxiliary state whose derivative is the integrand; bound that state at \(T\) | A budget, e.g. \(\int u^2\,\mathrm{d}t=10\) |
A box on \(x_i\) is not the same as a path on \(x_i+u_j\). Boxes apply to decision variables. Path expressions are residual constraints. There is no separate integral-constraint constructor; a budget is an auxiliary state (iso_constraint).
Inconsistent boxes (mf <= m <= m0 together with m(0) outside that
interval) make the NLP infeasible before IPOPT starts.
Where a path constraint is imposed¶
Path inequalities are applied at each interval start (where the piecewise-constant \(u\) is defined), at the collocation points, and at \(T\). Collocation points are interior (Legendre) or include the right end (Radau); they omit \(\tau=0\), so the interval-start residual is what constrains mixed \(g(\mathbf{x},\mathbf{u})\) at the left of each piece.
A state-only box on \(\mathbf{x}(0)\) remains a t_0 condition.
There is no strict() switch. Box bounds on \(\mathbf{x}\) and
\(\mathbf{u}\) already apply to every state node and every control
piece.
Time¶
eco_opt does not treat an omitted \(t_0\) as zero or an omitted
\(T\) as a free horizon. Initial and terminal time are declared
explicitly:
(0, "==", eco_opt.t_0(sys.t)) # t_0 = 0
(T, "==", eco_opt.t_f(sys.t)) # fixed horizon
(0, "<=", eco_opt.t_f(sys.t), "<=", Tmax) # free T, upper cap
A fixed horizon is a prescribed interval (a season, a campaign, a
mission). A free horizon is a burnout or a minimum-time problem:
t_f(sys.t) is bounded from below by zero, optionally from above, and
tf_guess is the same order of magnitude as \(T\).
First solve uses tf_guess=2 on a horizon of order
1.5. Goddard uses tf_guess=200; tf_guess=1.0 on a 200-second burn
is a common cause of solver failure. See
Guesses, mesh, scaling.
Closed loop with a shrinking window requires a remaining horizon that still contains the planned terminal time. If the open-loop problem had a free horizon, the closed-loop study uses a fixed \(T\). The microbial-growth and irrigation examples do that.
Multi-phase problems¶
A phase is a change of dynamics or objective. Examples: vegetative
then reproductive allocation with a free switch
(multiphase_cohen); ascent then
landing
(Goddard landing).
Continuity of time and state at the junction is
ocp.st(phases=[p1, p2], continuity=True).
A bang–bang \(u(t)\) on one system remains a single-phase problem (cohen_king_roughgarden).
Algebraics are not supported in multi-phase problems.