Skip to content

Commit

Permalink
Redesign default ODE solver to be fully type-grounded
Browse files Browse the repository at this point in the history
This accomplishes a few things:

* Faster precompile times by precompiling less
* Full inference of results when using the automatic algorithm
* Hopefully faster load times by also precompiling less

This is done the same way as

* linearsolve SciML/LinearSolve.jl#307
* nonlinearsolve SciML/NonlinearSolve.jl#238

and is thus the more modern SciML way of doing it. It avoids dispatch by having a single algorithm that always generates the full cache and instead of dispatching between algorithms always branches for the choice.

It turns out, the mechanism already existed for this in OrdinaryDiffEq... it's CompositeAlgorithm, the same bones as AutoSwitch! As such, this reuses quite a bit of code from the auto-switch algorithms but instead of just having two choices it (currently) has 6 that it chooses between. This means that it has stiffness detection and switching behavior, but also in a size-dependent way.

There are still some optimizations to do though. Like LinearSolve.jl, it would be more efficient to have a way to initialize the caches to size zero and then have a way to re-initialize them to the correct size. Right now, it'll generate the same Jacobian N times and it shouldn't need to do that.

fix typo / test

fix precompilation choices

Update src/composite_algs.jl

Co-authored-by: Nathanael Bosch <[email protected]>

Update src/composite_algs.jl

switch CompositeCache away from tuple so it can start undef

Default Cache

fix precompile

remove fallbacks

remove fallbacks
  • Loading branch information
ChrisRackauckas authored and oscardssmith committed May 8, 2024
1 parent 438f34b commit 817d250
Show file tree
Hide file tree
Showing 10 changed files with 500 additions and 268 deletions.
223 changes: 112 additions & 111 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,111 +1,112 @@
name = "OrdinaryDiffEq"
uuid = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
authors = ["Chris Rackauckas <[email protected]>", "Yingbo Ma <[email protected]>"]
version = "6.75.0"

[deps]
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e"
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
ExponentialUtilities = "d4d017d3-3776-5f7e-afef-a10c40355c18"
FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898"
FastClosures = "9aa1b823-49e4-5ca5-8b0f-3971ec8bab6a"
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"
FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
FunctionWrappersWrappers = "77dc65aa-8811-40c2-897b-53d922fa7daf"
IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
LineSearches = "d3d80556-e9d4-5f37-9878-2ab0fcc64255"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae"
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221"
NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec"
Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588"
PreallocationTools = "d236fae5-4411-538c-8e31-a6e3d9e00b46"
PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
Preferences = "21216c6a-2e73-6563-6e65-726566657250"
RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
SciMLOperators = "c0aeaf25-5076-4817-a8d5-81caf7dfa961"
SimpleNonlinearSolve = "727e6d20-b764-4bd8-a329-72de5adea6c7"
SimpleUnPack = "ce78b400-467f-4804-87d8-8f486da07d0a"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
SparseDiffTools = "47a9eef4-7e08-11e9-0b38-333d64bd3804"
StaticArrayInterface = "0d7ed370-da01-4f52-bd93-41d350b8b718"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77"

[compat]
ADTypes = "0.2, 1"
Adapt = "3.0, 4"
ArrayInterface = "7"
DataStructures = "0.18"
DiffEqBase = "6.147"
DocStringExtensions = "0.9"
ExponentialUtilities = "1.22"
FastBroadcast = "0.2"
FastClosures = "0.3"
FillArrays = "1.9"
FiniteDiff = "2"
ForwardDiff = "0.10.3"
FunctionWrappersWrappers = "0.1"
IfElse = "0.1"
InteractiveUtils = "1.9"
LineSearches = "7"
LinearAlgebra = "1.9"
LinearSolve = "2.1.10"
Logging = "1.9"
MacroTools = "0.5"
MuladdMacro = "0.2.1"
NLsolve = "4"
NonlinearSolve = "3.7.3"
Polyester = "0.7"
PreallocationTools = "0.4.15"
PrecompileTools = "1"
Preferences = "1.3"
RecursiveArrayTools = "2.36, 3"
Reexport = "1.0"
SciMLBase = "2.27.1"
SciMLOperators = "0.3"
SimpleNonlinearSolve = "1"
SimpleUnPack = "1"
SparseArrays = "1.9"
SparseDiffTools = "2.3"
StaticArrayInterface = "1.2"
StaticArrays = "1.0"
TruncatedStacktraces = "1.2"
julia = "1.10"

