def monomial_count(V, N): r""" Computes the number of monomials. The number of monomials is given by the following formula: .. math:: \frac{(\#V + N)!}{\#V! N!} where `N` is a total degree and `V` is a set of variables. **Examples** >>> from sympy import monomials, monomial_count >>> from sympy.abc import x, y >>> monomial_count(2, 2) 6 >>> M = monomials([x, y], 2) >>> sorted(M) [1, x, y, x**2, y**2, x*y] >>> len(M) 6 """ return C.factorial(V + N) / C.factorial(V) / C.factorial(N)
def as_real_imag(self, deep=True, **hints): # TODO: Handle deep and hints n, m, theta, phi = self.args re = (sqrt((2*n + 1)/(4*pi) * C.factorial(n - m)/C.factorial(n + m)) * C.cos(m*phi) * assoc_legendre(n, m, C.cos(theta))) im = (sqrt((2*n + 1)/(4*pi) * C.factorial(n - m)/C.factorial(n + m)) * C.sin(m*phi) * assoc_legendre(n, m, C.cos(theta))) return (re, im)
def _eval_rewrite_as_polynomial(self, n, m, x): k = C.Dummy("k") kern = ( C.factorial(2 * n - 2 * k) / (2 ** n * C.factorial(n - k) * C.factorial(k) * C.factorial(n - 2 * k - m)) * (-1) ** k * x ** (n - m - 2 * k) ) return (1 - x ** 2) ** (m / 2) * C.Sum(kern, (k, 0, C.floor((n - m) * S.Half)))
def _eval_expand_func(self, **hints): n, m, theta, phi = self.args rv = ( sqrt((2 * n + 1) / (4 * pi) * C.factorial(n - m) / C.factorial(n + m)) * C.exp(I * m * phi) * assoc_legendre(n, m, C.cos(theta)) ) # We can do this because of the range of theta return rv.subs(sqrt(-cos(theta) ** 2 + 1), sin(theta))
def _eval_rewrite_as_polynomial(self, n, a, b, x): # TODO: Make sure n \in N k = C.Dummy("k") kern = ( C.RisingFactorial(-n, k) * C.RisingFactorial(a + b + n + 1, k) * C.RisingFactorial(a + k + 1, n - k) / C.factorial(k) * ((1 - x) / 2) ** k ) return 1 / C.factorial(n) * C.Sum(kern, (k, 0, n))
def eval(cls, n, m, x): if n.is_integer and n >= 0 and m.is_integer and abs(m) <= n: assoc = cls.calc(int(n), abs(int(m))) if m < 0: assoc *= (-1)**(-m) * (C.factorial(n + m)/C.factorial(n - m)) return assoc.subs(_x, x) if n.is_negative: raise ValueError("%s : 1st index must be nonnegative integer (got %r)" % (cls, n)) if abs(m) > n: raise ValueError("%s : abs('2nd index') must be <= '1st index' (got %r, %r)" % (cls, n, m))
def eval(cls, n, m, x): if m.could_extract_minus_sign(): # P^{-m}_n ---> F * P^m_n return S.NegativeOne**(-m) * (C.factorial(m + n)/C.factorial(n - m)) * assoc_legendre(n, -m, x) if m == 0: # P^0_n ---> L_n return legendre(n, x) if x == 0: return 2**m*sqrt(S.Pi) / (C.gamma((1 - m - n)/2)*C.gamma(1 - (m - n)/2)) if n.is_Number and m.is_Number and n.is_integer and m.is_integer: if n.is_negative: raise ValueError("%s : 1st index must be nonnegative integer (got %r)" % (cls, n)) if abs(m) > n: raise ValueError("%s : abs('2nd index') must be <= '1st index' (got %r, %r)" % (cls, n, m)) return cls._eval_at_order(int(n), abs(int(m))).subs(_x, x)
def eval(cls, n, a, b, x): # Simplify to other polynomials # P^{a, a}_n(x) if a == b: if a == -S.Half: return C.RisingFactorial(S.Half, n) / C.factorial(n) * chebyshevt(n, x) elif a == S.Zero: return legendre(n, x) elif a == S.Half: return C.RisingFactorial(3 * S.Half, n) / C.factorial(n + 1) * chebyshevu(n, x) else: return C.RisingFactorial(a + 1, n) / C.RisingFactorial(2 * a + 1, n) * gegenbauer(n, a + S.Half, x) elif b == -a: # P^{a, -a}_n(x) return ( C.gamma(n + a + 1) / C.gamma(n + 1) * (1 + x) ** (a / 2) / (1 - x) ** (a / 2) * assoc_legendre(n, -a, x) ) elif a == -b: # P^{-b, b}_n(x) return ( C.gamma(n - b + 1) / C.gamma(n + 1) * (1 - x) ** (b / 2) / (1 + x) ** (b / 2) * assoc_legendre(n, b, x) ) if not n.is_Number: # Symbolic result P^{a,b}_n(x) # P^{a,b}_n(-x) ---> (-1)**n * P^{b,a}_n(-x) if x.could_extract_minus_sign(): return S.NegativeOne ** n * jacobi(n, b, a, -x) # We can evaluate for some special values of x if x == S.Zero: return ( 2 ** (-n) * C.gamma(a + n + 1) / (C.gamma(a + 1) * C.factorial(n)) * C.hyper([-b - n, -n], [a + 1], -1) ) if x == S.One: return C.RisingFactorial(a + 1, n) / C.factorial(n) elif x == S.Infinity: if n.is_positive: # TODO: Make sure a+b+2*n \notin Z return C.RisingFactorial(a + b + n + 1, n) * S.Infinity else: # n is a given fixed integer, evaluate into polynomial return jacobi_poly(n, a, b, x)
def taylor_term(n, x, *previous_terms): if n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) if len(previous_terms) > 2: p = previous_terms[-2] return -p * x**2 / (n * (n - 1)) else: return (-1)**(n // 2) * x**(n) / C.factorial(n)
def taylor_term(n, x, *previous_terms): if n < 0 or n % 2 == 1: return S.Zero else: x = sympify(x) if len(previous_terms) > 2: p = previous_terms[-2] return -p * x**2 / (n*(n-1)) else: return (-1)**(n//2)*x**(n)/C.factorial(n)
def taylor_term(n, x, *previous_terms): if n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) a, b = ((n-1)//2), 2**(n+1) B = C.bernoulli(n+1) F = C.factorial(n+1) return (-1)**a * b*(b-1) * B/F * x**n
def taylor_term(n, x, *previous_terms): if n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) a, b = ((n - 1) // 2), 2**(n + 1) B = C.bernoulli(n + 1) F = C.factorial(n + 1) return (-1)**a * b * (b - 1) * B / F * x**n
def taylor_term(n, x, *previous_terms): if n == 0: return 1 / sympify(x) elif n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) B = C.bernoulli(n+1) F = C.factorial(n+1) return (-1)**((n+1)//2) * 2**(n+1) * B/F * x**n
def taylor_term(n, x, *previous_terms): if n == 0: return 1 / sympify(x) elif n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) B = C.bernoulli(n + 1) F = C.factorial(n + 1) return (-1)**((n + 1) // 2) * 2**(n + 1) * B / F * x**n
def taylor_term(n, x, *previous_terms): if n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) if len(previous_terms) >= 2 and n > 2: p = previous_terms[-2] return p * (n-2)**2/(n*(n-1)) * x**2 else: k = (n - 1) // 2 R = C.RisingFactorial(S.Half, k) F = C.factorial(k) return R / F * x**n / n
def taylor_term(n, x, *previous_terms): if n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) if len(previous_terms) >= 2 and n > 2: p = previous_terms[-2] return p * (n - 2)**2 / (n * (n - 1)) * x**2 else: k = (n - 1) // 2 R = C.RisingFactorial(S.Half, k) F = C.factorial(k) return R / F * x**n / n
def eval(cls, n, m, x): if m.could_extract_minus_sign(): # P^{-m}_n ---> F * P^m_n return S.NegativeOne**(-m) * (C.factorial(m + n) / C.factorial(n - m)) * assoc_legendre( n, -m, x) if m == 0: # P^0_n ---> L_n return legendre(n, x) if x == 0: return 2**m * sqrt(S.Pi) / (C.gamma( (1 - m - n) / 2) * C.gamma(1 - (m - n) / 2)) if n.is_Number and m.is_Number and n.is_integer and m.is_integer: if n.is_negative: raise ValueError( "%s : 1st index must be nonnegative integer (got %r)" % (cls, n)) if abs(m) > n: raise ValueError( "%s : abs('2nd index') must be <= '1st index' (got %r, %r)" % (cls, n, m)) return cls._eval_at_order(int(n), abs(int(m))).subs(_x, x)
def eval(cls, n, a, b, x): # Simplify to other polynomials # P^{a, a}_n(x) if a == b: if a == -S.Half: return C.RisingFactorial(S.Half, n) / C.factorial(n) * chebyshevt(n, x) elif a == S.Zero: return legendre(n, x) elif a == S.Half: return C.RisingFactorial(3*S.Half, n) / C.factorial(n + 1) * chebyshevu(n, x) else: return C.RisingFactorial(a + 1, n) / C.RisingFactorial(2*a + 1, n) * gegenbauer(n, a + S.Half, x) elif b == -a: # P^{a, -a}_n(x) return C.gamma(n + a + 1) / C.gamma(n + 1) * (1 + x)**(a/2) / (1 - x)**(a/2) * assoc_legendre(n, -a, x) elif a == -b: # P^{-b, b}_n(x) return C.gamma(n - b + 1) / C.gamma(n + 1) * (1 - x)**(b/2) / (1 + x)**(b/2) * assoc_legendre(n, b, x) if not n.is_Number: # Symbolic result P^{a,b}_n(x) # P^{a,b}_n(-x) ---> (-1)**n * P^{b,a}_n(-x) if x.could_extract_minus_sign(): return S.NegativeOne**n * jacobi(n, b, a, -x) # We can evaluate for some special values of x if x == S.Zero: return (2**(-n) * C.gamma(a + n + 1) / (C.gamma(a + 1) * C.factorial(n)) * C.hyper([-b - n, -n], [a + 1], -1)) if x == S.One: return C.RisingFactorial(a + 1, n) / C.factorial(n) elif x == S.Infinity: if n.is_positive: # TODO: Make sure a+b+2*n \notin Z return C.RisingFactorial(a + b + n + 1, n) * S.Infinity else: # n is a given fixed integer, evaluate into polynomial return jacobi_poly(n, a, b, x)
def _eval_rewrite_as_polynomial(self, n, x): # TODO: Should make sure n is in N_0 k = C.Dummy("k") kern = C.RisingFactorial(-n, k) / C.factorial(k)**2 * x**k return C.Sum(kern, (k, 0, n))
def _eval_rewrite_as_polynomial(self, n, x): k = C.Dummy("k") kern = S.NegativeOne**k * C.factorial( n - k) * (2*x)**(n - 2*k) / (C.factorial(k) * C.factorial(n - 2*k)) return C.Sum(kern, (k, 0, C.floor(n/2)))
def _eval_rewrite_as_polynomial(self, n, a, x): k = C.Dummy("k") kern = ((-1)**k * C.RisingFactorial(a, n - k) * (2*x)**(n - 2*k) / (C.factorial(k) * C.factorial(n - 2*k))) return C.Sum(kern, (k, 0, C.floor(n/2)))
def _eval_expand_func(self, **hints): n, m, theta, phi = self.args return (sqrt( (2 * n + 1) / (4 * pi) * C.factorial(n - m) / C.factorial(n + m)) * C.exp(I * m * phi) * assoc_legendre(n, m, C.cos(theta)))
def _eval_rewrite_as_polynomial(self, n, x): # TODO: Should make sure n is in N_0 k = C.Dummy("k") kern = C.RisingFactorial( -n, k) / (C.gamma(k + alpha + 1) * C.factorial(k)) * x**k return C.gamma(n + alpha + 1) / C.factorial(n) * C.Sum(kern, (k, 0, n))
def _eval_rewrite_as_polynomial(self, n, a, x): k = C.Dummy("k") kern = ((-1)**k * C.RisingFactorial(a, n - k) * (2 * x)**(n - 2 * k) / (C.factorial(k) * C.factorial(n - 2 * k))) return C.Sum(kern, (k, 0, C.floor(n / 2)))
def _eval_rewrite_as_polynomial(self, n, x): k = C.Dummy("k") kern = (-1)**k / (C.factorial(k) * C.factorial(n - 2 * k)) * (2 * x)**(n - 2 * k) return C.factorial(n) * C.Sum(kern, (k, 0, C.floor(n / 2)))
def _eval_rewrite_as_polynomial(self, n, x): k = C.Dummy("k") kern = S.NegativeOne**k * C.factorial(n - k) * (2 * x)**(n - 2 * k) / ( C.factorial(k) * C.factorial(n - 2 * k)) return C.Sum(kern, (k, 0, C.floor(n / 2)))
def _eval_expand_func(self, **hints): n, m, theta, phi = self.args return (sqrt((2*n + 1)/(4*pi) * C.factorial(n - m)/C.factorial(n + m)) * C.exp(I*m*phi) * assoc_legendre(n, m, C.cos(theta)))
def _eval_rewrite_as_polynomial(self, n, x): k = C.Dummy("k") kern = (-1)**k / (C.factorial(k)*C.factorial(n - 2*k)) * (2*x)**(n - 2*k) return C.factorial(n)*C.Sum(kern, (k, 0, C.floor(n/2)))
def _eval_rewrite_as_polynomial(self, n, a, b, x): # TODO: Make sure n \in N k = C.Dummy("k") kern = (C.RisingFactorial(-n, k) * C.RisingFactorial(a + b + n + 1, k) * C.RisingFactorial(a + k + 1, n - k) / C.factorial(k) * ((1 - x)/2)**k) return 1 / C.factorial(n) * C.Sum(kern, (k, 0, n))
def _eval_rewrite_as_polynomial(self, n, m, x): k = C.Dummy("k") kern = C.factorial(2*n - 2*k)/(2**n*C.factorial(n - k)*C.factorial( k)*C.factorial(n - 2*k - m))*(-1)**k*x**(n - m - 2*k) return (1 - x**2)**(m/2) * C.Sum(kern, (k, 0, C.floor((n - m)*S.Half)))
def euler_maclaurin(self, m=0, n=0, eps=0, eval_integral=True): """ Return an Euler-Maclaurin approximation of self, where m is the number of leading terms to sum directly and n is the number of terms in the tail. With m = n = 0, this is simply the corresponding integral plus a first-order endpoint correction. Returns (s, e) where s is the Euler-Maclaurin approximation and e is the estimated error (taken to be the magnitude of the first omitted term in the tail): >>> from sympy.abc import k, a, b >>> from sympy import Sum >>> Sum(1/k, (k, 2, 5)).doit().evalf() 1.28333333333333 >>> s, e = Sum(1/k, (k, 2, 5)).euler_maclaurin() >>> s -log(2) + 7/20 + log(5) >>> from sympy import sstr >>> print(sstr((s.evalf(), e.evalf()), full_prec=True)) (1.26629073187415, 0.0175000000000000) The endpoints may be symbolic: >>> s, e = Sum(1/k, (k, a, b)).euler_maclaurin() >>> s -log(a) + log(b) + 1/(2*b) + 1/(2*a) >>> e Abs(-1/(12*b**2) + 1/(12*a**2)) If the function is a polynomial of degree at most 2n+1, the Euler-Maclaurin formula becomes exact (and e = 0 is returned): >>> Sum(k, (k, 2, b)).euler_maclaurin() (b**2/2 + b/2 - 1, 0) >>> Sum(k, (k, 2, b)).doit() b**2/2 + b/2 - 1 With a nonzero eps specified, the summation is ended as soon as the remainder term is less than the epsilon. """ m = int(m) n = int(n) f = self.function if len(self.limits) != 1: raise ValueError("More than 1 limit") i, a, b = self.limits[0] if (a > b) is True: if a - b == 1: return S.Zero,S.Zero a, b = b + 1, a - 1 f = -f s = S.Zero if m: if b.is_Integer and a.is_Integer: m = min(m, b - a + 1) if not eps: for k in range(m): s += f.subs(i, a + k) else: term = f.subs(i, a) if term: test = abs(term.evalf(3)) < eps if isinstance(test, bool): if test is True: return s, abs(term) else: # a symbolic Relational class, can't go further return term, S.Zero s += term for k in range(1, m): term = f.subs(i, a + k) if abs(term.evalf(3)) < eps: return s, abs(term) s += term if b - a + 1 == m: return s, S.Zero a += m x = Dummy('x') I = C.Integral(f.subs(i, x), (x, a, b)) if eval_integral: I = I.doit() s += I def fpoint(expr): if b is S.Infinity: return expr.subs(i, a), 0 return expr.subs(i, a), expr.subs(i, b) fa, fb = fpoint(f) iterm = (fa + fb)/2 g = f.diff(i) for k in xrange(1, n + 2): ga, gb = fpoint(g) term = C.bernoulli(2*k)/C.factorial(2*k)*(gb - ga) if (eps and term and abs(term.evalf(3)) < eps) or (k > n): break s += term g = g.diff(i, 2, simplify=False) return s + iterm, abs(term)
def euler_maclaurin(self, m=0, n=0, eps=0, eval_integral=True): """ Return an Euler-Maclaurin approximation of self, where m is the number of leading terms to sum directly and n is the number of terms in the tail. With m = n = 0, this is simply the corresponding integral plus a first-order endpoint correction. Returns (s, e) where s is the Euler-Maclaurin approximation and e is the estimated error (taken to be the magnitude of the first omitted term in the tail): >>> from sympy.abc import k, a, b >>> from sympy import Sum >>> Sum(1/k, (k, 2, 5)).doit().evalf() 1.28333333333333 >>> s, e = Sum(1/k, (k, 2, 5)).euler_maclaurin() >>> s -log(2) + 7/20 + log(5) >>> from sympy import sstr >>> print(sstr((s.evalf(), e.evalf()), full_prec=True)) (1.26629073187415, 0.0175000000000000) The endpoints may be symbolic: >>> s, e = Sum(1/k, (k, a, b)).euler_maclaurin() >>> s -log(a) + log(b) + 1/(2*b) + 1/(2*a) >>> e Abs(1/(12*b**2) - 1/(12*a**2)) If the function is a polynomial of degree at most 2n+1, the Euler-Maclaurin formula becomes exact (and e = 0 is returned): >>> Sum(k, (k, 2, b)).euler_maclaurin() (b**2/2 + b/2 - 1, 0) >>> Sum(k, (k, 2, b)).doit() b**2/2 + b/2 - 1 With a nonzero eps specified, the summation is ended as soon as the remainder term is less than the epsilon. """ m = int(m) n = int(n) f = self.function if len(self.limits) != 1: raise ValueError("More than 1 limit") i, a, b = self.limits[0] if (a > b) == True: if a - b == 1: return S.Zero,S.Zero a, b = b + 1, a - 1 f = -f s = S.Zero if m: if b.is_Integer and a.is_Integer: m = min(m, b - a + 1) if not eps or f.is_polynomial(i): for k in range(m): s += f.subs(i, a + k) else: term = f.subs(i, a) if term: test = abs(term.evalf(3)) < eps if test == True: return s, abs(term) elif not (test == False): # a symbolic Relational class, can't go further return term, S.Zero s += term for k in range(1, m): term = f.subs(i, a + k) if abs(term.evalf(3)) < eps and term != 0: return s, abs(term) s += term if b - a + 1 == m: return s, S.Zero a += m x = Dummy('x') I = C.Integral(f.subs(i, x), (x, a, b)) if eval_integral: I = I.doit() s += I def fpoint(expr): if b is S.Infinity: return expr.subs(i, a), 0 return expr.subs(i, a), expr.subs(i, b) fa, fb = fpoint(f) iterm = (fa + fb)/2 g = f.diff(i) for k in range(1, n + 2): ga, gb = fpoint(g) term = C.bernoulli(2*k)/C.factorial(2*k)*(gb - ga) if (eps and term and abs(term.evalf(3)) < eps) or (k > n): break s += term g = g.diff(i, 2, simplify=False) return s + iterm, abs(term)