Limitations & configuration
This page collects the constraints of the CTLie operators and the knobs available to configure them.
using CTLie # Lift, ad, Poisson, ∂ₜ, @Lie
using CTBase: Data # Data.VectorField, Data.Hamiltonian, …
# AD backend: CTBase's DifferentiationInterface extension + ForwardDiff
using DifferentiationInterface: DifferentiationInterface
using ForwardDiff: ForwardDiffLimitations
No in-place support
The operators are defined for out-of-place objects only. A field built with is_inplace=true (mutability InPlace) is rejected by ad and ∂ₜ with a CTBase.Exceptions.IncorrectArgument error. Reconstruct the field out-of-place before taking brackets or time derivatives:
julia> Xip = Data.VectorField((dx, x) -> (dx .= (x[2], -x[1])); is_inplace=true);
julia> ad(Xip, Xip)
ERROR: IncorrectArgument
│
│ ad does not support InPlace vector fields
│
│ Got InPlace vector field
│ Expected OutOfPlace vector field
│
│ Context ad on AbstractVectorField
│ Hint Reconstruct the VectorField without the in-place flag
└─No Lie operations on a Hamiltonian vector field
A HamiltonianVectorField lives on phase space with signature (x, p), not (x), so it is not a valid operand for the Lie bracket / Lie derivative, nor for the Lift. Both raise CTBase.Exceptions.IncorrectArgument:
julia> Z = Data.HamiltonianVectorField((x, p) -> (x, -p); is_autonomous=true);
julia> ad(Z, Z)
ERROR: IncorrectArgument
│
│ ad does not support HamiltonianVectorField (signature is (x, p), not (x))
│
│ Got HamiltonianVectorField
│ Expected plain VectorField
│
│ Context ad on AbstractVectorField
│ Hint Use a plain VectorField
└─
julia> Lift(Z)
ERROR: IncorrectArgument
│
│ Lift does not support HamiltonianVectorField (signature is (x, p), not (x))
│
│ Got HamiltonianVectorField
│ Expected plain VectorField
│
│ Context Lift on AbstractVectorField
│ Hint A HamiltonianVectorField already lives on the cotangent space: there is nothing to lift
└─Use the underlying plain VectorField instead.
Operands must share traits
ad (on two vector fields) and Poisson (on two Hamiltonians) require their operands to have the same time- and variable-dependence. Each operand is valid on its own — it is their combination that is rejected — so a mismatch raises CTBase.Exceptions.PreconditionError:
julia> Xa = Data.VectorField(x -> [x[2], -x[1]]; is_autonomous=true);
julia> Xt = Data.VectorField((t, x) -> [x[2], -x[1]]; is_autonomous=false);
julia> ad(Xa, Xt)
ERROR: PreconditionError
│
│ ad: TD/VD mismatch between X and Y
│
│ Reason X: CTBase.Traits.Autonomous/CTBase.Traits.Fixed ≠ Y: CTBase.Traits.NonAutonomous/CTBase.Traits.Fixed — both arguments must share the same TimeDependence and VariableDependence
│
│ Context ad on AbstractVectorField
│ Hint Ensure both vector fields have the same time and variable dependence traits
└─The same rule is enforced by @Lie; see The @Lie macro.
Plain functions default to autonomous & fixed
A bare Julia Function carries no traits, so the operators assume it is autonomous and fixed unless told otherwise via is_autonomous / is_variable (for ad, Poisson, Lift) or the matching keywords of @Lie. When in doubt, wrap the function in a typed VectorField / Hamiltonian so the traits are explicit and checked.
Configuration
AD backend
ad, Poisson and ∂ₜ differentiate through a pluggable backend. The default backend runs ForwardDiff through DifferentiationInterface.jl, and both packages must be loaded for derivatives to be available:
using DifferentiationInterface: DifferentiationInterface # AD extension
using ForwardDiff: ForwardDiff # default AD engineLoading DifferentiationInterface alone is not enough: the first evaluation then raises a CTBase.Exceptions.ExtensionError naming the missing ForwardDiff. A non-default engine (e.g. Mooncake for the GPU backend below) must likewise be loaded before a derivative is evaluated. The documentation build loads every extension, so the error is rendered from a fresh Julia process where only CTLie and DifferentiationInterface are loaded:
julia> using CTBase: Data
julia> using DifferentiationInterface: DifferentiationInterface
julia> X = Data.VectorField(x -> [x[2], -x[1]]);
julia> CTLie.ad(X, X)([1.0, 0.0])
ERROR: ExtensionError
│
│ missing dependencies to use the AutoForwardDiff AD backend
│
│ Missing ForwardDiff
│
│ Context CTBase.Differentiation
│ Hint Run: using ForwardDiff
└─ad_backend takes a CTBase.Differentiation.AbstractADBackend — never a raw ADTypes.AbstractADType — so that the choice of execution device (CPU or GPU) and the choice of underlying AD implementation are both explicit and swappable without touching CTLie itself:
using CTBase: CTBase, Differentiation
# CPU (default device): AutoForwardDiff
cpu_backend = Differentiation.DifferentiationInterface()
# GPU: AutoMooncake (Mooncake must be loaded to differentiate)
gpu_backend =
Differentiation.DifferentiationInterface{CTBase.Strategies.GPU}()The global default backend is read and set with dg_ad_backend / dg_ad_backend!:
dg_ad_backend!(cpu_backend) # set global default
dg_ad_backend() # query itEvery operator also accepts a per-call ad_backend keyword that overrides the global default for that call only — including @Lie via ad_backend=…:
ad(X, Y; ad_backend=cpu_backend)
@Lie [X, Y] ad_backend=cpu_backendCode generation by @Lie
The @Lie macro is hygienic: its expansion refers to the CTLie internals, the trait types and the exception type through module-qualified references, not through names looked up in the caller's module. It therefore works from any module, whatever the caller imported — using CTLie: @Lie alone is enough, and a caller that defines its own CTLie or CTBase binding is not affected.
The operands and the ad_backend expression are the caller's own code and are resolved in the caller's module, as usual. The AD backend extension must still be loaded (see above).