Good idea.  The ability to generate random expressions is very useful.  We 
should make this more general and add it to sympy/utilities/iterables.py.

I had to make a few modifications to your script. First off, you were testing 
if integral(function.diff(x)) == function, which has two problems: first, you 
don't even pass it to simplify().  As I said, the integral will usually not 
look like the original function.  

But more importantly, it need not even be true.  The function and the integral 
of the derivative of the function can differer by a constant.  

Second, it's better to catch NotImplementedError and continue.

Third, you should never use from import * outside of the interpreter (i.e., in 
a script).  I know it's lazy, but it's a bad habit to get into.

Fourth, I also regular print the original expression, which makes it easier to 
copy and paste it if it is wrong and I need to debug it.

I attached an improved script.  Thanks for taking the time to look into this.

Aaron Meurer



On Aug 19, 2010, at 11:06 AM, Christian Muise wrote:

>   So it's been about 6 years since I've done calculus, and in fact the only 
> math I see from day to day is pretty much 100% symbolic. That being said, 
> I've attached a script that may help, or at least satisfy some curiosity. 
> It's crude, but simple enough to toy around with and checks that the integral 
> of the diff is the same as the original (not sure what to do to check this 
> doesn't require constant factors). Just running it a few times finds 
> NotImplemented errors, odd looking results, etc. This is about all I can 
> offer as far as testing the thing goes ;).
> 
>   Cheers
> 
> On Thu, Aug 19, 2010 at 12:50 PM, Christian Muise <christian.mu...@gmail.com> 
> wrote:
> Apparently the setup.py is dated:
> 
> cjmu...@haz:~/Projects/sympy$ git diff
> diff --git a/setup.py b/setup.py
> index bdec104..538904d 100755
> --- a/setup.py
> +++ b/setup.py
> @@ -71,6 +71,7 @@
>      'sympy.mpmath.matrices',
>      'sympy.mpmath.calculus',
>      'sympy.polys',
> +    'sympy.polys.domains',
>      'sympy.printing',
>      'sympy.printing.pretty',
>      'sympy.series',
> cjmu...@haz:~/Projects/sympy$ 
> 
> On Thu, Aug 19, 2010 at 12:39 PM, Christian Muise <christian.mu...@gmail.com> 
> wrote:
> I'm having issues with the branch:
> 
> >>> from sympy import *
> Traceback (most recent call last):
>   File "<input>", line 1, in <module>
>   File "/usr/local/lib/python2.6/dist-packages/sympy/__init__.py", line 24, 
> in <module>
>     from polys import *
>   File "/usr/local/lib/python2.6/dist-packages/sympy/polys/__init__.py", line 
> 3, in <module>
>     from polytools import (
>   File "/usr/local/lib/python2.6/dist-packages/sympy/polys/polytools.py", 
> line 66, in <module>
>     from sympy.polys.domains import FF, QQ
> ImportError: No module named domains
> >>> 
> 
>   I guess it's the version I'm using? Python 2.6.5 is installed.
> 
> On Wed, Aug 18, 2010 at 11:43 PM, Aaron S. Meurer <asmeu...@gmail.com> wrote:
> So a few words.  First, if you just pass it a strictly rational function, it 
> is nothing new.  It will return the exact same result as integrate() because 
> it uses the exact same function, which is the already existing ratint() 
> (however, there is a fix in my branch for rational functions with symbolic 
> coefficients that fail in master).
> 
> To really test this, you need to pass it a function that has exp and/or log 
> in it. For example, here are some functions that you might try that better 
> test the algorithm:
> 
> In [2]: risch_integrate(1/(exp(x)**9 + 1), x)
> Out[2]:
>       ⎛     9⋅x⎞
>    log⎝1 + ℯ   ⎠
> x - ─────────────
>          9
> 
> (your example with x replaced with exp(x))
> 
> In [18]: risch_integrate(diff(exp(x)*log(x)/(x + 1), x), x)
> Out[18]:
>  x
> ℯ ⋅log(x)
> ─────────
>  1 + x
> 
> This seems to be a simple example, but observe that our current integrate() 
> cannot handle it:
> 
> In [19]: integrate(diff(exp(x)*log(x)/(x + 1), x), x)
> Out[19]:
> ⌠
> ⎮ ⎛ x           x               x   ⎞
> ⎮ ⎜ℯ ⋅log(x)   ℯ ⋅log(x)       ℯ    ⎟
> ⎮ ⎜───────── - ───────── + ─────────⎟ dx
> ⎮ ⎜  1 + x             2   x⋅(1 + x)⎟
> ⎮ ⎝             (1 + x)             ⎠
> ⌡
> 
> Also, it's fun to pass it functions that you know do not have elementary 
> anti-derivatives, to see if it can verify that fact:
> 
> In [20]: risch_integrate(exp(x**2), x)
> Out[20]:
> ⌠
> ⎮  ⎛ 2⎞
> ⎮  ⎝x ⎠
> ⎮ ℯ     dx
> ⌡
> 
> In [21]: risch_integrate(1/log(x), x)
> Out[21]:
> ⌠
> ⎮   1
> ⎮ ────── dx
> ⎮ log(x)
> ⌡
> 
> Also, remember what I said about integrating random functions.  If you try to 
> integrate a random function, the chances are pretty good that it will not be 
> elementary, and even if it is, the result could be quite complicated and it 
> could take a long time to compute.  Much better is to come up with an 
> expression that is as complex or not complex as you like, then differentiate 
> it and see if risch_integrate() can give you the original thing back again.
> 
> On Aug 18, 2010, at 9:05 PM, Ondrej Certik wrote:
> 
> > Hi Aaron!
> >
> > On Thu, Aug 5, 2010 at 2:01 PM, Aaron S. Meurer <asmeu...@gmail.com> wrote:
> >> (copied from issue 2010)
> >>
> >> I have ready in my integration3 branch a prototype risch_integrate() 
> >> function, that is a user-level function for the full Risch Algorithm I 
> >> have been implementing this summer.  Pull from 
> >> http://github.com/asmeurer/sympy/tree/integration3
> >
> > This is just excellent!
> >
> > I would like to invite everyone to try this. (Read Aaron's email above
> > for things to try and not to try yet.) So here are some tougher cases:
> >
> > In [1]: risch_integrate(1/(x**8+1), x)
> > [hangs]
> 
> This is our old friend expand() again (if you break anything that hangs in 
> sympy these days, it usually ends up being in expand in the traceback).  I am 
> hoping that Mateusz's continual Poly improvements will make this go away 
> eventually.
> 
> >
> >
> > In [4]: cancel(risch_integrate(1/(x**9+1), x).diff(x))
> > Out[4]:
> >      d ⎛       ⎛        6        3                          ⎞⎞      3 d ⎛
> > 1 + 3⋅──⎝RootSum⎝531441⋅t  + 729⋅t  + 1, Λ(t, t⋅log(x + 9⋅t))⎠⎠ + 3⋅x 
> > ⋅──⎝Root
> >      dx                                                               dx
> > ──────────────────────────────────────────────────────────────────────────────
> >                                                                   3
> >                                                            3 + 3⋅x
> >
> >   ⎛        6        3                          ⎞⎞
> > Sum⎝531441⋅t  + 729⋅t  + 1, Λ(t, t⋅log(x + 9⋅t))⎠⎠
> >
> > ──────────────────────────────────────────────────
> >
> >
> > It should be equivalent but it's a bit messy. Maybe we need to
> > implement some symbolic manipulation of RootSum().
> 
> Mateusz should look at this.
> 
> >
> > In [18]: risch_integrate(sqrt(1+exp(x)), x)
> > NotImplementedError: Couldn't find an elementary transcendental
> > extension for (1 + exp(x))**(1/2).  Try using a manual extension with
> > the extension flag.
> 
> No, and it won't be any time soon.  The algorithm I am implementing is only 
> the transcendental case (no algebraic functions like sqrt).  Now, the 
> algebraic part does exist, but it is much more difficult to implement, and I 
> won't even start to do it until the transcendental case is finished.  If you 
> get the above error, and you believe that the function is really not 
> algebraic, please post it here because it could be a bug in my preparser 
> algorithm, (be aware that you could be wrong, though).
> 
> >
> >
> > [18] is probably not supported yet.
> >
> >
> > Otherwise it works great. I wasn't able to make it break.
> 
> Well, I know it's possible, because I do it all the time (and then I go and 
> fix the bug).
> 
> >
> >
> > Ondrej
> 
> Aaron Meurer
> 
> --
> You received this message because you are subscribed to the Google Groups 
> "sympy" group.
> To post to this group, send email to sy...@googlegroups.com.
> To unsubscribe from this group, send email to 
> sympy+unsubscr...@googlegroups.com.
> For more options, visit this group at 
> http://groups.google.com/group/sympy?hl=en.
> 
> 
> 
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sympy" group.
> To post to this group, send email to sy...@googlegroups.com.
> To unsubscribe from this group, send email to 
> sympy+unsubscr...@googlegroups.com.
> For more options, visit this group at 
> http://groups.google.com/group/sympy?hl=en.
> <ri.py>

