[sympy] r3291 committed - More formatting fixes

0 views
Skip to first unread message

codesite...@google.com

unread,
Oct 10, 2009, 12:52:30 PM10/10/09
to sympy-...@googlegroups.com
Revision: 3291
Author: asmeurer
Date: Sat Oct 10 09:51:47 2009
Log: More formatting fixes
http://code.google.com/p/sympy/source/detail?r=3291

Modified:
/wiki/ODEsModuleReport.wiki

=======================================
--- /wiki/ODEsModuleReport.wiki Fri Oct 9 19:30:39 2009
+++ /wiki/ODEsModuleReport.wiki Sat Oct 10 09:51:47 2009
@@ -11,7 +11,7 @@
=Introduction=
My project was to implement Ordinary Differential Equations solvers in
sympy. The final module that I completed is able to do the following:

- * Solve ODEs using the following methods:
+ * Solve ODEs using the following methods (with `dsolve()`):
* 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.
@@ -21,13 +21,13 @@
* 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.
- * Classify an ODE that fits one of the above methods into that method
using the classify_ode() function.
- * Check a solution to an ODE using the checkodesol() function.
- * Separate the variables multiplicatively in an expression using the
separatevars() function.
- * Determine the homogeneous order of an expression using the
homogeneous_order() function.
+ * Classify an ODE that fits one of the above methods into that method
using the `classify_ode()` function.
+ * Check a solution to an ODE using the `checkodesol()` function.
+ * Separate the variables multiplicatively in an expression using the
`separatevars()` function.
+ * Determine the homogeneous order of an expression using the
`homogeneous_order()` function.

In addition, I also did work to do the following.
- * Remove automatic combination of exponents (exp(x)*exp(y) => exp(x +
y)).
+ * Remove automatic combination of exponents `(exp(x)*exp(y) => exp(x +
y))`.
* Expand hints for the expand() function.
* Refactor powsimp() to be able to simplify only the exponent or only
the base.

@@ -52,16 +52,16 @@
==The GSoC Period==
For the start of the period, I followed my timeline. I implemented 1st
order ODEs with homogeneous coefficients and 1st order exact ODEs. These
were both pretty simple to do, as I expected.

-The next thing I wanted to do was separable. My goal at this point was to
get every relevant exercise from my textbook to work with my solvers. One
of the exercises from my <a
href="http://books.google.com.np/books?id=29utVed7QMIC&amp;lpg=PA24&amp;ots=uxLSUKt_3P&amp;hl=en&amp;pg=PA56#v=onepage&amp;q=&amp;f=false">book</a>
(Pg. 56, No. 21) was $latex dy=e^{x + y}dx$. I soon discovered that it was
impossible for SymPy to separate $latex e^{x + y} \rightarrow e^{x}e^{y}$,
because the second would be automatically combined in the core. I also
discovered that <code>expand()</code>, which should have been the function
to split that, expanded using all possible methods indiscriminately. Part
of my <code>separatevars()</code> function that I was writing to separate
variables in expressions would be to split things like $latex x + yx
\rightarrow x(1 + y)$ and $latex 2 x y + x^{2} + y^{2} \rightarrow (x +
y)^{2}$, but <code>expand()</code>
+The next thing I wanted to do was separable. My goal at this point was to
get every relevant exercise from my textbook to work with my solvers. One
of the exercises from my <a
href="http://books.google.com.np/books?id=29utVed7QMIC&amp;lpg=PA24&amp;ots=uxLSUKt_3P&amp;hl=en&amp;pg=PA56#v=onepage&amp;q=&amp;f=false">book</a>
(Pg. 56, No. 21) was `dy/dx=exp**(x + y)`. I soon discovered that it was
impossible for SymPy to separate `e**(x + y)` into `exp(x)*exp(y)`, because
the second would be automatically combined in the core. I also discovered
that <code>expand()</code>, which should have been the function to split
that, expanded using all possible methods indiscriminately. Part of my
`separatevars()` function that I was writing to separate variables in
expressions would be to split things like `x + y*x` into `x*(1 + y)` and
`2*x*y + x**2 + y**2` into `(x + y)**2$, but `expand()`
as it was currently written would expand those.

-So I spent a few weeks hacking on the core to make it not auto-combine
exponents. I came up with a rule that exponents would only auto-combine if
they had the same term minus the coefficient, the same rule that
<code>Add</code> uses to determine what terms should auto combined by
addition. So it would combine $latex e^{x}e^{x} \rightarrow e^{2x}$, but
$latex e^{x}e^{y}$ would be left alone. It turns out that some of our
algorithms, namely the Gruntz limit algorithm, relies on auto-combining.
We already had a function that could combine exponents,
<code>powsimp()</code>, but it also combined bases, as in $latex x^zy^z
\rightarrow (xy)^z$, so I had to split the behavior so that it could act
only as auto-combining once did (by the way, use <code>powsimp(expr,
combine='exp', deep=True)</code> to do this). Then, after some help from
Ondrej on pinpointing the exact location of the bugs, I just applied the
function there. The last thing I did here was to split the behavior of
expand, so that you could do <code>expand(x*(y + 1), mul=False)</code> and
it would leave it alone, but <code>expand(exp(x + y), mul=False)</code>
would return <code>exp(x)*exp(y)</code>. This split behavior turned out to
be useful in more than one place in my code.
+So I spent a few weeks hacking on the core to make it not auto-combine
exponents. I came up with a rule that exponents would only auto-combine if
they had the same term minus the coefficient, the same rule that `Add` uses
to determine what terms should auto combined by addition. So it would
combine `exp(x)*exp(x)` into `e**(2x)$, but `exp(x)*exp(y)` would be left
alone. It turns out that some of our algorithms, namely the Gruntz limit
algorithm, relies on auto-combining. We already had a function that could
combine exponents, `powsimp()`, but it also combined bases, as in
`x**z*y**z` into `(x*y)**z`, so I had to split the behavior so that it
could act only as auto-combining once did (by the way, use `powsimp(expr,
combine='exp', deep=True)` to do this). Then, after some help from Ondrej
on pinpointing the exact location of the bugs, I just applied the function
there. The last thing I did here was to split the behavior of expand, so
that you could do`expand(x*(y + 1), mul=False)` and it would leave it
alone, but`expand(exp(x + y), mul=False)` would return `exp(x)*exp(y)`.
This split behavior turned out to be useful in more than one place in my
code.

