Skip to content

Commit

Permalink
[concrete/summations] Implement some binomial sums.
Browse files Browse the repository at this point in the history
Specifically, in the evaluation method using hypergeometric functions,
when encountering a finite sum from a to b, try to evaluate it by summing
from a to infinity and subtracting the sum from b+1 to infinity.

Fix a problem where _eval_sum_hyper substitutes zero in the expression
and, if it gets zero, adds one and starts over. This yields to an
inifinite loop if the expression is identically zero under the correct
assumptions.

Extend binomial.eval() to recognise that binomial(n, k) is always zero
if k is bigger than n.

Add tests.
  • Loading branch information
Tom Bachmann committed Apr 25, 2012
1 parent 0728d2c commit 340b130
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 2 deletions.
14 changes: 12 additions & 2 deletions sympy/concrete/summations.py
Expand Up @@ -479,13 +479,15 @@ def eval_sum_symbolic(f, limits):
def _eval_sum_hyper(f, i, a):
""" Returns (res, cond). Sums from a to oo. """
from sympy.functions import hyper
from sympy.simplify import hyperexpand, hypersimp, fraction
from sympy.simplify import hyperexpand, hypersimp, fraction, simplify
from sympy.polys.polytools import Poly, factor

if a != 0:
return _eval_sum_hyper(f.subs(i, i + a), i, 0)

if f.subs(i, 0) == 0:
if simplify(f.subs(i, Dummy('i', integer=True, positive=True))) == 0:
return S(0), True
return _eval_sum_hyper(f.subs(i, i + 1), i, 0)

hs = hypersimp(f, i)
Expand Down Expand Up @@ -532,7 +534,15 @@ def eval_sum_hyper(f, (i, a, b)):
if res is not None:
return Piecewise(res, (Sum(f, (i, a, b)), True))
else:
return None
res1 = _eval_sum_hyper(f, i, a)
res2 = _eval_sum_hyper(f, i, b + 1)
if res1 is None or res2 is None:
return None
(res1, cond1), (res2, cond2) = res1, res2
cond = And(cond1, cond2)
if cond is False:
return None
return Piecewise((res1 - res2, cond), (Sum(f, (i, a, b)), True))

if a == -oo:
res1 = _eval_sum_hyper(f.subs(i, -i), i, 1)
Expand Down
3 changes: 3 additions & 0 deletions sympy/concrete/tests/test_sums_products.py
Expand Up @@ -289,6 +289,9 @@ def test_hypersum():
assert s.args[0].args[0] == -1/(x*(1 - 1/x)**2)
assert s.args[0].args[1] == (abs(1/x) < 1)

m = Symbol('n', integer=True, positive=True)
assert summation(binomial(m, k), (k, 0, m)) == 2**m

def test_issue_1071():
assert summation(1/factorial(k), (k, 0, oo)) == E

Expand Down
2 changes: 2 additions & 0 deletions sympy/functions/combinatorial/factorials.py
Expand Up @@ -463,6 +463,8 @@ def eval(cls, n, k):
return result
elif k.is_negative:
return S.Zero
elif (n - k).simplify().is_negative:
return S.Zero
else:
d = n - k

Expand Down
Expand Up @@ -120,6 +120,7 @@ def test_binomial():
assert binomial(n, u) == 0
assert binomial(n, v).func == binomial
assert binomial(n, k).func == binomial
assert binomial(n, n + v) == 0

def test_binomial_diff():
n = Symbol('n', integer=True)
Expand Down

0 comments on commit 340b130

Please sign in to comment.