SciMLProblems

The cornerstone of the SciML common interface is the problem type definition. These definitions are the encoding of mathematical problems into a numerically computable form.

Note About Symbolics and ModelingToolkit

The symbolic analog to the problem interface is the ModelingToolkit AbstractSystem. For example, ODESystem is the symbolic analog to ODEProblem. Each of these system types have a method for constructing the associated problem and function types.

Definition of the AbstractSciMLProblem Interface

The following standard principles should be adhered to across all AbstractSciMLProblem instantiations.

In-place Specification

Each AbstractSciMLProblem type can be called with an "is inplace" (iip) choice. For example:

ODEProblem(f, u0, tspan, p)
ODEProblem{iip}(f, u0, tspan, p)

which is a boolean for whether the function is in the inplace form (mutating to change the first value). This is automatically determined using the methods table but note that for full type-inferability of the AbstractSciMLProblem this iip-ness should be specified.

Additionally, the functions are fully specialized to reduce the runtimes. If one would instead like to not specialize on the functions to reduce compile time, then one can set recompile to false.

Specialization Levels

Specialization levels in problem definitions are used to control the amount of compilation specialization is performed on the model functions in order to trade off between runtime performance, simplicity, and compile-time performance. The default choice of specialization is AutoSpecialize, which seeks to allow for using fully precompiled solvers in common scenarios but falls back to a runtime-optimal approach when further customization is used.

Specialization levels are given as the second type parameter in AbstractSciMLProblem constructors. For example, this is done via:

ODEProblem{iip, specialization}(f, u0, tspan, p)

Note that iip choice is required for specialization choices to be made.

Specialization Choices

SciMLBase.AbstractSpecializationType
abstract type AbstractSpecialization

Supertype for the specialization types. Controls the compilation and function specialization behavior of SciMLFunctions, ultimately controlling the runtime vs compile-time trade-off.

source
SciMLBase.AutoSpecializeType
struct AutoSpecialize <: SciMLBase.AbstractSpecialization

The default specialization level for problem functions. AutoSpecialize works by applying a function wrap just-in-time before the solve process to disable just-in-time re-specialization of the solver to the specific choice of model f and thus allow for using a cached solver compilation from a different f. This wrapping process can lead to a small decreased runtime performance with a benefit of a greatly decreased compile-time.

Note About Benchmarking and Runtime Optimality

It is recommended that AutoSpecialize is not used in any benchmarking due to the potential effect of function wrapping on runtimes. AutoSpecialize's use case is targeted at decreased latency for REPL performance and not for cases where where top runtime performance is required (such as in optimization loops). Generally, for non-stiff equations the cost will be minimal and potentially not even measurable. For stiff equations, function wrapping has the limitation that only chunk sized 1 Dual numbers are allowed, which can decrease Jacobian construction performance.

Limitations of AutoSpecialize

The following limitations are not fundamental to the implementation of AutoSpecialize, but are instead chosen as a compromise between default precompilation times and ease of maintenance. Please open an issue to discuss lifting any potential limitations.

  • AutoSpecialize is only setup to wrap the functions from in-place ODEs. Other cases are excluded for the time being due to time limitations.
  • AutoSpecialize will only lead to compilation reuse if the ODEFunction's other functions (such as jac and tgrad) are the default nothing. These could be JIT wrapped as well in a future version.
  • AutoSpecialize'd functions are only compatible with Jacobian calculations performed with chunk size 1, and only with tag DiffEqBase.OrdinaryDiffEqTag(). Thus ODE solvers written on the common interface must be careful to detect the AutoSpecialize case and perform differentiation under these constraints, use finite differencing, or manually unwrap before solving. This will lead to decreased runtime performance for sufficiently large Jacobians.
  • AutoSpecialize only wraps on Julia v1.8 and higher.
  • AutoSpecialize does not handle cases with units. If unitful values are detected, wrapping is automatically disabled.
  • AutoSpecialize only wraps cases for which promote_rule is defined between u0 and dual numbers, u0 and t, and for which ArrayInterface.promote_eltype is defined on u0 to dual numbers.
  • AutoSpecialize only wraps cases for which f.mass_matrix isa UniformScaling, the default.
  • AutoSpecialize does not wrap cases where f isa AbstractSciMLOperator
  • By default, only the u0 isa Vector{Float64}, eltype(tspan) isa Float64, and typeof(p) isa Union{Vector{Float64},SciMLBase.NullParameters} are specialized by the solver libraries. Other forms can be specialized with AutoSpecialize, but must be done in the precompilation of downstream libraries.
  • AutoSpecialized functions are manually unwrapped in adjoint methods in SciMLSensitivity.jl in order to allow compiler support for automatic differentiation. Improved versions of adjoints which decrease the recompilation surface will come in non-breaking updates.

