Skip to content

Solving

CommonSolve.solve Function
julia
CommonSolve.solve(args...; kwargs...) -> solution

Solve an equation or other mathematical problem using the algorithm specified in the arguments. Generally, downstream packages extend:

julia
CommonSolve.solve(prob::ProblemType, alg::SolverType; kwargs...)::SolutionType

If a package only defines the iterator interface, solve falls back to:

julia
solve(args...; kwargs...) = solve!(init(args...; kwargs...))

Arguments

  • args...: Problem, algorithm, and implementation-specific positional arguments.

Keywords

  • kwargs...: Implementation-specific solver options.

Interface

Extensions must dispatch the first positional argument on a type that they own. This prevents type piracy and ambiguities between independently developed solver packages.

Returns

The solution object defined by the downstream solver implementation.

Examples

julia
struct MyProblem end
struct MyAlg end

CommonSolve.solve(::MyProblem, ::MyAlg; kwargs...) = :solution

CommonSolve.solve(MyProblem(), MyAlg())
julia
solve(
    nlp,
    solver::CTSolvers.Solvers.AbstractNLPSolver;
    display
) -> SolverCore.GenericExecutionStats{T, S} where {T>:Float64, S>:Vector{Float64}}

Mid-level solve: solve an NLP problem directly with a solver strategy.

Contract

Concrete solvers implement this method, typically in a backend extension, dispatching on both the problem type and the solver type, e.g. CommonSolve.solve(nlp::NLPModels.AbstractNLPModel, solver::Ipopt; display) in the CTSolversIpopt extension. This generic stub throws NotImplemented. NLPModels is a weak dep — the typed method lives in each solver extension.

Arguments

  • nlp: The NLP problem to solve (type depends on backend).

  • solver::AbstractNLPSolver: Solver to use.

  • display::Bool: Whether to show solver output (default: true).

Returns

  • SolverCore.AbstractExecutionStats: Solver execution statistics.

Throws

See also: AbstractNLPSolver.

julia
solve(
    problem::CTSolvers.Optimization.AbstractOptimizationProblem,
    initial_guess,
    modeler::CTSolvers.Modelers.AbstractNLPModeler,
    solver::CTSolvers.Solvers.AbstractNLPSolver;
    display
) -> Any

High-level solve: Build NLP model, solve it, and build solution.

Arguments

  • problem::Optimization.AbstractOptimizationProblem: The optimization problem

  • initial_guess: Initial guess for the solution

  • modeler::Modelers.AbstractNLPModeler: Modeler to build NLP

  • solver::AbstractNLPSolver: Solver to use

  • display::Bool: Whether to show solver output (default: true)

Returns

  • Solution object from the optimization problem

Example

julia
# Conceptual usage pattern
# problem = ...
# x0 = ...
# modeler = Modelers.ADNLP()
# solver = Solvers.Ipopt(max_iter=1000)
# solution = solve(problem, x0, modeler, solver, display=true)

See also: Optimization.build_model, Optimization.build_solution

julia
solve(
    prob,
    integ::AbstractIntegrator;
    kwargs...
) -> CTSolversSciMLIntegrator.SciMLIntegrationResult

Mid-level solve: integrate an ODE problem directly with an integrator strategy.

Contract

Concrete integrators implement this method, typically in a backend extension, dispatching on both the problem type and the integrator type, e.g. CommonSolve.solve(prob::SciMLBase.AbstractODEProblem, integ::SciML; options, unsafe) in the CTSolversSciMLIntegrator extension. This generic stub throws NotImplemented. SciMLBase is a weak dep — the typed method lives in the integrator extension.

Arguments

  • prob: The ODE problem to integrate (type depends on backend; the time span is embedded).

  • integ::AbstractIntegrator: Integrator strategy to use.

  • options: Resolved solver options.

  • unsafe::Bool: If true, bypass retcode checking (default: false).

Returns

Throws

See also: CTSolvers.Integrators.AbstractIntegrator.

