factorials.py 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102
  1. from __future__ import annotations
  2. from functools import reduce
  3. from sympy.core import S, sympify, Dummy, Mod
  4. from sympy.core.cache import cacheit
  5. from sympy.core.function import Function, ArgumentIndexError, PoleError
  6. from sympy.core.logic import fuzzy_and
  7. from sympy.core.numbers import Integer, pi, I
  8. from sympy.core.relational import Eq
  9. from sympy.external.gmpy import HAS_GMPY, gmpy
  10. from sympy.ntheory import sieve
  11. from sympy.polys.polytools import Poly
  12. from math import factorial as _factorial, prod, sqrt as _sqrt
  13. class CombinatorialFunction(Function):
  14. """Base class for combinatorial functions. """
  15. def _eval_simplify(self, **kwargs):
  16. from sympy.simplify.combsimp import combsimp
  17. # combinatorial function with non-integer arguments is
  18. # automatically passed to gammasimp
  19. expr = combsimp(self)
  20. measure = kwargs['measure']
  21. if measure(expr) <= kwargs['ratio']*measure(self):
  22. return expr
  23. return self
  24. ###############################################################################
  25. ######################## FACTORIAL and MULTI-FACTORIAL ########################
  26. ###############################################################################
  27. class factorial(CombinatorialFunction):
  28. r"""Implementation of factorial function over nonnegative integers.
  29. By convention (consistent with the gamma function and the binomial
  30. coefficients), factorial of a negative integer is complex infinity.
  31. The factorial is very important in combinatorics where it gives
  32. the number of ways in which `n` objects can be permuted. It also
  33. arises in calculus, probability, number theory, etc.
  34. There is strict relation of factorial with gamma function. In
  35. fact `n! = gamma(n+1)` for nonnegative integers. Rewrite of this
  36. kind is very useful in case of combinatorial simplification.
  37. Computation of the factorial is done using two algorithms. For
  38. small arguments a precomputed look up table is used. However for bigger
  39. input algorithm Prime-Swing is used. It is the fastest algorithm
  40. known and computes `n!` via prime factorization of special class
  41. of numbers, called here the 'Swing Numbers'.
  42. Examples
  43. ========
  44. >>> from sympy import Symbol, factorial, S
  45. >>> n = Symbol('n', integer=True)
  46. >>> factorial(0)
  47. 1
  48. >>> factorial(7)
  49. 5040
  50. >>> factorial(-2)
  51. zoo
  52. >>> factorial(n)
  53. factorial(n)
  54. >>> factorial(2*n)
  55. factorial(2*n)
  56. >>> factorial(S(1)/2)
  57. factorial(1/2)
  58. See Also
  59. ========
  60. factorial2, RisingFactorial, FallingFactorial
  61. """
  62. def fdiff(self, argindex=1):
  63. from sympy.functions.special.gamma_functions import (gamma, polygamma)
  64. if argindex == 1:
  65. return gamma(self.args[0] + 1)*polygamma(0, self.args[0] + 1)
  66. else:
  67. raise ArgumentIndexError(self, argindex)
  68. _small_swing = [
  69. 1, 1, 1, 3, 3, 15, 5, 35, 35, 315, 63, 693, 231, 3003, 429, 6435, 6435, 109395,
  70. 12155, 230945, 46189, 969969, 88179, 2028117, 676039, 16900975, 1300075,
  71. 35102025, 5014575, 145422675, 9694845, 300540195, 300540195
  72. ]
  73. _small_factorials: list[int] = []
  74. @classmethod
  75. def _swing(cls, n):
  76. if n < 33:
  77. return cls._small_swing[n]
  78. else:
  79. N, primes = int(_sqrt(n)), []
  80. for prime in sieve.primerange(3, N + 1):
  81. p, q = 1, n
  82. while True:
  83. q //= prime
  84. if q > 0:
  85. if q & 1 == 1:
  86. p *= prime
  87. else:
  88. break
  89. if p > 1:
  90. primes.append(p)
  91. for prime in sieve.primerange(N + 1, n//3 + 1):
  92. if (n // prime) & 1 == 1:
  93. primes.append(prime)
  94. L_product = prod(sieve.primerange(n//2 + 1, n + 1))
  95. R_product = prod(primes)
  96. return L_product*R_product
  97. @classmethod
  98. def _recursive(cls, n):
  99. if n < 2:
  100. return 1
  101. else:
  102. return (cls._recursive(n//2)**2)*cls._swing(n)
  103. @classmethod
  104. def eval(cls, n):
  105. n = sympify(n)
  106. if n.is_Number:
  107. if n.is_zero:
  108. return S.One
  109. elif n is S.Infinity:
  110. return S.Infinity
  111. elif n.is_Integer:
  112. if n.is_negative:
  113. return S.ComplexInfinity
  114. else:
  115. n = n.p
  116. if n < 20:
  117. if not cls._small_factorials:
  118. result = 1
  119. for i in range(1, 20):
  120. result *= i
  121. cls._small_factorials.append(result)
  122. result = cls._small_factorials[n-1]
  123. # GMPY factorial is faster, use it when available
  124. elif HAS_GMPY:
  125. result = gmpy.fac(n)
  126. else:
  127. bits = bin(n).count('1')
  128. result = cls._recursive(n)*2**(n - bits)
  129. return Integer(result)
  130. def _facmod(self, n, q):
  131. res, N = 1, int(_sqrt(n))
  132. # Exponent of prime p in n! is e_p(n) = [n/p] + [n/p**2] + ...
  133. # for p > sqrt(n), e_p(n) < sqrt(n), the primes with [n/p] = m,
  134. # occur consecutively and are grouped together in pw[m] for
  135. # simultaneous exponentiation at a later stage
  136. pw = [1]*N
  137. m = 2 # to initialize the if condition below
  138. for prime in sieve.primerange(2, n + 1):
  139. if m > 1:
  140. m, y = 0, n // prime
  141. while y:
  142. m += y
  143. y //= prime
  144. if m < N:
  145. pw[m] = pw[m]*prime % q
  146. else:
  147. res = res*pow(prime, m, q) % q
  148. for ex, bs in enumerate(pw):
  149. if ex == 0 or bs == 1:
  150. continue
  151. if bs == 0:
  152. return 0
  153. res = res*pow(bs, ex, q) % q
  154. return res
  155. def _eval_Mod(self, q):
  156. n = self.args[0]
  157. if n.is_integer and n.is_nonnegative and q.is_integer:
  158. aq = abs(q)
  159. d = aq - n
  160. if d.is_nonpositive:
  161. return S.Zero
  162. else:
  163. isprime = aq.is_prime
  164. if d == 1:
  165. # Apply Wilson's theorem (if a natural number n > 1
  166. # is a prime number, then (n-1)! = -1 mod n) and
  167. # its inverse (if n > 4 is a composite number, then
  168. # (n-1)! = 0 mod n)
  169. if isprime:
  170. return -1 % q
  171. elif isprime is False and (aq - 6).is_nonnegative:
  172. return S.Zero
  173. elif n.is_Integer and q.is_Integer:
  174. n, d, aq = map(int, (n, d, aq))
  175. if isprime and (d - 1 < n):
  176. fc = self._facmod(d - 1, aq)
  177. fc = pow(fc, aq - 2, aq)
  178. if d%2:
  179. fc = -fc
  180. else:
  181. fc = self._facmod(n, aq)
  182. return fc % q
  183. def _eval_rewrite_as_gamma(self, n, piecewise=True, **kwargs):
  184. from sympy.functions.special.gamma_functions import gamma
  185. return gamma(n + 1)
  186. def _eval_rewrite_as_Product(self, n, **kwargs):
  187. from sympy.concrete.products import Product
  188. if n.is_nonnegative and n.is_integer:
  189. i = Dummy('i', integer=True)
  190. return Product(i, (i, 1, n))
  191. def _eval_is_integer(self):
  192. if self.args[0].is_integer and self.args[0].is_nonnegative:
  193. return True
  194. def _eval_is_positive(self):
  195. if self.args[0].is_integer and self.args[0].is_nonnegative:
  196. return True
  197. def _eval_is_even(self):
  198. x = self.args[0]
  199. if x.is_integer and x.is_nonnegative:
  200. return (x - 2).is_nonnegative
  201. def _eval_is_composite(self):
  202. x = self.args[0]
  203. if x.is_integer and x.is_nonnegative:
  204. return (x - 3).is_nonnegative
  205. def _eval_is_real(self):
  206. x = self.args[0]
  207. if x.is_nonnegative or x.is_noninteger:
  208. return True
  209. def _eval_as_leading_term(self, x, logx=None, cdir=0):
  210. arg = self.args[0].as_leading_term(x)
  211. arg0 = arg.subs(x, 0)
  212. if arg0.is_zero:
  213. return S.One
  214. elif not arg0.is_infinite:
  215. return self.func(arg)
  216. raise PoleError("Cannot expand %s around 0" % (self))
  217. class MultiFactorial(CombinatorialFunction):
  218. pass
  219. class subfactorial(CombinatorialFunction):
  220. r"""The subfactorial counts the derangements of $n$ items and is
  221. defined for non-negative integers as:
  222. .. math:: !n = \begin{cases} 1 & n = 0 \\ 0 & n = 1 \\
  223. (n-1)(!(n-1) + !(n-2)) & n > 1 \end{cases}
  224. It can also be written as ``int(round(n!/exp(1)))`` but the
  225. recursive definition with caching is implemented for this function.
  226. An interesting analytic expression is the following [2]_
  227. .. math:: !x = \Gamma(x + 1, -1)/e
  228. which is valid for non-negative integers `x`. The above formula
  229. is not very useful in case of non-integers. `\Gamma(x + 1, -1)` is
  230. single-valued only for integral arguments `x`, elsewhere on the positive
  231. real axis it has an infinite number of branches none of which are real.
  232. References
  233. ==========
  234. .. [1] https://en.wikipedia.org/wiki/Subfactorial
  235. .. [2] https://mathworld.wolfram.com/Subfactorial.html
  236. Examples
  237. ========
  238. >>> from sympy import subfactorial
  239. >>> from sympy.abc import n
  240. >>> subfactorial(n + 1)
  241. subfactorial(n + 1)
  242. >>> subfactorial(5)
  243. 44
  244. See Also
  245. ========
  246. factorial, uppergamma,
  247. sympy.utilities.iterables.generate_derangements
  248. """
  249. @classmethod
  250. @cacheit
  251. def _eval(self, n):
  252. if not n:
  253. return S.One
  254. elif n == 1:
  255. return S.Zero
  256. else:
  257. z1, z2 = 1, 0
  258. for i in range(2, n + 1):
  259. z1, z2 = z2, (i - 1)*(z2 + z1)
  260. return z2
  261. @classmethod
  262. def eval(cls, arg):
  263. if arg.is_Number:
  264. if arg.is_Integer and arg.is_nonnegative:
  265. return cls._eval(arg)
  266. elif arg is S.NaN:
  267. return S.NaN
  268. elif arg is S.Infinity:
  269. return S.Infinity
  270. def _eval_is_even(self):
  271. if self.args[0].is_odd and self.args[0].is_nonnegative:
  272. return True
  273. def _eval_is_integer(self):
  274. if self.args[0].is_integer and self.args[0].is_nonnegative:
  275. return True
  276. def _eval_rewrite_as_factorial(self, arg, **kwargs):
  277. from sympy.concrete.summations import summation
  278. i = Dummy('i')
  279. f = S.NegativeOne**i / factorial(i)
  280. return factorial(arg) * summation(f, (i, 0, arg))
  281. def _eval_rewrite_as_gamma(self, arg, piecewise=True, **kwargs):
  282. from sympy.functions.elementary.exponential import exp
  283. from sympy.functions.special.gamma_functions import (gamma, lowergamma)
  284. return (S.NegativeOne**(arg + 1)*exp(-I*pi*arg)*lowergamma(arg + 1, -1)
  285. + gamma(arg + 1))*exp(-1)
  286. def _eval_rewrite_as_uppergamma(self, arg, **kwargs):
  287. from sympy.functions.special.gamma_functions import uppergamma
  288. return uppergamma(arg + 1, -1)/S.Exp1
  289. def _eval_is_nonnegative(self):
  290. if self.args[0].is_integer and self.args[0].is_nonnegative:
  291. return True
  292. def _eval_is_odd(self):
  293. if self.args[0].is_even and self.args[0].is_nonnegative:
  294. return True
  295. class factorial2(CombinatorialFunction):
  296. r"""The double factorial `n!!`, not to be confused with `(n!)!`
  297. The double factorial is defined for nonnegative integers and for odd
  298. negative integers as:
  299. .. math:: n!! = \begin{cases} 1 & n = 0 \\
  300. n(n-2)(n-4) \cdots 1 & n\ \text{positive odd} \\
  301. n(n-2)(n-4) \cdots 2 & n\ \text{positive even} \\
  302. (n+2)!!/(n+2) & n\ \text{negative odd} \end{cases}
  303. References
  304. ==========
  305. .. [1] https://en.wikipedia.org/wiki/Double_factorial
  306. Examples
  307. ========
  308. >>> from sympy import factorial2, var
  309. >>> n = var('n')
  310. >>> n
  311. n
  312. >>> factorial2(n + 1)
  313. factorial2(n + 1)
  314. >>> factorial2(5)
  315. 15
  316. >>> factorial2(-1)
  317. 1
  318. >>> factorial2(-5)
  319. 1/3
  320. See Also
  321. ========
  322. factorial, RisingFactorial, FallingFactorial
  323. """
  324. @classmethod
  325. def eval(cls, arg):
  326. # TODO: extend this to complex numbers?
  327. if arg.is_Number:
  328. if not arg.is_Integer:
  329. raise ValueError("argument must be nonnegative integer "
  330. "or negative odd integer")
  331. # This implementation is faster than the recursive one
  332. # It also avoids "maximum recursion depth exceeded" runtime error
  333. if arg.is_nonnegative:
  334. if arg.is_even:
  335. k = arg / 2
  336. return 2**k * factorial(k)
  337. return factorial(arg) / factorial2(arg - 1)
  338. if arg.is_odd:
  339. return arg*(S.NegativeOne)**((1 - arg)/2) / factorial2(-arg)
  340. raise ValueError("argument must be nonnegative integer "
  341. "or negative odd integer")
  342. def _eval_is_even(self):
  343. # Double factorial is even for every positive even input
  344. n = self.args[0]
  345. if n.is_integer:
  346. if n.is_odd:
  347. return False
  348. if n.is_even:
  349. if n.is_positive:
  350. return True
  351. if n.is_zero:
  352. return False
  353. def _eval_is_integer(self):
  354. # Double factorial is an integer for every nonnegative input, and for
  355. # -1 and -3
  356. n = self.args[0]
  357. if n.is_integer:
  358. if (n + 1).is_nonnegative:
  359. return True
  360. if n.is_odd:
  361. return (n + 3).is_nonnegative
  362. def _eval_is_odd(self):
  363. # Double factorial is odd for every odd input not smaller than -3, and
  364. # for 0
  365. n = self.args[0]
  366. if n.is_odd:
  367. return (n + 3).is_nonnegative
  368. if n.is_even:
  369. if n.is_positive:
  370. return False
  371. if n.is_zero:
  372. return True
  373. def _eval_is_positive(self):
  374. # Double factorial is positive for every nonnegative input, and for
  375. # every odd negative input which is of the form -1-4k for an
  376. # nonnegative integer k
  377. n = self.args[0]
  378. if n.is_integer:
  379. if (n + 1).is_nonnegative:
  380. return True
  381. if n.is_odd:
  382. return ((n + 1) / 2).is_even
  383. def _eval_rewrite_as_gamma(self, n, piecewise=True, **kwargs):
  384. from sympy.functions.elementary.miscellaneous import sqrt
  385. from sympy.functions.elementary.piecewise import Piecewise
  386. from sympy.functions.special.gamma_functions import gamma
  387. return 2**(n/2)*gamma(n/2 + 1) * Piecewise((1, Eq(Mod(n, 2), 0)),
  388. (sqrt(2/pi), Eq(Mod(n, 2), 1)))
  389. ###############################################################################
  390. ######################## RISING and FALLING FACTORIALS ########################
  391. ###############################################################################
  392. class RisingFactorial(CombinatorialFunction):
  393. r"""
  394. Rising factorial (also called Pochhammer symbol [1]_) is a double valued
  395. function arising in concrete mathematics, hypergeometric functions
  396. and series expansions. It is defined by:
  397. .. math:: \texttt{rf(y, k)} = (x)^k = x \cdot (x+1) \cdots (x+k-1)
  398. where `x` can be arbitrary expression and `k` is an integer. For
  399. more information check "Concrete mathematics" by Graham, pp. 66
  400. or visit https://mathworld.wolfram.com/RisingFactorial.html page.
  401. When `x` is a `~.Poly` instance of degree $\ge 1$ with a single variable,
  402. `(x)^k = x(y) \cdot x(y+1) \cdots x(y+k-1)`, where `y` is the
  403. variable of `x`. This is as described in [2]_.
  404. Examples
  405. ========
  406. >>> from sympy import rf, Poly
  407. >>> from sympy.abc import x
  408. >>> rf(x, 0)
  409. 1
  410. >>> rf(1, 5)
  411. 120
  412. >>> rf(x, 5) == x*(1 + x)*(2 + x)*(3 + x)*(4 + x)
  413. True
  414. >>> rf(Poly(x**3, x), 2)
  415. Poly(x**6 + 3*x**5 + 3*x**4 + x**3, x, domain='ZZ')
  416. Rewriting is complicated unless the relationship between
  417. the arguments is known, but rising factorial can
  418. be rewritten in terms of gamma, factorial, binomial,
  419. and falling factorial.
  420. >>> from sympy import Symbol, factorial, ff, binomial, gamma
  421. >>> n = Symbol('n', integer=True, positive=True)
  422. >>> R = rf(n, n + 2)
  423. >>> for i in (rf, ff, factorial, binomial, gamma):
  424. ... R.rewrite(i)
  425. ...
  426. RisingFactorial(n, n + 2)
  427. FallingFactorial(2*n + 1, n + 2)
  428. factorial(2*n + 1)/factorial(n - 1)
  429. binomial(2*n + 1, n + 2)*factorial(n + 2)
  430. gamma(2*n + 2)/gamma(n)
  431. See Also
  432. ========
  433. factorial, factorial2, FallingFactorial
  434. References
  435. ==========
  436. .. [1] https://en.wikipedia.org/wiki/Pochhammer_symbol
  437. .. [2] Peter Paule, "Greatest Factorial Factorization and Symbolic
  438. Summation", Journal of Symbolic Computation, vol. 20, pp. 235-268,
  439. 1995.
  440. """
  441. @classmethod
  442. def eval(cls, x, k):
  443. x = sympify(x)
  444. k = sympify(k)
  445. if x is S.NaN or k is S.NaN:
  446. return S.NaN
  447. elif x is S.One:
  448. return factorial(k)
  449. elif k.is_Integer:
  450. if k.is_zero:
  451. return S.One
  452. else:
  453. if k.is_positive:
  454. if x is S.Infinity:
  455. return S.Infinity
  456. elif x is S.NegativeInfinity:
  457. if k.is_odd:
  458. return S.NegativeInfinity
  459. else:
  460. return S.Infinity
  461. else:
  462. if isinstance(x, Poly):
  463. gens = x.gens
  464. if len(gens)!= 1:
  465. raise ValueError("rf only defined for "
  466. "polynomials on one generator")
  467. else:
  468. return reduce(lambda r, i:
  469. r*(x.shift(i)),
  470. range(int(k)), 1)
  471. else:
  472. return reduce(lambda r, i: r*(x + i),
  473. range(int(k)), 1)
  474. else:
  475. if x is S.Infinity:
  476. return S.Infinity
  477. elif x is S.NegativeInfinity:
  478. return S.Infinity
  479. else:
  480. if isinstance(x, Poly):
  481. gens = x.gens
  482. if len(gens)!= 1:
  483. raise ValueError("rf only defined for "
  484. "polynomials on one generator")
  485. else:
  486. return 1/reduce(lambda r, i:
  487. r*(x.shift(-i)),
  488. range(1, abs(int(k)) + 1), 1)
  489. else:
  490. return 1/reduce(lambda r, i:
  491. r*(x - i),
  492. range(1, abs(int(k)) + 1), 1)
  493. if k.is_integer == False:
  494. if x.is_integer and x.is_negative:
  495. return S.Zero
  496. def _eval_rewrite_as_gamma(self, x, k, piecewise=True, **kwargs):
  497. from sympy.functions.elementary.piecewise import Piecewise
  498. from sympy.functions.special.gamma_functions import gamma
  499. if not piecewise:
  500. if (x <= 0) == True:
  501. return S.NegativeOne**k*gamma(1 - x) / gamma(-k - x + 1)
  502. return gamma(x + k) / gamma(x)
  503. return Piecewise(
  504. (gamma(x + k) / gamma(x), x > 0),
  505. (S.NegativeOne**k*gamma(1 - x) / gamma(-k - x + 1), True))
  506. def _eval_rewrite_as_FallingFactorial(self, x, k, **kwargs):
  507. return FallingFactorial(x + k - 1, k)
  508. def _eval_rewrite_as_factorial(self, x, k, **kwargs):
  509. from sympy.functions.elementary.piecewise import Piecewise
  510. if x.is_integer and k.is_integer:
  511. return Piecewise(
  512. (factorial(k + x - 1)/factorial(x - 1), x > 0),
  513. (S.NegativeOne**k*factorial(-x)/factorial(-k - x), True))
  514. def _eval_rewrite_as_binomial(self, x, k, **kwargs):
  515. if k.is_integer:
  516. return factorial(k) * binomial(x + k - 1, k)
  517. def _eval_rewrite_as_tractable(self, x, k, limitvar=None, **kwargs):
  518. from sympy.functions.special.gamma_functions import gamma
  519. if limitvar:
  520. k_lim = k.subs(limitvar, S.Infinity)
  521. if k_lim is S.Infinity:
  522. return (gamma(x + k).rewrite('tractable', deep=True) / gamma(x))
  523. elif k_lim is S.NegativeInfinity:
  524. return (S.NegativeOne**k*gamma(1 - x) / gamma(-k - x + 1).rewrite('tractable', deep=True))
  525. return self.rewrite(gamma).rewrite('tractable', deep=True)
  526. def _eval_is_integer(self):
  527. return fuzzy_and((self.args[0].is_integer, self.args[1].is_integer,
  528. self.args[1].is_nonnegative))
  529. class FallingFactorial(CombinatorialFunction):
  530. r"""
  531. Falling factorial (related to rising factorial) is a double valued
  532. function arising in concrete mathematics, hypergeometric functions
  533. and series expansions. It is defined by
  534. .. math:: \texttt{ff(x, k)} = (x)_k = x \cdot (x-1) \cdots (x-k+1)
  535. where `x` can be arbitrary expression and `k` is an integer. For
  536. more information check "Concrete mathematics" by Graham, pp. 66
  537. or [1]_.
  538. When `x` is a `~.Poly` instance of degree $\ge 1$ with single variable,
  539. `(x)_k = x(y) \cdot x(y-1) \cdots x(y-k+1)`, where `y` is the
  540. variable of `x`. This is as described in
  541. >>> from sympy import ff, Poly, Symbol
  542. >>> from sympy.abc import x
  543. >>> n = Symbol('n', integer=True)
  544. >>> ff(x, 0)
  545. 1
  546. >>> ff(5, 5)
  547. 120
  548. >>> ff(x, 5) == x*(x - 1)*(x - 2)*(x - 3)*(x - 4)
  549. True
  550. >>> ff(Poly(x**2, x), 2)
  551. Poly(x**4 - 2*x**3 + x**2, x, domain='ZZ')
  552. >>> ff(n, n)
  553. factorial(n)
  554. Rewriting is complicated unless the relationship between
  555. the arguments is known, but falling factorial can
  556. be rewritten in terms of gamma, factorial and binomial
  557. and rising factorial.
  558. >>> from sympy import factorial, rf, gamma, binomial, Symbol
  559. >>> n = Symbol('n', integer=True, positive=True)
  560. >>> F = ff(n, n - 2)
  561. >>> for i in (rf, ff, factorial, binomial, gamma):
  562. ... F.rewrite(i)
  563. ...
  564. RisingFactorial(3, n - 2)
  565. FallingFactorial(n, n - 2)
  566. factorial(n)/2
  567. binomial(n, n - 2)*factorial(n - 2)
  568. gamma(n + 1)/2
  569. See Also
  570. ========
  571. factorial, factorial2, RisingFactorial
  572. References
  573. ==========
  574. .. [1] https://mathworld.wolfram.com/FallingFactorial.html
  575. .. [2] Peter Paule, "Greatest Factorial Factorization and Symbolic
  576. Summation", Journal of Symbolic Computation, vol. 20, pp. 235-268,
  577. 1995.
  578. """
  579. @classmethod
  580. def eval(cls, x, k):
  581. x = sympify(x)
  582. k = sympify(k)
  583. if x is S.NaN or k is S.NaN:
  584. return S.NaN
  585. elif k.is_integer and x == k:
  586. return factorial(x)
  587. elif k.is_Integer:
  588. if k.is_zero:
  589. return S.One
  590. else:
  591. if k.is_positive:
  592. if x is S.Infinity:
  593. return S.Infinity
  594. elif x is S.NegativeInfinity:
  595. if k.is_odd:
  596. return S.NegativeInfinity
  597. else:
  598. return S.Infinity
  599. else:
  600. if isinstance(x, Poly):
  601. gens = x.gens
  602. if len(gens)!= 1:
  603. raise ValueError("ff only defined for "
  604. "polynomials on one generator")
  605. else:
  606. return reduce(lambda r, i:
  607. r*(x.shift(-i)),
  608. range(int(k)), 1)
  609. else:
  610. return reduce(lambda r, i: r*(x - i),
  611. range(int(k)), 1)
  612. else:
  613. if x is S.Infinity:
  614. return S.Infinity
  615. elif x is S.NegativeInfinity:
  616. return S.Infinity
  617. else:
  618. if isinstance(x, Poly):
  619. gens = x.gens
  620. if len(gens)!= 1:
  621. raise ValueError("rf only defined for "
  622. "polynomials on one generator")
  623. else:
  624. return 1/reduce(lambda r, i:
  625. r*(x.shift(i)),
  626. range(1, abs(int(k)) + 1), 1)
  627. else:
  628. return 1/reduce(lambda r, i: r*(x + i),
  629. range(1, abs(int(k)) + 1), 1)
  630. def _eval_rewrite_as_gamma(self, x, k, piecewise=True, **kwargs):
  631. from sympy.functions.elementary.piecewise import Piecewise
  632. from sympy.functions.special.gamma_functions import gamma
  633. if not piecewise:
  634. if (x < 0) == True:
  635. return S.NegativeOne**k*gamma(k - x) / gamma(-x)
  636. return gamma(x + 1) / gamma(x - k + 1)
  637. return Piecewise(
  638. (gamma(x + 1) / gamma(x - k + 1), x >= 0),
  639. (S.NegativeOne**k*gamma(k - x) / gamma(-x), True))
  640. def _eval_rewrite_as_RisingFactorial(self, x, k, **kwargs):
  641. return rf(x - k + 1, k)
  642. def _eval_rewrite_as_binomial(self, x, k, **kwargs):
  643. if k.is_integer:
  644. return factorial(k) * binomial(x, k)
  645. def _eval_rewrite_as_factorial(self, x, k, **kwargs):
  646. from sympy.functions.elementary.piecewise import Piecewise
  647. if x.is_integer and k.is_integer:
  648. return Piecewise(
  649. (factorial(x)/factorial(-k + x), x >= 0),
  650. (S.NegativeOne**k*factorial(k - x - 1)/factorial(-x - 1), True))
  651. def _eval_rewrite_as_tractable(self, x, k, limitvar=None, **kwargs):
  652. from sympy.functions.special.gamma_functions import gamma
  653. if limitvar:
  654. k_lim = k.subs(limitvar, S.Infinity)
  655. if k_lim is S.Infinity:
  656. return (S.NegativeOne**k*gamma(k - x).rewrite('tractable', deep=True) / gamma(-x))
  657. elif k_lim is S.NegativeInfinity:
  658. return (gamma(x + 1) / gamma(x - k + 1).rewrite('tractable', deep=True))
  659. return self.rewrite(gamma).rewrite('tractable', deep=True)
  660. def _eval_is_integer(self):
  661. return fuzzy_and((self.args[0].is_integer, self.args[1].is_integer,
  662. self.args[1].is_nonnegative))
  663. rf = RisingFactorial
  664. ff = FallingFactorial
  665. ###############################################################################
  666. ########################### BINOMIAL COEFFICIENTS #############################
  667. ###############################################################################
  668. class binomial(CombinatorialFunction):
  669. r"""Implementation of the binomial coefficient. It can be defined
  670. in two ways depending on its desired interpretation:
  671. .. math:: \binom{n}{k} = \frac{n!}{k!(n-k)!}\ \text{or}\
  672. \binom{n}{k} = \frac{(n)_k}{k!}
  673. First, in a strict combinatorial sense it defines the
  674. number of ways we can choose `k` elements from a set of
  675. `n` elements. In this case both arguments are nonnegative
  676. integers and binomial is computed using an efficient
  677. algorithm based on prime factorization.
  678. The other definition is generalization for arbitrary `n`,
  679. however `k` must also be nonnegative. This case is very
  680. useful when evaluating summations.
  681. For the sake of convenience, for negative integer `k` this function
  682. will return zero no matter the other argument.
  683. To expand the binomial when `n` is a symbol, use either
  684. ``expand_func()`` or ``expand(func=True)``. The former will keep
  685. the polynomial in factored form while the latter will expand the
  686. polynomial itself. See examples for details.
  687. Examples
  688. ========
  689. >>> from sympy import Symbol, Rational, binomial, expand_func
  690. >>> n = Symbol('n', integer=True, positive=True)
  691. >>> binomial(15, 8)
  692. 6435
  693. >>> binomial(n, -1)
  694. 0
  695. Rows of Pascal's triangle can be generated with the binomial function:
  696. >>> for N in range(8):
  697. ... print([binomial(N, i) for i in range(N + 1)])
  698. ...
  699. [1]
  700. [1, 1]
  701. [1, 2, 1]
  702. [1, 3, 3, 1]
  703. [1, 4, 6, 4, 1]
  704. [1, 5, 10, 10, 5, 1]
  705. [1, 6, 15, 20, 15, 6, 1]
  706. [1, 7, 21, 35, 35, 21, 7, 1]
  707. As can a given diagonal, e.g. the 4th diagonal:
  708. >>> N = -4
  709. >>> [binomial(N, i) for i in range(1 - N)]
  710. [1, -4, 10, -20, 35]
  711. >>> binomial(Rational(5, 4), 3)
  712. -5/128
  713. >>> binomial(Rational(-5, 4), 3)
  714. -195/128
  715. >>> binomial(n, 3)
  716. binomial(n, 3)
  717. >>> binomial(n, 3).expand(func=True)
  718. n**3/6 - n**2/2 + n/3
  719. >>> expand_func(binomial(n, 3))
  720. n*(n - 2)*(n - 1)/6
  721. References
  722. ==========
  723. .. [1] https://www.johndcook.com/blog/binomial_coefficients/
  724. """
  725. def fdiff(self, argindex=1):
  726. from sympy.functions.special.gamma_functions import polygamma
  727. if argindex == 1:
  728. # https://functions.wolfram.com/GammaBetaErf/Binomial/20/01/01/
  729. n, k = self.args
  730. return binomial(n, k)*(polygamma(0, n + 1) - \
  731. polygamma(0, n - k + 1))
  732. elif argindex == 2:
  733. # https://functions.wolfram.com/GammaBetaErf/Binomial/20/01/02/
  734. n, k = self.args
  735. return binomial(n, k)*(polygamma(0, n - k + 1) - \
  736. polygamma(0, k + 1))
  737. else:
  738. raise ArgumentIndexError(self, argindex)
  739. @classmethod
  740. def _eval(self, n, k):
  741. # n.is_Number and k.is_Integer and k != 1 and n != k
  742. if k.is_Integer:
  743. if n.is_Integer and n >= 0:
  744. n, k = int(n), int(k)
  745. if k > n:
  746. return S.Zero
  747. elif k > n // 2:
  748. k = n - k
  749. if HAS_GMPY:
  750. return Integer(gmpy.bincoef(n, k))
  751. d, result = n - k, 1
  752. for i in range(1, k + 1):
  753. d += 1
  754. result = result * d // i
  755. return Integer(result)
  756. else:
  757. d, result = n - k, 1
  758. for i in range(1, k + 1):
  759. d += 1
  760. result *= d
  761. return result / _factorial(k)
  762. @classmethod
  763. def eval(cls, n, k):
  764. n, k = map(sympify, (n, k))
  765. d = n - k
  766. n_nonneg, n_isint = n.is_nonnegative, n.is_integer
  767. if k.is_zero or ((n_nonneg or n_isint is False)
  768. and d.is_zero):
  769. return S.One
  770. if (k - 1).is_zero or ((n_nonneg or n_isint is False)
  771. and (d - 1).is_zero):
  772. return n
  773. if k.is_integer:
  774. if k.is_negative or (n_nonneg and n_isint and d.is_negative):
  775. return S.Zero
  776. elif n.is_number:
  777. res = cls._eval(n, k)
  778. return res.expand(basic=True) if res else res
  779. elif n_nonneg is False and n_isint:
  780. # a special case when binomial evaluates to complex infinity
  781. return S.ComplexInfinity
  782. elif k.is_number:
  783. from sympy.functions.special.gamma_functions import gamma
  784. return gamma(n + 1)/(gamma(k + 1)*gamma(n - k + 1))
  785. def _eval_Mod(self, q):
  786. n, k = self.args
  787. if any(x.is_integer is False for x in (n, k, q)):
  788. raise ValueError("Integers expected for binomial Mod")
  789. if all(x.is_Integer for x in (n, k, q)):
  790. n, k = map(int, (n, k))
  791. aq, res = abs(q), 1
  792. # handle negative integers k or n
  793. if k < 0:
  794. return S.Zero
  795. if n < 0:
  796. n = -n + k - 1
  797. res = -1 if k%2 else 1
  798. # non negative integers k and n
  799. if k > n:
  800. return S.Zero
  801. isprime = aq.is_prime
  802. aq = int(aq)
  803. if isprime:
  804. if aq < n:
  805. # use Lucas Theorem
  806. N, K = n, k
  807. while N or K:
  808. res = res*binomial(N % aq, K % aq) % aq
  809. N, K = N // aq, K // aq
  810. else:
  811. # use Factorial Modulo
  812. d = n - k
  813. if k > d:
  814. k, d = d, k
  815. kf = 1
  816. for i in range(2, k + 1):
  817. kf = kf*i % aq
  818. df = kf
  819. for i in range(k + 1, d + 1):
  820. df = df*i % aq
  821. res *= df
  822. for i in range(d + 1, n + 1):
  823. res = res*i % aq
  824. res *= pow(kf*df % aq, aq - 2, aq)
  825. res %= aq
  826. else:
  827. # Binomial Factorization is performed by calculating the
  828. # exponents of primes <= n in `n! /(k! (n - k)!)`,
  829. # for non-negative integers n and k. As the exponent of
  830. # prime in n! is e_p(n) = [n/p] + [n/p**2] + ...
  831. # the exponent of prime in binomial(n, k) would be
  832. # e_p(n) - e_p(k) - e_p(n - k)
  833. M = int(_sqrt(n))
  834. for prime in sieve.primerange(2, n + 1):
  835. if prime > n - k:
  836. res = res*prime % aq
  837. elif prime > n // 2:
  838. continue
  839. elif prime > M:
  840. if n % prime < k % prime:
  841. res = res*prime % aq
  842. else:
  843. N, K = n, k
  844. exp = a = 0
  845. while N > 0:
  846. a = int((N % prime) < (K % prime + a))
  847. N, K = N // prime, K // prime
  848. exp += a
  849. if exp > 0:
  850. res *= pow(prime, exp, aq)
  851. res %= aq
  852. return S(res % q)
  853. def _eval_expand_func(self, **hints):
  854. """
  855. Function to expand binomial(n, k) when m is positive integer
  856. Also,
  857. n is self.args[0] and k is self.args[1] while using binomial(n, k)
  858. """
  859. n = self.args[0]
  860. if n.is_Number:
  861. return binomial(*self.args)
  862. k = self.args[1]
  863. if (n-k).is_Integer:
  864. k = n - k
  865. if k.is_Integer:
  866. if k.is_zero:
  867. return S.One
  868. elif k.is_negative:
  869. return S.Zero
  870. else:
  871. n, result = self.args[0], 1
  872. for i in range(1, k + 1):
  873. result *= n - k + i
  874. return result / _factorial(k)
  875. else:
  876. return binomial(*self.args)
  877. def _eval_rewrite_as_factorial(self, n, k, **kwargs):
  878. return factorial(n)/(factorial(k)*factorial(n - k))
  879. def _eval_rewrite_as_gamma(self, n, k, piecewise=True, **kwargs):
  880. from sympy.functions.special.gamma_functions import gamma
  881. return gamma(n + 1)/(gamma(k + 1)*gamma(n - k + 1))
  882. def _eval_rewrite_as_tractable(self, n, k, limitvar=None, **kwargs):
  883. return self._eval_rewrite_as_gamma(n, k).rewrite('tractable')
  884. def _eval_rewrite_as_FallingFactorial(self, n, k, **kwargs):
  885. if k.is_integer:
  886. return ff(n, k) / factorial(k)
  887. def _eval_is_integer(self):
  888. n, k = self.args
  889. if n.is_integer and k.is_integer:
  890. return True
  891. elif k.is_integer is False:
  892. return False
  893. def _eval_is_nonnegative(self):
  894. n, k = self.args
  895. if n.is_integer and k.is_integer:
  896. if n.is_nonnegative or k.is_negative or k.is_even:
  897. return True
  898. elif k.is_even is False:
  899. return False
  900. def _eval_as_leading_term(self, x, logx=None, cdir=0):
  901. from sympy.functions.special.gamma_functions import gamma
  902. return self.rewrite(gamma)._eval_as_leading_term(x, logx=logx, cdir=cdir)