-- 
You received this message because you are subscribed to the Google Groups 
"sympy" group.
To post to this group, send email to sy...@googlegroups.com.
To unsubscribe from this group, send email to 
sympy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sympy?hl=en.


On Aug 19, 2010, at 11:06 AM, Christian Muise wrote:

  So it's been about 6 years since I've done calculus, and in fact the only math I see from day to day is pretty much 100% symbolic. That being said, I've attached a script that may help, or at least satisfy some curiosity. It's crude, but simple enough to toy around with and checks that the integral of the diff is the same as the original (not sure what to do to check this doesn't require constant factors). Just running it a few times finds NotImplemented errors, odd looking results, etc. This is about all I can offer as far as testing the thing goes ;).

  Cheers

On Thu, Aug 19, 2010 at 12:50 PM, Christian Muise <christian.mu...@gmail.com> wrote:
Apparently the setup.py is dated:

cjmu...@haz:~/Projects/sympy$ git diff
diff --git a/setup.py b/setup.py
index bdec104..538904d 100755
--- a/setup.py
+++ b/setup.py
@@ -71,6 +71,7 @@
     'sympy.mpmath.matrices',
     'sympy.mpmath.calculus',
     'sympy.polys',
+    'sympy.polys.domains',
     'sympy.printing',
     'sympy.printing.pretty',
     'sympy.series',
cjmu...@haz:~/Projects/sympy$ 

On Thu, Aug 19, 2010 at 12:39 PM, Christian Muise <christian.mu...@gmail.com> wrote:
I'm having issues with the branch:

>>> from sympy import *
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/usr/local/lib/python2.6/dist-packages/sympy/__init__.py", line 24, in <module>
    from polys import *
  File "/usr/local/lib/python2.6/dist-packages/sympy/polys/__init__.py", line 3, in <module>
    from polytools import (
  File "/usr/local/lib/python2.6/dist-packages/sympy/polys/polytools.py", line 66, in <module>
    from sympy.polys.domains import FF, QQ
ImportError: No module named domains
>>> 

  I guess it's the version I'm using? Python 2.6.5 is installed.

On Wed, Aug 18, 2010 at 11:43 PM, Aaron S. Meurer <asmeu...@gmail.com> wrote:
So a few words.  First, if you just pass it a strictly rational function, it is nothing new.  It will return the exact same result as integrate() because it uses the exact same function, which is the already existing ratint() (however, there is a fix in my branch for rational functions with symbolic coefficients that fail in master).

To really test this, you need to pass it a function that has exp and/or log in it. For example, here are some functions that you might try that better test the algorithm:

In [2]: risch_integrate(1/(exp(x)**9 + 1), x)
Out[2]:
      ⎛     9⋅x⎞
   log⎝1 + ℯ   ⎠
x - ─────────────
         9

(your example with x replaced with exp(x))

In [18]: risch_integrate(diff(exp(x)*log(x)/(x + 1), x), x)
Out[18]:
 x
ℯ ⋅log(x)
─────────
 1 + x

This seems to be a simple example, but observe that our current integrate() cannot handle it:

In [19]: integrate(diff(exp(x)*log(x)/(x + 1), x), x)
Out[19]:

⎮ ⎛ x           x               x   ⎞
⎮ ⎜ℯ ⋅log(x)   ℯ ⋅log(x)       ℯ    ⎟
⎮ ⎜───────── - ───────── + ─────────⎟ dx
⎮ ⎜  1 + x             2   x⋅(1 + x)⎟
⎮ ⎝             (1 + x)             ⎠


Also, it's fun to pass it functions that you know do not have elementary anti-derivatives, to see if it can verify that fact:

In [20]: risch_integrate(exp(x**2), x)
Out[20]:

⎮  ⎛ 2⎞
⎮  ⎝x ⎠
⎮ ℯ     dx


In [21]: risch_integrate(1/log(x), x)
Out[21]:

⎮   1
⎮ ────── dx
⎮ log(x)


Also, remember what I said about integrating random functions.  If you try to integrate a random function, the chances are pretty good that it will not be elementary, and even if it is, the result could be quite complicated and it could take a long time to compute.  Much better is to come up with an _expression_ that is as complex or not complex as you like, then differentiate it and see if risch_integrate() can give you the original thing back again.

On Aug 18, 2010, at 9:05 PM, Ondrej Certik wrote:

> Hi Aaron!
>
> On Thu, Aug 5, 2010 at 2:01 PM, Aaron S. Meurer <asmeu...@gmail.com> wrote:
>> (copied from issue 2010)
>>
>> I have ready in my integration3 branch a prototype risch_integrate() function, that is a user-level function for the full Risch Algorithm I have been implementing this summer.  Pull from http://github.com/asmeurer/sympy/tree/integration3
>
> This is just excellent!
>
> I would like to invite everyone to try this. (Read Aaron's email above
> for things to try and not to try yet.) So here are some tougher cases:
>
> In [1]: risch_integrate(1/(x**8+1), x)
> [hangs]

This is our old friend expand() again (if you break anything that hangs in sympy these days, it usually ends up being in expand in the traceback).  I am hoping that Mateusz's continual Poly improvements will make this go away eventually.

>
>
> In [4]: cancel(risch_integrate(1/(x**9+1), x).diff(x))
> Out[4]:
>      d ⎛       ⎛        6        3                          ⎞⎞      3 d ⎛
> 1 + 3⋅──⎝RootSum⎝531441⋅t  + 729⋅t  + 1, Λ(t, t⋅log(x + 9⋅t))⎠⎠ + 3⋅x ⋅──⎝Root
>      dx                                                               dx
> ──────────────────────────────────────────────────────────────────────────────
>                                                                   3
>                                                            3 + 3⋅x
>
>   ⎛        6        3                          ⎞⎞
> Sum⎝531441⋅t  + 729⋅t  + 1, Λ(t, t⋅log(x + 9⋅t))⎠⎠
>
> ──────────────────────────────────────────────────
>
>
> It should be equivalent but it's a bit messy. Maybe we need to
> implement some symbolic manipulation of RootSum().

Mateusz should look at this.

>
> In [18]: risch_integrate(sqrt(1+exp(x)), x)
> NotImplementedError: Couldn't find an elementary transcendental
> extension for (1 + exp(x))**(1/2).  Try using a manual extension with
> the extension flag.

No, and it won't be any time soon.  The algorithm I am implementing is only the transcendental case (no algebraic functions like sqrt).  Now, the algebraic part does exist, but it is much more difficult to implement, and I won't even start to do it until the transcendental case is finished.  If you get the above error, and you believe that the function is really not algebraic, please post it here because it could be a bug in my preparser algorithm, (be aware that you could be wrong, though).

>
>
> [18] is probably not supported yet.
>
>
> Otherwise it works great. I wasn't able to make it break.

Well, I know it's possible, because I do it all the time (and then I go and fix the bug).

>
>
> Ondrej

Aaron Meurer

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





--
You received this message because you are subscribed to the Google Groups "sympy" group.
To post to this group, send email to sympy@googlegroups.com.
To unsubscribe from this group, send email to sympy+unsubscr...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sympy?hl=en.
<ri.py>

#! /usr/bin/env python
from sympy import (exp, log, risch_integrate, cancel, pretty_print, Symbol,
    diff)
import random

x = Symbol('x')

unops = [exp, log, lambda x: -x]
binops = [lambda x,y: x+y, lambda x,y: x-y, lambda x,y: x*y, lambda x,y: x/y]
TRIALS = 5

def build_func(starting_vars = 2, starting_nums = 4, prob_unary = 0.5):
    parts = [x] * starting_vars
    for i in range(starting_nums):
        parts.append(random.randrange(1,10))
    #print "Working with the following building blocks: %s" % str(parts)

    while len(parts) > 1:
        if random.random() < prob_unary:
            index = random.randrange(0,len(parts))
            parts[index] = random.choice(unops)(parts[index])
        else:
            random.shuffle(parts)
            parts.append(random.choice(binops)(parts.pop(), parts.pop()))

    return parts[0]

for i in range(TRIALS):
    eq = build_func()
    print "\n\n------------------------------\nTesting the following equation:\n"
    print eq
    pretty_print(eq)
    print "\n\nDiff:\n"
    d = diff(eq, x)
    pretty_print(d)
    print "\n\nIntegral of Diff:\n"
    try:
        res = risch_integrate(d, x)
    except NotImplementedError, detail:
        print "\nNotImplemented (%s)" % detail
    else:
        pretty_print(res)
        print "\nDifference (should be constant): %s" % str(cancel(res - eq))
        print "\nDiff difference (should be 0): %s" % str(cancel(diff(res, x) - d))
    print "------------------------------"

Reply via email to