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

[GSoC] Concrete: Implemented Raabe's Test #18656

Merged
merged 9 commits into from
Aug 17, 2020
29 changes: 23 additions & 6 deletions sympy/concrete/summations.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,8 @@ def is_convergent(self):
sym = self.limits[0][0]
lower_limit = self.limits[0][1]
upper_limit = self.limits[0][2]
sequence_term = self.function
sequence_term = simplify(self.function)
sachin-4099 marked this conversation as resolved.
Show resolved Hide resolved


if len(sequence_term.free_symbols) > 1:
raise NotImplementedError("convergence checking for more than one symbol "
Expand All @@ -446,6 +447,7 @@ def is_convergent(self):

interval = Interval(lower_limit, upper_limit)


sachin-4099 marked this conversation as resolved.
Show resolved Hide resolved
# Piecewise function handle
if sequence_term.is_Piecewise:
for func, cond in sequence_term.args:
Expand All @@ -457,12 +459,13 @@ def is_convergent(self):

### -------- Divergence test ----------- ###
try:
lim_val = limit_seq(sequence_term, sym)
if lim_val is not None and lim_val.is_zero is False:
return S.false
lim_val = limit_seq(sequence_term, sym)
if lim_val is not None and lim_val.is_zero is False:
return S.false
except NotImplementedError:
pass


try:
lim_val_abs = limit_seq(abs(sequence_term), sym)
if lim_val_abs is not None and lim_val_abs.is_zero is False:
Expand Down Expand Up @@ -510,7 +513,22 @@ def is_convergent(self):
if abs(lim_ratio) < 1:
return S.true
except NotImplementedError:
pass
lim_ratio = None

### ---------- Raabe's test -------------- ###
if lim_ratio == 1: # ratio test inconclusive
Copy link
Member

Choose a reason for hiding this comment

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

There was a discussion in the other pull request about whether or not this is needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

imo it is necessary...

Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is it necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are you talking about raabe's test or the condition??

Copy link
Collaborator

Choose a reason for hiding this comment

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

The condition. Your answer above says "imo it is necessary". I am sure that I agree but I would prefer it if you write an explicit reason (an opinion is not a reason).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We implement Raabe's test only after ratio test fails, and the condition when ratio test fails is when it is 1, so definitely it is necessary, otherwise how will we come to know when to implement raabe's test.

test_val = sym*(sequence_term/
sequence_term.subs(sym, sym + 1) - 1)
test_val = test_val.gammasimp()
try:
lim_val = limit_seq(test_val, sym)
if lim_val is not None and lim_val.is_number:
if lim_val > 1:
Copy link
Member

Choose a reason for hiding this comment

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

I think we can check (lim_val - 1).is_positive here, to allow it to potentially work for symbols with the proper assumptions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK will change the line if lim_value > 1:

return S.true
if lim_val < 1:
return S.false
except NotImplementedError:
pass

### ----------- root test ---------------- ###
# lim = Limit(abs(sequence_term)**(1/sym), sym, S.Infinity)
Expand All @@ -529,7 +547,6 @@ def is_convergent(self):
if not dict_val[p].has(sym) and is_decreasing(dict_val[q], interval):
return S.true


### ------------- integral test -------------- ###
check_interval = None
maxima = solveset(sequence_term.diff(sym), sym, interval)
Expand Down
7 changes: 7 additions & 0 deletions sympy/concrete/tests/test_sums_products.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from sympy.abc import a, b, c, d, k, m, x, y, z
from sympy.concrete.summations import telescopic, _dummy_with_inherited_properties_concrete
from sympy.concrete.expr_with_intlimits import ReorderError
from sympy.functions.combinatorial.factorials import rf
from sympy.testing.pytest import XFAIL, raises, slow
from sympy.matrices import \
Matrix, SparseMatrix, ImmutableDenseMatrix, ImmutableSparseMatrix
Expand Down Expand Up @@ -995,6 +996,9 @@ def test_is_convergent():
assert Sum((-1)**n, (n, 1, oo)).is_convergent() is S.false
assert Sum(log(1/n), (n, 2, oo)).is_convergent() is S.false

# Raabe's test --
assert Sum(Product((3*m),(m,1,n))/Product((3*m+4),(m,1,n)),(n,1,oo)).is_convergent() is S.true

# root test --
assert Sum((-12)**n/n, (n, 1, oo)).is_convergent() is S.false

Expand All @@ -1005,6 +1009,9 @@ def test_is_convergent():
assert Sum(1/n**Rational(6, 5), (n, 1, oo)).is_convergent() is S.true
assert Sum(2/(n*sqrt(n - 1)), (n, 2, oo)).is_convergent() is S.true
assert Sum(1/(sqrt(n)*sqrt(n)), (n, 2, oo)).is_convergent() is S.false
assert Sum(factorial(n) / factorial(n+2), (n, 1, oo)).is_convergent() is S.true
assert Sum(rf(5,n)/rf(7,n),(n,1,oo)).is_convergent() is S.true
assert Sum((rf(1, n)*rf(2, n))/(rf(3, n)*factorial(n)),(n,1,oo)).is_convergent() is S.false

# comparison test --
assert Sum(1/(n + log(n)), (n, 1, oo)).is_convergent() is S.false
Expand Down