Cases where automatic wrapping is disabled are equivalent to FullSpecialize.

Example

f(du,u,p,t) = (du .= u)

# Note this is the same as ODEProblem(f, [1.0], (0.0,1.0))
# If no preferences are set
ODEProblem{true, SciMLBase.AutoSpecialize}(f, [1.0], (0.0,1.0))
source
SciMLBase.NoSpecializeType
struct NoSpecialize <: SciMLBase.AbstractSpecialization

NoSpecialize forces SciMLFunctions to not specialize on the types of functions wrapped within it. This ultimately contributes to a form such that every prob.f type is the same, meaning compilation caches are fully reused, with the downside of losing runtime performance. NoSpecialize is the form that most fully trades off runtime for compile time. Unlike AutoSpecialize, NoSpecialize can be used with any SciMLFunction.

Example

f(du,u,p,t) = (du .= u)
ODEProblem{true, SciMLBase.NoSpecialize}(f, [1.0], (0.0,1.0))
source
SciMLBase.FunctionWrapperSpecializeType
struct FunctionWrapperSpecialize <: SciMLBase.AbstractSpecialization

FunctionWrapperSpecialize is an eager wrapping choice which performs a function wrapping during the ODEProblem construction. This performs the function wrapping at the earliest possible point, giving the best compile-time vs runtime performance, but with the difficulty that any usage of prob.f needs to account for the function wrapper's presence. While optimal in a performance sense, this method has many usability issues with nonstandard solvers and analyses as it requires unwrapping before re-wrapping for any type changes. Thus this method is not used by default. Given that the compile-time different is almost undetectable from AutoSpecialize, this method is mostly used as a benchmarking reference for speed of light for AutoSpecialize.

Limitations of FunctionWrapperSpecialize

FunctionWrapperSpecialize has all of the limitations of AutoSpecialize, but also includes the limitations:

  • prob.f is directly specialized to the types of (u,p,t), and any usage of prob.f on other types first requires using SciMLBase.unwrapped_f(prob.f) to remove the function wrapper.
  • FunctionWrapperSpecialize can only be used by the ODEProblem constructor. If an ODEFunction is being constructed, the user must manually use DiffEqBase.wrap_iip on f before calling ODEFunction{true,FunctionWrapperSpecialize}(f). This is a fundamental limitation of the approach as the types of (u,p,t) are required in the construction process and not accessible in the AbstractSciMLFunction constructors.

Example

f(du,u,p,t) = (du .= u)
ODEProblem{true, SciMLBase.FunctionWrapperSpecialize}(f, [1.0], (0.0,1.0))
source
SciMLBase.FullSpecializeType
struct FullSpecialize <: SciMLBase.AbstractSpecialization

FullSpecialize is an eager specialization choice which directly types the AbstractSciMLFunction struct to match the type of the model f. This forces recompilation of the solver on each new function type f, leading to the most compile times with the benefit of having the best runtime performance.

FullSpecialize should be used in all cases where top runtime performance is required, such as in long-running simulations and benchmarking.

Example

f(du,u,p,t) = (du .= u)
ODEProblem{true, SciMLBase.FullSpecialize}(f, [1.0], (0.0,1.0))
source
Note

The specialization level must be precompile snooped in the appropriate solver package in order to enable the full precompilation and system image generation for zero-latency usage. By default, this is only done with AutoSpecialize and on types u isa Vector{Float64}, eltype(tspan) isa Float64, and p isa Union{Vector{Float64}, SciMLBase.NullParameters}. Precompilation snooping in the solvers can be done using the Preferences.jl setup on the appropriate solver. See the solver library's documentation for more details.

Default Parameters

By default, AbstractSciMLProblem types use the SciMLBase.NullParameters() singleton to define the absence of parameters by default. The reason is because this throws an informative error if the parameter is used or accessed within the user's function, for example, p[1] will throw an informative error about forgetting to pass parameters.

Keyword Argument Splatting

All AbstractSciMLProblem types allow for passing keyword arguments that would get forwarded to the solver. The reason for this is that in many cases, like in EnsembleProblem usage, a AbstractSciMLProblem might be associated with some solver configuration, such as a callback or tolerance. Thus, for flexibility the extra keyword arguments to the AbstractSciMLProblem are carried to the solver.

problem_type