[extras]
AlgebraicMultigrid = "2169fc97-5a83-5252-b627-83903c6c433c"
Calculus = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9"
ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66"
DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def"
DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d"
ElasticArrays = "fdbdab4c-e67f-52f5-8c3f-e7b388dad3d4"
IncompleteLU = "40713840-3770-5561-ab4c-a76e7d0d7895"
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78"
NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56"
ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
PoissonRandom = "e409e4f3-bfea-5376-8464-e040bb5c01ab"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267"
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"

[targets]
test = ["Calculus", "ComponentArrays", "Symbolics", "AlgebraicMultigrid", "IncompleteLU", "DiffEqCallbacks", "DiffEqDevTools", "ODEProblemLibrary", "ElasticArrays", "InteractiveUtils", "PoissonRandom", "Printf", "Random", "ReverseDiff", "SafeTestsets", "SparseArrays", "Statistics", "Test", "Unitful", "ModelingToolkit", "Pkg", "NLsolve"]
name = "OrdinaryDiffEq"
uuid = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
authors = ["Chris Rackauckas <[email protected]>", "Yingbo Ma <[email protected]>"]
version = "6.75.0"

[deps]
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e"
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
EnumX = "4e289a0a-7415-4d19-859d-a7e5c4648b56"
ExponentialUtilities = "d4d017d3-3776-5f7e-afef-a10c40355c18"
FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898"
FastClosures = "9aa1b823-49e4-5ca5-8b0f-3971ec8bab6a"
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"
FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
FunctionWrappersWrappers = "77dc65aa-8811-40c2-897b-53d922fa7daf"
IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
LineSearches = "d3d80556-e9d4-5f37-9878-2ab0fcc64255"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae"
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221"
NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec"
Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588"
PreallocationTools = "d236fae5-4411-538c-8e31-a6e3d9e00b46"
PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
Preferences = "21216c6a-2e73-6563-6e65-726566657250"
RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
SciMLOperators = "c0aeaf25-5076-4817-a8d5-81caf7dfa961"
SimpleNonlinearSolve = "727e6d20-b764-4bd8-a329-72de5adea6c7"
SimpleUnPack = "ce78b400-467f-4804-87d8-8f486da07d0a"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
SparseDiffTools = "47a9eef4-7e08-11e9-0b38-333d64bd3804"
StaticArrayInterface = "0d7ed370-da01-4f52-bd93-41d350b8b718"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77"

[compat]
ADTypes = "0.2, 1"
Adapt = "3.0, 4"
ArrayInterface = "7"
DataStructures = "0.18"
DiffEqBase = "6.147"
DocStringExtensions = "0.9"
ExponentialUtilities = "1.22"
FastBroadcast = "0.2"
FastClosures = "0.3"
FillArrays = "1.9"
FiniteDiff = "2"
ForwardDiff = "0.10.3"
FunctionWrappersWrappers = "0.1"
IfElse = "0.1"
InteractiveUtils = "1.9"
LineSearches = "7"
LinearAlgebra = "1.9"
LinearSolve = "2.1.10"
Logging = "1.9"
MacroTools = "0.5"
MuladdMacro = "0.2.1"
NLsolve = "4"
NonlinearSolve = "3.7.3"
Polyester = "0.7"
PreallocationTools = "0.4.15"
PrecompileTools = "1"
Preferences = "1.3"
RecursiveArrayTools = "2.36, 3"
Reexport = "1.0"
SciMLBase = "2.27.1"
SciMLOperators = "0.3"
SimpleNonlinearSolve = "1"
SimpleUnPack = "1"
SparseArrays = "1.9"
SparseDiffTools = "2.3"
StaticArrayInterface = "1.2"
StaticArrays = "1.0"
TruncatedStacktraces = "1.2"
julia = "1.10"

