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

Fix digamma integral #26563

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
24 changes: 24 additions & 0 deletions sympy/functions/special/tests/test_zeta_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,30 @@ def test_lerchphi_expansion():
assert myexpand(lerchphi(exp(I*pi*Rational(2, 5)), s, a), None)


def test_lerchphi_finite():
assert lerchphi(1, 1, a).is_finite is False
assert lerchphi(0, -3, 0).is_finite is True
assert lerchphi(2, s, 0).is_finite is None
assert lerchphi(2, 1, 0).is_finite is False
assert lerchphi(2, -1, 0).is_finite is True
assert lerchphi(2, 1j, 0).is_finite is None
assert lerchphi(z, s, -1).is_finite is None
assert lerchphi(0, s, -1).is_finite is True
assert lerchphi(z, -3, 0).is_finite is True
assert lerchphi(0, s, 0).is_finite is None
assert lerchphi(0, 1, 0).is_finite is False
assert lerchphi(0, -1, 0).is_finite is True
assert lerchphi(0.5, -1, 0).is_finite is True
assert lerchphi(0.5+0.5j, 0, 0).is_finite is True
assert lerchphi(1, 3, 0).is_finite is False


def test_lerchphi_leadterm():
from sympy.functions.special.gamma_functions import digamma
assert (lerchphi(1-x, 1, a)._eval_as_leading_term(x)
== -log(x) - S.EulerGamma - digamma(a))


def test_stieltjes():
assert isinstance(stieltjes(x), stieltjes)
assert isinstance(stieltjes(x, a), stieltjes)
Expand Down
19 changes: 19 additions & 0 deletions sympy/functions/special/zeta_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,25 @@ def _eval_rewrite_as_zeta(self, z, s, a, **kwargs):
def _eval_rewrite_as_polylog(self, z, s, a, **kwargs):
return self._eval_rewrite_helper(polylog)

def _eval_is_finite(self):
z, s, a = self.args
if z.is_infinite or s.is_infinite or a.is_infinite:
# TODO: Write a valid implementation for infinite numbers.
return
if z == 0:
if a.is_zero is False:
return True
if s.is_real:
return s.is_nonpositive
rogerbalsach marked this conversation as resolved.
Show resolved Hide resolved
return
if a.is_integer and a.is_nonpositive:
if s.is_real:
return s.is_nonpositive
return
exp_expr = self.expand(func=True)
if exp_expr != self:
return exp_expr.is_finite
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is expand(func=True) being used for here?

We should avoid creating new expressions during an assumptions query. Just creating the new expression runs the risk of triggering an identical assumptions query which leads to infinite recursion.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I did not think about that. My idea was that, since LerchPhi includes a lot of common functions as particular values (zeta function, polylog, Dirichlet eta, ...), I can try to write the function in terms of these other functions and then let them determine whether the function is finite or not. Is there a safe way to do it without the risks you are mentioning?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is not really a safe way to do it. We just have to accept that the core assumptions cannot resolve all queries:
https://docs.sympy.org/latest/guides/assumptions.html

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, sorry for the delay, but I haven't had time these last few weeks. I understand then that this part of the code should be changed and all the checks need to be implemented from scratch. Is that correct?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the checks need to be from scratch. It is also acceptable that some assumptions queries just return None.


###############################################################################
###################### POLYLOGARITHM ##########################################
###############################################################################
Expand Down
4 changes: 4 additions & 0 deletions sympy/integrals/tests/test_integrals.py
Original file line number Diff line number Diff line change
Expand Up @@ -2139,3 +2139,7 @@ def test_old_issues():
# https://github.com/sympy/sympy/issues/6278
I3 = integrate(1/(cos(x)+2),(x,0,2*pi))
assert I3 == 2*sqrt(3)*pi/3

def test_issue_26523():
Int = Integral((1 - t**z) / (1 - t), (t, 0, 1))
assert Int.doit() == polygamma(0, z + 1) + EulerGamma
17 changes: 16 additions & 1 deletion sympy/series/tests/test_limits.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
atan, cos, cot, csc, sec, sin, tan)
from sympy.functions.special.bessel import (besseli, bessely, besselj, besselk)
from sympy.functions.special.error_functions import (Ei, erf, erfc, erfi, fresnelc, fresnels)
from sympy.functions.special.gamma_functions import (digamma, gamma, uppergamma)
from sympy.functions.special.gamma_functions import (digamma, gamma, polygamma, uppergamma)
from sympy.functions.special.zeta_functions import lerchphi
from sympy.functions.special.hyper import meijerg
from sympy.integrals.integrals import (Integral, integrate)
from sympy.series.limits import (Limit, limit)
Expand Down Expand Up @@ -311,8 +312,11 @@ def test_set_signs():

def test_heuristic():
x = Symbol("x", real=True)
a = Symbol("a")
assert heuristics(sin(1/x) + atan(x), x, 0, '+') == AccumBounds(-1, 1)
assert limit(log(2 + sqrt(atan(x))*sqrt(sin(1/x))), x, 0) == log(2)
# https://github.com/sympy/sympy/issues/26523
assert heuristics(lerchphi(x, 1, a), x, 1, '-') != lerchphi(1, 1, a)


def test_issue_3871():
Expand Down Expand Up @@ -1412,3 +1416,14 @@ def test_issue_26250():
e1 = ((1-3*x**2)*e**2/2 - (x**2-2*x+1)*e*k/2)
e2 = pi**2*(x**8 - 2*x**7 - x**6 + 4*x**5 - x**4 - 2*x**3 + x**2)
assert limit(e1/e2, x, 0) == -S(1)/8


def test_issue_26523():
expr = -x**(z + 1)*lerchphi(x, 1, z + 1) - log(x - 1)
L = Limit(expr, x, 1, '-')
assert L.doit() == polygamma(0, z + 1) + EulerGamma - I*pi
expr = (-x*x**z*z*lerchphi(x, 1, z + 1)*gamma(z + 1)/gamma(z + 2)
- x*x**z*lerchphi(x, 1, z + 1)*gamma(z + 1)/gamma(z + 2)
- log(x - 1))
L = Limit(expr, x, 1, '-')
assert L.doit() == polygamma(0, z + 1) + EulerGamma - I*pi
Loading