2 from sympy
.core
import (Basic
, S
, C
, Add
, Mul
, Symbol
, Equality
, Interval
,
3 sympify
, symbols
, Wild
)
4 from sympy
.functions
import factorial
5 from sympy
.solvers
import solve
8 """Represents unevaluated summation."""
10 def __new__(cls
, f
, *symbols
, **assumptions
):
20 limits
= f
.atoms(Symbol
)
28 if isinstance(V
, Symbol
):
31 elif isinstance(V
, Equality
):
32 if isinstance(V
.lhs
, Symbol
):
33 if isinstance(V
.rhs
, Interval
):
34 limits
.append((V
.lhs
, V
.rhs
.start
, V
.rhs
.end
))
36 limits
.append((V
.lhs
, V
.rhs
))
39 elif isinstance(V
, (tuple, list)):
41 if isinstance(V
[0], Symbol
):
44 elif len(V
) in (2, 3):
45 if isinstance(V
[0], Symbol
):
46 limits
.append(tuple(map(sympify
, V
)))
49 raise ValueError("Invalid summation variable or limits")
51 obj
= Basic
.__new
__(cls
, **assumptions
)
52 obj
._args
= (f
, tuple(limits
))
64 def doit(self
, **hints
):
65 #if not hints.get('sums', True):
68 for i
, a
, b
in self
.limits
:
69 f
= eval_sum(f
, (i
, a
, b
))
74 def _eval_summation(self
, f
, x
):
77 def euler_maclaurin(self
, m
=0, n
=0, eps
=0, eval_integral
=True):
79 Return an Euler-Maclaurin approximation of self, where m is the
80 number of leading terms to sum directly and n is the number of
83 With m = n = 0, this is simply the corresponding integral
84 plus a first-order endpoint correction.
86 Returns (s, e) where s is the Euler-Maclaurin approximation
87 and e is the estimated error (taken to be the magnitude of
88 the first omitted term in the tail):
91 >>> Sum(1/k, (k, 2, 5)).doit().evalf()
93 >>> s, e = Sum(1/k, (k, 2, 5)).euler_maclaurin()
95 7/20 - log(2) + log(5)
96 >>> s.evalf(), e.evalf()
97 (1.26629073187416, 0.0175000000000000)
99 The endpoints may be symbolic:
101 >>> k, a, b = symbols('kab')
102 >>> s, e = Sum(1/k, (k, a, b)).euler_maclaurin()
104 -log(a) + log(b) + 1/(2*a) + 1/(2*b)
106 abs(-1/(12*b**2) + 1/(12*a**2))
108 If the function is a polynomial of degree at most 2n+1, the
109 Euler-Maclaurin formula becomes exact (and e = 0 is returned):
111 >>> Sum(k, (k, 2, b)).euler_maclaurin()
112 (-1 + b/2 + 1/2*b**2, 0)
113 >>> Sum(k, (k, 2, b)).doit()
116 With a nonzero eps specified, the summation is ended
117 as soon as the remainder term is less than the epsilon.
122 assert len(self
.limits
) == 1
123 i
, a
, b
= self
.limits
[0]
127 term
= f
.subs(i
, a
+k
)
128 if (eps
and term
and abs(term
.evalf(3)) < eps
):
132 x
= Symbol('x', dummy
=True)
133 I
= C
.Integral(f
.subs(i
, x
), (x
, a
, b
))
139 return expr
.subs(i
, a
), 0
140 return expr
.subs(i
, a
), expr
.subs(i
, b
)
144 for k
in xrange(1, n
+2):
146 term
= C
.bernoulli(2*k
)/C
.Factorial(2*k
)*(gb
-ga
)
147 if (eps
and term
and abs(term
.evalf(3)) < eps
) or (k
> n
):
151 return s
+ iterm
, abs(term
)
154 def sum(*args
, **kwargs
):
155 summation
= Sum(*args
, **kwargs
)
157 if isinstance(summation
, Sum
):
158 return summation
.doit()
165 return cls(expr
.args
[0]), cls(*expr
.args
[1:])
167 def telescopic_direct(L
, R
, n
, (i
, a
, b
)):
168 '''Returns the direct summation of the terms of a telescopic sum
170 L is the term with lower index
171 R is the term with higher index
172 n difference between the indexes of L and R
176 >>> k,a,b = symbols('kab')
177 >>> telescopic_direct(1/k, -1/(k+2), 2, (k, a, b))
178 1/a + 1/(1 + a) - 1/(1 + b) - 1/(2 + b)
182 s
+= L
.subs(i
,a
+m
) + R
.subs(i
,b
-m
)
185 def telescopic(L
, R
, (i
, a
, b
)):
186 '''Tries to perform the summation using the telescopic property
188 return None if not possible
190 if L
.is_Add
or R
.is_Add
:
193 #First we try to solve using match
194 #Maybe this should go inside solve
196 sol
= (-R
).match(L
.subs(i
, i
+ k
))
197 if sol
and sol
.has_key(k
):
198 if L
.subs(i
,i
+ sol
[k
]) == -R
:
199 #sometimes match fail(f(x+2).match(-f(x+k))->{k: -2 - 2x}))
201 #Then we try to solve using solve
202 if not s
or not s
.is_Integer
:
205 s
= solve(L
.subs(i
, i
+ m
) + R
, m
)[0]
208 if s
and s
.is_Integer
:
210 return telescopic_direct(R
, L
, abs(s
), (i
, a
, b
))
212 return telescopic_direct(L
, R
, s
, (i
, a
, b
))
215 def eval_sum(f
, (i
, a
, b
)):
218 definite
= a
.is_Integer
and b
.is_Integer
219 # Doing it directly may be faster if there are very few terms.
220 if definite
and (b
-a
< 100):
221 return eval_sum_direct(f
, (i
, a
, b
))
222 # Try to do it symbolically. Even when the number of terms is known,
223 # this can save time when b-a is big.
224 # We should try to transform to partial fractions
225 value
= eval_sum_symbolic(f
.expand(), (i
, a
, b
))
226 if value
is not None:
230 return eval_sum_direct(f
, (i
, a
, b
))
232 def eval_sum_symbolic(f
, (i
, a
, b
)):
239 sR
= eval_sum_symbolic(R
, (i
, a
, b
))
242 sL
= eval_sum_symbolic(L
, (i
, a
, b
))
246 lrsum
= telescopic(L
, R
, (i
, a
, b
))
247 if lrsum
: return lrsum
248 lsum
= eval_sum_symbolic(L
, (i
, a
, b
))
249 rsum
= eval_sum_symbolic(R
, (i
, a
, b
))
250 if None not in (lsum
, rsum
):
252 # Polynomial terms with Faulhaber's formula
258 if c
.is_integer
and c
>= 0:
259 s
= (B(c
+1, b
+1) - B(c
+1, a
))/(c
+1)
262 c1
= C
.Wild('c1', exclude
=[i
])
263 c2
= C
.Wild('c2', exclude
=[i
])
264 c3
= C
.Wild('c3', exclude
=[i
])
265 e
= f
.match(c1
**(c2
*i
+c3
))
270 # TODO: more general limit handling
271 return c1
**c3
* (c1
**(a
*c2
) - c1
**(c2
+b
*c2
)) / (1 - c1
**c2
)
274 def eval_sum_direct(expr
, (i
, a
, b
)):
277 for j
in xrange(a
, b
+1):
280 for j
in xrange(a
, b
+1):