[extras]
AlgebraicMultigrid = "2169fc97-5a83-5252-b627-83903c6c433c"
Calculus = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9"
ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66"
DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def"
DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d"
ElasticArrays = "fdbdab4c-e67f-52f5-8c3f-e7b388dad3d4"
IncompleteLU = "40713840-3770-5561-ab4c-a76e7d0d7895"
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78"
NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56"
ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
PoissonRandom = "e409e4f3-bfea-5376-8464-e040bb5c01ab"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267"
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"

[targets]
test = ["Calculus", "ComponentArrays", "Symbolics", "AlgebraicMultigrid", "IncompleteLU", "DiffEqCallbacks", "DiffEqDevTools", "ODEProblemLibrary", "ElasticArrays", "InteractiveUtils", "PoissonRandom", "Printf", "Random", "ReverseDiff", "SafeTestsets", "SparseArrays", "Statistics", "Test", "Unitful", "ModelingToolkit", "Pkg", "NLsolve"]
21 changes: 16 additions & 5 deletions src/OrdinaryDiffEq.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ using LinearSolve, SimpleNonlinearSolve

using LineSearches

import EnumX

import FillArrays: Trues

# Interfaces
Expand Down Expand Up @@ -139,6 +141,7 @@ include("nlsolve/functional.jl")
include("nlsolve/newton.jl")

include("generic_rosenbrock.jl")
include("composite_algs.jl")

include("caches/basic_caches.jl")
include("caches/low_order_rk_caches.jl")
Expand Down Expand Up @@ -232,7 +235,6 @@ include("constants.jl")
include("solve.jl")
include("initdt.jl")
include("interp_func.jl")
include("composite_algs.jl")

import PrecompileTools

Expand All @@ -251,9 +253,14 @@ PrecompileTools.@compile_workload begin
Tsit5(), Vern7()
]

