+
, eps
, etc.). I notoriously use BigFloat
in my work and I tested most of the iterative solvers with them. We don't have tests for that in ODE.jl
yet, but I tested the rk solvers with types that don't mix with floats to test if the solvers are not polluted with some sneaky floating point constants. The solvers with the old API (the calls via ode45
etc.) might not have this feature, but they will once we bring them up to standards and re-implement them as iterators (we will have tests for supporting arbitrary values).RKWhateverUnrolled
and make it completely unrelated to our RKIntegrator
integrator. You wouldn't even have to make it a part of ODE.jl
package, it would be enough if you implement the right backend interface so other people could use your solvers via our API and compare them with standard ones.ODE.jl
collect
you are explicitly saving the results (it does a copy
of y
and dy
at each time step), if you only want a save some results just do a for (t,y) in sol
loop and save whatever you like. We might also implement stuff like last(sol)
to facilitate extracting the end result of the integration.
@ChrisRackauckas: concerning (3), you could make it a RKIntegrator
and then just overload the onstep!
etc functions to use the unrolled stuff. For the user it would then be just like the other RK-solvers, just faster.
@pwl: I love the docs! Tnx!
Also, looking through both your and my PR (#19 & #17), I have the feeling we should make tstop
part of Problem
. It features in the options everywhere, so it should be in the most central place. Then tsteps
would be part of the options for fixed-step solvers (with @assert tsteps[end]==tstop
), adaptive solvers wouldn't need any time, and dense output has tout
(with @assert tout[end]<=tstop
).
tdir(ivp)
.
tdir
to Problem
or IVP
? On one hand, there are common options showing up in each solver/integrator, on the other hand keeping all options, without exceptions, in the solver/integrator makes our types isolated and keeps the communication between them to minimum.
tdir
might be more painful to use and implement but I would like to see it as a part of an internal implementation of a solver. Not everyone will want to use tdir
in exactly the same form, some solvers might even choose not implement the reverse time integration at all.
IVP
and Solver
types in there and a single int
tdir
outside of Solver
tdir
?
IVP
is immutable and it could get in conflict with tout
and others.
tdir
according to keyword arguments
Regarding #17 :
I think having solve(prob)
would be putting too much stuff into our interface, which exacerbates the problem with naming that we already have. I was imagining something like this (using the current names for clarity):
1) Have ode
for users who "just came here to solve an equation".
2) Have solve
as an iterator constructor and the recommended way to deal with differential equations.
We already have a function that "solves" the Problem
, and it's called collect
. It is clear what it does and it is consistent with how Julia deals with iterators. I don't think there is enough reason to introduce a special name for what you suggest as solve(prob)
, which is essentially a transpose of collect
(tuple of arrays instead of array of tuples coming from collect
), we could call it collect_transpose
or something but calling it solve
has several issues: it would be a waste of a good name (we are short on these), it would suggest that it does more then it actually does (it is collect
in a disguise) and it would cause confusion in the long run (isn't iterating the same as solving? which one is the recommended way? What's the difference between ode
and solve(prob)
?).
And, although I agree that ode
is not the best name I wouldn't rename it to solve
either. It would suggest that it is more general then it is, in practice it can only solve explicit ODEs. If we want to call it solve
we should think about generalizing it to other problems too, which is, in my opinion, beyond the scope of this PR.
I think that, independently of the name we choose for solve
, we have to make it very clear in the docs that solve
returns an iterable object and it can be, and should be, dealt with just as any other iterable object in Julia. This is way more important then a name we pick (let's face it, there is no perfect choice here). And if you don't know how iterators work, feel free to use ode
, which is still powerful enough for most use cases. Later on we could add functions like dae
or implicit
to solve other types of equations but that's a different story.
I wouldn't mind renaming solve
to problem
that much (my only gripe with it is the problem(initial value problem)
thing), but I would mind having solve(problem(ivp))
replace collect
and similar utility functions. That would be bad because people would no longer think in terms of iterators and that would be just one too many different ways to do the same thing, which is bad because we would have to maintain all of them at the same time.
I think it is fine and should be encouraged to not use the iterators if not needed. The mostly empty loops in our examples are testimony that usually iterators are not needed. Calling the function which solves an ode ode
is fine, but solve
would be good too.
The problem with collect
is that its return is essentially unusable: a vector of tuples. collect_transpose
's return is usable, but still suffers from y
being a vector and the old hcat(y...)
problem. Also collect_transpose
is really obscure.
So, having something like ode
, returning something useful, namely a vector for t
and an array for y
if applicable, will be important to make ODE.jl easily usable.
y
being a vector? In contrast to what?
collect_transpose
, or whatever you call it, is essentially an extremely simple wrapper around an iterator. It's still far from something that a name solve
would suggest.collect_transpose
as to how to accumulate the outputcollect_transpose
is the right name for the function we need but it's closer to what it actually does then solve
.
results(solve(...))
?