Spaces:
				
			
			
	
			
			
		Sleeping
		
	
	
	
			
			
	
	
	
	
		
		
		Sleeping
		
	| """ | |
| This module implements some special functions that commonly appear in | |
| combinatorial contexts (e.g. in power series); in particular, | |
| sequences of rational numbers such as Bernoulli and Fibonacci numbers. | |
| Factorials, binomial coefficients and related functions are located in | |
| the separate 'factorials' module. | |
| """ | |
| from math import prod | |
| from collections import defaultdict | |
| from typing import Tuple as tTuple | |
| from sympy.core import S, Symbol, Add, Dummy | |
| from sympy.core.cache import cacheit | |
| from sympy.core.containers import Dict | |
| from sympy.core.expr import Expr | |
| from sympy.core.function import ArgumentIndexError, Function, expand_mul | |
| from sympy.core.logic import fuzzy_not | |
| from sympy.core.mul import Mul | |
| from sympy.core.numbers import E, I, pi, oo, Rational, Integer | |
| from sympy.core.relational import Eq, is_le, is_gt, is_lt | |
| from sympy.external.gmpy import SYMPY_INTS, remove, lcm, legendre, jacobi, kronecker | |
| from sympy.functions.combinatorial.factorials import (binomial, | |
| factorial, subfactorial) | |
| from sympy.functions.elementary.exponential import log | |
| from sympy.functions.elementary.piecewise import Piecewise | |
| from sympy.ntheory.factor_ import (factorint, _divisor_sigma, is_carmichael, | |
| find_carmichael_numbers_in_range, find_first_n_carmichaels) | |
| from sympy.ntheory.generate import _primepi | |
| from sympy.ntheory.partitions_ import _partition, _partition_rec | |
| from sympy.ntheory.primetest import isprime, is_square | |
| from sympy.polys.appellseqs import bernoulli_poly, euler_poly, genocchi_poly | |
| from sympy.polys.polytools import cancel | |
| from sympy.utilities.enumerative import MultisetPartitionTraverser | |
| from sympy.utilities.exceptions import sympy_deprecation_warning | |
| from sympy.utilities.iterables import multiset, multiset_derangements, iterable | |
| from sympy.utilities.memoization import recurrence_memo | |
| from sympy.utilities.misc import as_int | |
| from mpmath import mp, workprec | |
| from mpmath.libmp import ifib as _ifib | |
| def _product(a, b): | |
| return prod(range(a, b + 1)) | |
| # Dummy symbol used for computing polynomial sequences | |
| _sym = Symbol('x') | |
| #----------------------------------------------------------------------------# | |
| # # | |
| # Carmichael numbers # | |
| # # | |
| #----------------------------------------------------------------------------# | |
| class carmichael(Function): | |
| r""" | |
| Carmichael Numbers: | |
| Certain cryptographic algorithms make use of big prime numbers. | |
| However, checking whether a big number is prime is not so easy. | |
| Randomized prime number checking tests exist that offer a high degree of | |
| confidence of accurate determination at low cost, such as the Fermat test. | |
| Let 'a' be a random number between $2$ and $n - 1$, where $n$ is the | |
| number whose primality we are testing. Then, $n$ is probably prime if it | |
| satisfies the modular arithmetic congruence relation: | |
| .. math :: a^{n-1} = 1 \pmod{n} | |
| (where mod refers to the modulo operation) | |
| If a number passes the Fermat test several times, then it is prime with a | |
| high probability. | |
| Unfortunately, certain composite numbers (non-primes) still pass the Fermat | |
| test with every number smaller than themselves. | |
| These numbers are called Carmichael numbers. | |
| A Carmichael number will pass a Fermat primality test to every base $b$ | |
| relatively prime to the number, even though it is not actually prime. | |
| This makes tests based on Fermat's Little Theorem less effective than | |
| strong probable prime tests such as the Baillie-PSW primality test and | |
| the Miller-Rabin primality test. | |
| Examples | |
| ======== | |
| >>> from sympy.ntheory.factor_ import find_first_n_carmichaels, find_carmichael_numbers_in_range | |
| >>> find_first_n_carmichaels(5) | |
| [561, 1105, 1729, 2465, 2821] | |
| >>> find_carmichael_numbers_in_range(0, 562) | |
| [561] | |
| >>> find_carmichael_numbers_in_range(0,1000) | |
| [561] | |
| >>> find_carmichael_numbers_in_range(0,2000) | |
| [561, 1105, 1729] | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Carmichael_number | |
| .. [2] https://en.wikipedia.org/wiki/Fermat_primality_test | |
| .. [3] https://www.jstor.org/stable/23248683?seq=1#metadata_info_tab_contents | |
| """ | |
| def is_perfect_square(n): | |
| sympy_deprecation_warning( | |
| """ | |
| is_perfect_square is just a wrapper around sympy.ntheory.primetest.is_square | |
| so use that directly instead. | |
| """, | |
| deprecated_since_version="1.11", | |
| active_deprecations_target='deprecated-carmichael-static-methods', | |
| ) | |
| return is_square(n) | |
| def divides(p, n): | |
| sympy_deprecation_warning( | |
| """ | |
| divides can be replaced by directly testing n % p == 0. | |
| """, | |
| deprecated_since_version="1.11", | |
| active_deprecations_target='deprecated-carmichael-static-methods', | |
| ) | |
| return n % p == 0 | |
| def is_prime(n): | |
| sympy_deprecation_warning( | |
| """ | |
| is_prime is just a wrapper around sympy.ntheory.primetest.isprime so use that | |
| directly instead. | |
| """, | |
| deprecated_since_version="1.11", | |
| active_deprecations_target='deprecated-carmichael-static-methods', | |
| ) | |
| return isprime(n) | |
| def is_carmichael(n): | |
| sympy_deprecation_warning( | |
| """ | |
| is_carmichael is just a wrapper around sympy.ntheory.factor_.is_carmichael so use that | |
| directly instead. | |
| """, | |
| deprecated_since_version="1.13", | |
| active_deprecations_target='deprecated-ntheory-symbolic-functions', | |
| ) | |
| return is_carmichael(n) | |
| def find_carmichael_numbers_in_range(x, y): | |
| sympy_deprecation_warning( | |
| """ | |
| find_carmichael_numbers_in_range is just a wrapper around sympy.ntheory.factor_.find_carmichael_numbers_in_range so use that | |
| directly instead. | |
| """, | |
| deprecated_since_version="1.13", | |
| active_deprecations_target='deprecated-ntheory-symbolic-functions', | |
| ) | |
| return find_carmichael_numbers_in_range(x, y) | |
| def find_first_n_carmichaels(n): | |
| sympy_deprecation_warning( | |
| """ | |
| find_first_n_carmichaels is just a wrapper around sympy.ntheory.factor_.find_first_n_carmichaels so use that | |
| directly instead. | |
| """, | |
| deprecated_since_version="1.13", | |
| active_deprecations_target='deprecated-ntheory-symbolic-functions', | |
| ) | |
| return find_first_n_carmichaels(n) | |
| #----------------------------------------------------------------------------# | |
| # # | |
| # Fibonacci numbers # | |
| # # | |
| #----------------------------------------------------------------------------# | |
| class fibonacci(Function): | |
| r""" | |
| Fibonacci numbers / Fibonacci polynomials | |
| The Fibonacci numbers are the integer sequence defined by the | |
| initial terms `F_0 = 0`, `F_1 = 1` and the two-term recurrence | |
| relation `F_n = F_{n-1} + F_{n-2}`. This definition | |
| extended to arbitrary real and complex arguments using | |
| the formula | |
| .. math :: F_z = \frac{\phi^z - \cos(\pi z) \phi^{-z}}{\sqrt 5} | |
| The Fibonacci polynomials are defined by `F_1(x) = 1`, | |
| `F_2(x) = x`, and `F_n(x) = x*F_{n-1}(x) + F_{n-2}(x)` for `n > 2`. | |
| For all positive integers `n`, `F_n(1) = F_n`. | |
| * ``fibonacci(n)`` gives the `n^{th}` Fibonacci number, `F_n` | |
| * ``fibonacci(n, x)`` gives the `n^{th}` Fibonacci polynomial in `x`, `F_n(x)` | |
| Examples | |
| ======== | |
| >>> from sympy import fibonacci, Symbol | |
| >>> [fibonacci(x) for x in range(11)] | |
| [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55] | |
| >>> fibonacci(5, Symbol('t')) | |
| t**4 + 3*t**2 + 1 | |
| See Also | |
| ======== | |
| bell, bernoulli, catalan, euler, harmonic, lucas, genocchi, partition, tribonacci | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Fibonacci_number | |
| .. [2] https://mathworld.wolfram.com/FibonacciNumber.html | |
| """ | |
| def _fib(n): | |
| return _ifib(n) | |
| def _fibpoly(n, prev): | |
| return (prev[-2] + _sym*prev[-1]).expand() | |
| def eval(cls, n, sym=None): | |
| if n is S.Infinity: | |
| return S.Infinity | |
| if n.is_Integer: | |
| if sym is None: | |
| n = int(n) | |
| if n < 0: | |
| return S.NegativeOne**(n + 1) * fibonacci(-n) | |
| else: | |
| return Integer(cls._fib(n)) | |
| else: | |
| if n < 1: | |
| raise ValueError("Fibonacci polynomials are defined " | |
| "only for positive integer indices.") | |
| return cls._fibpoly(n).subs(_sym, sym) | |
| def _eval_rewrite_as_tractable(self, n, **kwargs): | |
| from sympy.functions import sqrt, cos | |
| return (S.GoldenRatio**n - cos(S.Pi*n)/S.GoldenRatio**n)/sqrt(5) | |
| def _eval_rewrite_as_sqrt(self, n, **kwargs): | |
| from sympy.functions.elementary.miscellaneous import sqrt | |
| return 2**(-n)*sqrt(5)*((1 + sqrt(5))**n - (-sqrt(5) + 1)**n) / 5 | |
| def _eval_rewrite_as_GoldenRatio(self,n, **kwargs): | |
| return (S.GoldenRatio**n - 1/(-S.GoldenRatio)**n)/(2*S.GoldenRatio-1) | |
| #----------------------------------------------------------------------------# | |
| # # | |
| # Lucas numbers # | |
| # # | |
| #----------------------------------------------------------------------------# | |
| class lucas(Function): | |
| """ | |
| Lucas numbers | |
| Lucas numbers satisfy a recurrence relation similar to that of | |
| the Fibonacci sequence, in which each term is the sum of the | |
| preceding two. They are generated by choosing the initial | |
| values `L_0 = 2` and `L_1 = 1`. | |
| * ``lucas(n)`` gives the `n^{th}` Lucas number | |
| Examples | |
| ======== | |
| >>> from sympy import lucas | |
| >>> [lucas(x) for x in range(11)] | |
| [2, 1, 3, 4, 7, 11, 18, 29, 47, 76, 123] | |
| See Also | |
| ======== | |
| bell, bernoulli, catalan, euler, fibonacci, harmonic, genocchi, partition, tribonacci | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Lucas_number | |
| .. [2] https://mathworld.wolfram.com/LucasNumber.html | |
| """ | |
| def eval(cls, n): | |
| if n is S.Infinity: | |
| return S.Infinity | |
| if n.is_Integer: | |
| return fibonacci(n + 1) + fibonacci(n - 1) | |
| def _eval_rewrite_as_sqrt(self, n, **kwargs): | |
| from sympy.functions.elementary.miscellaneous import sqrt | |
| return 2**(-n)*((1 + sqrt(5))**n + (-sqrt(5) + 1)**n) | |
| #----------------------------------------------------------------------------# | |
| # # | |
| # Tribonacci numbers # | |
| # # | |
| #----------------------------------------------------------------------------# | |
| class tribonacci(Function): | |
| r""" | |
| Tribonacci numbers / Tribonacci polynomials | |
| The Tribonacci numbers are the integer sequence defined by the | |
| initial terms `T_0 = 0`, `T_1 = 1`, `T_2 = 1` and the three-term | |
| recurrence relation `T_n = T_{n-1} + T_{n-2} + T_{n-3}`. | |
| The Tribonacci polynomials are defined by `T_0(x) = 0`, `T_1(x) = 1`, | |
| `T_2(x) = x^2`, and `T_n(x) = x^2 T_{n-1}(x) + x T_{n-2}(x) + T_{n-3}(x)` | |
| for `n > 2`. For all positive integers `n`, `T_n(1) = T_n`. | |
| * ``tribonacci(n)`` gives the `n^{th}` Tribonacci number, `T_n` | |
| * ``tribonacci(n, x)`` gives the `n^{th}` Tribonacci polynomial in `x`, `T_n(x)` | |
| Examples | |
| ======== | |
| >>> from sympy import tribonacci, Symbol | |
| >>> [tribonacci(x) for x in range(11)] | |
| [0, 1, 1, 2, 4, 7, 13, 24, 44, 81, 149] | |
| >>> tribonacci(5, Symbol('t')) | |
| t**8 + 3*t**5 + 3*t**2 | |
| See Also | |
| ======== | |
| bell, bernoulli, catalan, euler, fibonacci, harmonic, lucas, genocchi, partition | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Generalizations_of_Fibonacci_numbers#Tribonacci_numbers | |
| .. [2] https://mathworld.wolfram.com/TribonacciNumber.html | |
| .. [3] https://oeis.org/A000073 | |
| """ | |
| def _trib(n, prev): | |
| return (prev[-3] + prev[-2] + prev[-1]) | |
| def _tribpoly(n, prev): | |
| return (prev[-3] + _sym*prev[-2] + _sym**2*prev[-1]).expand() | |
| def eval(cls, n, sym=None): | |
| if n is S.Infinity: | |
| return S.Infinity | |
| if n.is_Integer: | |
| n = int(n) | |
| if n < 0: | |
| raise ValueError("Tribonacci polynomials are defined " | |
| "only for non-negative integer indices.") | |
| if sym is None: | |
| return Integer(cls._trib(n)) | |
| else: | |
| return cls._tribpoly(n).subs(_sym, sym) | |
| def _eval_rewrite_as_sqrt(self, n, **kwargs): | |
| from sympy.functions.elementary.miscellaneous import cbrt, sqrt | |
| w = (-1 + S.ImaginaryUnit * sqrt(3)) / 2 | |
| a = (1 + cbrt(19 + 3*sqrt(33)) + cbrt(19 - 3*sqrt(33))) / 3 | |
| b = (1 + w*cbrt(19 + 3*sqrt(33)) + w**2*cbrt(19 - 3*sqrt(33))) / 3 | |
| c = (1 + w**2*cbrt(19 + 3*sqrt(33)) + w*cbrt(19 - 3*sqrt(33))) / 3 | |
| Tn = (a**(n + 1)/((a - b)*(a - c)) | |
| + b**(n + 1)/((b - a)*(b - c)) | |
| + c**(n + 1)/((c - a)*(c - b))) | |
| return Tn | |
| def _eval_rewrite_as_TribonacciConstant(self, n, **kwargs): | |
| from sympy.functions.elementary.integers import floor | |
| from sympy.functions.elementary.miscellaneous import cbrt, sqrt | |
| b = cbrt(586 + 102*sqrt(33)) | |
| Tn = 3 * b * S.TribonacciConstant**n / (b**2 - 2*b + 4) | |
| return floor(Tn + S.Half) | |
| #----------------------------------------------------------------------------# | |
| # # | |
| # Bernoulli numbers # | |
| # # | |
| #----------------------------------------------------------------------------# | |
| class bernoulli(Function): | |
| r""" | |
| Bernoulli numbers / Bernoulli polynomials / Bernoulli function | |
| The Bernoulli numbers are a sequence of rational numbers | |
| defined by `B_0 = 1` and the recursive relation (`n > 0`): | |
| .. math :: n+1 = \sum_{k=0}^n \binom{n+1}{k} B_k | |
| They are also commonly defined by their exponential generating | |
| function, which is `\frac{x}{1 - e^{-x}}`. For odd indices > 1, | |
| the Bernoulli numbers are zero. | |
| The Bernoulli polynomials satisfy the analogous formula: | |
| .. math :: B_n(x) = \sum_{k=0}^n (-1)^k \binom{n}{k} B_k x^{n-k} | |
| Bernoulli numbers and Bernoulli polynomials are related as | |
| `B_n(1) = B_n`. | |
| The generalized Bernoulli function `\operatorname{B}(s, a)` | |
| is defined for any complex `s` and `a`, except where `a` is a | |
| nonpositive integer and `s` is not a nonnegative integer. It is | |
| an entire function of `s` for fixed `a`, related to the Hurwitz | |
| zeta function by | |
| .. math:: \operatorname{B}(s, a) = \begin{cases} | |
| -s \zeta(1-s, a) & s \ne 0 \\ 1 & s = 0 \end{cases} | |
| When `s` is a nonnegative integer this function reduces to the | |
| Bernoulli polynomials: `\operatorname{B}(n, x) = B_n(x)`. When | |
| `a` is omitted it is assumed to be 1, yielding the (ordinary) | |
| Bernoulli function which interpolates the Bernoulli numbers and is | |
| related to the Riemann zeta function. | |
| We compute Bernoulli numbers using Ramanujan's formula: | |
| .. math :: B_n = \frac{A(n) - S(n)}{\binom{n+3}{n}} | |
| where: | |
| .. math :: A(n) = \begin{cases} \frac{n+3}{3} & | |
| n \equiv 0\ \text{or}\ 2 \pmod{6} \\ | |
| -\frac{n+3}{6} & n \equiv 4 \pmod{6} \end{cases} | |
| and: | |
| .. math :: S(n) = \sum_{k=1}^{[n/6]} \binom{n+3}{n-6k} B_{n-6k} | |
| This formula is similar to the sum given in the definition, but | |
| cuts `\frac{2}{3}` of the terms. For Bernoulli polynomials, we use | |
| Appell sequences. | |
| For `n` a nonnegative integer and `s`, `a`, `x` arbitrary complex numbers, | |
| * ``bernoulli(n)`` gives the nth Bernoulli number, `B_n` | |
| * ``bernoulli(s)`` gives the Bernoulli function `\operatorname{B}(s)` | |
| * ``bernoulli(n, x)`` gives the nth Bernoulli polynomial in `x`, `B_n(x)` | |
| * ``bernoulli(s, a)`` gives the generalized Bernoulli function | |
| `\operatorname{B}(s, a)` | |
| .. versionchanged:: 1.12 | |
| ``bernoulli(1)`` gives `+\frac{1}{2}` instead of `-\frac{1}{2}`. | |
| This choice of value confers several theoretical advantages [5]_, | |
| including the extension to complex parameters described above | |
| which this function now implements. The previous behavior, defined | |
| only for nonnegative integers `n`, can be obtained with | |
| ``(-1)**n*bernoulli(n)``. | |
| Examples | |
| ======== | |
| >>> from sympy import bernoulli | |
| >>> from sympy.abc import x | |
| >>> [bernoulli(n) for n in range(11)] | |
| [1, 1/2, 1/6, 0, -1/30, 0, 1/42, 0, -1/30, 0, 5/66] | |
| >>> bernoulli(1000001) | |
| 0 | |
| >>> bernoulli(3, x) | |
| x**3 - 3*x**2/2 + x/2 | |
| See Also | |
| ======== | |
| andre, bell, catalan, euler, fibonacci, harmonic, lucas, genocchi, | |
| partition, tribonacci, sympy.polys.appellseqs.bernoulli_poly | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Bernoulli_number | |
| .. [2] https://en.wikipedia.org/wiki/Bernoulli_polynomial | |
| .. [3] https://mathworld.wolfram.com/BernoulliNumber.html | |
| .. [4] https://mathworld.wolfram.com/BernoulliPolynomial.html | |
| .. [5] Peter Luschny, "The Bernoulli Manifesto", | |
| https://luschny.de/math/zeta/The-Bernoulli-Manifesto.html | |
| .. [6] Peter Luschny, "An introduction to the Bernoulli function", | |
| https://arxiv.org/abs/2009.06743 | |
| """ | |
| args: tTuple[Integer] | |
| # Calculates B_n for positive even n | |
| def _calc_bernoulli(n): | |
| s = 0 | |
| a = int(binomial(n + 3, n - 6)) | |
| for j in range(1, n//6 + 1): | |
| s += a * bernoulli(n - 6*j) | |
| # Avoid computing each binomial coefficient from scratch | |
| a *= _product(n - 6 - 6*j + 1, n - 6*j) | |
| a //= _product(6*j + 4, 6*j + 9) | |
| if n % 6 == 4: | |
| s = -Rational(n + 3, 6) - s | |
| else: | |
| s = Rational(n + 3, 3) - s | |
| return s / binomial(n + 3, n) | |
| # We implement a specialized memoization scheme to handle each | |
| # case modulo 6 separately | |
| _cache = {0: S.One, 1: Rational(1, 2), 2: Rational(1, 6), 4: Rational(-1, 30)} | |
| _highest = {0: 0, 1: 1, 2: 2, 4: 4} | |
| def eval(cls, n, x=None): | |
| if x is S.One: | |
| return cls(n) | |
| elif n.is_zero: | |
| return S.One | |
| elif n.is_integer is False or n.is_nonnegative is False: | |
| if x is not None and x.is_Integer and x.is_nonpositive: | |
| return S.NaN | |
| return | |
| # Bernoulli numbers | |
| elif x is None: | |
| if n is S.One: | |
| return S.Half | |
| elif n.is_odd and (n-1).is_positive: | |
| return S.Zero | |
| elif n.is_Number: | |
| n = int(n) | |
| # Use mpmath for enormous Bernoulli numbers | |
| if n > 500: | |
| p, q = mp.bernfrac(n) | |
| return Rational(int(p), int(q)) | |
| case = n % 6 | |
| highest_cached = cls._highest[case] | |
| if n <= highest_cached: | |
| return cls._cache[n] | |
| # To avoid excessive recursion when, say, bernoulli(1000) is | |
| # requested, calculate and cache the entire sequence ... B_988, | |
| # B_994, B_1000 in increasing order | |
| for i in range(highest_cached + 6, n + 6, 6): | |
| b = cls._calc_bernoulli(i) | |
| cls._cache[i] = b | |
| cls._highest[case] = i | |
| return b | |
| # Bernoulli polynomials | |
| elif n.is_Number: | |
| return bernoulli_poly(n, x) | |
| def _eval_rewrite_as_zeta(self, n, x=1, **kwargs): | |
| from sympy.functions.special.zeta_functions import zeta | |
| return Piecewise((1, Eq(n, 0)), (-n * zeta(1-n, x), True)) | |
| def _eval_evalf(self, prec): | |
| if not all(x.is_number for x in self.args): | |
| return | |
| n = self.args[0]._to_mpmath(prec) | |
| x = (self.args[1] if len(self.args) > 1 else S.One)._to_mpmath(prec) | |
| with workprec(prec): | |
| if n == 0: | |
| res = mp.mpf(1) | |
| elif n == 1: | |
| res = x - mp.mpf(0.5) | |
| elif mp.isint(n) and n >= 0: | |
| res = mp.bernoulli(n) if x == 1 else mp.bernpoly(n, x) | |
| else: | |
| res = -n * mp.zeta(1-n, x) | |
| return Expr._from_mpmath(res, prec) | |
| #----------------------------------------------------------------------------# | |
| # # | |
| # Bell numbers # | |
| # # | |
| #----------------------------------------------------------------------------# | |
| class bell(Function): | |
| r""" | |
| Bell numbers / Bell polynomials | |
| The Bell numbers satisfy `B_0 = 1` and | |
| .. math:: B_n = \sum_{k=0}^{n-1} \binom{n-1}{k} B_k. | |
| They are also given by: | |
| .. math:: B_n = \frac{1}{e} \sum_{k=0}^{\infty} \frac{k^n}{k!}. | |
| The Bell polynomials are given by `B_0(x) = 1` and | |
| .. math:: B_n(x) = x \sum_{k=1}^{n-1} \binom{n-1}{k-1} B_{k-1}(x). | |
| The second kind of Bell polynomials (are sometimes called "partial" Bell | |
| polynomials or incomplete Bell polynomials) are defined as | |
| .. math:: B_{n,k}(x_1, x_2,\dotsc x_{n-k+1}) = | |
| \sum_{j_1+j_2+j_2+\dotsb=k \atop j_1+2j_2+3j_2+\dotsb=n} | |
| \frac{n!}{j_1!j_2!\dotsb j_{n-k+1}!} | |
| \left(\frac{x_1}{1!} \right)^{j_1} | |
| \left(\frac{x_2}{2!} \right)^{j_2} \dotsb | |
| \left(\frac{x_{n-k+1}}{(n-k+1)!} \right) ^{j_{n-k+1}}. | |
| * ``bell(n)`` gives the `n^{th}` Bell number, `B_n`. | |
| * ``bell(n, x)`` gives the `n^{th}` Bell polynomial, `B_n(x)`. | |
| * ``bell(n, k, (x1, x2, ...))`` gives Bell polynomials of the second kind, | |
| `B_{n,k}(x_1, x_2, \dotsc, x_{n-k+1})`. | |
| Notes | |
| ===== | |
| Not to be confused with Bernoulli numbers and Bernoulli polynomials, | |
| which use the same notation. | |
| Examples | |
| ======== | |
| >>> from sympy import bell, Symbol, symbols | |
| >>> [bell(n) for n in range(11)] | |
| [1, 1, 2, 5, 15, 52, 203, 877, 4140, 21147, 115975] | |
| >>> bell(30) | |
| 846749014511809332450147 | |
| >>> bell(4, Symbol('t')) | |
| t**4 + 6*t**3 + 7*t**2 + t | |
| >>> bell(6, 2, symbols('x:6')[1:]) | |
| 6*x1*x5 + 15*x2*x4 + 10*x3**2 | |
| See Also | |
| ======== | |
| bernoulli, catalan, euler, fibonacci, harmonic, lucas, genocchi, partition, tribonacci | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Bell_number | |
| .. [2] https://mathworld.wolfram.com/BellNumber.html | |
| .. [3] https://mathworld.wolfram.com/BellPolynomial.html | |
| """ | |
| def _bell(n, prev): | |
| s = 1 | |
| a = 1 | |
| for k in range(1, n): | |
| a = a * (n - k) // k | |
| s += a * prev[k] | |
| return s | |
| def _bell_poly(n, prev): | |
| s = 1 | |
| a = 1 | |
| for k in range(2, n + 1): | |
| a = a * (n - k + 1) // (k - 1) | |
| s += a * prev[k - 1] | |
| return expand_mul(_sym * s) | |
| def _bell_incomplete_poly(n, k, symbols): | |
| r""" | |
| The second kind of Bell polynomials (incomplete Bell polynomials). | |
| Calculated by recurrence formula: | |
| .. math:: B_{n,k}(x_1, x_2, \dotsc, x_{n-k+1}) = | |
| \sum_{m=1}^{n-k+1} | |
| \x_m \binom{n-1}{m-1} B_{n-m,k-1}(x_1, x_2, \dotsc, x_{n-m-k}) | |
| where | |
| `B_{0,0} = 1;` | |
| `B_{n,0} = 0; for n \ge 1` | |
| `B_{0,k} = 0; for k \ge 1` | |
| """ | |
| if (n == 0) and (k == 0): | |
| return S.One | |
| elif (n == 0) or (k == 0): | |
| return S.Zero | |
| s = S.Zero | |
| a = S.One | |
| for m in range(1, n - k + 2): | |
| s += a * bell._bell_incomplete_poly( | |
| n - m, k - 1, symbols) * symbols[m - 1] | |
| a = a * (n - m) / m | |
| return expand_mul(s) | |
| def eval(cls, n, k_sym=None, symbols=None): | |
| if n is S.Infinity: | |
| if k_sym is None: | |
| return S.Infinity | |
| else: | |
| raise ValueError("Bell polynomial is not defined") | |
| if n.is_negative or n.is_integer is False: | |
| raise ValueError("a non-negative integer expected") | |
| if n.is_Integer and n.is_nonnegative: | |
| if k_sym is None: | |
| return Integer(cls._bell(int(n))) | |
| elif symbols is None: | |
| return cls._bell_poly(int(n)).subs(_sym, k_sym) | |
| else: | |
| r = cls._bell_incomplete_poly(int(n), int(k_sym), symbols) | |
| return r | |
| def _eval_rewrite_as_Sum(self, n, k_sym=None, symbols=None, **kwargs): | |
| from sympy.concrete.summations import Sum | |
| if (k_sym is not None) or (symbols is not None): | |
| return self | |
| # Dobinski's formula | |
| if not n.is_nonnegative: | |
| return self | |
| k = Dummy('k', integer=True, nonnegative=True) | |
| return 1 / E * Sum(k**n / factorial(k), (k, 0, S.Infinity)) | |
| #----------------------------------------------------------------------------# | |
| # # | |
| # Harmonic numbers # | |
| # # | |
| #----------------------------------------------------------------------------# | |
| class harmonic(Function): | |
| r""" | |
| Harmonic numbers | |
| The nth harmonic number is given by `\operatorname{H}_{n} = | |
| 1 + \frac{1}{2} + \frac{1}{3} + \ldots + \frac{1}{n}`. | |
| More generally: | |
| .. math:: \operatorname{H}_{n,m} = \sum_{k=1}^{n} \frac{1}{k^m} | |
| As `n \rightarrow \infty`, `\operatorname{H}_{n,m} \rightarrow \zeta(m)`, | |
| the Riemann zeta function. | |
| * ``harmonic(n)`` gives the nth harmonic number, `\operatorname{H}_n` | |
| * ``harmonic(n, m)`` gives the nth generalized harmonic number | |
| of order `m`, `\operatorname{H}_{n,m}`, where | |
| ``harmonic(n) == harmonic(n, 1)`` | |
| This function can be extended to complex `n` and `m` where `n` is not a | |
| negative integer or `m` is a nonpositive integer as | |
| .. math:: \operatorname{H}_{n,m} = \begin{cases} \zeta(m) - \zeta(m, n+1) | |
| & m \ne 1 \\ \psi(n+1) + \gamma & m = 1 \end{cases} | |
| Examples | |
| ======== | |
| >>> from sympy import harmonic, oo | |
| >>> [harmonic(n) for n in range(6)] | |
| [0, 1, 3/2, 11/6, 25/12, 137/60] | |
| >>> [harmonic(n, 2) for n in range(6)] | |
| [0, 1, 5/4, 49/36, 205/144, 5269/3600] | |
| >>> harmonic(oo, 2) | |
| pi**2/6 | |
| >>> from sympy import Symbol, Sum | |
| >>> n = Symbol("n") | |
| >>> harmonic(n).rewrite(Sum) | |
| Sum(1/_k, (_k, 1, n)) | |
| We can evaluate harmonic numbers for all integral and positive | |
| rational arguments: | |
| >>> from sympy import S, expand_func, simplify | |
| >>> harmonic(8) | |
| 761/280 | |
| >>> harmonic(11) | |
| 83711/27720 | |
| >>> H = harmonic(1/S(3)) | |
| >>> H | |
| harmonic(1/3) | |
| >>> He = expand_func(H) | |
| >>> He | |
| -log(6) - sqrt(3)*pi/6 + 2*Sum(log(sin(_k*pi/3))*cos(2*_k*pi/3), (_k, 1, 1)) | |
| + 3*Sum(1/(3*_k + 1), (_k, 0, 0)) | |
| >>> He.doit() | |
| -log(6) - sqrt(3)*pi/6 - log(sqrt(3)/2) + 3 | |
| >>> H = harmonic(25/S(7)) | |
| >>> He = simplify(expand_func(H).doit()) | |
| >>> He | |
| log(sin(2*pi/7)**(2*cos(16*pi/7))/(14*sin(pi/7)**(2*cos(pi/7))*cos(pi/14)**(2*sin(pi/14)))) + pi*tan(pi/14)/2 + 30247/9900 | |
| >>> He.n(40) | |
| 1.983697455232980674869851942390639915940 | |
| >>> harmonic(25/S(7)).n(40) | |
| 1.983697455232980674869851942390639915940 | |
| We can rewrite harmonic numbers in terms of polygamma functions: | |
| >>> from sympy import digamma, polygamma | |
| >>> m = Symbol("m", integer=True, positive=True) | |
| >>> harmonic(n).rewrite(digamma) | |
| polygamma(0, n + 1) + EulerGamma | |
| >>> harmonic(n).rewrite(polygamma) | |
| polygamma(0, n + 1) + EulerGamma | |
| >>> harmonic(n,3).rewrite(polygamma) | |
| polygamma(2, n + 1)/2 + zeta(3) | |
| >>> simplify(harmonic(n,m).rewrite(polygamma)) | |
| Piecewise((polygamma(0, n + 1) + EulerGamma, Eq(m, 1)), | |
| (-(-1)**m*polygamma(m - 1, n + 1)/factorial(m - 1) + zeta(m), True)) | |
| Integer offsets in the argument can be pulled out: | |
| >>> from sympy import expand_func | |
| >>> expand_func(harmonic(n+4)) | |
| harmonic(n) + 1/(n + 4) + 1/(n + 3) + 1/(n + 2) + 1/(n + 1) | |
| >>> expand_func(harmonic(n-4)) | |
| harmonic(n) - 1/(n - 1) - 1/(n - 2) - 1/(n - 3) - 1/n | |
| Some limits can be computed as well: | |
| >>> from sympy import limit, oo | |
| >>> limit(harmonic(n), n, oo) | |
| oo | |
| >>> limit(harmonic(n, 2), n, oo) | |
| pi**2/6 | |
| >>> limit(harmonic(n, 3), n, oo) | |
| zeta(3) | |
| For `m > 1`, `H_{n,m}` tends to `\zeta(m)` in the limit of infinite `n`: | |
| >>> m = Symbol("m", positive=True) | |
| >>> limit(harmonic(n, m+1), n, oo) | |
| zeta(m + 1) | |
| See Also | |
| ======== | |
| bell, bernoulli, catalan, euler, fibonacci, lucas, genocchi, partition, tribonacci | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Harmonic_number | |
| .. [2] https://functions.wolfram.com/GammaBetaErf/HarmonicNumber/ | |
| .. [3] https://functions.wolfram.com/GammaBetaErf/HarmonicNumber2/ | |
| """ | |
| def eval(cls, n, m=None): | |
| from sympy.functions.special.zeta_functions import zeta | |
| if m is S.One: | |
| return cls(n) | |
| if m is None: | |
| m = S.One | |
| if n.is_zero: | |
| return S.Zero | |
| elif m.is_zero: | |
| return n | |
| elif n is S.Infinity: | |
| if m.is_negative: | |
| return S.NaN | |
| elif is_le(m, S.One): | |
| return S.Infinity | |
| elif is_gt(m, S.One): | |
| return zeta(m) | |
| elif m.is_Integer and m.is_nonpositive: | |
| return (bernoulli(1-m, n+1) - bernoulli(1-m)) / (1-m) | |
| elif n.is_Integer: | |
| if n.is_negative and (m.is_integer is False or m.is_nonpositive is False): | |
| return S.ComplexInfinity if m is S.One else S.NaN | |
| if n.is_nonnegative: | |
| return Add(*(k**(-m) for k in range(1, int(n)+1))) | |
| def _eval_rewrite_as_polygamma(self, n, m=S.One, **kwargs): | |
| from sympy.functions.special.gamma_functions import gamma, polygamma | |
| if m.is_integer and m.is_positive: | |
| return Piecewise((polygamma(0, n+1) + S.EulerGamma, Eq(m, 1)), | |
| (S.NegativeOne**m * (polygamma(m-1, 1) - polygamma(m-1, n+1)) / | |
| gamma(m), True)) | |
| def _eval_rewrite_as_digamma(self, n, m=1, **kwargs): | |
| from sympy.functions.special.gamma_functions import polygamma | |
| return self.rewrite(polygamma) | |
| def _eval_rewrite_as_trigamma(self, n, m=1, **kwargs): | |
| from sympy.functions.special.gamma_functions import polygamma | |
| return self.rewrite(polygamma) | |
| def _eval_rewrite_as_Sum(self, n, m=None, **kwargs): | |
| from sympy.concrete.summations import Sum | |
| k = Dummy("k", integer=True) | |
| if m is None: | |
| m = S.One | |
| return Sum(k**(-m), (k, 1, n)) | |
| def _eval_rewrite_as_zeta(self, n, m=S.One, **kwargs): | |
| from sympy.functions.special.zeta_functions import zeta | |
| from sympy.functions.special.gamma_functions import digamma | |
| return Piecewise((digamma(n + 1) + S.EulerGamma, Eq(m, 1)), | |
| (zeta(m) - zeta(m, n+1), True)) | |
| def _eval_expand_func(self, **hints): | |
| from sympy.concrete.summations import Sum | |
| n = self.args[0] | |
| m = self.args[1] if len(self.args) == 2 else 1 | |
| if m == S.One: | |
| if n.is_Add: | |
| off = n.args[0] | |
| nnew = n - off | |
| if off.is_Integer and off.is_positive: | |
| result = [S.One/(nnew + i) for i in range(off, 0, -1)] + [harmonic(nnew)] | |
| return Add(*result) | |
| elif off.is_Integer and off.is_negative: | |
| result = [-S.One/(nnew + i) for i in range(0, off, -1)] + [harmonic(nnew)] | |
| return Add(*result) | |
| if n.is_Rational: | |
| # Expansions for harmonic numbers at general rational arguments (u + p/q) | |
| # Split n as u + p/q with p < q | |
| p, q = n.as_numer_denom() | |
| u = p // q | |
| p = p - u * q | |
| if u.is_nonnegative and p.is_positive and q.is_positive and p < q: | |
| from sympy.functions.elementary.exponential import log | |
| from sympy.functions.elementary.integers import floor | |
| from sympy.functions.elementary.trigonometric import sin, cos, cot | |
| k = Dummy("k") | |
| t1 = q * Sum(1 / (q * k + p), (k, 0, u)) | |
| t2 = 2 * Sum(cos((2 * pi * p * k) / S(q)) * | |
| log(sin((pi * k) / S(q))), | |
| (k, 1, floor((q - 1) / S(2)))) | |
| t3 = (pi / 2) * cot((pi * p) / q) + log(2 * q) | |
| return t1 + t2 - t3 | |
| return self | |
| def _eval_rewrite_as_tractable(self, n, m=1, limitvar=None, **kwargs): | |
| from sympy.functions.special.zeta_functions import zeta | |
| from sympy.functions.special.gamma_functions import polygamma | |
| pg = self.rewrite(polygamma) | |
| if not isinstance(pg, harmonic): | |
| return pg.rewrite("tractable", deep=True) | |
| arg = m - S.One | |
| if arg.is_nonzero: | |
| return (zeta(m) - zeta(m, n+1)).rewrite("tractable", deep=True) | |
| def _eval_evalf(self, prec): | |
| if not all(x.is_number for x in self.args): | |
| return | |
| n = self.args[0]._to_mpmath(prec) | |
| m = (self.args[1] if len(self.args) > 1 else S.One)._to_mpmath(prec) | |
| if mp.isint(n) and n < 0: | |
| return S.NaN | |
| with workprec(prec): | |
| if m == 1: | |
| res = mp.harmonic(n) | |
| else: | |
| res = mp.zeta(m) - mp.zeta(m, n+1) | |
| return Expr._from_mpmath(res, prec) | |
| def fdiff(self, argindex=1): | |
| from sympy.functions.special.zeta_functions import zeta | |
| if len(self.args) == 2: | |
| n, m = self.args | |
| else: | |
| n, m = self.args + (1,) | |
| if argindex == 1: | |
| return m * zeta(m+1, n+1) | |
| else: | |
| raise ArgumentIndexError | |
| #----------------------------------------------------------------------------# | |
| # # | |
| # Euler numbers # | |
| # # | |
| #----------------------------------------------------------------------------# | |
| class euler(Function): | |
| r""" | |
| Euler numbers / Euler polynomials / Euler function | |
| The Euler numbers are given by: | |
| .. math:: E_{2n} = I \sum_{k=1}^{2n+1} \sum_{j=0}^k \binom{k}{j} | |
| \frac{(-1)^j (k-2j)^{2n+1}}{2^k I^k k} | |
| .. math:: E_{2n+1} = 0 | |
| Euler numbers and Euler polynomials are related by | |
| .. math:: E_n = 2^n E_n\left(\frac{1}{2}\right). | |
| We compute symbolic Euler polynomials using Appell sequences, | |
| but numerical evaluation of the Euler polynomial is computed | |
| more efficiently (and more accurately) using the mpmath library. | |
| The Euler polynomials are special cases of the generalized Euler function, | |
| related to the Genocchi function as | |
| .. math:: \operatorname{E}(s, a) = -\frac{\operatorname{G}(s+1, a)}{s+1} | |
| with the limit of `\psi\left(\frac{a+1}{2}\right) - \psi\left(\frac{a}{2}\right)` | |
| being taken when `s = -1`. The (ordinary) Euler function interpolating | |
| the Euler numbers is then obtained as | |
| `\operatorname{E}(s) = 2^s \operatorname{E}\left(s, \frac{1}{2}\right)`. | |
| * ``euler(n)`` gives the nth Euler number `E_n`. | |
| * ``euler(s)`` gives the Euler function `\operatorname{E}(s)`. | |
| * ``euler(n, x)`` gives the nth Euler polynomial `E_n(x)`. | |
| * ``euler(s, a)`` gives the generalized Euler function `\operatorname{E}(s, a)`. | |
| Examples | |
| ======== | |
| >>> from sympy import euler, Symbol, S | |
| >>> [euler(n) for n in range(10)] | |
| [1, 0, -1, 0, 5, 0, -61, 0, 1385, 0] | |
| >>> [2**n*euler(n,1) for n in range(10)] | |
| [1, 1, 0, -2, 0, 16, 0, -272, 0, 7936] | |
| >>> n = Symbol("n") | |
| >>> euler(n + 2*n) | |
| euler(3*n) | |
| >>> x = Symbol("x") | |
| >>> euler(n, x) | |
| euler(n, x) | |
| >>> euler(0, x) | |
| 1 | |
| >>> euler(1, x) | |
| x - 1/2 | |
| >>> euler(2, x) | |
| x**2 - x | |
| >>> euler(3, x) | |
| x**3 - 3*x**2/2 + 1/4 | |
| >>> euler(4, x) | |
| x**4 - 2*x**3 + x | |
| >>> euler(12, S.Half) | |
| 2702765/4096 | |
| >>> euler(12) | |
| 2702765 | |
| See Also | |
| ======== | |
| andre, bell, bernoulli, catalan, fibonacci, harmonic, lucas, genocchi, | |
| partition, tribonacci, sympy.polys.appellseqs.euler_poly | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Euler_numbers | |
| .. [2] https://mathworld.wolfram.com/EulerNumber.html | |
| .. [3] https://en.wikipedia.org/wiki/Alternating_permutation | |
| .. [4] https://mathworld.wolfram.com/AlternatingPermutation.html | |
| """ | |
| def eval(cls, n, x=None): | |
| if n.is_zero: | |
| return S.One | |
| elif n is S.NegativeOne: | |
| if x is None: | |
| return S.Pi/2 | |
| from sympy.functions.special.gamma_functions import digamma | |
| return digamma((x+1)/2) - digamma(x/2) | |
| elif n.is_integer is False or n.is_nonnegative is False: | |
| return | |
| # Euler numbers | |
| elif x is None: | |
| if n.is_odd and n.is_positive: | |
| return S.Zero | |
| elif n.is_Number: | |
| from mpmath import mp | |
| n = n._to_mpmath(mp.prec) | |
| res = mp.eulernum(n, exact=True) | |
| return Integer(res) | |
| # Euler polynomials | |
| elif n.is_Number: | |
| return euler_poly(n, x) | |
| def _eval_rewrite_as_Sum(self, n, x=None, **kwargs): | |
| from sympy.concrete.summations import Sum | |
| if x is None and n.is_even: | |
| k = Dummy("k", integer=True) | |
| j = Dummy("j", integer=True) | |
| n = n / 2 | |
| Em = (S.ImaginaryUnit * Sum(Sum(binomial(k, j) * (S.NegativeOne**j * | |
| (k - 2*j)**(2*n + 1)) / | |
| (2**k*S.ImaginaryUnit**k * k), (j, 0, k)), (k, 1, 2*n + 1))) | |
| return Em | |
| if x: | |
| k = Dummy("k", integer=True) | |
| return Sum(binomial(n, k)*euler(k)/2**k*(x - S.Half)**(n - k), (k, 0, n)) | |
| def _eval_rewrite_as_genocchi(self, n, x=None, **kwargs): | |
| if x is None: | |
| return Piecewise((S.Pi/2, Eq(n, -1)), | |
| (-2**n * genocchi(n+1, S.Half) / (n+1), True)) | |
| from sympy.functions.special.gamma_functions import digamma | |
| return Piecewise((digamma((x+1)/2) - digamma(x/2), Eq(n, -1)), | |
| (-genocchi(n+1, x) / (n+1), True)) | |
| def _eval_evalf(self, prec): | |
| if not all(i.is_number for i in self.args): | |
| return | |
| from mpmath import mp | |
| m, x = (self.args[0], None) if len(self.args) == 1 else self.args | |
| m = m._to_mpmath(prec) | |
| if x is not None: | |
| x = x._to_mpmath(prec) | |
| with workprec(prec): | |
| if mp.isint(m) and m >= 0: | |
| res = mp.eulernum(m) if x is None else mp.eulerpoly(m, x) | |
| else: | |
| if m == -1: | |
| res = mp.pi if x is None else mp.digamma((x+1)/2) - mp.digamma(x/2) | |
| else: | |
| y = 0.5 if x is None else x | |
| res = 2 * (mp.zeta(-m, y) - 2**(m+1) * mp.zeta(-m, (y+1)/2)) | |
| if x is None: | |
| res *= 2**m | |
| return Expr._from_mpmath(res, prec) | |
| #----------------------------------------------------------------------------# | |
| # # | |
| # Catalan numbers # | |
| # # | |
| #----------------------------------------------------------------------------# | |
| class catalan(Function): | |
| r""" | |
| Catalan numbers | |
| The `n^{th}` catalan number is given by: | |
| .. math :: C_n = \frac{1}{n+1} \binom{2n}{n} | |
| * ``catalan(n)`` gives the `n^{th}` Catalan number, `C_n` | |
| Examples | |
| ======== | |
| >>> from sympy import (Symbol, binomial, gamma, hyper, | |
| ... catalan, diff, combsimp, Rational, I) | |
| >>> [catalan(i) for i in range(1,10)] | |
| [1, 2, 5, 14, 42, 132, 429, 1430, 4862] | |
| >>> n = Symbol("n", integer=True) | |
| >>> catalan(n) | |
| catalan(n) | |
| Catalan numbers can be transformed into several other, identical | |
| expressions involving other mathematical functions | |
| >>> catalan(n).rewrite(binomial) | |
| binomial(2*n, n)/(n + 1) | |
| >>> catalan(n).rewrite(gamma) | |
| 4**n*gamma(n + 1/2)/(sqrt(pi)*gamma(n + 2)) | |
| >>> catalan(n).rewrite(hyper) | |
| hyper((-n, 1 - n), (2,), 1) | |
| For some non-integer values of n we can get closed form | |
| expressions by rewriting in terms of gamma functions: | |
| >>> catalan(Rational(1, 2)).rewrite(gamma) | |
| 8/(3*pi) | |
| We can differentiate the Catalan numbers C(n) interpreted as a | |
| continuous real function in n: | |
| >>> diff(catalan(n), n) | |
| (polygamma(0, n + 1/2) - polygamma(0, n + 2) + log(4))*catalan(n) | |
| As a more advanced example consider the following ratio | |
| between consecutive numbers: | |
| >>> combsimp((catalan(n + 1)/catalan(n)).rewrite(binomial)) | |
| 2*(2*n + 1)/(n + 2) | |
| The Catalan numbers can be generalized to complex numbers: | |
| >>> catalan(I).rewrite(gamma) | |
| 4**I*gamma(1/2 + I)/(sqrt(pi)*gamma(2 + I)) | |
| and evaluated with arbitrary precision: | |
| >>> catalan(I).evalf(20) | |
| 0.39764993382373624267 - 0.020884341620842555705*I | |
| See Also | |
| ======== | |
| andre, bell, bernoulli, euler, fibonacci, harmonic, lucas, genocchi, | |
| partition, tribonacci, sympy.functions.combinatorial.factorials.binomial | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Catalan_number | |
| .. [2] https://mathworld.wolfram.com/CatalanNumber.html | |
| .. [3] https://functions.wolfram.com/GammaBetaErf/CatalanNumber/ | |
| .. [4] http://geometer.org/mathcircles/catalan.pdf | |
| """ | |
| def eval(cls, n): | |
| from sympy.functions.special.gamma_functions import gamma | |
| if (n.is_Integer and n.is_nonnegative) or \ | |
| (n.is_noninteger and n.is_negative): | |
| return 4**n*gamma(n + S.Half)/(gamma(S.Half)*gamma(n + 2)) | |
| if (n.is_integer and n.is_negative): | |
| if (n + 1).is_negative: | |
| return S.Zero | |
| if (n + 1).is_zero: | |
| return Rational(-1, 2) | |
| def fdiff(self, argindex=1): | |
| from sympy.functions.elementary.exponential import log | |
| from sympy.functions.special.gamma_functions import polygamma | |
| n = self.args[0] | |
| return catalan(n)*(polygamma(0, n + S.Half) - polygamma(0, n + 2) + log(4)) | |
| def _eval_rewrite_as_binomial(self, n, **kwargs): | |
| return binomial(2*n, n)/(n + 1) | |
| def _eval_rewrite_as_factorial(self, n, **kwargs): | |
| return factorial(2*n) / (factorial(n+1) * factorial(n)) | |
| def _eval_rewrite_as_gamma(self, n, piecewise=True, **kwargs): | |
| from sympy.functions.special.gamma_functions import gamma | |
| # The gamma function allows to generalize Catalan numbers to complex n | |
| return 4**n*gamma(n + S.Half)/(gamma(S.Half)*gamma(n + 2)) | |
| def _eval_rewrite_as_hyper(self, n, **kwargs): | |
| from sympy.functions.special.hyper import hyper | |
| return hyper([1 - n, -n], [2], 1) | |
| def _eval_rewrite_as_Product(self, n, **kwargs): | |
| from sympy.concrete.products import Product | |
| if not (n.is_integer and n.is_nonnegative): | |
| return self | |
| k = Dummy('k', integer=True, positive=True) | |
| return Product((n + k) / k, (k, 2, n)) | |
| def _eval_is_integer(self): | |
| if self.args[0].is_integer and self.args[0].is_nonnegative: | |
| return True | |
| def _eval_is_positive(self): | |
| if self.args[0].is_nonnegative: | |
| return True | |
| def _eval_is_composite(self): | |
| if self.args[0].is_integer and (self.args[0] - 3).is_positive: | |
| return True | |
| def _eval_evalf(self, prec): | |
| from sympy.functions.special.gamma_functions import gamma | |
| if self.args[0].is_number: | |
| return self.rewrite(gamma)._eval_evalf(prec) | |
| #----------------------------------------------------------------------------# | |
| # # | |
| # Genocchi numbers # | |
| # # | |
| #----------------------------------------------------------------------------# | |
| class genocchi(Function): | |
| r""" | |
| Genocchi numbers / Genocchi polynomials / Genocchi function | |
| The Genocchi numbers are a sequence of integers `G_n` that satisfy the | |
| relation: | |
| .. math:: \frac{-2t}{1 + e^{-t}} = \sum_{n=0}^\infty \frac{G_n t^n}{n!} | |
| They are related to the Bernoulli numbers by | |
| .. math:: G_n = 2 (1 - 2^n) B_n | |
| and generalize like the Bernoulli numbers to the Genocchi polynomials and | |
| function as | |
| .. math:: \operatorname{G}(s, a) = 2 \left(\operatorname{B}(s, a) - | |
| 2^s \operatorname{B}\left(s, \frac{a+1}{2}\right)\right) | |
| .. versionchanged:: 1.12 | |
| ``genocchi(1)`` gives `-1` instead of `1`. | |
| Examples | |
| ======== | |
| >>> from sympy import genocchi, Symbol | |
| >>> [genocchi(n) for n in range(9)] | |
| [0, -1, -1, 0, 1, 0, -3, 0, 17] | |
| >>> n = Symbol('n', integer=True, positive=True) | |
| >>> genocchi(2*n + 1) | |
| 0 | |
| >>> x = Symbol('x') | |
| >>> genocchi(4, x) | |
| -4*x**3 + 6*x**2 - 1 | |
| See Also | |
| ======== | |
| bell, bernoulli, catalan, euler, fibonacci, harmonic, lucas, partition, tribonacci | |
| sympy.polys.appellseqs.genocchi_poly | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Genocchi_number | |
| .. [2] https://mathworld.wolfram.com/GenocchiNumber.html | |
| .. [3] Peter Luschny, "An introduction to the Bernoulli function", | |
| https://arxiv.org/abs/2009.06743 | |
| """ | |
| def eval(cls, n, x=None): | |
| if x is S.One: | |
| return cls(n) | |
| elif n.is_integer is False or n.is_nonnegative is False: | |
| return | |
| # Genocchi numbers | |
| elif x is None: | |
| if n.is_odd and (n-1).is_positive: | |
| return S.Zero | |
| elif n.is_Number: | |
| return 2 * (1-S(2)**n) * bernoulli(n) | |
| # Genocchi polynomials | |
| elif n.is_Number: | |
| return genocchi_poly(n, x) | |
| def _eval_rewrite_as_bernoulli(self, n, x=1, **kwargs): | |
| if x == 1 and n.is_integer and n.is_nonnegative: | |
| return 2 * (1-S(2)**n) * bernoulli(n) | |
| return 2 * (bernoulli(n, x) - 2**n * bernoulli(n, (x+1) / 2)) | |
| def _eval_rewrite_as_dirichlet_eta(self, n, x=1, **kwargs): | |
| from sympy.functions.special.zeta_functions import dirichlet_eta | |
| return -2*n * dirichlet_eta(1-n, x) | |
| def _eval_is_integer(self): | |
| if len(self.args) > 1 and self.args[1] != 1: | |
| return | |
| n = self.args[0] | |
| if n.is_integer and n.is_nonnegative: | |
| return True | |
| def _eval_is_negative(self): | |
| if len(self.args) > 1 and self.args[1] != 1: | |
| return | |
| n = self.args[0] | |
| if n.is_integer and n.is_nonnegative: | |
| if n.is_odd: | |
| return fuzzy_not((n-1).is_positive) | |
| return (n/2).is_odd | |
| def _eval_is_positive(self): | |
| if len(self.args) > 1 and self.args[1] != 1: | |
| return | |
| n = self.args[0] | |
| if n.is_integer and n.is_nonnegative: | |
| if n.is_zero or n.is_odd: | |
| return False | |
| return (n/2).is_even | |
| def _eval_is_even(self): | |
| if len(self.args) > 1 and self.args[1] != 1: | |
| return | |
| n = self.args[0] | |
| if n.is_integer and n.is_nonnegative: | |
| if n.is_even: | |
| return n.is_zero | |
| return (n-1).is_positive | |
| def _eval_is_odd(self): | |
| if len(self.args) > 1 and self.args[1] != 1: | |
| return | |
| n = self.args[0] | |
| if n.is_integer and n.is_nonnegative: | |
| if n.is_even: | |
| return fuzzy_not(n.is_zero) | |
| return fuzzy_not((n-1).is_positive) | |
| def _eval_is_prime(self): | |
| if len(self.args) > 1 and self.args[1] != 1: | |
| return | |
| n = self.args[0] | |
| # only G_6 = -3 and G_8 = 17 are prime, | |
| # but SymPy does not consider negatives as prime | |
| # so only n=8 is tested | |
| return (n-8).is_zero | |
| def _eval_evalf(self, prec): | |
| if all(i.is_number for i in self.args): | |
| return self.rewrite(bernoulli)._eval_evalf(prec) | |
| #----------------------------------------------------------------------------# | |
| # # | |
| # Andre numbers # | |
| # # | |
| #----------------------------------------------------------------------------# | |
| class andre(Function): | |
| r""" | |
| Andre numbers / Andre function | |
| The Andre number `\mathcal{A}_n` is Luschny's name for half the number of | |
| *alternating permutations* on `n` elements, where a permutation is alternating | |
| if adjacent elements alternately compare "greater" and "smaller" going from | |
| left to right. For example, `2 < 3 > 1 < 4` is an alternating permutation. | |
| This sequence is A000111 in the OEIS, which assigns the names *up/down numbers* | |
| and *Euler zigzag numbers*. It satisfies a recurrence relation similar to that | |
| for the Catalan numbers, with `\mathcal{A}_0 = 1` and | |
| .. math:: 2 \mathcal{A}_{n+1} = \sum_{k=0}^n \binom{n}{k} \mathcal{A}_k \mathcal{A}_{n-k} | |
| The Bernoulli and Euler numbers are signed transformations of the odd- and | |
| even-indexed elements of this sequence respectively: | |
| .. math :: \operatorname{B}_{2k} = \frac{2k \mathcal{A}_{2k-1}}{(-4)^k - (-16)^k} | |
| .. math :: \operatorname{E}_{2k} = (-1)^k \mathcal{A}_{2k} | |
| Like the Bernoulli and Euler numbers, the Andre numbers are interpolated by the | |
| entire Andre function: | |
| .. math :: \mathcal{A}(s) = (-i)^{s+1} \operatorname{Li}_{-s}(i) + | |
| i^{s+1} \operatorname{Li}_{-s}(-i) = \\ \frac{2 \Gamma(s+1)}{(2\pi)^{s+1}} | |
| (\zeta(s+1, 1/4) - \zeta(s+1, 3/4) \cos{\pi s}) | |
| Examples | |
| ======== | |
| >>> from sympy import andre, euler, bernoulli | |
| >>> [andre(n) for n in range(11)] | |
| [1, 1, 1, 2, 5, 16, 61, 272, 1385, 7936, 50521] | |
| >>> [(-1)**k * andre(2*k) for k in range(7)] | |
| [1, -1, 5, -61, 1385, -50521, 2702765] | |
| >>> [euler(2*k) for k in range(7)] | |
| [1, -1, 5, -61, 1385, -50521, 2702765] | |
| >>> [andre(2*k-1) * (2*k) / ((-4)**k - (-16)**k) for k in range(1, 8)] | |
| [1/6, -1/30, 1/42, -1/30, 5/66, -691/2730, 7/6] | |
| >>> [bernoulli(2*k) for k in range(1, 8)] | |
| [1/6, -1/30, 1/42, -1/30, 5/66, -691/2730, 7/6] | |
| See Also | |
| ======== | |
| bernoulli, catalan, euler, sympy.polys.appellseqs.andre_poly | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Alternating_permutation | |
| .. [2] https://mathworld.wolfram.com/EulerZigzagNumber.html | |
| .. [3] Peter Luschny, "An introduction to the Bernoulli function", | |
| https://arxiv.org/abs/2009.06743 | |
| """ | |
| def eval(cls, n): | |
| if n is S.NaN: | |
| return S.NaN | |
| elif n is S.Infinity: | |
| return S.Infinity | |
| if n.is_zero: | |
| return S.One | |
| elif n == -1: | |
| return -log(2) | |
| elif n == -2: | |
| return -2*S.Catalan | |
| elif n.is_Integer: | |
| if n.is_nonnegative and n.is_even: | |
| return abs(euler(n)) | |
| elif n.is_odd: | |
| from sympy.functions.special.zeta_functions import zeta | |
| m = -n-1 | |
| return I**m * Rational(1-2**m, 4**m) * zeta(-n) | |
| def _eval_rewrite_as_zeta(self, s, **kwargs): | |
| from sympy.functions.elementary.trigonometric import cos | |
| from sympy.functions.special.gamma_functions import gamma | |
| from sympy.functions.special.zeta_functions import zeta | |
| return 2 * gamma(s+1) / (2*pi)**(s+1) * \ | |
| (zeta(s+1, S.One/4) - cos(pi*s) * zeta(s+1, S(3)/4)) | |
| def _eval_rewrite_as_polylog(self, s, **kwargs): | |
| from sympy.functions.special.zeta_functions import polylog | |
| return (-I)**(s+1) * polylog(-s, I) + I**(s+1) * polylog(-s, -I) | |
| def _eval_is_integer(self): | |
| n = self.args[0] | |
| if n.is_integer and n.is_nonnegative: | |
| return True | |
| def _eval_is_positive(self): | |
| if self.args[0].is_nonnegative: | |
| return True | |
| def _eval_evalf(self, prec): | |
| if not self.args[0].is_number: | |
| return | |
| s = self.args[0]._to_mpmath(prec+12) | |
| with workprec(prec+12): | |
| sp, cp = mp.sinpi(s/2), mp.cospi(s/2) | |
| res = 2*mp.dirichlet(-s, (-sp, cp, sp, -cp)) | |
| return Expr._from_mpmath(res, prec) | |
| #----------------------------------------------------------------------------# | |
| # # | |
| # Partition numbers # | |
| # # | |
| #----------------------------------------------------------------------------# | |
| class partition(Function): | |
| r""" | |
| Partition numbers | |
| The Partition numbers are a sequence of integers `p_n` that represent the | |
| number of distinct ways of representing `n` as a sum of natural numbers | |
| (with order irrelevant). The generating function for `p_n` is given by: | |
| .. math:: \sum_{n=0}^\infty p_n x^n = \prod_{k=1}^\infty (1 - x^k)^{-1} | |
| Examples | |
| ======== | |
| >>> from sympy import partition, Symbol | |
| >>> [partition(n) for n in range(9)] | |
| [1, 1, 2, 3, 5, 7, 11, 15, 22] | |
| >>> n = Symbol('n', integer=True, negative=True) | |
| >>> partition(n) | |
| 0 | |
| See Also | |
| ======== | |
| bell, bernoulli, catalan, euler, fibonacci, harmonic, lucas, genocchi, tribonacci | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Partition_(number_theory%29 | |
| .. [2] https://en.wikipedia.org/wiki/Pentagonal_number_theorem | |
| """ | |
| is_integer = True | |
| is_nonnegative = True | |
| def eval(cls, n): | |
| if n.is_integer is False: | |
| raise TypeError("n should be an integer") | |
| if n.is_negative is True: | |
| return S.Zero | |
| if n.is_zero is True or n is S.One: | |
| return S.One | |
| if n.is_Integer is True: | |
| return S(_partition(as_int(n))) | |
| def _eval_is_positive(self): | |
| if self.args[0].is_nonnegative is True: | |
| return True | |
| class divisor_sigma(Function): | |
| r""" | |
| Calculate the divisor function `\sigma_k(n)` for positive integer n | |
| ``divisor_sigma(n, k)`` is equal to ``sum([x**k for x in divisors(n)])`` | |
| If n's prime factorization is: | |
| .. math :: | |
| n = \prod_{i=1}^\omega p_i^{m_i}, | |
| then | |
| .. math :: | |
| \sigma_k(n) = \prod_{i=1}^\omega (1+p_i^k+p_i^{2k}+\cdots | |
| + p_i^{m_ik}). | |
| Examples | |
| ======== | |
| >>> from sympy.functions.combinatorial.numbers import divisor_sigma | |
| >>> divisor_sigma(18, 0) | |
| 6 | |
| >>> divisor_sigma(39, 1) | |
| 56 | |
| >>> divisor_sigma(12, 2) | |
| 210 | |
| >>> divisor_sigma(37) | |
| 38 | |
| See Also | |
| ======== | |
| sympy.ntheory.factor_.divisor_count, totient, sympy.ntheory.factor_.divisors, sympy.ntheory.factor_.factorint | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Divisor_function | |
| """ | |
| is_integer = True | |
| is_positive = True | |
| def eval(cls, n, k=S.One): | |
| if n.is_integer is False: | |
| raise TypeError("n should be an integer") | |
| if n.is_positive is False: | |
| raise ValueError("n should be a positive integer") | |
| if k.is_integer is False: | |
| raise TypeError("k should be an integer") | |
| if k.is_nonnegative is False: | |
| raise ValueError("k should be a nonnegative integer") | |
| if n.is_prime is True: | |
| return 1 + n**k | |
| if n is S.One: | |
| return S.One | |
| if n.is_Integer is True: | |
| if k.is_zero is True: | |
| return Mul(*[e + 1 for e in factorint(n).values()]) | |
| if k.is_Integer is True: | |
| return S(_divisor_sigma(as_int(n), as_int(k))) | |
| if k.is_zero is False: | |
| return Mul(*[cancel((p**(k*(e + 1)) - 1) / (p**k - 1)) for p, e in factorint(n).items()]) | |
| class udivisor_sigma(Function): | |
| r""" | |
| Calculate the unitary divisor function `\sigma_k^*(n)` for positive integer n | |
| ``udivisor_sigma(n, k)`` is equal to ``sum([x**k for x in udivisors(n)])`` | |
| If n's prime factorization is: | |
| .. math :: | |
| n = \prod_{i=1}^\omega p_i^{m_i}, | |
| then | |
| .. math :: | |
| \sigma_k^*(n) = \prod_{i=1}^\omega (1+ p_i^{m_ik}). | |
| Parameters | |
| ========== | |
| k : power of divisors in the sum | |
| for k = 0, 1: | |
| ``udivisor_sigma(n, 0)`` is equal to ``udivisor_count(n)`` | |
| ``udivisor_sigma(n, 1)`` is equal to ``sum(udivisors(n))`` | |
| Default for k is 1. | |
| Examples | |
| ======== | |
| >>> from sympy.functions.combinatorial.numbers import udivisor_sigma | |
| >>> udivisor_sigma(18, 0) | |
| 4 | |
| >>> udivisor_sigma(74, 1) | |
| 114 | |
| >>> udivisor_sigma(36, 3) | |
| 47450 | |
| >>> udivisor_sigma(111) | |
| 152 | |
| See Also | |
| ======== | |
| sympy.ntheory.factor_.divisor_count, totient, sympy.ntheory.factor_.divisors, | |
| sympy.ntheory.factor_.udivisors, sympy.ntheory.factor_.udivisor_count, divisor_sigma, | |
| sympy.ntheory.factor_.factorint | |
| References | |
| ========== | |
| .. [1] https://mathworld.wolfram.com/UnitaryDivisorFunction.html | |
| """ | |
| is_integer = True | |
| is_positive = True | |
| def eval(cls, n, k=S.One): | |
| if n.is_integer is False: | |
| raise TypeError("n should be an integer") | |
| if n.is_positive is False: | |
| raise ValueError("n should be a positive integer") | |
| if k.is_integer is False: | |
| raise TypeError("k should be an integer") | |
| if k.is_nonnegative is False: | |
| raise ValueError("k should be a nonnegative integer") | |
| if n.is_prime is True: | |
| return 1 + n**k | |
| if n.is_Integer: | |
| return Mul(*[1+p**(k*e) for p, e in factorint(n).items()]) | |
| class legendre_symbol(Function): | |
| r""" | |
| Returns the Legendre symbol `(a / p)`. | |
| For an integer ``a`` and an odd prime ``p``, the Legendre symbol is | |
| defined as | |
| .. math :: | |
| \genfrac(){}{}{a}{p} = \begin{cases} | |
| 0 & \text{if } p \text{ divides } a\\ | |
| 1 & \text{if } a \text{ is a quadratic residue modulo } p\\ | |
| -1 & \text{if } a \text{ is a quadratic nonresidue modulo } p | |
| \end{cases} | |
| Examples | |
| ======== | |
| >>> from sympy.functions.combinatorial.numbers import legendre_symbol | |
| >>> [legendre_symbol(i, 7) for i in range(7)] | |
| [0, 1, 1, -1, 1, -1, -1] | |
| >>> sorted(set([i**2 % 7 for i in range(7)])) | |
| [0, 1, 2, 4] | |
| See Also | |
| ======== | |
| sympy.ntheory.residue_ntheory.is_quad_residue, jacobi_symbol | |
| """ | |
| is_integer = True | |
| is_prime = False | |
| def eval(cls, a, p): | |
| if a.is_integer is False: | |
| raise TypeError("a should be an integer") | |
| if p.is_integer is False: | |
| raise TypeError("p should be an integer") | |
| if p.is_prime is False or p.is_odd is False: | |
| raise ValueError("p should be an odd prime integer") | |
| if (a % p).is_zero is True: | |
| return S.Zero | |
| if a is S.One: | |
| return S.One | |
| if a.is_Integer is True and p.is_Integer is True: | |
| return S(legendre(as_int(a), as_int(p))) | |
| class jacobi_symbol(Function): | |
| r""" | |
| Returns the Jacobi symbol `(m / n)`. | |
| For any integer ``m`` and any positive odd integer ``n`` the Jacobi symbol | |
| is defined as the product of the Legendre symbols corresponding to the | |
| prime factors of ``n``: | |
| .. math :: | |
| \genfrac(){}{}{m}{n} = | |
| \genfrac(){}{}{m}{p^{1}}^{\alpha_1} | |
| \genfrac(){}{}{m}{p^{2}}^{\alpha_2} | |
| ... | |
| \genfrac(){}{}{m}{p^{k}}^{\alpha_k} | |
| \text{ where } n = | |
| p_1^{\alpha_1} | |
| p_2^{\alpha_2} | |
| ... | |
| p_k^{\alpha_k} | |
| Like the Legendre symbol, if the Jacobi symbol `\genfrac(){}{}{m}{n} = -1` | |
| then ``m`` is a quadratic nonresidue modulo ``n``. | |
| But, unlike the Legendre symbol, if the Jacobi symbol | |
| `\genfrac(){}{}{m}{n} = 1` then ``m`` may or may not be a quadratic residue | |
| modulo ``n``. | |
| Examples | |
| ======== | |
| >>> from sympy.functions.combinatorial.numbers import jacobi_symbol, legendre_symbol | |
| >>> from sympy import S | |
| >>> jacobi_symbol(45, 77) | |
| -1 | |
| >>> jacobi_symbol(60, 121) | |
| 1 | |
| The relationship between the ``jacobi_symbol`` and ``legendre_symbol`` can | |
| be demonstrated as follows: | |
| >>> L = legendre_symbol | |
| >>> S(45).factors() | |
| {3: 2, 5: 1} | |
| >>> jacobi_symbol(7, 45) == L(7, 3)**2 * L(7, 5)**1 | |
| True | |
| See Also | |
| ======== | |
| sympy.ntheory.residue_ntheory.is_quad_residue, legendre_symbol | |
| """ | |
| is_integer = True | |
| is_prime = False | |
| def eval(cls, m, n): | |
| if m.is_integer is False: | |
| raise TypeError("m should be an integer") | |
| if n.is_integer is False: | |
| raise TypeError("n should be an integer") | |
| if n.is_positive is False or n.is_odd is False: | |
| raise ValueError("n should be an odd positive integer") | |
| if m is S.One or n is S.One: | |
| return S.One | |
| if (m % n).is_zero is True: | |
| return S.Zero | |
| if m.is_Integer is True and n.is_Integer is True: | |
| return S(jacobi(as_int(m), as_int(n))) | |
| class kronecker_symbol(Function): | |
| r""" | |
| Returns the Kronecker symbol `(a / n)`. | |
| Examples | |
| ======== | |
| >>> from sympy.functions.combinatorial.numbers import kronecker_symbol | |
| >>> kronecker_symbol(45, 77) | |
| -1 | |
| >>> kronecker_symbol(13, -120) | |
| 1 | |
| See Also | |
| ======== | |
| jacobi_symbol, legendre_symbol | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Kronecker_symbol | |
| """ | |
| is_integer = True | |
| is_prime = False | |
| def eval(cls, a, n): | |
| if a.is_integer is False: | |
| raise TypeError("a should be an integer") | |
| if n.is_integer is False: | |
| raise TypeError("n should be an integer") | |
| if a is S.One or n is S.One: | |
| return S.One | |
| if a.is_Integer is True and n.is_Integer is True: | |
| return S(kronecker(as_int(a), as_int(n))) | |
| class mobius(Function): | |
| """ | |
| Mobius function maps natural number to {-1, 0, 1} | |
| It is defined as follows: | |
| 1) `1` if `n = 1`. | |
| 2) `0` if `n` has a squared prime factor. | |
| 3) `(-1)^k` if `n` is a square-free positive integer with `k` | |
| number of prime factors. | |
| It is an important multiplicative function in number theory | |
| and combinatorics. It has applications in mathematical series, | |
| algebraic number theory and also physics (Fermion operator has very | |
| concrete realization with Mobius Function model). | |
| Examples | |
| ======== | |
| >>> from sympy.functions.combinatorial.numbers import mobius | |
| >>> mobius(13*7) | |
| 1 | |
| >>> mobius(1) | |
| 1 | |
| >>> mobius(13*7*5) | |
| -1 | |
| >>> mobius(13**2) | |
| 0 | |
| Even in the case of a symbol, if it clearly contains a squared prime factor, it will be zero. | |
| >>> from sympy import Symbol | |
| >>> n = Symbol("n", integer=True, positive=True) | |
| >>> mobius(4*n) | |
| 0 | |
| >>> mobius(n**2) | |
| 0 | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/M%C3%B6bius_function | |
| .. [2] Thomas Koshy "Elementary Number Theory with Applications" | |
| .. [3] https://oeis.org/A008683 | |
| """ | |
| is_integer = True | |
| is_prime = False | |
| def eval(cls, n): | |
| if n.is_integer is False: | |
| raise TypeError("n should be an integer") | |
| if n.is_positive is False: | |
| raise ValueError("n should be a positive integer") | |
| if n.is_prime is True: | |
| return S.NegativeOne | |
| if n is S.One: | |
| return S.One | |
| result = None | |
| for m, e in (_.as_base_exp() for _ in Mul.make_args(n)): | |
| if m.is_integer is True and m.is_positive is True and \ | |
| e.is_integer is True and e.is_positive is True: | |
| lt = is_lt(S.One, e) # 1 < e | |
| if lt is True: | |
| result = S.Zero | |
| elif m.is_Integer is True: | |
| factors = factorint(m) | |
| if any(v > 1 for v in factors.values()): | |
| result = S.Zero | |
| elif lt is False: | |
| s = S.NegativeOne if len(factors) % 2 else S.One | |
| if result is None: | |
| result = s | |
| else: | |
| result *= s | |
| else: | |
| return | |
| return result | |
| class primenu(Function): | |
| r""" | |
| Calculate the number of distinct prime factors for a positive integer n. | |
| If n's prime factorization is: | |
| .. math :: | |
| n = \prod_{i=1}^k p_i^{m_i}, | |
| then ``primenu(n)`` or `\nu(n)` is: | |
| .. math :: | |
| \nu(n) = k. | |
| Examples | |
| ======== | |
| >>> from sympy.functions.combinatorial.numbers import primenu | |
| >>> primenu(1) | |
| 0 | |
| >>> primenu(30) | |
| 3 | |
| See Also | |
| ======== | |
| sympy.ntheory.factor_.factorint | |
| References | |
| ========== | |
| .. [1] https://mathworld.wolfram.com/PrimeFactor.html | |
| .. [2] https://oeis.org/A001221 | |
| """ | |
| is_integer = True | |
| is_nonnegative = True | |
| def eval(cls, n): | |
| if n.is_integer is False: | |
| raise TypeError("n should be an integer") | |
| if n.is_positive is False: | |
| raise ValueError("n should be a positive integer") | |
| if n.is_prime is True: | |
| return S.One | |
| if n is S.One: | |
| return S.Zero | |
| if n.is_Integer is True: | |
| return S(len(factorint(n))) | |
| class primeomega(Function): | |
| r""" | |
| Calculate the number of prime factors counting multiplicities for a | |
| positive integer n. | |
| If n's prime factorization is: | |
| .. math :: | |
| n = \prod_{i=1}^k p_i^{m_i}, | |
| then ``primeomega(n)`` or `\Omega(n)` is: | |
| .. math :: | |
| \Omega(n) = \sum_{i=1}^k m_i. | |
| Examples | |
| ======== | |
| >>> from sympy.functions.combinatorial.numbers import primeomega | |
| >>> primeomega(1) | |
| 0 | |
| >>> primeomega(20) | |
| 3 | |
| See Also | |
| ======== | |
| sympy.ntheory.factor_.factorint | |
| References | |
| ========== | |
| .. [1] https://mathworld.wolfram.com/PrimeFactor.html | |
| .. [2] https://oeis.org/A001222 | |
| """ | |
| is_integer = True | |
| is_nonnegative = True | |
| def eval(cls, n): | |
| if n.is_integer is False: | |
| raise TypeError("n should be an integer") | |
| if n.is_positive is False: | |
| raise ValueError("n should be a positive integer") | |
| if n.is_prime is True: | |
| return S.One | |
| if n is S.One: | |
| return S.Zero | |
| if n.is_Integer is True: | |
| return S(sum(factorint(n).values())) | |
| class totient(Function): | |
| r""" | |
| Calculate the Euler totient function phi(n) | |
| ``totient(n)`` or `\phi(n)` is the number of positive integers `\leq` n | |
| that are relatively prime to n. | |
| Examples | |
| ======== | |
| >>> from sympy.functions.combinatorial.numbers import totient | |
| >>> totient(1) | |
| 1 | |
| >>> totient(25) | |
| 20 | |
| >>> totient(45) == totient(5)*totient(9) | |
| True | |
| See Also | |
| ======== | |
| sympy.ntheory.factor_.divisor_count | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Euler%27s_totient_function | |
| .. [2] https://mathworld.wolfram.com/TotientFunction.html | |
| .. [3] https://oeis.org/A000010 | |
| """ | |
| is_integer = True | |
| is_positive = True | |
| def eval(cls, n): | |
| if n.is_integer is False: | |
| raise TypeError("n should be an integer") | |
| if n.is_positive is False: | |
| raise ValueError("n should be a positive integer") | |
| if n is S.One: | |
| return S.One | |
| if n.is_prime is True: | |
| return n - 1 | |
| if isinstance(n, Dict): | |
| return S(prod(p**(k-1)*(p-1) for p, k in n.items())) | |
| if n.is_Integer is True: | |
| return S(prod(p**(k-1)*(p-1) for p, k in factorint(n).items())) | |
| class reduced_totient(Function): | |
| r""" | |
| Calculate the Carmichael reduced totient function lambda(n) | |
| ``reduced_totient(n)`` or `\lambda(n)` is the smallest m > 0 such that | |
| `k^m \equiv 1 \mod n` for all k relatively prime to n. | |
| Examples | |
| ======== | |
| >>> from sympy.functions.combinatorial.numbers import reduced_totient | |
| >>> reduced_totient(1) | |
| 1 | |
| >>> reduced_totient(8) | |
| 2 | |
| >>> reduced_totient(30) | |
| 4 | |
| See Also | |
| ======== | |
| totient | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Carmichael_function | |
| .. [2] https://mathworld.wolfram.com/CarmichaelFunction.html | |
| .. [3] https://oeis.org/A002322 | |
| """ | |
| is_integer = True | |
| is_positive = True | |
| def eval(cls, n): | |
| if n.is_integer is False: | |
| raise TypeError("n should be an integer") | |
| if n.is_positive is False: | |
| raise ValueError("n should be a positive integer") | |
| if n is S.One: | |
| return S.One | |
| if n.is_prime is True: | |
| return n - 1 | |
| if isinstance(n, Dict): | |
| t = 1 | |
| if 2 in n: | |
| t = (1 << (n[2] - 2)) if 2 < n[2] else n[2] | |
| return S(lcm(int(t), *(int(p-1)*int(p)**int(k-1) for p, k in n.items() if p != 2))) | |
| if n.is_Integer is True: | |
| n, t = remove(int(n), 2) | |
| if not t: | |
| t = 1 | |
| elif 2 < t: | |
| t = 1 << (t - 2) | |
| return S(lcm(t, *((p-1)*p**(k-1) for p, k in factorint(n).items()))) | |
| class primepi(Function): | |
| r""" Represents the prime counting function pi(n) = the number | |
| of prime numbers less than or equal to n. | |
| Examples | |
| ======== | |
| >>> from sympy.functions.combinatorial.numbers import primepi | |
| >>> from sympy import prime, prevprime, isprime | |
| >>> primepi(25) | |
| 9 | |
| So there are 9 primes less than or equal to 25. Is 25 prime? | |
| >>> isprime(25) | |
| False | |
| It is not. So the first prime less than 25 must be the | |
| 9th prime: | |
| >>> prevprime(25) == prime(9) | |
| True | |
| See Also | |
| ======== | |
| sympy.ntheory.primetest.isprime : Test if n is prime | |
| sympy.ntheory.generate.primerange : Generate all primes in a given range | |
| sympy.ntheory.generate.prime : Return the nth prime | |
| References | |
| ========== | |
| .. [1] https://oeis.org/A000720 | |
| """ | |
| is_integer = True | |
| is_nonnegative = True | |
| def eval(cls, n): | |
| if n is S.Infinity: | |
| return S.Infinity | |
| if n is S.NegativeInfinity: | |
| return S.Zero | |
| if n.is_real is False: | |
| raise TypeError("n should be a real") | |
| if is_lt(n, S(2)) is True: | |
| return S.Zero | |
| try: | |
| n = int(n) | |
| except TypeError: | |
| return | |
| return S(_primepi(n)) | |
| ####################################################################### | |
| ### | |
| ### Functions for enumerating partitions, permutations and combinations | |
| ### | |
| ####################################################################### | |
| class _MultisetHistogram(tuple): | |
| pass | |
| _N = -1 | |
| _ITEMS = -2 | |
| _M = slice(None, _ITEMS) | |
| def _multiset_histogram(n): | |
| """Return tuple used in permutation and combination counting. Input | |
| is a dictionary giving items with counts as values or a sequence of | |
| items (which need not be sorted). | |
| The data is stored in a class deriving from tuple so it is easily | |
| recognized and so it can be converted easily to a list. | |
| """ | |
| if isinstance(n, dict): # item: count | |
| if not all(isinstance(v, int) and v >= 0 for v in n.values()): | |
| raise ValueError | |
| tot = sum(n.values()) | |
| items = sum(1 for k in n if n[k] > 0) | |
| return _MultisetHistogram([n[k] for k in n if n[k] > 0] + [items, tot]) | |
| else: | |
| n = list(n) | |
| s = set(n) | |
| lens = len(s) | |
| lenn = len(n) | |
| if lens == lenn: | |
| n = [1]*lenn + [lenn, lenn] | |
| return _MultisetHistogram(n) | |
| m = dict(zip(s, range(lens))) | |
| d = dict(zip(range(lens), (0,)*lens)) | |
| for i in n: | |
| d[m[i]] += 1 | |
| return _multiset_histogram(d) | |
| def nP(n, k=None, replacement=False): | |
| """Return the number of permutations of ``n`` items taken ``k`` at a time. | |
| Possible values for ``n``: | |
| integer - set of length ``n`` | |
| sequence - converted to a multiset internally | |
| multiset - {element: multiplicity} | |
| If ``k`` is None then the total of all permutations of length 0 | |
| through the number of items represented by ``n`` will be returned. | |
| If ``replacement`` is True then a given item can appear more than once | |
| in the ``k`` items. (For example, for 'ab' permutations of 2 would | |
| include 'aa', 'ab', 'ba' and 'bb'.) The multiplicity of elements in | |
| ``n`` is ignored when ``replacement`` is True but the total number | |
| of elements is considered since no element can appear more times than | |
| the number of elements in ``n``. | |
| Examples | |
| ======== | |
| >>> from sympy.functions.combinatorial.numbers import nP | |
| >>> from sympy.utilities.iterables import multiset_permutations, multiset | |
| >>> nP(3, 2) | |
| 6 | |
| >>> nP('abc', 2) == nP(multiset('abc'), 2) == 6 | |
| True | |
| >>> nP('aab', 2) | |
| 3 | |
| >>> nP([1, 2, 2], 2) | |
| 3 | |
| >>> [nP(3, i) for i in range(4)] | |
| [1, 3, 6, 6] | |
| >>> nP(3) == sum(_) | |
| True | |
| When ``replacement`` is True, each item can have multiplicity | |
| equal to the length represented by ``n``: | |
| >>> nP('aabc', replacement=True) | |
| 121 | |
| >>> [len(list(multiset_permutations('aaaabbbbcccc', i))) for i in range(5)] | |
| [1, 3, 9, 27, 81] | |
| >>> sum(_) | |
| 121 | |
| See Also | |
| ======== | |
| sympy.utilities.iterables.multiset_permutations | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Permutation | |
| """ | |
| try: | |
| n = as_int(n) | |
| except ValueError: | |
| return Integer(_nP(_multiset_histogram(n), k, replacement)) | |
| return Integer(_nP(n, k, replacement)) | |
| def _nP(n, k=None, replacement=False): | |
| if k == 0: | |
| return 1 | |
| if isinstance(n, SYMPY_INTS): # n different items | |
| # assert n >= 0 | |
| if k is None: | |
| return sum(_nP(n, i, replacement) for i in range(n + 1)) | |
| elif replacement: | |
| return n**k | |
| elif k > n: | |
| return 0 | |
| elif k == n: | |
| return factorial(k) | |
| elif k == 1: | |
| return n | |
| else: | |
| # assert k >= 0 | |
| return _product(n - k + 1, n) | |
| elif isinstance(n, _MultisetHistogram): | |
| if k is None: | |
| return sum(_nP(n, i, replacement) for i in range(n[_N] + 1)) | |
| elif replacement: | |
| return n[_ITEMS]**k | |
| elif k == n[_N]: | |
| return factorial(k)/prod([factorial(i) for i in n[_M] if i > 1]) | |
| elif k > n[_N]: | |
| return 0 | |
| elif k == 1: | |
| return n[_ITEMS] | |
| else: | |
| # assert k >= 0 | |
| tot = 0 | |
| n = list(n) | |
| for i in range(len(n[_M])): | |
| if not n[i]: | |
| continue | |
| n[_N] -= 1 | |
| if n[i] == 1: | |
| n[i] = 0 | |
| n[_ITEMS] -= 1 | |
| tot += _nP(_MultisetHistogram(n), k - 1) | |
| n[_ITEMS] += 1 | |
| n[i] = 1 | |
| else: | |
| n[i] -= 1 | |
| tot += _nP(_MultisetHistogram(n), k - 1) | |
| n[i] += 1 | |
| n[_N] += 1 | |
| return tot | |
| def _AOP_product(n): | |
| """for n = (m1, m2, .., mk) return the coefficients of the polynomial, | |
| prod(sum(x**i for i in range(nj + 1)) for nj in n); i.e. the coefficients | |
| of the product of AOPs (all-one polynomials) or order given in n. The | |
| resulting coefficient corresponding to x**r is the number of r-length | |
| combinations of sum(n) elements with multiplicities given in n. | |
| The coefficients are given as a default dictionary (so if a query is made | |
| for a key that is not present, 0 will be returned). | |
| Examples | |
| ======== | |
| >>> from sympy.functions.combinatorial.numbers import _AOP_product | |
| >>> from sympy.abc import x | |
| >>> n = (2, 2, 3) # e.g. aabbccc | |
| >>> prod = ((x**2 + x + 1)*(x**2 + x + 1)*(x**3 + x**2 + x + 1)).expand() | |
| >>> c = _AOP_product(n); dict(c) | |
| {0: 1, 1: 3, 2: 6, 3: 8, 4: 8, 5: 6, 6: 3, 7: 1} | |
| >>> [c[i] for i in range(8)] == [prod.coeff(x, i) for i in range(8)] | |
| True | |
| The generating poly used here is the same as that listed in | |
| https://tinyurl.com/cep849r, but in a refactored form. | |
| """ | |
| n = list(n) | |
| ord = sum(n) | |
| need = (ord + 2)//2 | |
| rv = [1]*(n.pop() + 1) | |
| rv.extend((0,) * (need - len(rv))) | |
| rv = rv[:need] | |
| while n: | |
| ni = n.pop() | |
| N = ni + 1 | |
| was = rv[:] | |
| for i in range(1, min(N, len(rv))): | |
| rv[i] += rv[i - 1] | |
| for i in range(N, need): | |
| rv[i] += rv[i - 1] - was[i - N] | |
| rev = list(reversed(rv)) | |
| if ord % 2: | |
| rv = rv + rev | |
| else: | |
| rv[-1:] = rev | |
| d = defaultdict(int) | |
| for i, r in enumerate(rv): | |
| d[i] = r | |
| return d | |
| def nC(n, k=None, replacement=False): | |
| """Return the number of combinations of ``n`` items taken ``k`` at a time. | |
| Possible values for ``n``: | |
| integer - set of length ``n`` | |
| sequence - converted to a multiset internally | |
| multiset - {element: multiplicity} | |
| If ``k`` is None then the total of all combinations of length 0 | |
| through the number of items represented in ``n`` will be returned. | |
| If ``replacement`` is True then a given item can appear more than once | |
| in the ``k`` items. (For example, for 'ab' sets of 2 would include 'aa', | |
| 'ab', and 'bb'.) The multiplicity of elements in ``n`` is ignored when | |
| ``replacement`` is True but the total number of elements is considered | |
| since no element can appear more times than the number of elements in | |
| ``n``. | |
| Examples | |
| ======== | |
| >>> from sympy.functions.combinatorial.numbers import nC | |
| >>> from sympy.utilities.iterables import multiset_combinations | |
| >>> nC(3, 2) | |
| 3 | |
| >>> nC('abc', 2) | |
| 3 | |
| >>> nC('aab', 2) | |
| 2 | |
| When ``replacement`` is True, each item can have multiplicity | |
| equal to the length represented by ``n``: | |
| >>> nC('aabc', replacement=True) | |
| 35 | |
| >>> [len(list(multiset_combinations('aaaabbbbcccc', i))) for i in range(5)] | |
| [1, 3, 6, 10, 15] | |
| >>> sum(_) | |
| 35 | |
| If there are ``k`` items with multiplicities ``m_1, m_2, ..., m_k`` | |
| then the total of all combinations of length 0 through ``k`` is the | |
| product, ``(m_1 + 1)*(m_2 + 1)*...*(m_k + 1)``. When the multiplicity | |
| of each item is 1 (i.e., k unique items) then there are 2**k | |
| combinations. For example, if there are 4 unique items, the total number | |
| of combinations is 16: | |
| >>> sum(nC(4, i) for i in range(5)) | |
| 16 | |
| See Also | |
| ======== | |
| sympy.utilities.iterables.multiset_combinations | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Combination | |
| .. [2] https://tinyurl.com/cep849r | |
| """ | |
| if isinstance(n, SYMPY_INTS): | |
| if k is None: | |
| if not replacement: | |
| return 2**n | |
| return sum(nC(n, i, replacement) for i in range(n + 1)) | |
| if k < 0: | |
| raise ValueError("k cannot be negative") | |
| if replacement: | |
| return binomial(n + k - 1, k) | |
| return binomial(n, k) | |
| if isinstance(n, _MultisetHistogram): | |
| N = n[_N] | |
| if k is None: | |
| if not replacement: | |
| return prod(m + 1 for m in n[_M]) | |
| return sum(nC(n, i, replacement) for i in range(N + 1)) | |
| elif replacement: | |
| return nC(n[_ITEMS], k, replacement) | |
| # assert k >= 0 | |
| elif k in (1, N - 1): | |
| return n[_ITEMS] | |
| elif k in (0, N): | |
| return 1 | |
| return _AOP_product(tuple(n[_M]))[k] | |
| else: | |
| return nC(_multiset_histogram(n), k, replacement) | |
| def _eval_stirling1(n, k): | |
| if n == k == 0: | |
| return S.One | |
| if 0 in (n, k): | |
| return S.Zero | |
| # some special values | |
| if n == k: | |
| return S.One | |
| elif k == n - 1: | |
| return binomial(n, 2) | |
| elif k == n - 2: | |
| return (3*n - 1)*binomial(n, 3)/4 | |
| elif k == n - 3: | |
| return binomial(n, 2)*binomial(n, 4) | |
| return _stirling1(n, k) | |
| def _stirling1(n, k): | |
| row = [0, 1]+[0]*(k-1) # for n = 1 | |
| for i in range(2, n+1): | |
| for j in range(min(k,i), 0, -1): | |
| row[j] = (i-1) * row[j] + row[j-1] | |
| return Integer(row[k]) | |
| def _eval_stirling2(n, k): | |
| if n == k == 0: | |
| return S.One | |
| if 0 in (n, k): | |
| return S.Zero | |
| # some special values | |
| if n == k: | |
| return S.One | |
| elif k == n - 1: | |
| return binomial(n, 2) | |
| elif k == 1: | |
| return S.One | |
| elif k == 2: | |
| return Integer(2**(n - 1) - 1) | |
| return _stirling2(n, k) | |
| def _stirling2(n, k): | |
| row = [0, 1]+[0]*(k-1) # for n = 1 | |
| for i in range(2, n+1): | |
| for j in range(min(k,i), 0, -1): | |
| row[j] = j * row[j] + row[j-1] | |
| return Integer(row[k]) | |
| def stirling(n, k, d=None, kind=2, signed=False): | |
| r"""Return Stirling number $S(n, k)$ of the first or second (default) kind. | |
| The sum of all Stirling numbers of the second kind for $k = 1$ | |
| through $n$ is ``bell(n)``. The recurrence relationship for these numbers | |
| is: | |
| .. math :: {0 \brace 0} = 1; {n \brace 0} = {0 \brace k} = 0; | |
| .. math :: {{n+1} \brace k} = j {n \brace k} + {n \brace {k-1}} | |
| where $j$ is: | |
| $n$ for Stirling numbers of the first kind, | |
| $-n$ for signed Stirling numbers of the first kind, | |
| $k$ for Stirling numbers of the second kind. | |
| The first kind of Stirling number counts the number of permutations of | |
| ``n`` distinct items that have ``k`` cycles; the second kind counts the | |
| ways in which ``n`` distinct items can be partitioned into ``k`` parts. | |
| If ``d`` is given, the "reduced Stirling number of the second kind" is | |
| returned: $S^{d}(n, k) = S(n - d + 1, k - d + 1)$ with $n \ge k \ge d$. | |
| (This counts the ways to partition $n$ consecutive integers into $k$ | |
| groups with no pairwise difference less than $d$. See example below.) | |
| To obtain the signed Stirling numbers of the first kind, use keyword | |
| ``signed=True``. Using this keyword automatically sets ``kind`` to 1. | |
| Examples | |
| ======== | |
| >>> from sympy.functions.combinatorial.numbers import stirling, bell | |
| >>> from sympy.combinatorics import Permutation | |
| >>> from sympy.utilities.iterables import multiset_partitions, permutations | |
| First kind (unsigned by default): | |
| >>> [stirling(6, i, kind=1) for i in range(7)] | |
| [0, 120, 274, 225, 85, 15, 1] | |
| >>> perms = list(permutations(range(4))) | |
| >>> [sum(Permutation(p).cycles == i for p in perms) for i in range(5)] | |
| [0, 6, 11, 6, 1] | |
| >>> [stirling(4, i, kind=1) for i in range(5)] | |
| [0, 6, 11, 6, 1] | |
| First kind (signed): | |
| >>> [stirling(4, i, signed=True) for i in range(5)] | |
| [0, -6, 11, -6, 1] | |
| Second kind: | |
| >>> [stirling(10, i) for i in range(12)] | |
| [0, 1, 511, 9330, 34105, 42525, 22827, 5880, 750, 45, 1, 0] | |
| >>> sum(_) == bell(10) | |
| True | |
| >>> len(list(multiset_partitions(range(4), 2))) == stirling(4, 2) | |
| True | |
| Reduced second kind: | |
| >>> from sympy import subsets, oo | |
| >>> def delta(p): | |
| ... if len(p) == 1: | |
| ... return oo | |
| ... return min(abs(i[0] - i[1]) for i in subsets(p, 2)) | |
| >>> parts = multiset_partitions(range(5), 3) | |
| >>> d = 2 | |
| >>> sum(1 for p in parts if all(delta(i) >= d for i in p)) | |
| 7 | |
| >>> stirling(5, 3, 2) | |
| 7 | |
| See Also | |
| ======== | |
| sympy.utilities.iterables.multiset_partitions | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Stirling_numbers_of_the_first_kind | |
| .. [2] https://en.wikipedia.org/wiki/Stirling_numbers_of_the_second_kind | |
| """ | |
| # TODO: make this a class like bell() | |
| n = as_int(n) | |
| k = as_int(k) | |
| if n < 0: | |
| raise ValueError('n must be nonnegative') | |
| if k > n: | |
| return S.Zero | |
| if d: | |
| # assert k >= d | |
| # kind is ignored -- only kind=2 is supported | |
| return _eval_stirling2(n - d + 1, k - d + 1) | |
| elif signed: | |
| # kind is ignored -- only kind=1 is supported | |
| return S.NegativeOne**(n - k)*_eval_stirling1(n, k) | |
| if kind == 1: | |
| return _eval_stirling1(n, k) | |
| elif kind == 2: | |
| return _eval_stirling2(n, k) | |
| else: | |
| raise ValueError('kind must be 1 or 2, not %s' % k) | |
| def _nT(n, k): | |
| """Return the partitions of ``n`` items into ``k`` parts. This | |
| is used by ``nT`` for the case when ``n`` is an integer.""" | |
| # really quick exits | |
| if k > n or k < 0: | |
| return 0 | |
| if k in (1, n): | |
| return 1 | |
| if k == 0: | |
| return 0 | |
| # exits that could be done below but this is quicker | |
| if k == 2: | |
| return n//2 | |
| d = n - k | |
| if d <= 3: | |
| return d | |
| # quick exit | |
| if 3*k >= n: # or, equivalently, 2*k >= d | |
| # all the information needed in this case | |
| # will be in the cache needed to calculate | |
| # partition(d), so... | |
| # update cache | |
| tot = _partition_rec(d) | |
| # and correct for values not needed | |
| if d - k > 0: | |
| tot -= sum(_partition_rec.fetch_item(slice(d - k))) | |
| return tot | |
| # regular exit | |
| # nT(n, k) = Sum(nT(n - k, m), (m, 1, k)); | |
| # calculate needed nT(i, j) values | |
| p = [1]*d | |
| for i in range(2, k + 1): | |
| for m in range(i + 1, d): | |
| p[m] += p[m - i] | |
| d -= 1 | |
| # if p[0] were appended to the end of p then the last | |
| # k values of p are the nT(n, j) values for 0 < j < k in reverse | |
| # order p[-1] = nT(n, 1), p[-2] = nT(n, 2), etc.... Instead of | |
| # putting the 1 from p[0] there, however, it is simply added to | |
| # the sum below which is valid for 1 < k <= n//2 | |
| return (1 + sum(p[1 - k:])) | |
| def nT(n, k=None): | |
| """Return the number of ``k``-sized partitions of ``n`` items. | |
| Possible values for ``n``: | |
| integer - ``n`` identical items | |
| sequence - converted to a multiset internally | |
| multiset - {element: multiplicity} | |
| Note: the convention for ``nT`` is different than that of ``nC`` and | |
| ``nP`` in that | |
| here an integer indicates ``n`` *identical* items instead of a set of | |
| length ``n``; this is in keeping with the ``partitions`` function which | |
| treats its integer-``n`` input like a list of ``n`` 1s. One can use | |
| ``range(n)`` for ``n`` to indicate ``n`` distinct items. | |
| If ``k`` is None then the total number of ways to partition the elements | |
| represented in ``n`` will be returned. | |
| Examples | |
| ======== | |
| >>> from sympy.functions.combinatorial.numbers import nT | |
| Partitions of the given multiset: | |
| >>> [nT('aabbc', i) for i in range(1, 7)] | |
| [1, 8, 11, 5, 1, 0] | |
| >>> nT('aabbc') == sum(_) | |
| True | |
| >>> [nT("mississippi", i) for i in range(1, 12)] | |
| [1, 74, 609, 1521, 1768, 1224, 579, 197, 50, 9, 1] | |
| Partitions when all items are identical: | |
| >>> [nT(5, i) for i in range(1, 6)] | |
| [1, 2, 2, 1, 1] | |
| >>> nT('1'*5) == sum(_) | |
| True | |
| When all items are different: | |
| >>> [nT(range(5), i) for i in range(1, 6)] | |
| [1, 15, 25, 10, 1] | |
| >>> nT(range(5)) == sum(_) | |
| True | |
| Partitions of an integer expressed as a sum of positive integers: | |
| >>> from sympy import partition | |
| >>> partition(4) | |
| 5 | |
| >>> nT(4, 1) + nT(4, 2) + nT(4, 3) + nT(4, 4) | |
| 5 | |
| >>> nT('1'*4) | |
| 5 | |
| See Also | |
| ======== | |
| sympy.utilities.iterables.partitions | |
| sympy.utilities.iterables.multiset_partitions | |
| sympy.functions.combinatorial.numbers.partition | |
| References | |
| ========== | |
| .. [1] https://web.archive.org/web/20210507012732/https://teaching.csse.uwa.edu.au/units/CITS7209/partition.pdf | |
| """ | |
| if isinstance(n, SYMPY_INTS): | |
| # n identical items | |
| if k is None: | |
| return partition(n) | |
| if isinstance(k, SYMPY_INTS): | |
| n = as_int(n) | |
| k = as_int(k) | |
| return Integer(_nT(n, k)) | |
| if not isinstance(n, _MultisetHistogram): | |
| try: | |
| # if n contains hashable items there is some | |
| # quick handling that can be done | |
| u = len(set(n)) | |
| if u <= 1: | |
| return nT(len(n), k) | |
| elif u == len(n): | |
| n = range(u) | |
| raise TypeError | |
| except TypeError: | |
| n = _multiset_histogram(n) | |
| N = n[_N] | |
| if k is None and N == 1: | |
| return 1 | |
| if k in (1, N): | |
| return 1 | |
| if k == 2 or N == 2 and k is None: | |
| m, r = divmod(N, 2) | |
| rv = sum(nC(n, i) for i in range(1, m + 1)) | |
| if not r: | |
| rv -= nC(n, m)//2 | |
| if k is None: | |
| rv += 1 # for k == 1 | |
| return rv | |
| if N == n[_ITEMS]: | |
| # all distinct | |
| if k is None: | |
| return bell(N) | |
| return stirling(N, k) | |
| m = MultisetPartitionTraverser() | |
| if k is None: | |
| return m.count_partitions(n[_M]) | |
| # MultisetPartitionTraverser does not have a range-limited count | |
| # method, so need to enumerate and count | |
| tot = 0 | |
| for discard in m.enum_range(n[_M], k-1, k): | |
| tot += 1 | |
| return tot | |
| #-----------------------------------------------------------------------------# | |
| # # | |
| # Motzkin numbers # | |
| # # | |
| #-----------------------------------------------------------------------------# | |
| class motzkin(Function): | |
| """ | |
| The nth Motzkin number is the number | |
| of ways of drawing non-intersecting chords | |
| between n points on a circle (not necessarily touching | |
| every point by a chord). The Motzkin numbers are named | |
| after Theodore Motzkin and have diverse applications | |
| in geometry, combinatorics and number theory. | |
| Motzkin numbers are the integer sequence defined by the | |
| initial terms `M_0 = 1`, `M_1 = 1` and the two-term recurrence relation | |
| `M_n = \frac{2*n + 1}{n + 2} * M_{n-1} + \frac{3n - 3}{n + 2} * M_{n-2}`. | |
| Examples | |
| ======== | |
| >>> from sympy import motzkin | |
| >>> motzkin.is_motzkin(5) | |
| False | |
| >>> motzkin.find_motzkin_numbers_in_range(2,300) | |
| [2, 4, 9, 21, 51, 127] | |
| >>> motzkin.find_motzkin_numbers_in_range(2,900) | |
| [2, 4, 9, 21, 51, 127, 323, 835] | |
| >>> motzkin.find_first_n_motzkins(10) | |
| [1, 1, 2, 4, 9, 21, 51, 127, 323, 835] | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Motzkin_number | |
| .. [2] https://mathworld.wolfram.com/MotzkinNumber.html | |
| """ | |
| def is_motzkin(n): | |
| try: | |
| n = as_int(n) | |
| except ValueError: | |
| return False | |
| if n > 0: | |
| if n in (1, 2): | |
| return True | |
| tn1 = 1 | |
| tn = 2 | |
| i = 3 | |
| while tn < n: | |
| a = ((2*i + 1)*tn + (3*i - 3)*tn1)/(i + 2) | |
| i += 1 | |
| tn1 = tn | |
| tn = a | |
| if tn == n: | |
| return True | |
| else: | |
| return False | |
| else: | |
| return False | |
| def find_motzkin_numbers_in_range(x, y): | |
| if 0 <= x <= y: | |
| motzkins = [] | |
| if x <= 1 <= y: | |
| motzkins.append(1) | |
| tn1 = 1 | |
| tn = 2 | |
| i = 3 | |
| while tn <= y: | |
| if tn >= x: | |
| motzkins.append(tn) | |
| a = ((2*i + 1)*tn + (3*i - 3)*tn1)/(i + 2) | |
| i += 1 | |
| tn1 = tn | |
| tn = int(a) | |
| return motzkins | |
| else: | |
| raise ValueError('The provided range is not valid. This condition should satisfy x <= y') | |
| def find_first_n_motzkins(n): | |
| try: | |
| n = as_int(n) | |
| except ValueError: | |
| raise ValueError('The provided number must be a positive integer') | |
| if n < 0: | |
| raise ValueError('The provided number must be a positive integer') | |
| motzkins = [1] | |
| if n >= 1: | |
| motzkins.append(1) | |
| tn1 = 1 | |
| tn = 2 | |
| i = 3 | |
| while i <= n: | |
| motzkins.append(tn) | |
| a = ((2*i + 1)*tn + (3*i - 3)*tn1)/(i + 2) | |
| i += 1 | |
| tn1 = tn | |
| tn = int(a) | |
| return motzkins | |
| def _motzkin(n, prev): | |
| return ((2*n + 1)*prev[-1] + (3*n - 3)*prev[-2]) // (n + 2) | |
| def eval(cls, n): | |
| try: | |
| n = as_int(n) | |
| except ValueError: | |
| raise ValueError('The provided number must be a positive integer') | |
| if n < 0: | |
| raise ValueError('The provided number must be a positive integer') | |
| return Integer(cls._motzkin(n - 1)) | |
| def nD(i=None, brute=None, *, n=None, m=None): | |
| """return the number of derangements for: ``n`` unique items, ``i`` | |
| items (as a sequence or multiset), or multiplicities, ``m`` given | |
| as a sequence or multiset. | |
| Examples | |
| ======== | |
| >>> from sympy.utilities.iterables import generate_derangements as enum | |
| >>> from sympy.functions.combinatorial.numbers import nD | |
| A derangement ``d`` of sequence ``s`` has all ``d[i] != s[i]``: | |
| >>> set([''.join(i) for i in enum('abc')]) | |
| {'bca', 'cab'} | |
| >>> nD('abc') | |
| 2 | |
| Input as iterable or dictionary (multiset form) is accepted: | |
| >>> assert nD([1, 2, 2, 3, 3, 3]) == nD({1: 1, 2: 2, 3: 3}) | |
| By default, a brute-force enumeration and count of multiset permutations | |
| is only done if there are fewer than 9 elements. There may be cases when | |
| there is high multiplicity with few unique elements that will benefit | |
| from a brute-force enumeration, too. For this reason, the `brute` | |
| keyword (default None) is provided. When False, the brute-force | |
| enumeration will never be used. When True, it will always be used. | |
| >>> nD('1111222233', brute=True) | |
| 44 | |
| For convenience, one may specify ``n`` distinct items using the | |
| ``n`` keyword: | |
| >>> assert nD(n=3) == nD('abc') == 2 | |
| Since the number of derangments depends on the multiplicity of the | |
| elements and not the elements themselves, it may be more convenient | |
| to give a list or multiset of multiplicities using keyword ``m``: | |
| >>> assert nD('abc') == nD(m=(1,1,1)) == nD(m={1:3}) == 2 | |
| """ | |
| from sympy.integrals.integrals import integrate | |
| from sympy.functions.special.polynomials import laguerre | |
| from sympy.abc import x | |
| def ok(x): | |
| if not isinstance(x, SYMPY_INTS): | |
| raise TypeError('expecting integer values') | |
| if x < 0: | |
| raise ValueError('value must not be negative') | |
| return True | |
| if (i, n, m).count(None) != 2: | |
| raise ValueError('enter only 1 of i, n, or m') | |
| if i is not None: | |
| if isinstance(i, SYMPY_INTS): | |
| raise TypeError('items must be a list or dictionary') | |
| if not i: | |
| return S.Zero | |
| if type(i) is not dict: | |
| s = list(i) | |
| ms = multiset(s) | |
| elif type(i) is dict: | |
| all(ok(_) for _ in i.values()) | |
| ms = {k: v for k, v in i.items() if v} | |
| s = None | |
| if not ms: | |
| return S.Zero | |
| N = sum(ms.values()) | |
| counts = multiset(ms.values()) | |
| nkey = len(ms) | |
| elif n is not None: | |
| ok(n) | |
| if not n: | |
| return S.Zero | |
| return subfactorial(n) | |
| elif m is not None: | |
| if isinstance(m, dict): | |
| all(ok(i) and ok(j) for i, j in m.items()) | |
| counts = {k: v for k, v in m.items() if k*v} | |
| elif iterable(m) or isinstance(m, str): | |
| m = list(m) | |
| all(ok(i) for i in m) | |
| counts = multiset([i for i in m if i]) | |
| else: | |
| raise TypeError('expecting iterable') | |
| if not counts: | |
| return S.Zero | |
| N = sum(k*v for k, v in counts.items()) | |
| nkey = sum(counts.values()) | |
| s = None | |
| big = int(max(counts)) | |
| if big == 1: # no repetition | |
| return subfactorial(nkey) | |
| nval = len(counts) | |
| if big*2 > N: | |
| return S.Zero | |
| if big*2 == N: | |
| if nkey == 2 and nval == 1: | |
| return S.One # aaabbb | |
| if nkey - 1 == big: # one element repeated | |
| return factorial(big) # e.g. abc part of abcddd | |
| if N < 9 and brute is None or brute: | |
| # for all possibilities, this was found to be faster | |
| if s is None: | |
| s = [] | |
| i = 0 | |
| for m, v in counts.items(): | |
| for j in range(v): | |
| s.extend([i]*m) | |
| i += 1 | |
| return Integer(sum(1 for i in multiset_derangements(s))) | |
| from sympy.functions.elementary.exponential import exp | |
| return Integer(abs(integrate(exp(-x)*Mul(*[ | |
| laguerre(i, x)**m for i, m in counts.items()]), (x, 0, oo)))) | |
