Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sympy is unable to integrate this #23299

Open
Scoodood opened this issue Mar 30, 2022 · 6 comments
Open

Sympy is unable to integrate this #23299

Scoodood opened this issue Mar 30, 2022 · 6 comments

Comments

@Scoodood
Copy link

Scoodood commented Mar 30, 2022

Sympy is unable to integrate this equation

import sympy as sp
sp.init_printing(use_latex=True)

a, x = sp.symbols('a x')
sp.integrate(a * x**(a-1) * sp.ln(x), (x,0,1))

  1                 
  ⌠                 
  ⎮  a - 1          
a⋅⎮ x     ⋅log(x) dx
  ⌡                 
  0                 

The output from WolframAlpha is

Any idea why Sympy couldn't do it?

@oscarbenjamin
Copy link
Contributor

Wolfram alpha makes the assumption that Re(a) > 0. You can also assume that a is positive with sympy:

In [1]: a, x = symbols('a, x', positive=True)

In [2]: integrate(a* x**(a-1) * ln(x), (x, 0, 1))
Out[2]: 
-1 
───
 a 

@asmeurer
Copy link
Member

asmeurer commented Mar 30, 2022

SymPy is able to compute the indefinite integral

>>> pprint(integrate(a* x**(a-1) * ln(x), x))
  ⎛⎧ a           a           ⎞
  ⎜⎪xlog(x)   x            ⎟
  ⎜⎪───────── - ──  for a0⎟
  ⎜⎪    a        2           ⎟
  ⎜⎪            aa⋅⎜⎨                         ⎟
  ⎜⎪      2                  ⎟
  ⎜⎪   log (x)               ⎟
  ⎜⎪   ───────      otherwise⎟
  ⎜⎪      2                  ⎟
  ⎝⎩                         ⎠

The problem is it doesn't know how to compute the lower limits with the symbolic term.

>>> integrate(a* x**(a-1) * ln(x), x).limit(x, 0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/aaronmeurer/Documents/Python/sympy/sympy/./sympy/core/expr.py", line 3390, in limit
  File "/Users/aaronmeurer/Documents/Python/sympy/sympy/./sympy/series/limits.py", line 64, in limit
    return Limit(e, z, z0, dir).doit(deep=False)
  File "/Users/aaronmeurer/Documents/Python/sympy/sympy/./sympy/series/limits.py", line 359, in doit
    r = gruntz(e, z, z0, dir)
  File "/Users/aaronmeurer/Documents/Python/sympy/sympy/./sympy/series/gruntz.py", line 711, in gruntz
    r = limitinf(e0, z)
  File "/Users/aaronmeurer/Documents/Python/sympy/sympy/./sympy/core/cache.py", line 70, in wrapper
    retval = cfunc(*args, **kwargs)
  File "/Users/aaronmeurer/Documents/Python/sympy/sympy/./sympy/series/gruntz.py", line 452, in limitinf
    c0, e0 = mrv_leadterm(e, x)
  File "/Users/aaronmeurer/Documents/Python/sympy/sympy/./sympy/core/cache.py", line 70, in wrapper
    retval = cfunc(*args, **kwargs)
  File "/Users/aaronmeurer/Documents/Python/sympy/sympy/./sympy/series/gruntz.py", line 527, in mrv_leadterm
    Omega, exps = mrv(e, x)
  File "/Users/aaronmeurer/Documents/Python/sympy/sympy/./sympy/series/gruntz.py", line 261, in mrv
    s, expr = mrv(d, x)
  File "/Users/aaronmeurer/Documents/Python/sympy/sympy/./sympy/series/gruntz.py", line 306, in mrv
    l = [mrv(a, x) for a in e.args]
  File "/Users/aaronmeurer/Documents/Python/sympy/sympy/./sympy/series/gruntz.py", line 306, in <listcomp>
    l = [mrv(a, x) for a in e.args]
  File "/Users/aaronmeurer/Documents/Python/sympy/sympy/./sympy/series/gruntz.py", line 318, in mrv
    raise NotImplementedError(
NotImplementedError: Don't know how to calculate the mrv of '(log(1/_p)/(_p**a*a) - 1/(_p**a*a**2), Ne(a, 0))'

This this is an instance of the problem described here #13312. If limit were able to split out symbolic constants into piecewise components, it might have a chance of computing this, and thus resulting in a (Piecewise) answer to this integral for general a.

Although in this case, it also looks like it is trying to handle the ExprCondPair from the Piecewise, so for this to work, Gruntz would need to be fixed to be able to handle Piecewise correctly as well.

In any case, manually setting the assumptions on a so that the a!=0 term is always true (like Symbol('a', positive=True)) makes the Piecewise go away and makes Gruntz able to determine what it needs to know about expressions containing a.

@Scoodood
Copy link
Author

Scoodood commented Mar 30, 2022

Wow, great tricks! Thanks
The documentation didn't say much about positive=True.

@anutosh491
Copy link
Member

Although in this case, it also looks like it is trying to handle the ExprCondPair from the Piecewise, so for this to work, Gruntz would need to be fixed to be able to handle Piecewise correctly as well.

It seems we would need to implement an elif isinstance(e, Piecewise) block in def mrv() method to address this . I'm not sure how mrv is defined for a Piecewise function though , is it just mrv of the piece ( the piece at f(x0) where x0 is the point concerning the limit) . Something around this lines did give me the answer locally but not sure if that's completely mathematically correct . Maybe @jksuom could have a look here.

@asmeurer
Copy link
Member

Doing that without actual support in the algorithm for splitting symbolic constants into piecewise components would lead to the same problems if the piecewise conditions themselves contain symbolic constants (so that the condition containing the point x0 depends on their value).

@asmeurer
Copy link
Member

Or alternatively if the point x0 itself is symbolic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants