m2m模型翻译
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1110 lines
37 KiB

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