Strategies Catalogue
This page lists every strategy CTSolvers provides: what it wraps, which package activates it, and on which device it runs. Most users reach these strategies through OptimalControl.jl (e.g. solve(ocp, :adnlp, :ipopt)); the symbols used there are the strategy ids below.
NLP solvers — CTSolvers.Solvers
| Strategy | id | Load | Parameters | Backend |
|---|---|---|---|---|
Solvers.Ipopt | :ipopt | NLPModelsIpopt | CPU | Interior point (COIN-OR Ipopt) |
Solvers.MadNLP | :madnlp | MadNLP | CPU, GPU | Pure-Julia interior point |
Solvers.MadNCL | :madncl | MadNCL, MadNLP | CPU, GPU | Augmented Lagrangian (NCL) on top of MadNLP |
Solvers.Knitro | :knitro | NLPModelsKnitro | CPU | Commercial solver by Artelys (license required) |
Solvers.Uno | :uno | UnoSolver | CPU | Unified Lagrange-Newton solver (interior point, SQP, …) |
Every solver solves an NLPModels.AbstractNLPModel through CommonSolve.solve and returns a SolverCore.AbstractExecutionStats:
using ADNLPModels, NLPModelsIpopt
using CommonSolve: solve
nlp = ADNLPModel(x -> sum(x .^ 2), ones(10))
solver = CTSolvers.Solvers.Ipopt(max_iter = 100)
stats = solve(nlp, solver; display = false)display = false silences the backend's output. Solvers.extract_solver_infos turns the stats into the (objective, iterations, constraints_violation, message, status, successful) tuple used to build an optimal control solution.
NLP modelers — CTSolvers.Modelers
A modeler chooses the NLP backend used to transcribe a discretized problem and carries its options. It does not build anything itself: the package providing the problem (e.g. CTDirect) builds the NLP model for each (problem, modeler) pair.
| Strategy | id | Load | Parameters | Backend |
|---|---|---|---|---|
Modelers.ADNLP | :adnlp | ADNLPModels | CPU | ADNLPModels — automatic differentiation |
Modelers.Exa | :exa | ExaModels | CPU, GPU | ExaModels — SIMD abstraction, GPU-ready |
ADNLP backends based on Enzyme or Zygote additionally require that package to be loaded.
Single precision
Modelers.Exa(base_type = Float32) builds a Float32 model, which only MadNLP accepts, with a tolerance reachable in single precision (e.g. tol = 1e-5). Ipopt, MadNCL and Uno have no method for a Float32 model. On the GPU, MadNLP runs on it but did not converge on the probe problem.
ODE integrators — CTSolvers.Integrators
| Strategy | id | Load | Parameters | Backend |
|---|---|---|---|---|
Integrators.SciML | :sciml | OrdinaryDiffEqTsit5 (or OrdinaryDiffEq, DifferentialEquations) | CPU, GPU | Any SciML ODE algorithm |
Tsit5() is the default algorithm when OrdinaryDiffEqTsit5 is loaded; any other algorithm is passed through alg (e.g. alg = Vern9() after using OrdinaryDiffEqVerner). See Integration Results for what solve returns.
Options
Options are validated when the strategy is built. Each name, type, default and description is available from the strategy type:
julia> CTBase.Strategies.metadata(CTSolvers.Solvers.Knitro)
StrategyMetadata with 9 options:
│
├─ maxit (max_iter, maxiter, max_iterations)::Integer (default: 1000)
│ description: Maximum number of iterations before termination
│
├─ maxtime (max_wall_time, max_time, time_limit)::Real (default: 1.0e8)
│ description: Maximum allowable real time in seconds before termination
│
├─ maxfevals::Integer (default: -1)
│ description: Maximum number of function evaluations before termination (-1 for unlimited)
│
├─ feastol_abs::Real (default: 1.0e-8)
│ description: Absolute feasibility tolerance for successful termination
│
├─ opttol_abs::Real (default: 1.0e-8)
│ description: Absolute optimality tolerance for KKT error
│
├─ ftol::Real (default: 1.0e-12)
│ description: Relative change tolerance for objective function
│
├─ xtol::Real (default: 1.0e-12)
│ description: Relative change tolerance for solution point estimate
│
├─ soltype::Integer (default: 0)
│ description: Solution type returned by Knitro (0=final, 1=bestfeas)
│
└─ outlev (print_level)::Integer (default: 2)
description: Controls the level of output produced by KnitroAn instance shows its actual values, with their provenance (user or default):
julia> CTSolvers.Integrators.SciML(reltol = 1e-10, abstol = 1e-10)
SciML{CPU} (instance, id=:sciml)
├─ internalnorm = real_norm [default]
├─ alg = Tsit5 [default]
├─ reltol = 1.0e-10 [user]
├─ save_everystep = auto [default]
├─ abstol = 1.0e-10 [user]
├─ save_start = auto [default]
└─ dense = auto [default]
Tip: use describe(SciML{CPU}) to see all available options.Unknown options are rejected with a suggestion; mode = :permissive accepts them with a warning and passes them to the backend unchanged, which gives access to backend options CTSolvers does not declare:
julia> CTSolvers.Solvers.Ipopt(max_itr = 100)
ERROR: IncorrectArgument
│
│ Unknown options provided for Ipopt
│
│ Unrecognized options: [:max_itr]
│
│ These options are not defined in the metadata of Ipopt.
│
│ Available options:
│ :acceptable_iter, :acceptable_tol, :constr_viol_tol, :derivative_test, :derivative_test_print_all, :derivative_test_tol, :diverging_iterates_tol, :dual_inf_tol, :hessian_approximation, :limited_memory_update_type, :linear_solver, :max_cpu_time, :max_iter, :max_wall_time, :mu_init, :mu_max, :mu_max_fact, :mu_min, :mu_strategy, :print_frequency_iter, :print_frequency_time, :print_level, :print_timing_statistics, :sb, :timing_statistics, :tol, :warm_start_bound_push, :warm_start_init_point, :warm_start_mult_bound_push
│
│ Suggestions for :max_itr:
│ - :max_iter (aliases: maxiter, max_iterations, maxit) [distance: 1]
│ - :max_wall_time (aliases: maxtime, max_time, time_limit) [distance: 3]
│ - :mu_init [distance: 5]
│
│ If you are certain these options exist for the backend, you can:
│ - bypass validation for a specific option (recommended):
│ Ipopt(..., max_itr=bypass(value)) # or force(value)
│ - or accept all unknown options with permissive mode:
│ Ipopt(..., mode=:permissive)
│
│ Context build_strategy_options - strict validation
└─CTSolvers.Solvers.Ipopt(bound_relax_factor = 1e-10; mode = :permissive)┌ Warning: Unrecognized options passed to backend
│
│ Unvalidated options: [:bound_relax_factor]
│
│ These options will be passed directly to the Ipopt backend
│ without validation by CTBase. Ensure they are correct.
│
└ @ CTBase.Strategies
Ipopt{CPU} (instance, id=:ipopt)
├─ max_iter = 1000 [default]
├─ tol = 1.0e-8 [default]
├─ linear_solver = mumps [default]
├─ mu_strategy = adaptive [default]
├─ sb = yes [default]
├─ bound_relax_factor = 1.0e-10 [user]
└─ print_level = 5 [default]
Tip: use describe(Ipopt{CPU}) to see all available options.To skip validation for a single option only, wrap its value: Solvers.Ipopt(bound_relax_factor = CTBase.Strategies.bypass(1e-10)).
Several options have aliases (e.g. maxiter for Ipopt's max_iter, rtol for SciML's reltol); metadata lists them.
Choosing a parameter
CPU is the default for every strategy: Solvers.MadNLP() is Solvers.MadNLP{CPU}(). Pass the parameter explicitly to target the GPU — see GPU.