Lift
Given a vector field
It is a purely algebraic construction — no differentiation, no AD.
using OptimalControlFrom a plain function
X(x) = [x[2], -x[1]]
H = Lift(X)
H([1.0, 2.0], [3.0, 4.0])2.0H is an OptimalControl.LiftedHamiltonianFunction — a callable, not a Hamiltonian:
typeof(H)LiftedHamiltonianFunction{typeof(Main.X), CTBase.Traits.Autonomous, CTBase.Traits.Fixed}From a typed vector field
Lifting a typed VectorField instead gives back a real Hamiltonian:
XV = VectorField(x -> [x[2], -x[1]])
HV = Lift(XV)
HV isa AbstractHamiltoniantrueHV([1.0, 2.0], [3.0, 4.0])2.0Non-autonomous and variable forms
Xt(t, x) = [t * x[2], -x[1]]
Ht = Lift(Xt; is_autonomous=false)
Ht(2.0, [1.0, 2.0], [3.0, 4.0]) # H(t, x, p)8.0Xv(x, v) = [x[2] + v, -x[1]]
Hv = Lift(Xv; is_variable=true)
Hv([1.0, 2.0], [3.0, 4.0], 1.0) # H(x, p, v)5.0Which one do I get
| You lift | You get | Signature |
|---|---|---|
f::Function | OptimalControl.LiftedHamiltonianFunction (<: Function) | h(x,p), h(t,x,p), h(x,p,v), h(t,x,p,v) depending on the keywords |
X::AbstractVectorField | Hamiltonian | same call signatures, inherited from X's own traits |
Lift(f::Function) is not an AbstractHamiltonian
OptimalControl.LiftedHamiltonianFunction <: Function only, not <: AbstractHamiltonian — a change from v2.0, where the plain-function form and the typed-VectorField form both produced the same kind of object. Any isa/<: test against the old hierarchy is now quietly wrong:
H = Lift(X) # X::Function
H isa AbstractHamiltonianfalseOnly the plain-Function overload changed — Lift(X::AbstractVectorField) still returns a Hamiltonian, confirmed above. See Migration for the full list of silent v2.0 → v2.1 semantics changes.
What you can do with it
Feed a lift straight into Poisson (see The bridge identity), or into Flow to integrate the associated Hamiltonian system — see From Hamiltonians and vector fields.
A trap to know about
Lifting a HamiltonianVectorField doesn't work — it already lives on the cotangent space, so there's nothing left to lift:
julia> hvf = HamiltonianVectorField((x, p) -> (p, -x));
julia> Lift(hvf)
NotImplemented → top-level scope, REPL[2]:2
│
│ ad on AbstractHamiltonianVectorField is not implemented (signature is (x,p), not (x))
│
│ Context ad on AbstractVectorField
│ Hint Use ad on a plain VectorField
└─The message talks about ad, not Lift — both operations share the same internal guard against HamiltonianVectorField operands, so the wording doesn't adapt to which one triggered it. Harmless, but don't be thrown by it: the operation that actually failed is Lift.
See also
Overview — the bridge identity this page is one half of.
Poisson bracket — what a lift is usually fed into.
From Hamiltonians and vector fields — turning a lift into a flow.