AbstractSciMLProblem types include a non-public API definition of problem_type which holds a trait type corresponding to the way the AbstractSciMLProblem was constructed. For example, if a SecondOrderODEProblem constructor is used, the returned problem is simply a ODEProblem for interoperability with any ODEProblem algorithm. However, in this case the problem_type will be populated with the SecondOrderODEProblem type, indicating the original definition and extra structure.

Remake

SciMLBase.remakeFunction
remake(thing; <keyword arguments>)

Re-construct thing with new field values specified by the keyword arguments.

source
remake(prob::ODEProblem; f = missing, u0 = missing, tspan = missing,
       p = missing, kwargs = missing, _kwargs...)

Remake the given ODEProblem. If u0 or p are given as symbolic maps ModelingToolkit.jl has to be loaded.

source
remake(prob::BVProblem; f = missing, u0 = missing, tspan = missing,
       p = missing, kwargs = missing, problem_type = missing, _kwargs...)

Remake the given BVProblem.

source
remake(prob::SDEProblem; f = missing, u0 = missing, tspan = missing,
       p = missing, noise = missing, noise_rate_prototype = missing,
       seed = missing, kwargs = missing, _kwargs...)

Remake the given SDEProblem.

source
remake(prob::OptimizationProblem; f = missing, u0 = missing, p = missing,
    lb = missing, ub = missing, int = missing, lcons = missing, ucons = missing,
    sense = missing, kwargs = missing, _kwargs...)

Remake the given OptimizationProblem. If u0 or p are given as symbolic maps ModelingToolkit.jl has to be loaded.

source
remake(prob::NonlinearProblem; f = missing, u0 = missing, p = missing,
    problem_type = missing, kwargs = missing, _kwargs...)

Remake the given NonlinearProblem. If u0 or p are given as symbolic maps ModelingToolkit.jl has to be loaded.

source
remake(prob::NonlinearLeastSquaresProblem; f = missing, u0 = missing, p = missing,
    kwargs = missing, _kwargs...)

Remake the given NonlinearLeastSquaresProblem.

source

Problem Traits

SciMLBase.isinplaceMethod
isinplace(prob::AbstractSciMLProblem)

Determine whether the function of the given problem operates in place or not.

source

AbstractSciMLProblem API

Defaults and Preferences

SpecializationLevel at SciMLBase can be used to set the default specialization level. The following shows how to set the specialization default to FullSpecialize:

using Preferences, UUIDs
set_preferences!(
    UUID("0bca4576-84f4-4d90-8ffe-ffa030f20462"), "SpecializationLevel" => "FullSpecialize")

The default is AutoSpecialize.

Abstract SciMLProblems

SciMLBase.AbstractDEProblemType
abstract type AbstractDEProblem <: SciMLBase.AbstractSciMLProblem

Base type for all DifferentialEquations.jl problems. Concrete subtypes of AbstractDEProblem contain the necessary information to fully define a differential equation of the corresponding type.

source
SciMLBase.AbstractODEProblemType
abstract type AbstractODEProblem{uType, tType, isinplace} <: SciMLBase.AbstractDEProblem

Base for types which define ODE problems.

source
SciMLBase.AbstractDiscreteProblemType
abstract type AbstractDiscreteProblem{uType, tType, isinplace} <: SciMLBase.AbstractODEProblem{uType, tType, isinplace}

Base for types which define discrete problems.

source
SciMLBase.AbstractRODEProblemType
abstract type AbstractRODEProblem{uType, tType, isinplace, ND} <: SciMLBase.AbstractDEProblem

Base for types which define RODE problems.

source
SciMLBase.AbstractSDEProblemType
abstract type AbstractSDEProblem{uType, tType, isinplace, ND} <: SciMLBase.AbstractRODEProblem{uType, tType, isinplace, ND}

Base for types which define SDE problems.

source
SciMLBase.AbstractDAEProblemType
abstract type AbstractDAEProblem{uType, duType, tType, isinplace} <: SciMLBase.AbstractDEProblem

Base for types which define DAE problems.

source
SciMLBase.AbstractDDEProblemType
abstract type AbstractDDEProblem{uType, tType, lType, isinplace} <: SciMLBase.AbstractDEProblem

Base for types which define DDE problems.

source
SciMLBase.AbstractBVProblemType
abstract type AbstractBVProblem{uType, tType, isinplace, nlls} <: SciMLBase.AbstractODEProblem{uType, tType, isinplace}

Base for types which define BVP problems.

source
SciMLBase.AbstractSDDEProblemType
abstract type AbstractSDDEProblem{uType, tType, lType, isinplace, ND} <: SciMLBase.AbstractDEProblem

Base for types which define SDDE problems.

source