Skip to content

Support tuples? #566

@dlfivefifty

Description

@dlfivefifty

Fairly regularly (in teaching) I need to turn a second order ODE to a first order one. I'm surprised tuples can't be used to do this, see below. I also don't understand the conceptional reason why: tuples do not support addition or multiplication but they do support broadcasting addition and multiplication, which is what the "time-stepping" algorithms should be using.

I realise StaticArrays gives a work around but this is less than ideal for pedagogical usages, and also practical reasons when one has mixed types (say first argument is complex and the second real).

julia> using DifferentialEquations, Plots

julia> V = x -> x^2/2  # Potential
#5 (generic function with 1 method)

julia> Vp = x -> x     # Force
#7 (generic function with 1 method)

julia> λ_0 = 2.3  # initial location
2.3

julia> v_0 = 1.2  # initial position
1.2

julia> λv = solve(ODEProblem(((λ,v),_,t) -> (v,-Vp(λ)), (λ_0,v_0), (0.0, 10.0)); reltol=1E-6);
ERROR: MethodError: no method matching vec(::Tuple{Float64,Float64})
Closest candidates are:
  vec(::Transpose{T,#s627} where #s627<:(AbstractArray{T,1} where T) where T) at /Users/sheehanolver/Projects/julia-1.3/usr/share/julia/stdlib/v1.3/LinearAlgebra/src/adjtrans.jl:201
  vec(::AbstractSparseArray{Tv,Ti,1} where Ti where Tv) at /Users/sheehanolver/Projects/julia-1.3/usr/share/julia/stdlib/v1.3/SparseArrays/src/sparsevector.jl:913
  vec(::FillArrays.Ones{T,N,Axes} where Axes where N) where T at /Users/sheehanolver/.julia/packages/FillArrays/Aj0C4/src/fillalgebra.jl:3
  ...
Stacktrace:
 [1] _vec(::Tuple{Float64,Float64}) at /Users/sheehanolver/.julia/packages/DiffEqBase/avuk1/src/utils.jl:224
 [2] build_J_W(::Rodas4{0,false,DefaultLinSolve,DataType}, ::Tuple{Float64,Float64}, ::Tuple{Float64,Float64}, ::DiffEqBase.NullParameters, ::Float64, ::Float64, ::Function, ::Type, ::Val{false}) at /Users/sheehanolver/.julia/packages/OrdinaryDiffEq/nV9bA/src/derivative_utils.jl:534
 [3] alg_cache(::Rodas4{0,false,DefaultLinSolve,DataType}, ::Tuple{Float64,Float64}, ::Tuple{Float64,Float64}, ::Type, ::Type, ::Type, ::Tuple{Float64,Float64}, ::Tuple{Float64,Float64}, ::ODEFunction{false,var"#9#10",UniformScaling{Bool},Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing}, ::Float64, ::Float64, ::Float64, ::DiffEqBase.NullParameters, ::Bool, ::Val{false}) at /Users/sheehanolver/.julia/packages/OrdinaryDiffEq/nV9bA/src/caches/rosenbrock_caches.jl:389
 [4] (::OrdinaryDiffEq.var"#194#195"{Tuple{Float64,Float64},Tuple{Float64,Float64},DataType,DataType,DataType,Tuple{Float64,Float64},Tuple{Float64,Float64},ODEFunction{false,var"#9#10",UniformScaling{Bool},Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing},Float64,Float64,Float64,DiffEqBase.NullParameters,Bool})(::Rodas4{0,false,DefaultLinSolve,DataType}) at /Users/sheehanolver/.julia/packages/OrdinaryDiffEq/nV9bA/src/caches/basic_caches.jl:15
 [5] map(::OrdinaryDiffEq.var"#194#195"{Tuple{Float64,Float64},Tuple{Float64,Float64},DataType,DataType,DataType,Tuple{Float64,Float64},Tuple{Float64,Float64},ODEFunction{false,var"#9#10",UniformScaling{Bool},Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing},Float64,Float64,Float64,DiffEqBase.NullParameters,Bool}, ::Tuple{Vern7,Rodas4{0,false,DefaultLinSolve,DataType}}) at ./tuple.jl:140
 [6] alg_cache(::CompositeAlgorithm{Tuple{Vern7,Rodas4{0,false,DefaultLinSolve,DataType}},AutoSwitch{Vern7,Rodas4{0,false,DefaultLinSolve,DataType},Rational{Int64},Int64}}, ::Tuple{Float64,Float64}, ::Tuple{Float64,Float64}, ::Type, ::Type, ::Type, ::Tuple{Float64,Float64}, ::Tuple{Float64,Float64}, ::ODEFunction{false,var"#9#10",UniformScaling{Bool},Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing}, ::Float64, ::Float64, ::Float64, ::DiffEqBase.NullParameters, ::Bool, ::Val{false}) at /Users/sheehanolver/.julia/packages/OrdinaryDiffEq/nV9bA/src/caches/basic_caches.jl:14
 [7] #__init#328(::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}, ::Nothing, ::Bool, ::Bool, ::Bool, ::Bool, ::Nothing, ::Bool, ::Bool, ::Float64, ::Float64, ::Float64, ::Bool, ::Bool, ::Rational{Int64}, ::Nothing, ::Float64, ::Rational{Int64}, ::Int64, ::Int64, ::Int64, ::Rational{Int64}, ::Bool, ::Int64, ::Nothing, ::Nothing, ::Int64, ::typeof(DiffEqBase.ODE_DEFAULT_NORM), ::typeof(opnorm), ::typeof(DiffEqBase.ODE_DEFAULT_ISOUTOFDOMAIN), ::typeof(DiffEqBase.ODE_DEFAULT_UNSTABLE_CHECK), ::Bool, ::Bool, ::Bool, ::Bool, ::Bool, ::Bool, ::Bool, ::Int64, ::String, ::typeof(DiffEqBase.ODE_DEFAULT_PROG_MESSAGE), ::Nothing, ::Bool, ::Bool, ::Bool, ::Bool, ::Base.Iterators.Pairs{Symbol,Bool,Tuple{Symbol,Symbol},NamedTuple{(:default_set, :second_time),Tuple{Bool,Bool}}}, ::typeof(DiffEqBase.__init), ::ODEProblem{Tuple{Float64,Float64},Tuple{Float64,Float64},false,DiffEqBase.NullParameters,ODEFunction{false,var"#9#10",UniformScaling{Bool},Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing},Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},DiffEqBase.StandardODEProblem}, ::CompositeAlgorithm{Tuple{Vern7,Rodas4{0,false,DefaultLinSolve,DataType}},AutoSwitch{Vern7,Rodas4{0,false,DefaultLinSolve,DataType},Rational{Int64},Int64}}, ::Array{Tuple{Float64,Float64},1}, ::Array{Float64,1}, ::Array{Any,1}, ::Type{Val{true}}) at /Users/sheehanolver/.julia/packages/OrdinaryDiffEq/nV9bA/src/solve.jl:278
 [8] (::DiffEqBase.var"#kw##__init")(::NamedTuple{(:default_set, :second_time, :reltol),Tuple{Bool,Bool,Float64}}, ::typeof(DiffEqBase.__init), ::ODEProblem{Tuple{Float64,Float64},Tuple{Float64,Float64},false,DiffEqBase.NullParameters,ODEFunction{false,var"#9#10",UniformScaling{Bool},Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing},Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},DiffEqBase.StandardODEProblem}, ::CompositeAlgorithm{Tuple{Vern7,Rodas4{0,false,DefaultLinSolve,DataType}},AutoSwitch{Vern7,Rodas4{0,false,DefaultLinSolve,DataType},Rational{Int64},Int64}}, ::Array{Tuple{Float64,Float64},1}, ::Array{Float64,1}, ::Array{Any,1}, ::Type{Val{true}}) at ./none:0 (repeats 5 times)
 [9] #__solve#327(::Base.Iterators.Pairs{Symbol,Real,Tuple{Symbol,Symbol,Symbol},NamedTuple{(:default_set, :second_time, :reltol),Tuple{Bool,Bool,Float64}}}, ::typeof(DiffEqBase.__solve), ::ODEProblem{Tuple{Float64,Float64},Tuple{Float64,Float64},false,DiffEqBase.NullParameters,ODEFunction{false,var"#9#10",UniformScaling{Bool},Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing},Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},DiffEqBase.StandardODEProblem}, ::CompositeAlgorithm{Tuple{Vern7,Rodas4{0,false,DefaultLinSolve,DataType}},AutoSwitch{Vern7,Rodas4{0,false,DefaultLinSolve,DataType},Rational{Int64},Int64}}) at /Users/sheehanolver/.julia/packages/OrdinaryDiffEq/nV9bA/src/solve.jl:4
 [10] (::DiffEqBase.var"#kw##__solve")(::NamedTuple{(:default_set, :second_time, :reltol),Tuple{Bool,Bool,Float64}}, ::typeof(DiffEqBase.__solve), ::ODEProblem{Tuple{Float64,Float64},Tuple{Float64,Float64},false,DiffEqBase.NullParameters,ODEFunction{false,var"#9#10",UniformScaling{Bool},Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing},Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},DiffEqBase.StandardODEProblem}, ::CompositeAlgorithm{Tuple{Vern7,Rodas4{0,false,DefaultLinSolve,DataType}},AutoSwitch{Vern7,Rodas4{0,false,DefaultLinSolve,DataType},Rational{Int64},Int64}}) at ./none:0
 [11] #__solve#1(::Bool, ::Base.Iterators.Pairs{Symbol,Real,Tuple{Symbol,Symbol},NamedTuple{(:second_time, :reltol),Tuple{Bool,Float64}}}, ::typeof(DiffEqBase.__solve), ::ODEProblem{Tuple{Float64,Float64},Tuple{Float64,Float64},false,DiffEqBase.NullParameters,ODEFunction{false,var"#9#10",UniformScaling{Bool},Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing},Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},DiffEqBase.StandardODEProblem}, ::Nothing) at /Users/sheehanolver/.julia/packages/DifferentialEquations/9ez1L/src/default_solve.jl:7
 [12] #__solve at ./none:0 [inlined]
 [13] #__solve#447 at /Users/sheehanolver/.julia/packages/DiffEqBase/avuk1/src/solve.jl:179 [inlined]
 [14] #__solve at ./none:0 [inlined]
 [15] #solve_call#442(::Base.Iterators.Pairs{Symbol,Float64,Tuple{Symbol},NamedTuple{(:reltol,),Tuple{Float64}}}, ::typeof(DiffEqBase.solve_call), ::ODEProblem{Tuple{Float64,Float64},Tuple{Float64,Float64},false,DiffEqBase.NullParameters,ODEFunction{false,var"#9#10",UniformScaling{Bool},Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing},Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},DiffEqBase.StandardODEProblem}) at /Users/sheehanolver/.julia/packages/DiffEqBase/avuk1/src/solve.jl:38
 [16] #solve_call at ./none:0 [inlined]
 [17] #solve#443 at /Users/sheehanolver/.julia/packages/DiffEqBase/avuk1/src/solve.jl:61 [inlined]
 [18] (::DiffEqBase.var"#kw##solve")(::NamedTuple{(:reltol,),Tuple{Float64}}, ::typeof(solve), ::ODEProblem{Tuple{Float64,Float64},Tuple{Float64,Float64},false,DiffEqBase.NullParameters,ODEFunction{false,var"#9#10",UniformScaling{Bool},Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing},Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},DiffEqBase.StandardODEProblem}) at ./none:0
 [19] top-level scope at REPL[7]:1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions