2 from sympy
.core
.basic
import Basic
, S
3 from sympy
.core
.function
import SingleValuedFunction
4 from sympy
.ntheory
import sieve
7 ###############################################################################
8 ######################## FACTORIAL and MULTI-FACTORIAL ########################
9 ###############################################################################
11 class Factorial(SingleValuedFunction
):
12 """Implementation of factorial function over nonnegative integers.
13 For the sake of convenience and simplicity of procedures using
14 this function it is defined for negative integers and returns
17 The factorial is very important in combinatorics where it gives
18 the number of ways in which 'n' objects can be permuted. It also
19 arises in calculus, probability, number theory etc.
21 There is strict relation of factorial with gamma function. In
22 fact n! = gamma(n+1) for nonnegarive integers. Rewrite of this
23 kind is very useful in case of combinatorial simplification.
25 Computation of the factorial is done using two algorithms. For
26 small arguments naive product is evaluated. However for bigger
27 input algorithm Prime-Swing is used. It is the fastest algorithm
28 known and computes n! via prime factorization of special class
29 of numbers, called here the 'Swing Numbers'.
31 >>> from sympy import *
32 >>> n = Symbol('n', integer=True)
54 1,1,1,3,3,15,5,35,35,315,63,693,231,3003,429,6435,6435,109395,
55 12155,230945,46189,969969,88179,2028117,676039,16900975,1300075,
56 35102025,5014575,145422675,9694845,300540195,300540195
62 return cls
._small
_swing
[n
]
64 N
, primes
= int(sqrt(n
)), []
66 for prime
in sieve
.primerange(3, N
+1):
81 for prime
in sieve
.primerange(N
+1, n
/3 + 1):
82 if (n
/ prime
) & 1 == 1:
85 L_product
= R_product
= 1
87 for prime
in sieve
.primerange(n
/2 + 1, n
+1):
93 return L_product
*R_product
96 def _recursive(cls
, n
):
100 return (cls
._recursive
(n
/2)**2)*cls
._swing
(n
)
103 def canonize(cls
, n
):
106 if isinstance(n
, Basic
.Number
):
107 if isinstance(n
, Basic
.Zero
):
109 elif isinstance(n
, Basic
.Integer
):
116 for i
in range(2, n
+1):
127 result
= cls
._recursive
(n
)*2**(n
-bits
)
129 return Basic
.Integer(result
)
135 return Basic
.gamma(n
+1)
139 def _eval_rewrite_as_gamma(self
, arg
):
140 return Basic
.gamma(1 + arg
)
142 def tostr(self
, level
=0):
143 return '%s!' % self
[0].tostr(self
.precedence
)
145 def _eval_is_integer(self
):
146 return self
[0].is_integer
148 class MultiFactorial(SingleValuedFunction
):
152 factorial
= Factorial
154 ###############################################################################
155 ######################## RISING and FALLING FACTORIALS ########################
156 ###############################################################################
158 class RisingFactorial(SingleValuedFunction
):
159 """Rising factorial (also called Pochhammer symbol) is a double valued
160 function arising in concrete mathematics, hypergeometric functions
161 and series expanansions. It is defined by
163 rf(x, k) = x * (x+1) * ... * (x + k-1)
165 where 'x' can be arbitrary expression and 'k' is an integer. For
166 more information check "Concrete mathematics" by Graham, pp. 66
167 or visit http://mathworld.wolfram.com/RisingFactorial.html page.
169 >>> from sympy import *
179 x*(1 + x)*(2 + x)*(3 + x)*(4 + x)
186 def canonize(cls
, x
, k
):
190 if isinstance(x
, Basic
.NaN
):
192 elif isinstance(x
, Basic
.One
):
194 elif isinstance(k
, Basic
.Integer
):
195 if isinstance(k
, Basic
.NaN
):
197 elif isinstance(k
, Basic
.Zero
):
201 if isinstance(x
, Basic
.Infinity
):
203 elif isinstance(x
, Basic
.NegativeInfinity
):
205 return S
.NegativeInfinity
209 return reduce(lambda r
, i
: r
*(x
+i
), xrange(0, int(k
)), 1)
211 if isinstance(x
, Basic
.Infinity
):
213 elif isinstance(x
, Basic
.NegativeInfinity
):
216 return 1/reduce(lambda r
, i
: r
*(x
-i
), xrange(1, abs(int(k
))+1), 1)
218 def _eval_rewrite_as_gamma(self
, x
, k
):
219 return Basic
.gamma(x
+ k
) / Basic
.gamma(x
)
221 class FallingFactorial(SingleValuedFunction
):
222 """Falling factorial (related to rising factorial) is a double valued
223 function arising in concrete mathematics, hypergeometric functions
224 and series expanansions. It is defined by
226 ff(x, k) = x * (x-1) * ... * (x - k+1)
228 where 'x' can be arbitrary expression and 'k' is an integer. For
229 more information check "Concrete mathematics" by Graham, pp. 66
230 or visit http://mathworld.wolfram.com/FallingFactorial.html page.
232 >>> from sympy import *
242 x*(1 - x)*(2 - x)*(3 - x)*(4 - x)
249 def canonize(cls
, x
, k
):
253 if isinstance(x
, Basic
.NaN
):
255 elif isinstance(k
, Basic
.Integer
):
256 if isinstance(k
, Basic
.NaN
):
258 elif isinstance(k
, Basic
.Zero
):
264 if isinstance(x
, Basic
.Infinity
):
266 elif isinstance(x
, Basic
.NegativeInfinity
):
268 return S
.NegativeInfinity
272 return reduce(lambda r
, i
: r
*(x
-i
), xrange(0, int(k
)), 1)
274 if isinstance(x
, Basic
.Infinity
):
276 elif isinstance(x
, Basic
.NegativeInfinity
):
279 return 1/reduce(lambda r
, i
: r
*(x
+i
), xrange(1, abs(int(k
))+1), 1)
282 def _eval_rewrite_as_gamma(self
, x
, k
):
283 return (-1)**k
* Basic
.gamma(-x
+ k
) / Basic
.gamma(-x
)
286 ff
= FallingFactorial
288 ###############################################################################
289 ########################### BINOMIAL COEFFICIENTS #############################
290 ###############################################################################
292 class Binomial(SingleValuedFunction
):
293 """Implementation of the binomial coefficient. It can be defined
294 in two ways depending on its desired interpretation:
296 C(n,k) = n!/(k!(n-k)!) or C(n, k) = ff(n, k)/k!
298 First formula has strict combinatorial meaning, definig the
299 number of ways we can choose 'k' elements from 'n' element
300 set. In this case both arguments are nonnegative integers
301 and binomial is computed using efficient algorithm based
302 on prime factorisation.
304 The other definition is generalisation for arbitaty 'n',
305 however 'k' must be also nonnegative. This case is very
306 useful in case for evaluating summations.
308 For the sake of convenience for negative 'k' this function
309 will return zero no matter what valued is the other argument.
311 >>> from sympy import *
312 >>> n = symbols('n', integer=True)
320 >>> [ binomial(0, i) for i in range(1)]
322 >>> [ binomial(1, i) for i in range(2)]
324 >>> [ binomial(2, i) for i in range(3)]
326 >>> [ binomial(3, i) for i in range(4)]
328 >>> [ binomial(4, i) for i in range(5)]
331 >>> binomial(Rational(5,4), 3)
335 (1/6)*n*(1 - n)*(2 - n)
342 def canonize(cls
, r
, k
):
343 r
, k
= map(Basic
.sympify
, (r
, k
))
345 if isinstance(k
, Basic
.Number
):
346 if isinstance(k
, Basic
.Zero
):
348 elif isinstance(k
, Basic
.Integer
):
352 if isinstance(r
, Basic
.Integer
) and r
.is_nonnegative
:
353 r
, k
= int(r
), int(k
)
360 M
, result
= int(sqrt(r
)), 1
362 for prime
in sieve
.primerange(2, r
+1):
368 if r
% prime
< k
% prime
:
375 a
= int((R
% prime
) < (K
% prime
+ a
))
376 R
, K
= R
/ prime
, K
/ prime
382 return Basic
.Integer(result
)
386 for i
in xrange(2, k
+1):
396 return Basic
.gamma(r
+1)/(Basic
.gamma(r
-k
+1)*Basic
.gamma(k
+1))
399 def _eval_rewrite_as_gamma(self
, r
, k
):
400 return Basic
.gamma(r
+1) / (Basic
.gamma(r
-k
+1)*Basic
.gamma(k
+1))
402 def _eval_is_integer(self
):
403 return self
[0].is_integer
and self
[1].is_integer