New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add common interface bindings #119
Conversation
@@ -0,0 +1,99 @@ | |||
abstract ODEJLAlgorithm <: AbstractODEAlgorithm | |||
immutable ode23Alg <: ODEJLAlgorithm end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd make those Ode23Alg
, etc.
|
||
u0 = prob.u0 | ||
|
||
Ts = sort(unique([tspan[1];saveat;tspan[2]])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you sort those?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two reasons. One is that it allows you to check for errors when saveat goes past tspan
(I actually didn't include that error check, oops!). Also, I've had a request for this in the chats (a long time ago) by someone who wanted to save at 100 random timepoints. When I profiled everything, this sort never even showed up on the radar. But what should probably happen is it should be a sort which is very fast when the array is already sorted, but I don't know how to choose sort algorithms in Julia.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I'm not a fan of this: it adds unnecessary complexity. It's not much complexity but feature creep needs to be avoided actively. That user could easily have done that himself with one or two lines of code. Now we need to support X lines of code for this instead.
Also, this is wrong when integration is backward in time. Ah, I see, that is not allowed. Why not? ODE.jl solver can do it. (I guess I have my feature-creep priorities elsewhere...)
@@ -0,0 +1,21 @@ | |||
using ODE, DiffEqBase, DiffEqProblemLibrary |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you test something more here than just throws-no-error? Maybe shape of solution? Within certain tolerance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. That's (and missing some algorithms) is why I had it as WIP.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guess I never did name it WIP, my bad. Should be complete now though, sans the ode23s issue which I think is beyond this PR.
Thanks! I think you can just drop Julia 0.4 (to make the travis error go away). |
Aren't functions also types now, as of Julia 0.5? |
Ahh yes. I actually see that the problem was that I was putting the type declaration after the function declaration. If you have that the actual immutable ode23 end
ode23(fn, y0, tspan; kwargs...) = So then the question is just whether you prefer it as |
This was updated to have the |
maxstep=dtmax, | ||
minstep=dtmin, | ||
initstep=dt, | ||
points=points) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, if you're willing to give up the type declaration, and since all of the algorithms accept a kwargs...
parameter, you could simplify the code greatly:
function solve{uType,tType,isinplace,F}(prob::AbstractODEProblem{uType,tType,isinplace,F}, ode_alg,...* rest of args *)
< snip >
ts,timeseries_tmp = ode_alg(f,u0,Ts,
norm = norm,
abstol=abstol,
reltol=reltol,
maxstep=dtmax,
minstep=dtmin,
initstep=dt,
points=points)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, if you're willing to give up the type declaration
No, that would be a huge change and would have some big downsides for usage with things like Sundials.jl.
I could also just do the call via typeof(alg)
since now they are the same name. The problem is that not all of the algorithms do accept kwargs
parameters (ode4
is an example which does not). Maybe the better solution to make them all accept it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious why removing the type declaration would be a problem for usage with Sundials.jl? Even if this function doesn't have a type on the parameter, those solvers could be passed in. Or are you trying to prevent, e.g., a DAE algorithm from being passed into a ODE solver?
Either way, if there are only a few ode*
algorithms which don't accept kwargs
, then yes, I think giving all of them kwargs
(and ignoring thes parameters if necessary) is worthwhile, since it let's you simplify this code considerably.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I thought you meant type constructor. My bad for the confusion. No, the type declaration ode_alg::T with T<ODEJLAlgorithm
is necessary for dispatch to work correctly, otherwise it doesn't know which solve
function to use.
And sure, I'll change the others to use kwargs
.
I did the suggested changes. Please take another look. Thanks! |
1 similar comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Current coverage is 93.39% (diff: 93.93%)@@ master #119 diff @@
==========================================
Files 2 4 +2
Lines 320 348 +28
Methods 0 0
Messages 0 0
Branches 0 0
==========================================
+ Hits 298 325 +27
- Misses 22 23 +1
Partials 0 0
|
I'll wait for @mauro3 's approval. |
Bump. |
I'll give @mauro3 a few more days. |
@@ -16,6 +21,9 @@ export ode23s | |||
# non-adaptive stiff: | |||
export ode4s | |||
|
|||
# Common Interface | |||
export ODEJLAlgorithm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ODEjlAlgorithm
would be easier to read.
@@ -152,7 +160,7 @@ include("runge_kutta.jl") | |||
|
|||
# ODE_MS Fixed-step, fixed-order multi-step numerical method | |||
# with Adams-Bashforth-Moulton coefficients | |||
function ode_ms(F, x0, tspan, order::Integer) | |||
function ode_ms(F, x0, tspan, order::Integer; kwargs...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these kwargs...
really necessary? It just seems like the abstraction is a bit leaky if they now need to accept throw away kwargs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These kwargs are necessary for the call
AlgType(f,u0,Ts;
norm = norm,
abstol=abstol,
reltol=reltol,
maxstep=dtmax,
minstep=dtmin,
initstep=dt,
points=points)
to not throw an error.
@@ -0,0 +1,8 @@ | |||
abstract ODEJLAlgorithm <: AbstractODEAlgorithm | |||
immutable ode23 <: ODEJLAlgorithm end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit magical. How about a comment like:
Making the ODE-solver functions into types lets us dispatch on them. Used in the DiffEqBase interface.
|
||
u0 = prob.u0 | ||
|
||
Ts = sort(unique([tspan[1];saveat;tspan[2]])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I'm not a fan of this: it adds unnecessary complexity. It's not much complexity but feature creep needs to be avoided actively. That user could easily have done that himself with one or two lines of code. Now we need to support X lines of code for this instead.
Also, this is wrong when integration is backward in time. Ah, I see, that is not allowed. Why not? ODE.jl solver can do it. (I guess I have my feature-creep priorities elsewhere...)
u0 = vec(prob.u0) | ||
else | ||
u0 = prob.u0 | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To save a few LOCs u0 = uType <: AbstractArray ? vec(prob.u0) : prob.u0
u0 = prob.u0 | ||
end | ||
|
||
ts,timeseries_tmp = AlgType(f,u0,Ts; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment along the lines: Calling the solver
Thanks Chris! Have you run your bigger test suites using this? |
Ahh yes, I forgot ODE.jl can integrate backwards in time. I got rid of the sort and the error for this. |
I pushed an update which addressed most of what you mentioned. Tests on the nightly will fail because of an unrelated thing (macro hygiene change, which has been fixed, but a tag needs to happen somewhere else in the ecosystem for it to pass). I got rid of the sorting and time direction check because indeed, one of the nice things about ODE.jl is that it can integrate backwards in time (and I'm hoping to try and get that in other places as well). I don't know what you want to do about the
Yes, I have already been using it some places. I haven't used it in the full benchmarking suite yet because I am waiting for the PR49 changes to go through so I can update the benchmarks to include all of them. I can't actually run them simultaneously until the package is renamed, so I've just been holding off and doing other things in the meantime. |
LGTM |
I renamed JuliaODE/ODE.jl to PR49.jl |
Don't you need to rename the module too? |
Yes, the module needs to be renamed for it to be referenced correctly. |
Hm, if we are going to put an effort and rename the whole module anyway, shouldn't we think about a better name then PR49? We can discuss it in SciML/Roadmap#7. |
Sorry, I'll revert it. |
You could also dispatch on |
In other cases they are used as functions in order to specify more type information. Some examples include:
The ODE.jl algorithms are too simple to need this (at least for right now), but they are setup in a way that is standardized because it would be more difficult to know to use |
This adds common interface bindings to ODE.jl. Currently it only includes the algorithms in the README:
I had to put the
Alg
in the type name because otherwise it matches the function's name. If anyone has a better idea of how to handle this let me know.