Skip to content

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 ​

StrategyidLoadParametersBackend
Solvers.Ipopt:ipoptNLPModelsIpoptCPUInterior point (COIN-OR Ipopt)
Solvers.MadNLP:madnlpMadNLPCPU, GPUPure-Julia interior point
Solvers.MadNCL:madnclMadNCL, MadNLPCPU, GPUAugmented Lagrangian (NCL) on top of MadNLP
Solvers.Knitro:knitroNLPModelsKnitroCPUCommercial solver by Artelys (license required)
Solvers.Uno:unoUnoSolverCPUUnified Lagrange-Newton solver (interior point, SQP, …)

Every solver solves an NLPModels.AbstractNLPModel through CommonSolve.solve and returns a SolverCore.AbstractExecutionStats:

julia
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.

StrategyidLoadParametersBackend
Modelers.ADNLP:adnlpADNLPModelsCPUADNLPModels — automatic differentiation
Modelers.Exa:exaExaModelsCPU, GPUExaModels — 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 ​

StrategyidLoadParametersBackend
Integrators.SciML:scimlOrdinaryDiffEqTsit5 (or OrdinaryDiffEq, DifferentialEquations)CPU, GPUAny 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 Knitro

An 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
└─
julia
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.