julia
solve(
    ocp::CTModels.Models.AbstractModel,
    description::Symbol...;
    kwargs...
) -> CTModels.Solutions.Solution{TimeGridModelType, TimesModelType, StateModelType, ControlModelType, VariableModelType, ModelType, CostateModelType, Float64, DualModelType, CTModels.Solutions.SolverInfos{Any, Dict{Symbol, Any}}} where {TimeGridModelType<:Union{CTModels.Solutions.MultipleTimeGridModel, CTModels.Solutions.UnifiedTimeGridModel{Vector{Float64}}}, TimesModelType<:CTModels.Components.TimesModel, StateModelType<:(CTModels.Components.StateModelSolution{TS} where TS<:CTModels.Components.CoercedTrajectory), ControlModelType<:(CTModels.Components.ControlModelSolution{TS} where TS<:CTModels.Components.CoercedTrajectory), VariableModelType<:Union{CTModels.Components.VariableModelSolution{Vector{Float64}}, CTModels.Components.VariableModelSolution{Float64}}, ModelType<:(CTModels.Models.Model{<:CTBase.Traits.TimeDependence, T} where T<:CTModels.Components.TimesModel), CostateModelType<:CTModels.Components.CoercedTrajectory, DualModelType<:Union{CTModels.Solutions.DualModel{PC_Dual, Vector{Float64}, SC_LB_Dual, SC_UB_Dual, CC_LB_Dual, CC_UB_Dual, Vector{Float64}, Vector{Float64}} where {PC_Dual<:CTModels.Components.CoercedTrajectory, SC_LB_Dual<:CTModels.Components.CoercedTrajectory, SC_UB_Dual<:CTModels.Components.CoercedTrajectory, CC_LB_Dual<:CTModels.Components.CoercedTrajectory, CC_UB_Dual<:CTModels.Components.CoercedTrajectory}, CTModels.Solutions.DualModel{PC_Dual, Nothing, SC_LB_Dual, SC_UB_Dual, CC_LB_Dual, CC_UB_Dual, Vector{Float64}, Vector{Float64}} where {PC_Dual<:CTModels.Components.CoercedTrajectory, SC_LB_Dual<:CTModels.Components.CoercedTrajectory, SC_UB_Dual<:CTModels.Components.CoercedTrajectory, CC_LB_Dual<:CTModels.Components.CoercedTrajectory, CC_UB_Dual<:CTModels.Components.CoercedTrajectory}}}

Main entry point for optimal control problem resolution.

This function orchestrates the complete solve workflow by: 2. Detecting the resolution mode (explicit vs descriptive) from arguments

  1. Extracting or creating the strategy registry for component completion

  2. Dispatching to the appropriate Layer 2 solver based on the detected mode

Arguments

  • ocp::CTModels.AbstractModel: The optimal control problem to solve

  • description::Symbol...: Symbolic description tokens (e.g., :collocation, :adnlp, :ipopt)

  • kwargs...: All keyword arguments. Action options (initial_guess/init, display) are extracted by the appropriate Layer 2 function. Explicit components (discretizer, modeler, solver) are identified by abstract type. A registry keyword can be provided to override the default strategy registry.

Returns

  • CTModels.AbstractSolution: Solution to the optimal control problem

Examples

julia
# Descriptive mode (symbolic description)
solve(ocp, :collocation, :adnlp, :ipopt)

# With initial guess alias
solve(ocp, :collocation; init=x0, display=false)

# Explicit mode (typed components)
solve(ocp; discretizer=OptimalControl.Collocation(),
           modeler=OptimalControl.ADNLP(), solver=OptimalControl.Ipopt())

Throws

Notes

  • This is the main entry point (Layer 1) of the solve architecture

  • Mode detection determines whether to use explicit or descriptive resolution path

  • The registry can be injected for testing or customization purposes

  • Action options and strategy-specific options are handled by Layer 2 functions

See also: _explicit_or_descriptive, solve_explicit, solve_descriptive, get_strategy_registry

julia
solve(
    ocp::CTModels.Models.AbstractModel,
    initial_guess::CTModels.Init.AbstractInitialGuess,
    discretizer::CTSolvers.DOCP.AbstractDiscretizer,
    modeler::CTSolvers.Modelers.AbstractNLPModeler,
    solver::CTSolvers.Solvers.AbstractNLPSolver;
    display
)

Resolve an optimal control problem using fully specified, concrete components (Layer 3).

This is the lowest-level execution layer for solving an optimal control problem. It expects all components (initial guess, discretizer, modeler, and solver) to be fully instantiated and normalized. It discretizes the problem and passes it to the underlying solve pipeline.

Arguments

  • ocp::CTModels.AbstractModel: The optimal control problem to solve

  • initial_guess::CTModels.AbstractInitialGuess: Normalized initial guess for the solution

  • discretizer::CTSolvers.DOCP.AbstractDiscretizer: Concrete discretization strategy

  • modeler::CTSolvers.Modelers.AbstractNLPModeler: Concrete NLP modeling strategy

  • solver::CTSolvers.Solvers.AbstractNLPSolver: Concrete NLP solver strategy

  • display::Bool: Whether to display the OCP configuration before solving

Returns

  • CTModels.AbstractSolution: The solution to the optimal control problem

Example

julia
# Conceptual usage pattern for Layer 3 solve
ocp = Model(time=:final)
# ... define OCP ...
init = CTModels.build_initial_guess(ocp, nothing)
disc = OptimalControl.Collocation(grid_size=100)
mod  = OptimalControl.ADNLP()
sol  = OptimalControl.Ipopt()

solution = solve(ocp, init, disc, mod, sol; display=true)

Notes

  • This is Layer 3 of the solve architecture - all inputs must be concrete, fully specified types

  • No defaults, no normalization, no component completion occurs at this level

  • The function performs: (1) optional configuration display, (2) problem discretization, (3) NLP solving

  • This function is typically called by higher-level solvers (solve_explicit, solve_descriptive)

See also: solve_explicit, solve_descriptive

julia
solve(
    nlp::NLPModels.AbstractNLPModel,
    solver::CTSolvers.Solvers.MadNLP;
    display
) -> MadNLPExecutionStats

