GPU
GPU support runs through ExaModels.jl and MadNLPGPU.jl, NVIDIA GPUs only, via CUDA.jl.
This page doesn't execute
Unlike every other page in this section, the code blocks here are not run when the docs are built — there is no CUDA-capable GPU in CI or in this development environment. Loading CUDA/MadNLPGPU and constructing CPU-side handles works fine without a device, but the GPU-parameterized solver strategies pull in extensions (CUDSS in particular) that only finish loading with real GPU hardware present. Everything below is accurate as prose and matches the source it describes, but treat it as reference, not as tested output.
Prerequisites
using OptimalControl
using ExaModels
using MadNLPGPU
using CUDACheck CUDA.functional() before assuming a :gpu solve will actually run on the device.
The problem must be coordinatewise
:exa — the only GPU-capable modeler — requires dynamics (and any path constraint) written one coordinate at a time, ∂(x₁)(t) == ..., not ẋ(t) == [...]. See Abstract syntax for the two forms side by side.
ocp = @def begin
t ∈ [0, 1], time
x ∈ R², state
u ∈ R, control
v ∈ R, variable
x(0) == [0, 1]
x(1) == [0, -1]
∂(x₁)(t) == x₂(t) # coordinatewise
∂(x₂)(t) == u(t) # — not ẋ(t) == [x₂(t), u(t)]
0 ≤ x₁(t) + v^2 ≤ 1.1
-10 ≤ u(t) ≤ 10
1 ≤ v ≤ 2
∫(u(t)^2 + v) → min
endDescriptive mode
The :gpu parameter token selects GPU-optimized defaults:
sol = solve(ocp, :exa, :madnlp, :gpu; grid_size=100, print_level=MadNLP.ERROR)
# or, letting completion fill in the rest — first match with :gpu:
sol = solve(ocp, :gpu; grid_size=100, print_level=MadNLP.ERROR):gpu changes what a strategy's own defaults are: Exa{GPU} uses a CUDA differentiation backend, MadNLP{GPU} uses the CUDSSSolver linear solver instead of MUMPS. describe(:gpu) lists every strategy with a GPU-parameterized variant (:exa, :madnlp, :madncl, plus the indirect-side :di and :sciml) — this call needs nothing GPU-specific and runs fine on CPU alone.
Explicit mode
disc = OptimalControl.Collocation(grid_size=100, scheme=:midpoint)
mod = OptimalControl.Exa{GPU}()
sol = OptimalControl.MadNLP{GPU}(print_level=MadNLP.ERROR)
result = solve(ocp; discretizer=disc, modeler=mod, solver=sol)What combinations work
Only :exa × {:madnlp, :madncl} on :gpu — the two entries at the end of methods() (see Choosing a method). Everything else is a compile-time or runtime error, confirmed directly against the type system:
OptimalControl.ADNLP{GPU}()—TypeError,ADNLP's parameter is constrained to<:CPU.OptimalControl.Ipopt{GPU}()— same,Ipopt's parameter is<:CPU-only.Descriptively,
solve(ocp, :adnlp, :gpu)orsolve(ocp, :ipopt, :gpu)fail asAmbiguousDescription: no entry inmethods()has:adnlpor:ipopttogether with:gpu.
Performance notes
GPU solving amortizes best on large-scale problems (thousands of variables/constraints) or repeated solves in a loop, where the per-call setup overhead is paid once. For small problems, plain CPU solving is typically faster.
if CUDA.functional()
sol = solve(ocp, :gpu)
else
sol = solve(ocp, :cpu)
endSee also
Overview — CPU solving basics.
Choosing a method — the full method list, GPU entries included.
Explicit mode — typed components in general.
The same
:cpu/:gpudistinction applies toFlow; see Flows overview.