This was the first non bug fix patch of mine that was pushed in to SymPy,
and at the time of this writing, it is the last major one in the latest
stable version. It took some major rebasing to get my convoluted commit
history ready for submission, and it was during this phase that I git
finally clicked for me, especial the <code>git rebase</code> command. This
work took a few weeks from my ODEs time, and it became clear that I would
not be doing every possible thing from my application. The reason that I
included so much in my application was that my project was non-atomic. I
could implement a little or a lot and still have a working useful module.

If you look at my timeline on my application, you can see that the first
half is symbolic methods, and the second half is other methods, things like
series. It turns out that we didn't really learn much about systems of
ODEs in my course and we learned very little about numerical methods (and
it would take much more to know how to implement them). We did learn
series methods, but they were so annoying to do that I came to hate them
with a passion. So I decided to just focus on symbolic methods, which were
my favorite anyway. My goal was to implement as many as I could.

-After I finished up separable equations, I came up with an idea that I did
not have during the application period. <code>dsolve()</code> was becoming
cluttered fast with all of my solution methods. The way that it worked was
that it took an ODE and it tried to match methods one by one until it found
one that worked, which it then used. This had some drawbacks. First, as
I mentioned, the code was very cluttered. Second, the ODEs methods would
have to be applied in a predetermined order. There are several ODEs that
match more than one method. For example, $latex 2xy + (x^2 +
y^2)\frac{dy}{dx}=0$ has coefficients that are both homogeneous of order 2,
and is also exact, so it can be solved by either method. The two solvers
return differently formatted solutions for each one. A simpler example is
that 1st order ODEs with homogeneous coefficients can be solved in two
different ways. My working solution was to try them both and then apply
some heuristics to return the simplest one. But sometimes, one way would
create an impossible integral that would hand the integration engine. And
it made debugging the two solvers more difficult because I had to override
my heuristic. This also touches on the third point. Sometimes the
solution to an ODE can only be represented in the form of an unevaluatable
integral. SymPy's <code>integrate()</code> function is supposed to return
an unevaluated <code>Integral</code> class if it cannot do it, but all too
often it will just hang forever.
+After I finished up separable equations, I came up with an idea that I did
not have during the application period. <code>dsolve()</code> was becoming
cluttered fast with all of my solution methods. The way that it worked was
that it took an ODE and it tried to match methods one by one until it found
one that worked, which it then used. This had some drawbacks. First, as
I mentioned, the code was very cluttered. Second, the ODEs methods would
have to be applied in a predetermined order. There are several ODEs that
match more than one method. For example, `2*x*y + (x**2 + y**2)*dy/dx=0$
has coefficients that are both homogeneous of order 2, and is also exact,
so it can be solved by either method. The two solvers return differently
formatted solutions for each one. A simpler example is that 1st order ODEs
with homogeneous coefficients can be solved in two different ways. My
working solution was to try them both and then apply some heuristics to
return the simplest one. But sometimes, one way would create an impossible
integral that would hand the integration engine. And it made debugging the
two solvers more difficult because I had to override my heuristic. This
also touches on the third point. Sometimes the solution to an ODE can only
be represented in the form of an unevaluatable integral. SymPy's
<code>integrate()</code> function is supposed to return an unevaluated
<code>Integral</code> class if it cannot do it, but all too often it will
just hang forever.

The solution I came up with was to rewrite dsolve using a hints method. I
would create a new function called <code>classify_ode()</code> that would
do all of the ODE classification, removing it from the solving code. By
default, dsolve would still use a predetermined order of matching methods.
But you could override it by passing a "hint" to <code>dsolve</code> for
any matching method, and it would apply that method. There would also be
options to only return unevaluated integrals when applicable.

@@ -87,5 +87,5 @@

I finished off the summer by writing extensive documentation for all of my
solvers and functions. Hopefully someone who uses SymPy to solve ODEs can
learn something about ODE solving methods as well as how to use the
function I wrote when they read my documentation.

-<strong> Post-GSoC</strong>
+== Post-GSoC ==
I plan on continuing development with SymPy now that the Google Summer of
Code period is over. SymPy is an amazing project, mixing Python and
Computer Algebra, and I want to help it grow. I may even apply again in a
future year to implement some other thing in SymPy, or maybe apply as a
mentor for SymPy to help someone else improve it.

Reply all
Reply to author
Forward
0 new messages