Solve an NLP problem using MadNLP.

Arguments

  • nlp::NLPModels.AbstractNLPModel: The NLP problem to solve

  • display::Bool: Whether to show solver output (default: true)

Returns

  • MadNLP.MadNLPExecutionStats: MadNLP execution statistics
julia
solve(
    nlp::NLPModels.AbstractNLPModel,
    solver::CTSolvers.Solvers.MadNCL;
    display
) -> MadNCL.NCLStats

Solve an NLP problem using MadNCL.

Arguments

  • nlp::NLPModels.AbstractNLPModel: The NLP problem to solve

  • display::Bool: Whether to show solver output (default: true)

Returns

  • MadNCL.NCLStats: MadNCL execution statistics
julia
solve(
    nlp::NLPModels.AbstractNLPModel,
    solver::CTSolvers.Solvers.Ipopt;
    display
) -> SolverCore.GenericExecutionStats{T, S} where {T>:Float64, S>:Vector{Float64}}

Solve an NLP problem using Ipopt.

Arguments

  • nlp::NLPModels.AbstractNLPModel: The NLP problem to solve

  • display::Bool: Whether to show solver output (default: true)

Returns

  • SolverCore.GenericExecutionStats: Solver execution statistics
julia
solve(
    nlp::NLPModels.AbstractNLPModel,
    solver::CTSolvers.Solvers.Knitro;
    display
) -> SolverCore.GenericExecutionStats{T, S} where {T>:Float64, S>:Vector{Float64}}

Solve an NLP problem using Knitro.

Arguments

  • nlp::NLPModels.AbstractNLPModel: The NLP problem to solve

  • display::Bool: Whether to show solver output (default: true)

Returns

  • SolverCore.GenericExecutionStats: Solver execution statistics
julia
solve(prob::NonlinearProblem, alg::Union{AbstractNonlinearAlgorithm,Nothing}; kwargs...)

Arguments

The only positional argument is alg which is optional. By default, alg = nothing. If alg = nothing, then solve dispatches to the NonlinearSolve.jl automated algorithm selection (if using NonlinearSolve was done, otherwise it will error with a MethodError).

Keyword Arguments

The NonlinearSolve.jl universe has a large set of common arguments available for the solve function. These arguments apply to solve on any problem type and are only limited by limitations of the specific implementations.

Many of the defaults depend on the algorithm or the package the algorithm derives from. Not all of the interface is provided by every algorithm. For more detailed information on the defaults and the available options for specific algorithms / packages, see the manual pages for the solvers of specific problems.

Error Control

  • abstol: Absolute tolerance.

  • reltol: Relative tolerance.

These tolerances are interpreted by the termination condition.

Nonlinear Preconditioning

  • precondition: a left preconditioner G applied to the residual, giving the root-equivalent system G(f(u, p), u, p) = 0. Out-of-place problems return the transformed residual, Gfu = precondition(fu, u, p); in-place problems overwrite the first argument, precondition(fu, u, p) -> nothing. The composition is what the solver evaluates and differentiates, so termination and sol.resid are measured on it. G must be root-preserving: G(r, u, p) = 0 if and only if r = 0.

  • postcondition: an iterate corrector H applied to every accepted iterate before the residual is evaluated or convergence tested there, and once to the initial guess. Out-of-place problems return the corrected iterate, u_new = postcondition(u_proposed, u_prev, p, cache); in-place problems overwrite the first argument, postcondition(u_proposed, u_prev, p, cache) -> nothing. The fourth argument is the solver cache — nothing for the initial-guess correction, since that runs before a cache exists — and correctors that do not need solver state simply ignore it. H must satisfy H(u, u, p, cache) = u at solutions so that roots are unchanged. On a problem with lb/ub bounds the solver iterates on an unconstrained reparameterization of u, and H is applied in the original bounded variable by default. Wrap it in a PostconditionSpecifier to say otherwise: postcondition = PostconditionSpecifier(H; space = PostconditionSpace.Transformed) applies it to the unconstrained iterate instead.

Both are ordinary solver options: pass them to solve/init, or carry them on the problem and have them forwarded like any other keyword.

Miscellaneous

  • maxiters: Maximum number of iterations before stopping. Defaults to 1000.

  • verbose: Toggles whether warnings are thrown when the solver exits early. Defaults to true.

Sensitivity Algorithms (sensealg)

sensealg is used for choosing the way the automatic differentiation is performed. For more information, see the documentation for SciMLSensitivity

julia
solve(prob::AbstractDEProblem, alg::Union{AbstractDEAlgorithm, Nothing}; kwargs...)

Arguments

The only positional argument is alg which is optional. By default, alg = nothing. If alg = nothing, then solve dispatches to the DifferentialEquations.jl automated algorithm selection (if using DifferentialEquations was done, otherwise it will error with a MethodError).

Keyword Arguments

The DifferentialEquations.jl universe has a large set of common arguments available for the solve function. These arguments apply to solve on any problem type and are only limited by limitations of the specific implementations.

