Input formats
Each component of an initial guess (state, control, variable) accepts several shapes. CTModels normalises them all to a callable of time, so the rest of the stack sees one interface.
| Per-component input | Interpreted as |
|---|---|
a function t -> … | used directly |
a vector [a, b, …] | the constant trajectory t -> [a, b, …] |
| a scalar (dim-1 component) | the constant trajectory t -> [a] |
nothing | a built-in default |
using CTModels
pre = CTModels.PreModel()
CTModels.variable!(pre, 0)
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)
CTModels.time_dependence!(pre; autonomous=true)
ocp = CTModels.build(pre)Functions
The most general form — a time-varying guess:
init = CTModels.build_initial_guess(ocp,
(state = t -> [cos(t), -sin(t)], control = t -> [0.5 * t]))
(init.state(0.0), init.state(1.0), init.control(1.0))([1.0, -0.0], [0.5403023058681398, -0.8414709848078965], [0.5])Constants
A vector (or a scalar for a one-dimensional component) is broadcast to a constant trajectory:
init = CTModels.build_initial_guess(ocp, (state = [0.0, 1.0], control = 0.1))
(init.state(0.0), init.state(0.9), init.control(0.5)) # constant in time([0.0, 1.0], [0.0, 1.0], 0.1)Defaults
Omitting a component (or passing nothing / ()) yields the built-in default guess, sized to the problem:
init = CTModels.build_initial_guess(ocp, ())
(init.state(0.5), init.control(0.5))([0.1, 0.1], 0.1)Pre-initialisation
pre_initial_guess packages raw, model-independent data into a PreInitialGuess; the model is only needed later when build_initial_guess validates it:
pre_ig = CTModels.pre_initial_guess(state = t -> [0.0, 0.0], control = t -> [1.0])
init = CTModels.build_initial_guess(ocp, pre_ig)
init.control(0.25)1-element Vector{Float64}:
1.0How the dimensions are checked, and how to warm-start from a previous solution, is covered in Validation & warm-start.