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]))julia> init.state(0.0)
2-element Vector{Float64}:
1.0
-0.0
julia> init.state(1.0)
2-element Vector{Float64}:
0.5403023058681398
-0.8414709848078965
julia> init.control(1.0)
1-element Vector{Float64}:
0.5Constants
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))julia> init.state(0.0)
2-element Vector{Float64}:
0.0
1.0
julia> init.state(0.9)
2-element Vector{Float64}:
0.0
1.0
julia> init.control(0.5)
0.1Defaults
Omitting a component (or passing nothing / ()) yields the built-in default guess, sized to the problem:
init = CTModels.build_initial_guess(ocp, ())julia> init.state(0.5)
2-element Vector{Float64}:
0.1
0.1
julia> init.control(0.5)
0.1Pre-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)julia> 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.
Per-component constructors
Behind the convenience of build_initial_guess, each component is built by a dedicated constructor that normalises the input to a callable:
| Constructor | Purpose |
|---|---|
initial_state | normalise a state guess (function, vector, scalar, nothing, or (T, X) grid pair) |
initial_control | normalise a control guess (same shapes) |
initial_variable | normalise a variable guess (scalar, vector, or nothing) |
When nothing is passed, each constructor returns a built-in default (constant 0.1 for non-empty components, Float64[] for empty ones). A 2-tuple (time_grid, data_matrix) is interpreted as grid data that gets interpolated linearly in time.