Many of the defaults depend on the algorithm or the package the algorithm derives from. Not all of the interface is provided by every algorithm. For more detailed information on the defaults and the available options for specific algorithms / packages, see the manual pages for the solvers of specific problems. To see whether a specific package is compatible with the use of a given option, see the Solver Compatibility Chart

Default Algorithm Hinting

To help choose the default algorithm, the keyword argument alg_hints is provided to solve. alg_hints is a Vector{Symbol} which describe the problem at a high level to the solver. The options are:

  • :auto vs :nonstiff vs :stiff - Denotes the equation as nonstiff/stiff. :auto allow the default handling algorithm to choose stiffness detection algorithms. The default handling defaults to using :auto.

Currently unused options include:

  • :interpolant - Denotes that a high-precision interpolation is important.

  • :memorybound - Denotes that the solver will be memory bound.

This functionality is derived via the benchmarks in SciMLBenchmarks.jl

SDE Specific Alghints

  • :additive - Denotes that the underlying SDE has additive noise.

  • :stratonovich - Denotes that the solution should adhere to the Stratonovich interpretation.

Output Control

These arguments control the output behavior of the solvers. It defaults to maximum output to give the best interactive user experience, but can be reduced all the way to only saving the solution at the final timepoint.

The following options are all related to output control. See the "Examples" section at the end of this page for some example usage.

  • dense: Denotes whether to save the extra pieces required for dense (continuous) output. Default is save_everystep && isempty(saveat) for algorithms which have the ability to produce dense output, i.e. by default it's true unless the user has turned off saving on steps or has chosen a saveat value. If dense=false, the solution still acts like a function, and sol(t) is a linear interpolation between the saved time points.

  • saveat: Denotes specific times to save the solution at, during the solving phase. The solver will save at each of the timepoints in this array in the most efficient manner available to the solver. If only saveat is given, then the arguments save_everystep and dense are false by default. If saveat is given a number, then it will automatically expand to tspan[1]:saveat:tspan[2]. For methods where interpolation is not possible, saveat may be equivalent to tstops. The default value is [].

  • save_idxs: Denotes the indices for the components of the equation to save. Defaults to saving all indices. For example, if you are solving a 3-dimensional ODE, and given save_idxs = [1, 3], only the first and third components of the solution will be outputted. Notice that of course in this case the outputted solution will be two-dimensional.

  • tstops: Denotes extra times that the timestepping algorithm must step to. This should be used to help the solver deal with discontinuities and singularities, since stepping exactly at the time of the discontinuity will improve accuracy. If a method cannot change timesteps (fixed timestep multistep methods), then tstops will use an interpolation, matching the behavior of saveat. If a method cannot change timesteps and also cannot interpolate, then tstops must be a multiple of dt or else an error will be thrown. tstops may also be a function tstops(p, tspan), accepting the parameter object and tspan, returning the vector of time points to stop at. Default is [].

  • d_discontinuities: Denotes locations of discontinuities in low-order derivatives of the vector field f. Each entry t_d is added as a tstop, and when the integrator lands on t_d it advances t by one ULP in the integration direction and re-evaluates the FSAL cache on the post-discontinuity side. The convention is right-continuous: f evaluated at t_d is the "old" regime and f at nextfloat(t_d) is the "new" regime, so user code should be written as

    julia
    if t > t_d
        # new regime
    else
        # old regime
    end

    Writing t >= t_d also works but means the solver takes one step of post-regime integration with a pre-regime-evaluated FSAL, which is less efficient and can reduce step acceptance near the discontinuity. A d_discontinuities entry at tspan[1] is supported (the starting-time case), in which case the first step begins at nextfloat(tspan[1]); this is useful for callbacks that need to activate immediately. The default is [].

  • save_everystep: Saves the result at every step. Default is true if isempty(saveat).

  • save_on: Denotes whether intermediate solutions are saved. This overrides the settings of dense, saveat and save_everystep and is used by some applications to manually turn off saving temporarily. Everyday use of the solvers should leave this unchanged. Defaults to true.

  • save_start: Denotes whether the initial condition should be included in the solution type as the first timepoint. This setting overrides saveat when set to false. Defaults to save_everystep || isempty(saveat) || saveat isa Number || prob.tspan[1] in saveat.

  • save_end: Denotes whether the final condition should be included in the solution type as the final timepoint. This setting is overridden by other saving settings when set to false. Defaults to save_everystep || isempty(saveat) || saveat isa Number || prob.tspan[2] in saveat.

  • initialize_save: Denotes whether to save after the callback initialization phase (when derivative_discontinuity=true). Defaults to true.

Note that dense requires save_everystep=true and saveat=false. If you need additional saving while keeping dense output, see the SavingCallback in the Callback Library.

Stepsize Control

These arguments control the timestepping routines.

Basic Stepsize Control

These are the standard options for controlling stepping behavior. Error estimates do the comparison