stiff = [Rosenbrock23(), Rosenbrock23(autodiff = false),
Rodas5P(), Rodas5P(autodiff = false),
FBDF(), FBDF(autodiff = false)
stiff = [Rosenbrock23(),
Rodas5P(),
FBDF()
]

default_ode = [
DefaultODEAlgorithm(autodiff=false),
DefaultODEAlgorithm()
]

autoswitch = [
Expand Down Expand Up @@ -282,7 +289,11 @@ PrecompileTools.@compile_workload begin
append!(solver_list, stiff)
end

if Preferences.@load_preference("PrecompileAutoSwitch", true)
if Preferences.@load_preference("PrecompileDefault", true)
append!(solver_list, default_ode)
end

if Preferences.@load_preference("PrecompileAutoSwitch", false)
append!(solver_list, autoswitch)
end

Expand Down
29 changes: 21 additions & 8 deletions src/alg_utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ isimplicit(alg::CompositeAlgorithm) = any(isimplicit.(alg.algs))

isdtchangeable(alg::Union{OrdinaryDiffEqAlgorithm, DAEAlgorithm}) = true
isdtchangeable(alg::CompositeAlgorithm) = all(isdtchangeable.(alg.algs))
isdtchangeable(alg::DefaultSolverAlgorithm) = true

function isdtchangeable(alg::Union{LawsonEuler, NorsettEuler, LieEuler, MagnusGauss4,
CayleyEuler, ETDRK2, ETDRK3, ETDRK4, HochOst4, ETD2})
false
Expand All @@ -180,12 +182,14 @@ ismultistep(alg::ETD2) = true
isadaptive(alg::Union{OrdinaryDiffEqAlgorithm, DAEAlgorithm}) = false
isadaptive(alg::OrdinaryDiffEqAdaptiveAlgorithm) = true
isadaptive(alg::OrdinaryDiffEqCompositeAlgorithm) = all(isadaptive.(alg.algs))
isadaptive(alg::DefaultSolverAlgorithm) = true
isadaptive(alg::DImplicitEuler) = true
isadaptive(alg::DABDF2) = true
isadaptive(alg::DFBDF) = true

anyadaptive(alg::Union{OrdinaryDiffEqAlgorithm, DAEAlgorithm}) = isadaptive(alg)
anyadaptive(alg::OrdinaryDiffEqCompositeAlgorithm) = any(isadaptive, alg.algs)
anyadaptive(alg::DefaultSolverAlgorithm) = true

isautoswitch(alg) = false
isautoswitch(alg::CompositeAlgorithm) = alg.choice_function isa AutoSwitch
Expand All @@ -195,9 +199,11 @@ function qmin_default(alg::Union{OrdinaryDiffEqAlgorithm, DAEAlgorithm})
end
qmin_default(alg::CompositeAlgorithm) = maximum(qmin_default.(alg.algs))
qmin_default(alg::DP8) = 1 // 3
qmin_default(alg::DefaultSolverAlgorithm) = 1 // 5

qmax_default(alg::Union{OrdinaryDiffEqAlgorithm, DAEAlgorithm}) = 10
qmax_default(alg::CompositeAlgorithm) = minimum(qmax_default.(alg.algs))
qmax_default(alg::DefaultSolverAlgorithm) = 10
qmax_default(alg::DP8) = 6
qmax_default(alg::Union{RadauIIA3, RadauIIA5}) = 8

Expand Down Expand Up @@ -283,7 +289,7 @@ end

function DiffEqBase.prepare_alg(alg::CompositeAlgorithm, u0, p, prob)
algs = map(alg -> DiffEqBase.prepare_alg(alg, u0, p, prob), alg.algs)
CompositeAlgorithm(algs, alg.choice_function)
CompositeAlgorithm(algs, alg.choice_function,)
end

has_autodiff(alg::OrdinaryDiffEqAlgorithm) = false
Expand Down Expand Up @@ -366,6 +372,7 @@ end

alg_extrapolates(alg::Union{OrdinaryDiffEqAlgorithm, DAEAlgorithm}) = false
alg_extrapolates(alg::CompositeAlgorithm) = any(alg_extrapolates.(alg.algs))
alg_extrapolates(alg::DefaultSolverAlgorithm) = false
alg_extrapolates(alg::ImplicitEuler) = true
alg_extrapolates(alg::DImplicitEuler) = true
alg_extrapolates(alg::DABDF2) = true
Expand Down Expand Up @@ -726,6 +733,7 @@ alg_order(alg::QPRK98) = 9

alg_maximum_order(alg) = alg_order(alg)
alg_maximum_order(alg::CompositeAlgorithm) = maximum(alg_order(x) for x in alg.algs)
alg_maximum_order(alg::DefaultSolverAlgorithm) = 7
alg_maximum_order(alg::ExtrapolationMidpointDeuflhard) = 2(alg.max_order + 1)
alg_maximum_order(alg::ImplicitDeuflhardExtrapolation) = 2(alg.max_order + 1)
alg_maximum_order(alg::ExtrapolationMidpointHairerWanner) = 2(alg.max_order + 1)
Expand Down Expand Up @@ -862,6 +870,7 @@ function gamma_default(alg::Union{OrdinaryDiffEqAlgorithm, DAEAlgorithm})
isadaptive(alg) ? 9 // 10 : 0
end
gamma_default(alg::CompositeAlgorithm) = maximum(gamma_default, alg.algs)
gamma_default(alg::DefaultSolverAlgorithm) = 9 // 10
gamma_default(alg::RKC) = 8 // 10
gamma_default(alg::IRKC) = 8 // 10
function gamma_default(alg::ExtrapolationMidpointDeuflhard)
Expand Down Expand Up @@ -982,14 +991,18 @@ function unwrap_alg(integrator, is_stiff)
if !iscomp
return alg
elseif alg.choice_function isa AutoSwitchCache
if is_stiff === nothing
throwautoswitch(alg)
end
num = is_stiff ? 2 : 1
if num == 1
return alg.algs[1]
if alg.choice_function.algtrait isa DefaultODESolver
alg.algs[alg.choice_function.current]
else
return alg.algs[2]
if is_stiff === nothing
throwautoswitch(alg)
end
num = is_stiff ? 2 : 1
if num == 1
return alg.algs[1]
else
return alg.algs[2]
end
end
else
return _eval_index(identity, alg.algs, integrator.cache.current)
Expand Down
Loading

0 comments on commit 817d250

Please sign in to comment.