DifferentialEquations.jl icon indicating copy to clipboard operation
DifferentialEquations.jl copied to clipboard

RFC: Move default_algorithm to OrdinaryDiffEq etc.

Open tkf opened this issue 6 years ago • 4 comments

It would be convenient if we can do solve(prob) without loading the whole DifferentialEquations. I think it can be done with, for example, something like this:

module OrdinaryDiffEq

    """
        algorithm(name::Symbol) :: AbstractODEAlgorithm
        algorithm(::Val{name}) :: AbstractODEAlgorithm

    Get an algorithm constructor given its name.
    """
    algorithm(name::Symbol) = algorithm(Val(name))  # for convenience

    for alg in [Vern6, Vern7, ...]  # list of algorithms in OrdinaryDiffEq
        @eval algorithm(::Val{$(nameof(alg))}) = $alg
    end

    # fallback error handling for better user experience
    function algorithm(@nospecialize ::Val{name}) where {name}
        downstreams = Dict(
            :CVODE_BDF => :Sundials,
            ...
        )
        pkg = downstream[name]
        error("""
        Algorithm $name cannot be used. You need to run:
            using $pkg
        or
            using DifferentialEquations
        """)
    end

    # Same as `DifferentialEquations.default_algorithm` but each
    # algorithm constructor `XXX` is replaced with `algorithm(:XXX)`.
    function default_algorithm(...)
        ...
        if ...
            alg = algorithm(:CVODE_BDF)(linear_solver=:GMRES)
        elseif ...
        end
        ...
    end
end


module Sundials
    OrdinaryDiffEq.algorithm(::Val{:CVODE_BDF}) = CVODE_BDF
end

tkf avatar Apr 29 '19 02:04 tkf

It would be interesting to do this in DiffEqBase, and instead somehow define algorithm(:X)(args...) = X(args...) generically, then yes we could move the default handling out of DifferentialEquations.jl proper.

ChrisRackauckas avatar Apr 29 '19 15:04 ChrisRackauckas

do this in DiffEqBase

We can define algorithm(name::Symbol) and algorithm(::Val) (which throws an error to indicate which package to load to use such algorithm) in DiffEqBase. But I think something like

for alg in [Vern6, Vern7, ...]  # list of algorithms in OrdinaryDiffEq
    @eval algorithm(::Val{$(nameof(alg))}) = $alg
end

needs to go into OrdinaryDiffEq (and similar definitions for all *DiffEq packages).

However, I think it has some downsides:

  1. The algorithm names are put in the same namespace. We can't have the algorithm of the same name for, say, solving ODE and SDE. But that's probably not going to happen anyway? Also, that's how it works in DifferentialEquations now.
  2. The error-throwing DiffEqBase.algorithm(::Val) now needs to know all algorithms in all diffeq packages (or we can print a less specific message like "You need to run: using DifferentialEquations"). For example, it has to know Vern6 etc. are in OrdinaryDiffEq. We can avoid this if we define algorithm in OrdinaryDiffEq and we only have to record optional packages.

tkf avatar Apr 29 '19 20:04 tkf

I think this will be more pressing by this summer when our native methods are performing better than BDF even in the asymtopic cases (we are getting close), but until we narrow down the libraries used in the default handling I think it makes sense to require DifferentialEquations.jl, but that makes it not my priority right now (though I'd like to see it)

ChrisRackauckas avatar Apr 29 '19 21:04 ChrisRackauckas

Well, it's good news for me if it's (likely to) going to happen eventually.

tkf avatar Apr 29 '19 22:04 tkf