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). 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"? 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. Aaron Meurer --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