The scaled error is guaranteed to be <1 for a given local error estimate (note: error estimates are local unless the method specifies otherwise). abstol controls the non-scaling error and thus can be thought of as the error around zero. reltol scales with the size of the dependent variables and so one can interpret reltol=1e-3 as roughly being (locally) correct to 3 digits. Note tolerances can be specified element-wise by passing a vector whose size matches u0.

  • adaptive: Turns on adaptive timestepping for appropriate methods. Default is true.

  • abstol: Absolute tolerance in adaptive timestepping. This is the tolerance on local error estimates, not necessarily the global error (though these quantities are related). Defaults to 1e-6 on deterministic equations (ODEs/DDEs/DAEs) and 1e-2 on stochastic equations (SDEs/RODEs).

  • reltol: Relative tolerance in adaptive timestepping. This is the tolerance on local error estimates, not necessarily the global error (though these quantities are related). Defaults to 1e-3 on deterministic equations (ODEs/DDEs/DAEs) and 1e-2 on stochastic equations (SDEs/RODEs).

  • dt: Sets the initial stepsize. This is also the stepsize for fixed timestep methods. Defaults to an automatic choice if the method is adaptive.

  • dtmax: Maximum dt for adaptive timestepping. Defaults are package-dependent.

  • dtmin: Minimum dt for adaptive timestepping. Defaults are package-dependent.

  • force_dtmin: Declares whether to continue, forcing the minimum dt usage. Default is false, which has the solver throw a warning and exit early when encountering the minimum dt. Setting this true allows the solver to continue, never letting dt go below dtmin (and ignoring error tolerances in those cases). Note that true is not compatible with most interop packages.

Fixed Stepsize Usage

Note that if a method does not have adaptivity, the following rules apply:

  • If dt is set, then the algorithm will step with size dt each iteration.

  • If tstops and dt are both set, then the algorithm will step with either a size dt, or use a smaller step to hit the tstops point.

  • If tstops is set without dt, then the algorithm will step directly to each value in tstops

  • If neither dt nor tstops are set, the solver will throw an error.

Advanced Adaptive Stepsize Control

These arguments control more advanced parts of the internals of adaptive timestepping and are mostly used to make it more efficient on specific problems. For detailed explanations of the timestepping algorithms, see the timestepping descriptions

  • internalnorm: The norm function internalnorm(u,t) which error estimates are calculated. Required are two dispatches: one dispatch for the state variable and the other on the elements of the state variable (scalar norm). Defaults are package-dependent.

  • controller: Possible examples are IController, PIController, PIDController, PredictiveController. Default is algorithm-dependent.

  • gamma: The risk-factor γ in the q equation for adaptive timestepping of the controllers using it. Default is algorithm-dependent.

  • beta1: The Lund stabilization α parameter. Default is algorithm-dependent.

  • beta2: The Lund stabilization β parameter. Default is algorithm-dependent.

  • qmax: Defines the maximum value possible for the adaptive q. Default is algorithm-dependent.

  • qmin: Defines the minimum value possible for the adaptive q. Default is algorithm-dependent.

  • qsteady_min: Defines the minimum for the range around 1 where the timestep is held constant. Default is algorithm-dependent.

  • qsteady_max: Defines the maximum for the range around 1 where the timestep is held constant. Default is algorithm-dependent.

  • qoldinit: The initial qold in stabilization stepping. Default is algorithm-dependent.

  • failfactor: The amount to decrease the timestep by if the Newton iterations of an implicit method fail. Default is 2.

Memory Optimizations

  • calck: Turns on and off the internal ability for intermediate interpolations (also known as intermediate density). Not the same as dense, which is post-solution interpolation. This defaults to dense || !isempty(saveat) || "no custom callback is given". This can be used to turn off interpolations (to save memory) if one isn't using interpolations when a custom callback is used. Another case where this may be used is to turn on interpolations for usage in the integrator interface even when interpolations are used nowhere else. Note that this is only required if the algorithm doesn't have a free or lazy interpolation (DP8()). If calck = false, saveat cannot be used. The rare keyword calck can be useful in event handling.

  • alias: an AbstractAliasSpecifier object that holds fields specifying which variables to alias when solving. For example, to tell an ODE solver to alias the u0 array, you can use an ODEAliases object, and the alias_u0 keyword argument, e.g. solve(prob,alias = ODEAliases(alias_u0 = true)). For more information on what can be aliased for each problem type, see the documentation for the AbstractAliasSpecifier associated with that problem type. Set to true to alias every variable possible, or to false to disable aliasing. Defaults to an AbstractAliasSpecifier instance with nothing for all fields, which tells the solver to use the default behavior.

