Status: Accepted
Owner: asmeurer
Labels: Type-Enhancement Priority-High NeedsReview

New issue 1611 by asmeurer: New ODEs module
http://code.google.com/p/sympy/issues/detail?id=1611

I have finished up my Google Summer of Code 2009 project, which was to  
implement various ODE
solvers in SymPy.  Please pull from  
http://github.com/asmeurer/sympy/tree/odes-review.  Note that
I have elected to do only moderate rebasing from my original tree (branch  
odes), so you should really
only be reviewing the HEAD.

This includes the following features:

- All ODE solving now happens in ode.py, instead of solvers.py where it was  
crowding stuff.
- dsolve() remains the function to use to solve an ODE.  The syntax is the  
same for default solving:
dsolve(ode, func).
For example:
>>> dsolve(diff(f(x), x, 2) - 1, f(x))
f(x) == C1 + C2*x + x**2/2

dsolve() always returns an Equality instance, because it very often cannot  
solve for f(x) and must
return an implicit solution.

- The function classify_ode() was added.  This function classifies ODEs  
into the various methods (or
"hints", as I also call them) that dsolve() can use to solve them.
For example:
>>> classify_ode(f(x).diff(x) - 1, f(x))
('separable', '1st_exact', '1st_linear', 'Bernoulli', 
'1st_homogeneous_coeff_best',
'1st_homogeneous_coeff_subs_indep_div_dep', 
'1st_homogeneous_coeff_subs_dep_div_indep',
'nth_linear_constant_coeff_undetermined_coefficients',
'nth_linear_constant_coeff_variation_of_parameters', 'separable_Integral', 
'1st_exact_Integral',
'1st_linear_Integral', 'Bernoulli_Integral', 
'1st_homogeneous_coeff_subs_indep_div_dep_Integral',
'1st_homogeneous_coeff_subs_dep_div_indep_Integral',
'nth_linear_constant_coeff_variation_of_parameters_Integral')

- The function deriv_degree() remains the function to use for determining  
the degree, or order, of an
ODE.
For example:
>>> deriv_degree(f(x).diff(x, 5) + sin(x) + f(x).diff(x, 2), f(x))
5

- The new function checkodesol() checks if a solution to an ODE is valid by  
substituting it in and
either returning True if it finds 0 equivalence or the expression that it  
could not reduce to 0.
For example:
>>> checkodesol(f(x).diff(x, 2) - 1, f(x), Eq(f(x), C1 + C2*x + x**2/2))
True
>>> checkodesol(f(x).diff(x, 2) - 1, f(x), Eq(f(x), C1 + C2*x + x**2))
1

- The function separatevars(), which I wrote to help with the 1st order  
separable method, attempts to
intelligently separate variables an expression  multiplicatively.
For example:
>>> separatevars(x**2 + x**2*sin(y))
x**2*(1 + sin(y))
>>> separatevars(exp(x + y))
exp(x)*exp(y)

This function resides in simplify.py.

- The new function homogeneous_order(), which I wrote to help with the 1st  
order ODE with
homogeneous coefficients method, determines the homogeneous order of an  
expression.  An
expression F(x, y, ...) is homogeneous of order n if F(x*t, y*t, t*...) ==  
t**n*F(x, y, ...).
For example:
>>> homogeneous_order(x**2*sqrt(x**2 + y**2) + x*y**2*sin(x/y), x, y)
3

- dsolve() will simplify arbitrary constants, and renumber them in order in  
the expression.  You
should never see something like x + 2*C1 or 1 + C2*x + C1*x**2 returned  
from dsolve().  You can
disable this by using simplify=False in dsolve().

- Internally, the solving engine has been completely refactored.  The old  
way was to match the ODE
to various solvers in a predetermined order, and as soon as it matched one,  
it would solve it using
that method and return a result.  This had several problems with it.

First, several ODEs can be solved with more than one method (c.f. the  
simple ODE in the
classify_ode() example above), and sometimes you want to see the result  
from a different method.

Second, sometimes the default solver would return a result that was much  
more complex than
another one would have returned if the ODE had gotten to it.  For example,  
it may return an implicit
solution that is difficult for solve() to solve, whereas the other method  
would return the equation
already solver.  Another common case is that one method would set up an  
integral that integrate()
could not do, whereas another method would set up a simpler integral.  That  
leads to the third point.

Third, whenever a solver would set up a hard integral, integrate() would  
either hand for a while then
return an Integral, or it would hang forever.  Either way, you would get an  
unevaluatable (by SymPy)
integral, when sometimes another method might not give you that.

Fourth, there was a lot of code duplicated this way.  For example, whenever  
a method had the
potential to return an implicit solution, it had to duplicate the same code  
chunk that tried to solve it
and return a solved solution if it could be solved or else an implicit  
solution.

The new way is for dsolve to have an optional hint argument that you can  
use to specify whatever
method you want to use, if it fits.  dsolve() calls classify_ode() on the  
ODE and gets all of the possible
hints.  By default, hint="default" is used, which uses a predetermined  
order, much like the old way.
But you can easily use something like hint="1st_exact" to change the hint  
from the default method to
the 1st order exact ODE solver.  Aside from "default", there are also some  
other 'meta-hints' that you
can use.  "all" will return a dictionary of hint: solution terms for all  
matching hints.  "best" will use a
heuristic to return the simplest of all possible solutions.  This heuristic  
is based on whether the
solution has unevaluated Integrals in it, whether it can be solved  
explicitly, and finally, just which one
is the shortest.  All hints that set up integrals also have a  
coresponding "hint_Integral" hint, which will
not attempt to evaluate the integrals but instead return unevaluated  
Integrals in the solution.
"all_Integral" acts like "all", but it skips hints that attempt to evaluate  
integrals.  This is so you can
quickly get an unevaluated integral of something you know SymPy cannot do,  
instead of letting
integrate() hang.  It also lets you discover how the solvers work by  
showing you what integrals they
do.

- Along with extensive documentation on all of the functions, I have  
included a guide in the module
docstring on how to add more methods to the module using the hints system.   
It can give you an
idea of how the system works internally.


The following ODE solving methods have been implemented.  See the internal  
docstrings for more
information on each method:
- 1st order separable differential equations
- 1st order differential equations whose coefficients or dx and dy
   are functions homogeneous of the same order.
- 1st order exact differential equations.
- 1st order linear differential equations.  (this is already implemented in  
the current SymPy)
- 1st order Bernoulli differential equations. (this is already implemented  
in the current SymPy by a
patch I sent in in the spring)
- 2nd order Liouville differential equations.
- nth order linear homogeneous differential equation with constant
   coefficients.
- nth order linear inhomogeneous differential equation with constant
   coefficients using the method of undetermined coefficients.
- nth order linear inhomogeneous differential equation with constant
   coefficients using the method of variation of parameters.

In addition to the ode module, this branch includes fixes to the following  
issues, which were
necessary for me throughout my work:
- Issues 1582, 1566, 1530, and 1429 (the first part only).
- Integral.__getnewargs__ now properly works.  If r is an Integral  
instance, then r ==
r.new(r.__getnewargs__(r.args)) should always be True.
- Changed two assertions and one raise TypeError in solve() to raise  
NotImplementedError.  This way,
you do not have to check for AssertionError or TypeError to see if solve()  
has failed, only
NotImplementedError.  See issues 1425 and 1338.


--
You received this message because you are listed in the owner
or CC fields of this issue, or because you starred this issue.
You may adjust your issue notification preferences at:
http://code.google.com/hosting/settings

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sympy-issues" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/sympy-issues?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to