Compatibility
This section is a living compatibility reference for the Flow constructors. For each way of building a flow — from a vector field, a Hamiltonian vector field, a Hamiltonian, a SciML function/problem, or an optimal control problem — a dedicated page lists the supported state types, scalar types, and call styles in a table, with a minimal, executable example for every supported cell.
Two properties keep these pages trustworthy:
Probe-backed. Each page's table is generated from a capability probe under
probe/that runs every combination against the current source and records what works, what warns, and what fails. The CPU probe isprobe/cpu/probe_cpu.jl.Executed on build. Every ✓ / ⚠ example is a Documenter
@exampleblock re-run on each documentation build, so a page cannot silently drift from the code.
Scope: the 9 per-constructor pages below cover CPU, with every example executed on build. GPU is covered by a separate page, sourced from a dated probe run rather than build-executed — see that page's note on why.
This work tracks issue #343.
Pages
| Constructor | Builds | Page | Status |
|---|---|---|---|
| (cross-cutting) | — | Shape contract | ✅ live |
Flow(::VectorField) | StateFlow | Flow(VectorField) | ✅ live |
Flow(::HamiltonianVectorField) | HamiltonianFlow | Flow(HamiltonianVectorField) | ✅ live |
Flow(::Hamiltonian) | HamiltonianFlow | Flow(Hamiltonian) | ✅ live |
Flow(::ODEFunction) / Flow(::ODEProblem) | StateFlow / SciMLProblemFlow | Flow(SciML) | ✅ live |
Flow(ocp) (control-free) | OptimalControlFlow | Flow(ocp) | ✅ live |
Flow(ocp, law) | OptimalControlFlow / ControlledFlow | Flow(ocp, law) | ✅ live |
Flow(h̃, law) | HamiltonianFlow | Flow(h̃, law) | ✅ live |
Flow(h̃vf, law) | HamiltonianFlow | Flow(h̃vf, law) | ✅ live |
Flow(fc, law) | ControlledFlow | Flow(fc, law) | ✅ live |
| (all of the above, on GPU) | — | GPU | ✅ live (probe-sourced, not build-executed) |
At a glance
Flow(VectorField)andFlow(HamiltonianVectorField)report the same result on CPU: every state/costate type tested works — scalar,Vector,Matrix(batched columns),MVector/SVector,MMatrix/SMatrix, withReal,Complex, orForwardDiff.Dualelements — in both the point and trajectory call styles. The only caveat in both cases is that an in-place vector field with an immutable initial condition (SVector/SMatrix) works but emits a performance warning. Both are also "1-D = scalar" end to end (point and trajectory) — a scalar or length-1Vector/SVectorstate always collapses to a scalar — since the fix for #357; see the Shape contract page.Flow(Hamiltonian)(AD-backed, no in-place variant) supports every real container the same way, but its default backend (AutoForwardDiff) does not supportComplexstates. To differentiate the flow itself with respect to(x0, p0)(e.g. for shooting), wrap the call in an outerForwardDiff.jacobian/gradient— never construct aDualby hand and pass it asx0/p0. It is also 1-D = scalar end to end, via the same coercion machinery asFlow(HamiltonianVectorField)(see #357).Flow(SciML)covers two constructors with very different mechanics.Flow(::ODEFunction)goes through the same CTFlows pipeline asFlow(VectorField)and reports the identical result, including the 1-D = scalar collapse above (every container works; in-place + immutable state warns and falls back).Flow(::ODEProblem)bypasses that pipeline entirely —SciMLBase.remakefeeds the new state straight to the original function, with no CTFlows-level guard, and no shape coercion: a length-1Vectorstate stays a length-1Vector, by design (see the Shape contract page for why this constructor is deliberately left out of the fix). For a problem built from an out-of-place function, every state type remakes cleanly; for one built in-place, remaking with an immutable state (including a bare scalar) is a hard, native SciML error — not a warning with a fallback like everywhere else on this site. Build theODEProblemfrom an out-of-place function if you need to call it with immutable states.Flow(ocp)andFlow(ocp, law)— unlike every flow above, the state dimension is fixed at OCP construction (state!(pre, n)), so no single flow accepts every container size; two problems (n=1,n=2) stand in for that pattern on both pages. Until 2026-07-24, an OCP-derived fixed-size internal buffer broke batchedMatrixstates everywhere andSVectorstates specifically on the non-AD (state-only /OpenLoop/ClosedLoop) paths (#358) — fixed: the buffer is now sized from the runtime shape of the value passed in, so the fullMatrix/MMatrix/SMatrix/SVector/MVectorfamily works on every path, matching every other constructor on this site. The remaining ✗ cells are the AD-backed paths (Flow(ocp),Flow(ocp, DynClosedLoop)) rejectingComplexand hand-builtDual, for the same reason asFlow(Hamiltonian). Two things are not broken, worth calling out explicitly: addingconstraint=/multiplier=to aDynClosedLoopflow never changes which state types work (measured, not assumed), and:total/:partialagree exactly for a stationary feedback law. One asymmetry is new to these pages:Flow(ocp, OpenLoop/ClosedLoop)accepts aForwardDiff.Dualstate at a point call but not in a trajectory call (the objective computation is notDual-transparent).Flow(h̃, law)is the pseudo-Hamiltonian counterpart ofFlow(ocp, DynClosedLoop), but without an OCP — onlyDynClosedLoopis accepted (OpenLoop/ClosedLoopare rejected withPreconditionError, since a pseudo-Hamiltonian needs the costate).PseudoHamiltonianSystem/Data.ComposedHamiltonianwrap the user'sH̃directly, with no OCP-derived buffer to size, so — likeFlow(ocp, DynClosedLoop)since the #358 fix — the fullMatrix/MMatrix/SMatrixfamily works, on both:totaland:partial. Its compatibility profile otherwise matchesFlow(Hamiltonian)exactly: everyRealcontainer works,Complexfails (AD-backed), and a hand-builtDualcollides with the flow's own internal AD.Flow(h̃vf, law)is the vector-field counterpart ofFlow(h̃, law)— sameDynClosedLoop-only restriction, buth̃vfsupplies the derivatives directly instead of an AD-differentiated scalarH̃, so there is nohamiltonian_typeoption. Measured: its profile matchesFlow(HamiltonianVectorField)exactly, includingComplexand hand-builtDual(both fail onFlow(h̃, law), both work here — no internal AD to collide with). The only caveat is the same in-place + immutable-u0(SVector/SMatrix) performance warning asFlow(HamiltonianVectorField).Flow(fc, law)is the controlled-vector-field counterpart ofFlow(h̃, law)— onlyOpenLoop/ClosedLoopaccepted (DynClosedLooprejected, needs the costate).Data.ControlledVectorFieldhas no in-place variant and, without an OCP, no fixed-size buffer either, so it builds the same plain out-of-placeVectorFieldSystemasFlow(VectorField). Measured: fully green, no unsupported combination at all — the most permissive of the four no-OCP/OCP "control law" pages.Flow(ocp, law)'sOpenLoop/ClosedLooppath now matches it on every state-shape axis; the one remaining difference is the trajectory-Dualrestriction, which comes from the OCP's own objective computation (notDual-transparent) and has no counterpart here sinceFlow(fc, law)computes no objective at all.GPU covers all constructors on NVIDIA/CUDA, sourced from a dated
probe/gpurun rather than build-executed (no device in the Documenter build). Headline finding:AutoMooncakeis the only AD backend that survives every measured device call shape —AutoZygotebreaks once a call reduces over a device array or mutates one,AutoEnzymebreaks on GPU array reductions (sum/mapreduce) specifically, which real Hamiltonians always contain. AD-free flows (VectorField,HamiltonianVectorField,ODEProblem) need no keyword at all — just passCuArrays.
This completes the compatibility table for every Flow constructor, on both CPU and GPU.
See also
Flows overview — the data → systems → flows → trajectories pipeline.
Building a flow — the shortcut constructor and explicit pipeline.
Integrating — call styles, variable parameters, and integrator options.