Miscellaneous

  • maxiters: Maximum number of iterations before stopping. Defaults to 1e5.

  • callback: Specifies a callback. Defaults to a callback function which performs the saving routine. For more information, see the Event Handling and Callback Functions manual page.

  • initializealg: The initialization algorithm for DAEs and ODEs with constraints. Available options include:

    • DefaultInit() (default): Automatically chooses the best initialization algorithm

    • CheckInit(): Only checks that initial conditions are consistent, errors if not

    • NoInit(): Skip initialization completely (for when you know conditions are consistent)

    • OverrideInit(): Use problem's initialization_data (typically from ModelingToolkit)

    • BrownBasicInit(): Brown's basic initialization algorithm for index-1 DAEs

    • ShampineCollocationInit(): Shampine's collocation initialization for general DAEs

    See the DAE initialization documentation for more details.

  • isoutofdomain: Specifies a function isoutofdomain(u,p,t) where, when it returns true, it will reject the timestep. Disabled by default.

  • unstable_check: Specifies a function unstable_check(dt,u,p,t) where, when it returns true, it will cause the solver to exit and throw a warning. Defaults to any(isnan,u), i.e. checking if any value is a NaN.

  • verbose: Toggles whether warnings are thrown when the solver exits early. Defaults to true.

  • merge_callbacks: Toggles whether to merge prob.callback with the solve keyword argument callback. Defaults to true.

  • wrap: Toggles whether to wrap the solution if prob.problem_type has a preferred alternate wrapper type for the solution. Useful when speed, but not shape of solution is important. Defaults to Val(true). Val(false) will cancel wrapping the solution.

  • u0: The initial condition, overrides the one defined in the problem struct. Defaults to nothing (no override, use the u0 defined in prob).

  • p: The parameters, overrides the one defined in the problem struct. Defaults to nothing (no override, use the p defined in prob).

Progress Monitoring

These arguments control the usage of the progressbar in ProgressLogging.jl compatible environments. For information on setting up progress bars in VS Code and other environments, see the progress bar documentation.

  • progress: Turns on/off the Juno progressbar. Default is false.

  • progress_steps: Numbers of steps between updates of the progress bar. Default is 1000.

  • progress_name: Controls the name of the progressbar. Default is the name of the problem type.

  • progress_message: Controls the message with the progressbar. Defaults to showing dt, t, the maximum of u.

  • progress_id: Controls the ID of the progress log message to distinguish simultaneous simulations.

Error Calculations

If you are using the test problems (ex: ODETestProblem), then the following options control the errors which are calculated:

  • timeseries_errors: Turns on and off the calculation of errors at the steps which were taken, such as the l2 error. Default is true.

  • dense_errors: Turns on and off the calculation of errors at the steps which require dense output and calculate the error at 100 evenly-spaced points throughout tspan. An example is the L2 error. Default is false.

Sensitivity Algorithms (sensealg)

sensealg is used for choosing the way the automatic differentiation is performed. For more information, see the documentation for SciMLSensitivity: https://docs.sciml.ai/SciMLSensitivity/stable/

Examples

The following lines are examples of how one could use the configuration of solve(). For these examples a 3-dimensional ODE problem is assumed, however the extension to other types is straightforward. 2. solve(prob, AlgorithmName()) : The "default" setting, with a user-specified algorithm (given by AlgorithmName()). All parameters get their default values. This means that the solution is saved at the steps the Algorithm stops internally and dense output is enabled if the chosen algorithm allows for it. All other integration parameters (e.g. stepsize) are chosen automatically.

  1. solve(prob, saveat = 0.01, abstol = 1e-9, reltol = 1e-9) : Standard setting for accurate output at specified (and equidistant) time intervals, used for e.g. Fourier Transform. The solution is given every 0.01 time units, starting from tspan[1]. The solver used is Tsit5() since no keyword alg_hints is given.

  2. solve(prob, maxiters = 1e7, progress = true, save_idxs = [1]) : Using longer maximum number of solver iterations can be useful when a given tspan is very long. This example only saves the first of the variables of the system, either to save size or because the user does not care about the others. Finally, with progress = true you are enabling the progress bar.

julia
solve(
    prob::SciMLBase.AbstractODEProblem,
    integ::SciML;
    options,
    unsafe
) -> CTSolversSciMLIntegrator.SciMLIntegrationResult

Integrate an ODEProblem with a SciML integrator and resolved options. Returns a SciMLIntegrationResult wrapping the raw ODESolution.

