Optimal control problems

CTModels defines and builds optimal control problems (OCPs) through four focused modules: CTModels.Components, CTModels.Models, CTModels.Building, and CTModels.Solutions. An OCP is assembled incrementally into a mutable PreModel, then frozen into an immutable Model by build.

CTModels builds a model through a three-stage pipeline:

PreModel  →  declare components  →  build  →  Model
(mutable)    state!/control!/...           (immutable)

The OCP layer is organised by responsibility across four modules:

LayerSubdirectoryWhat it provides
TypesOCP/Types/Component, model and solution types (StateModel, Model, …)
CoreOCP/Core/Defaults and the TimeDependence trait
ValidationOCP/Validation/Name-uniqueness checks across components
ComponentsOCP/Components/The state!, control!, dynamics!, … declaration verbs
BuildingOCP/Building/build (model) and build_solution

Reading order

PageTopicKey symbols
Types and traitsThe noun/trait architectureTimeDependence, AbstractStateModel, Empty*
ComponentsDeclaring the spacesstate!, control!, variable!, time!
Dynamics and objectiveThe equations of motion and costdynamics!, objective!
ConstraintsPath, boundary and box constraintsconstraint!
Building a modelFreezing the PreModelbuild, Model

Qualified access

CTModels exports nothing at the package level: every public symbol is reached through a qualified path CTModels.symbol. Bring the package into scope and call its verbs qualified:

using CTModels

Minimal end-to-end example

We build the beam problem: minimise $\int_0^1 u(t)^2\,\mathrm{d}t$ subject to $\dot{x} = (x_2, u)$, fixed boundary conditions, and box constraints on $x_1$ and $u$.

# 1. A fresh, mutable pre-model
pre = CTModels.PreModel()

# 2. Declare the time interval, the spaces and (here) no optimisation variable
CTModels.variable!(pre, 0)
CTModels.time!(pre; t0=0.0, tf=1.0)
CTModels.state!(pre, 2)        # x ∈ ℝ²
CTModels.control!(pre, 1)      # u ∈ ℝ

# 3. Dynamics ẋ = (x₂, u), written in place
function beam_dynamics!(r, t, x, u, v)
    r[1] = x[2]
    r[2] = u[1]
    return nothing
end
CTModels.dynamics!(pre, beam_dynamics!)

# 4. Lagrange cost ∫ u² → min
beam_lagrange(t, x, u, v) = u[1]^2
CTModels.objective!(pre, :min; lagrange=beam_lagrange)

# 5. Boundary and box constraints
function beam_boundary!(r, x0, xf, v)
    r[1] = x0[1]      # x₁(0) = 0
    r[2] = x0[2] - 1  # x₂(0) = 1
    r[3] = xf[1]      # x₁(1) = 0
    r[4] = xf[2] + 1  # x₂(1) = -1
    return nothing
end
CTModels.constraint!(pre, :boundary; f=beam_boundary!, lb=zeros(4), ub=zeros(4), label=:bc)
CTModels.constraint!(pre, :state;   rg=1:1, lb=[0.0],   ub=[0.1],  label=:x1_box)
CTModels.constraint!(pre, :control; rg=1:1, lb=[-10.0], ub=[10.0], label=:u_box)

# 6. Mark the system autonomous and freeze it into an immutable Model
CTModels.time_dependence!(pre; autonomous=true)
ocp = CTModels.build(pre)
The (autonomous) optimal control problem is of the form:

    minimize  J(x, u) = ∫ f⁰(x(t), u(t)) dt, over [0.0, 1.0]

    subject to

        ẋ(t) = f(x(t), u(t)), t in [0.0, 1.0] a.e.,

        ϕ₋ ≤ ϕ(x(0.0), x(1.0)) ≤ ϕ₊, 
        x₋ ≤ x(t) ≤ x₊, 
        u₋ ≤ u(t) ≤ u₊, 

    where x(t) ∈ R² and u(t) ∈ R.

Once built, the Model answers queries through accessors:

(CTModels.state_dimension(ocp),
 CTModels.control_dimension(ocp),
 CTModels.variable_dimension(ocp),
 CTModels.is_autonomous(ocp))
(2, 1, 0, true)

The shortcut CTModels.build_model(pre) is an alias for CTModels.build(pre); see Building a model for what build checks and guarantees.

Mathematical setting

CTModels represents a continuous-time OCP in Bolza form. With state $x : [t_0, t_f] \to \mathbb{R}^n$, control $u : [t_0, t_f] \to \mathbb{R}^m$ and an optimisation variable $v \in \mathbb{R}^q$ (free final time, design parameters, …):

\[\begin{aligned} \min_{x,\,u,\,v}\quad & g\big(x(t_0), x(t_f), v\big) + \int_{t_0}^{t_f} f^0\big(t, x(t), u(t), v\big)\,\mathrm{d}t \\ \text{s.t.}\quad & \dot{x}(t) = f\big(t, x(t), u(t), v\big), \\ & \text{path, boundary and box constraints.} \end{aligned}\]

Two orthogonal axes shape the representation:

How these axes become traits rather than separate types is the subject of Types and traits.