On Thu, Jun 25, 2009 at 11:14 AM, Aaron S. Meurer<[email protected]> wrote:
>
>
> On Jun 25, 2009, at 5:51 AM, Fabian Pedregosa wrote:
>
>>
>> Aaron S. Meurer wrote:
>>> So before I spend a lot of time implementing this, I figured it would
>>> be a good idea to get some feedback here on what I plan on doing.
>>>
>>> As most of you probably know, my Google Summer of Code project is to
>>> improve the ordinary differential equation solving capabilities of
>>> SymPy.  So far, I have been able to implement quite a few methods
>>> (though none of them except for Bernoulli have actually made it in
>>> yet).  Just for 1st order alone, dsolve, in my branch, can solve
>>> linear, Bernoulli, exact, first order equations with homogeneous
>>> coefficients, and I am finishing separable equations.  Each of these
>>> is rather simple for the most part.  dsolve matches the equation to a
>>> pattern, and as soon as it finds a pattern that it fits, for example
>>> a(x)*b(f(x)) + c(x)*d(f(x))*f'(x) for separable, then it applies the
>>> appropriate solution, which usually just involves rearranging the
>>> matched terms in an integral.
>>>
>>> The thing is that, sometimes, an ODE can fit more than one kind of
>>> pattern, expecially for first order ODE's.  Here is an example:
>>>
>>> 2xy + (x**2 + y**2)*dy/dx is exact, because ∂(2xy)/∂y ==
>>> ∂(x**2 +
>>> y**2)/∂x == 2x (those are partials, in case they don't render).
>>> Also, the substitutions u == y/x and v == x/y make the equation
>>> separable, because the terms are homogeneous of the same order (see
>>> my
>>> blog: 
>>> http://asmeurersympy.wordpress.com/2009/05/31/first-order-differential-equations-with-homogeneous-coefficients/)
>>> .  These three methods produce the same result written in three
>>> different ways (the solution is not solvable in y, so SymPy would
>>> return all three ways as they are).  The three ways are:
>>> exact:  x**2*y + y**3/3 == C1
>>> substitution u == y/x:  x == C2(y**3/x**3+3y/x)**(-1/3)
>>> substitution u == x/y:  y == C3(3x**3/y**3+1)**(-1/3)
>>>
>>> These three solutions are all equivalent, though the arbitrary
>>> constants in each one are not necessarily equal to one another (see
>>> my
>>> blog post for a proof of their equivalence).  Because the arbitrary
>>> constants are not equal, SymPy would be unable to recognize their
>>> equivalence (though I hope to fix this with issue 1336).
>>>
>>> So as you can see, many differential equations can be solved in more
>>> than one way.  Currently, dsolve just spits out the solution for the
>>> first method that it matches the ODE to.  I would like to have it so
>>> that the user can choose to return a different (equivalent) solution
>>> if he wants to.
>>>
>>> So here is what I propose.  Please let me know if you think this is a
>>> good idea and how it could be improved upon:
>>>
>>> First, create the function classify_ode.  The function will apply
>>> match patterns to an ode and return a list of strings of possible
>>> patterns, like ("exact", "1st_homogeneous_coeff",
>>> "1st_homogeneous_coeff_alt") for the above.  The list would be
>>> ordered
>>> such that dsolve would use the first hint by default.  I would
>>> determine the default ordering based on testing of many odes to see
>>> which methods generally return cleaner solutions than others.  Also,
>>> dsolve will call the function as classify_ode(ode, match=True) (what
>>> is a better word than match?), and it will return a dict with the key
>>> type set to the first string that would be returned in the list, and
>>> the other keys are the match keys that dsolve needs to solve the ode
>>> (that way it doesn't have to match it twice).
>>
>> That's nice. It is similar to function guess_solve_strategy in
>> sympy.solvers (consider naming these two functions is a similar
>> fashion)
>>
>>>
>>> For hints like "1st_homogeneous_coeff" which always have two possible
>>> solutions, there will be two hints, one with '_alt' at the end.  The
>>> '_alt' one is chosen so that the one without '_alt' is the better one
>>> based on a metric (see below).  Another option would be to use
>>> "1st_homogeneous_coeff_f(x)/x" and "1st_homogeneous_coeff_x/f(x)",
>>> which is more explicit, but doesn't allow classify_ode to place the
>>> better one first without evaluating integrals (which I don't want to
>>> do, because the integrals for those problems tend to be hard and
>>> takes
>>> SymPy some time).  I could also just use all 4.  The only
>>> disadvantage
>>> with that is that it would be redundant, though I don't think it
>>> would
>>> be ambiguously so.
>>>
>>> Also, what is the best hint name for "1st_homogeneous_coeff_f(x)/x"?
>>
>> Maybe passing a hints dict: {'type': 'homegeneous', 'lst': True,
>> 'coeff': f, 'args': x} or a tuple ...
> This seems way more complex than I want.  I think if I document that
> f(x) refers to function and x refers to the independent variable in
> the docstring of classify_ode that it shouldn't be too ambiguous.
>>
>>> The function and independent variable might not necessarily be f and
>>> x, but I want the hint name to be same regardless of the function.
>>> Is
>>> it clear enough that that means "function divided by independent
>>> variable", regardless of whether those happen to be f and x or not?
>>> Of course, it would all be in the docstring.
>>>
>>> Second, add the following to dsolve:  add default argument
>>> hint="default" (so dsolve(ode, function, hint="default").  If hint is
>>> set to a different hint from classify_ode, then it will return the
>>> solution based on that method (of course, if hint is something that
>>> isn't a supported type or doesn't match the ode, it will raise an
>>> exception).  Also, hint="all" would return a dict of method:solution
>>> items, and hint="best" would try all fitted methods and return the
>>> one
>>> that is the simplest based on a metric (contains no Integral class
>>> (i.e., unsolvable integrals), solvable in the function, and shortest
>>> expression, in that order. Any other good ideas for this?).
>>>
>>> So what do you think?  Is this a good strategy?  Are there any good
>>> features that I could add?  Sorry for the kind of long post.
>>>
>>
>> Seems to me a good strategy. Any ideas how do other CAS implement this
>> classification/solving strategy?
> Maple has a very expansive ode classification system.  If you do
> with(DEtools);
> you get among other things a function odeanalyser, which is about the
> same as my proposed classify_ode.  You can add the classifications as
> arguments to dsolve to have it solve in that way.  See also 
> http://www.maplesoft.com/support/help/view.aspx?path=DEtools/odeadvisor
>  and some of the stuff in the side bar under Differential Equations.

I would do it exactly as you proposed above. The only place where I
currently don't know which way is better is:

1) the clasification method will return a string representing the
type+way of solving it in one string
2) the clasification method return a string with type and another
variable stating the best solve strategy
3) the same as 2), but it also returns the function "f" and "x".

You suggested that 3) is too complex, well I don't know until I can
see the code. I think all 1), 2) and 3) can be trivially converted to
each other once you have the code written, so I guess just use your
intuition to do it right and we can then improve it.

Ondrej

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sympy" 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?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to