Arguments

  • prob::SciMLBase.AbstractODEProblem: The ODE problem to integrate (time span embedded).

  • integ::Integrators.SciML: The SciML integrator strategy.

  • options: Resolved solver options (defaults to the integrator's trajectory option dict).

  • unsafe::Bool: If true, bypass retcode checking; if false, throw on integration failure.

Throws

  • CTBase.Exceptions.SolverFailure: If the ODE solver returns an unsuccessful retcode and unsafe=false.
Base.methods Function
julia
methods(f, [types], [module])

Return the method table for f.

If types is specified, return an array of methods whose types match. If module is specified, return an array of methods defined in that module. A list of modules can also be specified as an array or set.

Julia 1.4

At least Julia 1.4 is required for specifying a module.

See also: which, @which and methodswith.

julia
methods() -> NTuple{12, NTuple{4, Symbol}}

Return the tuple of available method quadruplets for solving optimal control problems.

Each quadruplet consists of (discretizer_id, modeler_id, solver_id, parameter) where:

  • discretizer_id::Symbol: Discretization strategy identifier (e.g., :collocation)

  • modeler_id::Symbol: NLP modeling strategy identifier (e.g., :adnlp, :exa)

  • solver_id::Symbol: NLP solver identifier (e.g., :ipopt, :madnlp, :madncl, :knitro)

  • parameter::Symbol: Execution parameter (:cpu or :gpu)

Returns

  • Tuple{Vararg{Tuple{Symbol, Symbol, Symbol, Symbol&#125;&#125;}: Available method combinations

Examples

julia
julia> m = methods()
((:collocation, :adnlp, :ipopt, :cpu), (:collocation, :adnlp, :madnlp, :cpu), ...)

julia> length(m)
12  # 10 CPU methods + 2 GPU methods

julia> # CPU methods
julia> methods()[1]
(:collocation, :adnlp, :ipopt, :cpu)

julia> methods()[9]
(:collocation, :exa, :madncl, :cpu)

julia> # GPU methods
julia> methods()[11]
(:collocation, :exa, :madnlp, :gpu)

Notes

  • Returns a precomputed constant tuple (allocation-free, type-stable)

  • All methods currently use :collocation discretization

  • CPU methods (10 total): All combinations of {adnlp, exa} × {ipopt, madnlp, uno, madncl, knitro}

  • GPU methods (2 total): Only GPU-capable combinations exa × {madnlp, madncl}

  • GPU-capable strategies use parameterized types with automatic defaults

  • Used by CTBase.Descriptions.complete to complete partial method descriptions

See also: solve, CTBase.Descriptions.complete, get_strategy_registry

CTSolvers.DOCP.discretize Function
julia
discretize(
    ocp::CTModels.Models.AbstractModel,
    discretizer::CTSolvers.DOCP.AbstractDiscretizer
) -> CTSolvers.DOCP.DiscretizedModel{TO, CTDirect.Collocation, TC} where {TO<:CTModels.Models.AbstractModel, TC<:(CTDirect.DOCPCache{D} where D<:(CTDirect.DOCP{_A, CTModels.Models.Model{TD, TimesModelType, StateModelType, ControlModelType, VariableModelType, DynamicsModelType, ObjectiveModelType, ConstraintsModelType, DefinitionType, BuildExaModelType}, CTDirect.DOCPshape{CX, CU, CV}} where {_A<:CTDirect.Scheme, TD<:CTBase.Traits.TimeDependence, TimesModelType<:CTModels.Components.AbstractTimesModel, StateModelType<:CTModels.Components.AbstractStateModel, ControlModelType<:CTModels.Components.AbstractControlModel, VariableModelType<:CTModels.Components.AbstractVariableModel, DynamicsModelType<:Function, ObjectiveModelType<:CTModels.Components.AbstractObjectiveModel, ConstraintsModelType<:CTModels.Components.AbstractConstraintsModel, DefinitionType<:CTModels.Components.AbstractDefinition, BuildExaModelType<:Union{Nothing, Function}, CX<:Union{typeof(identity), typeof(only)}, CU<:Union{typeof(identity), typeof(only)}, CV<:Union{typeof(identity), typeof(only)}}))}

Discretize an optimal control problem into a DiscretizedModel.

Contract

Must be implemented in the package providing discretizer, dispatching on its concrete type, e.g. CTSolvers.discretize(ocp, ::Collocation) in CTDirect.

Arguments

  • ocp::CTModels.AbstractModel: The optimal control problem.

  • discretizer::AbstractDiscretizer: The discretization strategy.

Returns

See also: build_model, build_solution.

julia
discretize(
    ocp::CTModels.Models.AbstractModel,
    discretizer::CTDirect.Collocation
) -> CTSolvers.DOCP.DiscretizedModel{TO, CTDirect.Collocation, TC} where {TO<:CTModels.Models.AbstractModel, TC<:(CTDirect.DOCPCache{D} where D<:(CTDirect.DOCP{_A, CTModels.Models.Model{TD, TimesModelType, StateModelType, ControlModelType, VariableModelType, DynamicsModelType, ObjectiveModelType, ConstraintsModelType, DefinitionType, BuildExaModelType}, CTDirect.DOCPshape{CX, CU, CV}} where {_A<:CTDirect.Scheme, TD<:CTBase.Traits.TimeDependence, TimesModelType<:CTModels.Components.AbstractTimesModel, StateModelType<:CTModels.Components.AbstractStateModel, ControlModelType<:CTModels.Components.AbstractControlModel, VariableModelType<:CTModels.Components.AbstractVariableModel, DynamicsModelType<:Function, ObjectiveModelType<:CTModels.Components.AbstractObjectiveModel, ConstraintsModelType<:CTModels.Components.AbstractConstraintsModel, DefinitionType<:CTModels.Components.AbstractDefinition, BuildExaModelType<:Union{Nothing, Function}, CX<:Union{typeof(identity), typeof(only)}, CU<:Union{typeof(identity), typeof(only)}, CV<:Union{typeof(identity), typeof(only)}}))}

Discretize an OCP with the Collocation strategy into a CTSolvers.DiscretizedModel holding a DOCPCache with the precomputed DOCP.

julia
discretize(
    ocp::CTModels.Models.AbstractModel,
    discretizer::CTDirect.DirectShooting
) -> CTSolvers.DOCP.DiscretizedModel{TO, CTDirect.DirectShooting, TC} where {TO<:CTModels.Models.AbstractModel, TC<:(CTDirect.DOCPCache{D} where D<:(CTDirect.DOCP{_A, CTModels.Models.Model{TD, TimesModelType, StateModelType, ControlModelType, VariableModelType, DynamicsModelType, ObjectiveModelType, ConstraintsModelType, DefinitionType, BuildExaModelType}, CTDirect.DOCPshape{CX, CU, CV}} where {_A<:CTDirect.Scheme, TD<:CTBase.Traits.TimeDependence, TimesModelType<:CTModels.Components.AbstractTimesModel, StateModelType<:CTModels.Components.AbstractStateModel, ControlModelType<:CTModels.Components.AbstractControlModel, VariableModelType<:CTModels.Components.AbstractVariableModel, DynamicsModelType<:Function, ObjectiveModelType<:CTModels.Components.AbstractObjectiveModel, ConstraintsModelType<:CTModels.Components.AbstractConstraintsModel, DefinitionType<:CTModels.Components.AbstractDefinition, BuildExaModelType<:Union{Nothing, Function}, CX<:Union{typeof(identity), typeof(only)}, CU<:Union{typeof(identity), typeof(only)}, CV<:Union{typeof(identity), typeof(only)}}))}

Discretize an OCP with the DirectShooting strategy into a CTSolvers.DiscretizedModel holding a DOCPCache with the precomputed DOCP.

CTSolvers.DOCP.ocp_model Function
julia
ocp_model(
    docp::CTSolvers.DOCP.DiscretizedModel
) -> CTModels.Models.AbstractModel

Extract the original optimal control problem from a discretized problem.

Arguments

  • docp::DiscretizedModel: The discretized optimal control problem

Returns

  • The original optimal control problem

Example

julia
ocp = ocp_model(docp)

See also: DiscretizedModel

CTSolvers.DOCP.nlp_model Function
julia
nlp_model(
    prob::CTSolvers.DOCP.DiscretizedModel,
    initial_guess,
    modeler::CTSolvers.Modelers.AbstractNLPModeler
) -> Any

Build an NLP model from a discretized optimal control problem.

This is a convenience wrapper around build_model that returns only the backend NLP model (the nlp field of the BuiltModel). Use build_model directly when the build-time cache is needed (e.g. before build_solution).

Arguments

  • prob::DiscretizedModel: The discretized OCP

  • initial_guess: Initial guess for the NLP solver

  • modeler: The modeler to use (e.g., Modelers.ADNLP, Modelers.Exa)

Returns

  • NLPModels.AbstractNLPModel: The NLP model

Example

julia
nlp = nlp_model(docp, initial_guess, modeler)

See also: ocp_solution, Optimization.build_model, Optimization.BuiltModel

CTSolvers.DOCP.ocp_solution Function
julia
ocp_solution(
    built::CTSolvers.Optimization.BuiltModel,
    model_solution::SolverCore.AbstractExecutionStats,
    modeler::CTSolvers.Modelers.AbstractNLPModeler
) -> Any

Build an optimal control solution from NLP execution statistics.

This is a convenience wrapper around build_solution that dispatches on the BuiltModel returned by build_model and ensures the return type is an optimal control solution.

Arguments

  • built::BuiltModel: The built model bundle returned by build_model

  • model_solution::SolverCore.AbstractExecutionStats: NLP solver output

  • modeler: The modeler used for building

Returns

  • AbstractSolution: The OCP solution

Example

julia
built = build_model(docp, initial_guess, modeler)
sol = ocp_solution(built, nlp_stats, modeler)

See also: nlp_model, Optimization.build_solution, Optimization.BuiltModel

CTModels.Models.get_build_examodel Function
julia
get_build_examodel(
    ocp::CTModels.Models.Model{<:CTBase.Traits.TimeDependence, <:CTModels.Components.AbstractTimesModel, <:CTModels.Components.AbstractStateModel, <:CTModels.Components.AbstractControlModel, <:CTModels.Components.AbstractVariableModel, <:Function, <:CTModels.Components.AbstractObjectiveModel, <:CTModels.Components.AbstractConstraintsModel, <:CTModels.Components.AbstractDefinition, BE<:Function}
) -> Function

Return the build_examodel.

Arguments

  • ocp::Model: The optimal control problem with ExaModels builder.

Returns

  • BE: The ExaModels builder function.

See also: CTModels.Models.dynamics.

julia
get_build_examodel(
    _::CTModels.Models.Model{<:CTBase.Traits.TimeDependence, <:CTModels.Components.AbstractTimesModel, <:CTModels.Components.AbstractStateModel, <:CTModels.Components.AbstractControlModel, <:CTModels.Components.AbstractVariableModel, <:Function, <:CTModels.Components.AbstractObjectiveModel, <:CTModels.Components.AbstractConstraintsModel, <:CTModels.Components.AbstractDefinition, <:Nothing}
)

Fallback: throw when no Exa builder is present.