Skip to content
This repository has been archived by the owner on Sep 9, 2024. It is now read-only.

API decisions for all solvers #4

Closed
tomasaschan opened this issue May 10, 2013 · 8 comments
Closed

API decisions for all solvers #4

tomasaschan opened this issue May 10, 2013 · 8 comments

Comments

@tomasaschan
Copy link
Contributor

I think the API to these solvers is sometimes a bit confusing, and would like to propose some improvements. In general, I want the API to be as similar as Matlab's as possible - but that's because I'm coming from that direction. I don't know if e.g. R has this functionality, and if the API is different there, so some of these suggestions might be very biased.

  • If the problem is scalar, the output should be a Vector rather than a Matrix with one column. Both tout and yout should be column vectors (but I think that's already the case, right?)
  • If the problem is not scalar, each row in yout should correspond to a time, rather than each column. This is how Matlab does it, and it also makes sense since tout and yout then has the same number of rows, and the rows correspond to each other.
  • As input, all solvers should accept scalars or vectors for e.g. y0, and as return value of odefun, to make it easier to use them on scalar problems.

I'd be happy to put some work in towards this, but I'd like to hear your ideas before I start coding =)

@tomasaschan
Copy link
Contributor Author

As mentioned in #2, we probably want to make the support for time ranges work the same on all solvers as well.

@vtjnash
Copy link
Contributor

vtjnash commented May 10, 2013

I don't see any issues with making these improvements and would be happy to merge them.

It is sometimes worth considering what numpy does since they too often have a matlab background. It typically follows this same API, but it also provides an object-oriented single-step interface which seems quite handy.

@tomasaschan
Copy link
Contributor Author

I haven't worked a lot with NumPy - do you have anything specific in mind, or was it just a general comment? The only NumPy-related ODE stuff I can find is in scipy.integrate, and the API there doesn't look like something I'd like to try to match...

@vtjnash
Copy link
Contributor

vtjnash commented May 10, 2013

I haven't used it much either -- just a general comment. Specifically, I was looking at scipy.integrate.ode and while the non-reentrant behavior is a terrible decision, the flexibility to single-step the integration could be very nice

@tomasaschan
Copy link
Contributor Author

I agree - that is a nice feature, which as a bonus is really easy to implement if one has a good way to let the user ask for it.

We could do something like that (and open up for many other customizations in the future without having to change the API) by allowing the user to pass a Dict with extra settings. I'm very hesitant, though - Matlab does exactly that via odeset, and I've always hated that part of the API... but I suppose it's less awful when you can construct the settings object inline:

tout, yout = ode45(f, ts, y0, { single_step => true })

doesn't look nearly as bad as

opts = odeset('singlestep', 1)
[tout, yout] = ode45(@f, ts, y0, opts)

which would be the Matlab equivalent if there was one...

@vtjnash
Copy link
Contributor

vtjnash commented May 10, 2013

Don't forget that Julia now has named arguments, so that can be written:
tout, yout = ode45(f, ts, y0; single_step::Bool=true)
I've also rather hated odeset -- it just seemed too strange.

I'm just brainstorming ideas here, but this is roughly what I had in mind for an alternative:

solver = ode(@f, t0, y0; reltol=0.01)
solver[:method] = "45"
solver[:abstol] = 0.0001
t, y = solver[:step] # step for solver's "default" time step
t, y = solver[1.2] # step for +1.2 "second"
tout, yout = solver[0:100] # vector of solutions for +0 to +100 "seconds"

@tomasaschan
Copy link
Contributor Author

Named arguments is a fantastic way to do that. The user doesn't have to give the type, right? So it would just be tout, yout = ode45(f, ts, y0; single_step=true) which is dead simple and just what I'd want.

And when you mention it, I do kind of like the idea of being able to get a "solver object", where I can get a solution, change one property (but not touch others) and then get another solution to compare with. Consider instead the following syntax:

solver = ode(ode45, f, tspan, y0; reltol = 0.01) # first argument is solver method, the rest is like for e.g. ode45
t1, y1 = solver.solve()
solver.reltol = 0.001
t2, y2 = solver.solve()
# can now compare first and second solution

Maybe we could have both - as long as the signatures of the different odeXX methods are consistent, we could both have the cake and eat it, exposing the API in both ways. That would also make it easier to approach Julia from different directions - always a plus.

@acroy
Copy link
Contributor

acroy commented Mar 5, 2014

Discussion continues in #20 ...

@acroy acroy closed this as completed Mar 5, 2014
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants