Skip to content

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.