Skip to content

From Hamiltonians ​

The constructors on this page build a flow without an optimal control problem: from a Hamiltonian, a Hamiltonian vector field, a pseudo-Hamiltonian and a control law, or a plain vector field. They are the building blocks From an OCP is made of, and they are useful when you have worked out the Hamiltonian yourself.

julia
using OptimalControl
using OrdinaryDiffEqTsit5

Extremals ​

We take the energy-minimal double integrator again:  ,  , cost , from    to on . With the notation of Notation and conventions and   , the pseudo-Hamiltonian is

maximised by  . The maximised Hamiltonian is   , and the pairs solutions of its Hamiltonian system

are the extremals. From the initial costate  , the extremal reaches the target:   and   . Each constructor below computes it from a different description of the same system.

julia
t0, tf = 0, 1
x0 = [-1, 0]
p0 = [12, 6]

From a Hamiltonian ​

Give ; its Hamiltonian vector field    is computed by automatic differentiation:

julia
H(x, p) = p[1] * x[2] + p[2]^2 / 2

f_h = Flow(Hamiltonian(H))
xf, pf = f_h(t0, x0, p0, tf)
([-4.158277980903794e-16, 5.038973481527467e-15], [12.0, -5.999999999999998])

A Hamiltonian is H(x, p) by default. If it depends on time, write H(t, x, p) and declare it with Hamiltonian(H; is_autonomous=false); if it depends on a variable, H(x, p, v) with is_variable=true. Without the declaration, the call fails with a MethodError.

From a Hamiltonian vector field ​

Give directly, as a function returning the pair . No automatic differentiation is involved:

julia
Hv(x, p) = ([x[2], p[2]], [0, -p[1]])

f_hv = Flow(HamiltonianVectorField(Hv))
f_hv(t0, x0, p0, tf)
([-4.158277980903794e-16, 5.038973481527467e-15], [12.0, -5.999999999999998])

From a pseudo-Hamiltonian and a control law ​

Give and the law : the flow is the one of  , differentiated through the law by automatic differentiation. This is what From an OCP does, with the pseudo-Hamiltonian read from the problem.

julia
Hp(x, p, u) = p[1] * x[2] + p[2] * u - u^2 / 2
law(x, p) = p[2]

f_hp = Flow(PseudoHamiltonian(Hp), DynClosedLoop(law))
f_hp(t0, x0, p0, tf)
([-4.158277980903794e-16, 5.038973481527467e-15], [12.0, -5.999999999999998])

hamiltonian_type=:partial freezes the control instead of differentiating through the law (see Total or partial Hamiltonian).

From a pseudo-Hamiltonian vector field and a control law ​

Give   as a function of , and the law:

julia
Hpv(x, p, u) = ([x[2], u], [0, -p[1]])

f_hpv = Flow(PseudoHamiltonianVectorField(Hpv), DynClosedLoop(law))
f_hpv(t0, x0, p0, tf)
([-4.158277980903794e-16, 5.038973481527467e-15], [12.0, -5.999999999999998])

Here the partial derivatives are given, so there is nothing to differentiate through the law, and hamiltonian_type is not an option of this flow. Passing it raises an error, which reads as an unknown integrator option:

julia
julia> Flow(PseudoHamiltonianVectorField(Hpv), DynClosedLoop(law); hamiltonian_type=:partial)
IncorrectArgument → top-level scope, REPL[1]:2
│
│  Unknown option provided
│
│  Got       option :hamiltonian_type in method (:sciml, :cpu)
│  Expected  valid option name for one of the strategies
│
│  Context   route_options - unknown option validation
│  Hint      Did you mean?
│              - :alg (aliases: algorithm, solver) [distance: 11]
│              - :adaptive (aliases: adaptive_step, adaptive_stepping) [distance: 11]
│              - :d_discontinuities [distance: 12]
│            If you're confident this option exists for a specific strategy, use bypass() to skip validation:
│              custom_opt = route_to(<strategy_id>=bypass(<value>))
└─

From a vector field ​

A flow of the state alone,  , or when declared with is_autonomous=false. With the optimal control    written as a function of time, the state reaches the target:

julia
f_x = Flow(VectorField((t, x) -> [x[2], 6 - 12t]; is_autonomous=false))
f_x(t0, x0, tf)
2-element Vector{Float64}:
 -2.7259067227910837e-15
 -9.06882116070656e-16

To simulate a control system under a given control, open-loop or feedback, see Simulation.

From a SciML problem ​

An ODEFunction or an ODEProblem of the SciML ecosystem can be used directly, with OrdinaryDiffEqTsit5 alone. The parameter p of the SciML function f!(dx, x, p, t) is the variable of the flow, passed with the keyword variable. Here    :

julia
rhs!(dx, x, p, t) = (dx[1] = -p * x[1]; nothing)

f_ode = Flow(ODEFunction(rhs!))
f_ode(0, [1.0], 1; variable=2)   # exp(-2)
0.13533528340900092

So the keyword is required even when the function does not use p: pass variable=nothing. Without it, the call raises an error:

julia
julia> f_ode(0, [1.0], 1)
PreconditionError → top-level scope, REPL[1]:2
│
│  variable not provided for a NonFixed flow
│
│  Reason   flow depends on an extra variable parameter but none was given
│
│  Context  call — NonFixed flow with missing variable
│  Hint     Pass `variable=v` when calling the flow
└─

An ODEProblem works the same way:

julia
f_prob = Flow(ODEProblem(rhs!, [1.0], (0.0, 1.0), 2.0))
f_prob(0, [1.0], 1; variable=2)
1-element Vector{Float64}:
 0.13533528340900092

Summary ​

ConstructorYou giveAutomatic differentiationPoint call returns
Flow(Hamiltonian(H))yes(x(tf), p(tf))
Flow(HamiltonianVectorField(Hv)) no(x(tf), p(tf))
Flow(PseudoHamiltonian(Hp), law) and yes(x(tf), p(tf))
Flow(PseudoHamiltonianVectorField(Hpv), law)  and no(x(tf), p(tf))
Flow(VectorField(f))nox(tf)
Flow(ODEFunction(f!)), Flow(ODEProblem(…))a SciML function or problemnox(tf)

Hamiltonian, HamiltonianVectorField, PseudoHamiltonian, PseudoHamiltonianVectorField and VectorField take the keywords is_autonomous=false and is_variable=true for a function of time or of a variable. Every Flow takes the integrator options of Flows overview. Called on a time span, f((t0, tf), x0, p0) returns a trajectory: see Simulation.

See also ​

  • From an OCP: the same flows, with the problem supplying the pseudo-Hamiltonian; you only write the law.

  • Accessors: read the Hamiltonian, its vector field and the law back from a flow.

  • Lift: the Hamiltonian lift of a vector field, and the other tools of the geometry section.