def _eval_expand_log(self, deep=True, **hints): from sympy import unpolarify force = hints.get('force', False) arg = self.args[0] if arg.is_Mul: expr = [] nonpos = [] for x in arg.args: if force or x.is_positive or x.is_polar: a = self.func(x) if isinstance(a, log): expr.append(self.func(x)._eval_expand_log(**hints)) else: expr.append(a) else: nonpos.append(x) return Add(*expr) + log(Mul(*nonpos)) elif arg.is_Pow: if force or (arg.exp.is_real and arg.base.is_positive) or \ arg.base.is_polar: b = arg.base e = arg.exp a = self.func(b) if isinstance(a, log): return unpolarify(e) * a._eval_expand_log(**hints) else: return unpolarify(e) * a return self.func(arg)
def eval(cls, nu, z): if z.is_zero: if nu.is_zero: return S.One elif (nu.is_integer and nu.is_zero is False) or re(nu).is_positive: return S.Zero elif re(nu).is_negative and not (nu.is_integer is True): return S.ComplexInfinity elif nu.is_imaginary: return S.NaN if z is S.Infinity or (z is S.NegativeInfinity): return S.Zero if z.could_extract_minus_sign(): return (z)**nu*(-z)**(-nu)*besselj(nu, -z) if nu.is_integer: if nu.could_extract_minus_sign(): return S(-1)**(-nu)*besselj(-nu, z) newz = z.extract_multiplicatively(I) if newz: # NOTE we don't want to change the function if z==0 return I**(nu)*besseli(nu, newz) # branch handling: from sympy import unpolarify, exp if nu.is_integer: newz = unpolarify(z) if newz != z: return besselj(nu, newz) else: newz, n = z.extract_branch_factor() if n != 0: return exp(2*n*pi*nu*I)*besselj(nu, newz) nnu = unpolarify(nu) if nu != nnu: return besselj(nnu, z)
def test_expint(): """ Test various exponential integrals. """ from sympy import (expint, unpolarify, Symbol, Ci, Si, Shi, Chi, sin, cos, sinh, cosh, Ei) assert simplify(unpolarify(integrate(exp(-z*x)/x**y, (x, 1, oo), meijerg=True, conds='none' ).rewrite(expint).expand(func=True))) == expint(y, z) assert integrate(exp(-z*x)/x, (x, 1, oo), meijerg=True, conds='none').rewrite(expint).expand() == \ expint(1, z) assert integrate(exp(-z*x)/x**2, (x, 1, oo), meijerg=True, conds='none').rewrite(expint).expand() == \ expint(2, z).rewrite(Ei).rewrite(expint) assert integrate(exp(-z*x)/x**3, (x, 1, oo), meijerg=True, conds='none').rewrite(expint).expand() == \ expint(3, z).rewrite(Ei).rewrite(expint).expand() t = Symbol('t', positive=True) assert integrate(-cos(x)/x, (x, t, oo), meijerg=True).expand() == Ci(t) assert integrate(-sin(x)/x, (x, t, oo), meijerg=True).expand() == \ Si(t) - pi/2 assert integrate(sin(x)/x, (x, 0, z), meijerg=True) == Si(z) assert integrate(sinh(x)/x, (x, 0, z), meijerg=True) == Shi(z) assert integrate(exp(-x)/x, x, meijerg=True).expand().rewrite(expint) == \ I*pi - expint(1, x) assert integrate(exp(-x)/x**2, x, meijerg=True).rewrite(expint).expand() \ == expint(1, x) - exp(-x)/x - I*pi u = Symbol('u', polar=True) assert integrate(cos(u)/u, u, meijerg=True).expand().as_independent(u)[1] \ == Ci(u) assert integrate(cosh(u)/u, u, meijerg=True).expand().as_independent(u)[1] \ == Chi(u) assert integrate(expint(1, x), x, meijerg=True ).rewrite(expint).expand() == x*expint(1, x) - exp(-x) assert integrate(expint(2, x), x, meijerg=True ).rewrite(expint).expand() == \ -x**2*expint(1, x)/2 + x*exp(-x)/2 - exp(-x)/2 assert simplify(unpolarify(integrate(expint(y, x), x, meijerg=True).rewrite(expint).expand(func=True))) == \ -expint(y + 1, x) assert integrate(Si(x), x, meijerg=True) == x*Si(x) + cos(x) assert integrate(Ci(u), u, meijerg=True).expand() == u*Ci(u) - sin(u) assert integrate(Shi(x), x, meijerg=True) == x*Shi(x) - cosh(x) assert integrate(Chi(u), u, meijerg=True).expand() == u*Chi(u) - sinh(u) assert integrate(Si(x)*exp(-x), (x, 0, oo), meijerg=True) == pi/4 assert integrate(expint(1, x)*sin(x), (x, 0, oo), meijerg=True) == log(2)/2
def _eval_expand_func(self, **hints): from sympy import exp, I, floor, Add, Poly, Dummy, exp_polar, unpolarify z, s, a = self.args if z == 1: return zeta(s, a) if s.is_Integer and s <= 0: t = Dummy('t') p = Poly((t + a)**(-s), t) start = 1/(1 - t) res = S(0) for c in reversed(p.all_coeffs()): res += c*start start = t*start.diff(t) return res.subs(t, z) if a.is_Rational: # See section 18 of # Kelly B. Roach. Hypergeometric Function Representations. # In: Proceedings of the 1997 International Symposium on Symbolic and # Algebraic Computation, pages 205-211, New York, 1997. ACM. # TODO should something be polarified here? add = S(0) mul = S(1) # First reduce a to the interaval (0, 1] if a > 1: n = floor(a) if n == a: n -= 1 a -= n mul = z**(-n) add = Add(*[-z**(k - n)/(a + k)**s for k in xrange(n)]) elif a <= 0: n = floor(-a) + 1 a += n mul = z**n add = Add(*[z**(n - 1 - k)/(a - k - 1)**s for k in xrange(n)]) m, n = S([a.p, a.q]) zet = exp_polar(2*pi*I/n) root = z**(1/n) return add + mul*n**(s - 1)*Add( *[polylog(s, zet**k*root)._eval_expand_func(**hints) / (unpolarify(zet)**k*root)**m for k in xrange(n)]) # TODO use minpoly instead of ad-hoc methods when issue 2789 is fixed if z.func is exp and (z.args[0]/(pi*I)).is_Rational or z in [-1, I, -I]: # TODO reference? if z == -1: p, q = S([1, 2]) elif z == I: p, q = S([1, 4]) elif z == -I: p, q = S([-1, 4]) else: arg = z.args[0]/(2*pi*I) p, q = S([arg.p, arg.q]) return Add(*[exp(2*pi*I*k*p/q)/q**s*zeta(s, (k + a)/q) for k in xrange(q)]) return lerchphi(z, s, a)
def _eval_expand_log(self, deep=True, **hints): from sympy import unpolarify force = hints.get('force', False) if deep: arg = self.args[0].expand(deep=deep, **hints) else: arg = self.args[0] if arg.is_Mul: expr = [] nonpos = [] for x in arg.args: if deep: x = x.expand(deep=deep, **hints) if force or x.is_positive or x.is_polar: expr.append(self.func(x)._eval_expand_log(deep=deep, **hints)) else: nonpos.append(x) return Add(*expr) + log(Mul(*nonpos)) elif arg.is_Pow: if force or (arg.exp.is_real and arg.base.is_positive) or \ arg.base.is_polar: if deep: b = arg.base.expand(deep=deep, **hints) e = arg.exp.expand(deep=deep, **hints) else: b = arg.base e = arg.exp return unpolarify(e) * self.func(b)._eval_expand_log(deep=deep,\ **hints) return self.func(arg)
def can_do_meijer(a1, a2, b1, b2, numeric=True): """ This helper function tries to hyperexpand() the meijer g-function corresponding to the parameters a1, a2, b1, b2. It returns False if this expansion still contains g-functions. If numeric is True, it also tests the so-obtained formula numerically (at random values) and returns False if the test fails. Else it returns True. """ from sympy import unpolarify, expand r = hyperexpand(meijerg(a1, a2, b1, b2, z)) if r.has(meijerg): return False # NOTE hyperexpand() returns a truly branched function, whereas numerical # evaluation only works on the main branch. Since we are evaluating on # the main branch, this should not be a problem, but expressions like # exp_polar(I*pi/2*x)**a are evaluated incorrectly. We thus have to get # rid of them. The expand heuristically does this... r = unpolarify(expand(r, force=True, power_base=True, power_exp=False, mul=False, log=False, multinomial=False, basic=False)) if not numeric: return True repl = {} for n, a in enumerate(meijerg(a1, a2, b1, b2, z).free_symbols - set([z])): repl[a] = randcplx(n) return tn(meijerg(a1, a2, b1, b2, z).subs(repl), r.subs(repl), z)
def fdiff(self, argindex=1): from sympy import unpolarify arg = unpolarify(self.args[0]) if argindex == 1: return C.exp(arg)/arg else: raise ArgumentIndexError(self, argindex)
def eval(cls, s, z): s, z = sympify((s, z)) if z == 1: return zeta(s) elif z == -1: return -dirichlet_eta(s) elif z == 0: return S.Zero elif s == 2: if z == S.Half: return pi**2/12 - log(2)**2/2 elif z == 2: return pi**2/4 - I*pi*log(2) elif z == -(sqrt(5) - 1)/2: return -pi**2/15 + log((sqrt(5)-1)/2)**2/2 elif z == -(sqrt(5) + 1)/2: return -pi**2/10 - log((sqrt(5)+1)/2)**2 elif z == (3 - sqrt(5))/2: return pi**2/15 - log((sqrt(5)-1)/2)**2 elif z == (sqrt(5) - 1)/2: return pi**2/10 - log((sqrt(5)-1)/2)**2 # For s = 0 or -1 use explicit formulas to evaluate, but # automatically expanding polylog(1, z) to -log(1-z) seems undesirable # for summation methods based on hypergeometric functions elif s == 0: return z/(1 - z) elif s == -1: return z/(1 - z)**2 # polylog is branched, but not over the unit disk from sympy.functions.elementary.complexes import (Abs, unpolarify, polar_lift) if z.has(exp_polar, polar_lift) and (Abs(z) <= S.One) == True: return cls(s, unpolarify(z))
def eval(cls, arg, base=None): from sympy import unpolarify if base is not None: base = sympify(base) if arg.is_positive and arg.is_Integer and \ base.is_positive and base.is_Integer: base = int(base) arg = int(arg) n = multiplicity(base, arg) return S(n) + log(arg // base ** n) / log(base) if base is not S.Exp1: return cls(arg)/cls(base) else: return cls(arg) arg = sympify(arg) if arg.is_Number: if arg is S.Zero: return S.ComplexInfinity elif arg is S.One: return S.Zero elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.Infinity elif arg is S.NaN: return S.NaN elif arg.is_negative: return S.Pi * S.ImaginaryUnit + cls(-arg) elif arg.is_Rational: if arg.q != 1: return cls(arg.p) - cls(arg.q) # remove perfect powers automatically p = perfect_power(int(arg)) if p is not False: return p[1]*cls(p[0]) elif arg is S.ComplexInfinity: return S.ComplexInfinity elif arg is S.Exp1: return S.One elif arg.func is exp and arg.args[0].is_real: return arg.args[0] elif arg.func is exp_polar: return unpolarify(arg.exp) #don't autoexpand Pow or Mul (see the issue 252): elif not arg.is_Add: coeff = arg.as_coefficient(S.ImaginaryUnit) if coeff is not None: if coeff is S.Infinity: return S.Infinity elif coeff is S.NegativeInfinity: return S.Infinity elif coeff.is_Rational: if coeff.is_nonnegative: return S.Pi * S.ImaginaryUnit * S.Half + cls(coeff) else: return -S.Pi * S.ImaginaryUnit * S.Half + cls(-coeff)
def eval(cls, n, z): n, z = list(map(sympify, (n, z))) from sympy import unpolarify if n.is_integer: if n.is_nonnegative: nz = unpolarify(z) if z != nz: return polygamma(n, nz) if n == -1: return loggamma(z) else: if z.is_Number: if z is S.NaN: return S.NaN elif z is S.Infinity: if n.is_Number: if n is S.Zero: return S.Infinity else: return S.Zero elif z.is_Integer: if z.is_nonpositive: return S.ComplexInfinity else: if n is S.Zero: return -S.EulerGamma + C.harmonic(z - 1, 1) elif n.is_odd: return (-1) ** (n + 1) * C.factorial(n) * zeta(n + 1, z) if n == 0: if z is S.NaN: return S.NaN elif z.is_Rational: # TODO actually *any* n/m can be done, but that is messy lookup = { S(1) / 2: -2 * log(2) - S.EulerGamma, S(1) / 3: -S.Pi / 2 / sqrt(3) - 3 * log(3) / 2 - S.EulerGamma, S(1) / 4: -S.Pi / 2 - 3 * log(2) - S.EulerGamma, S(3) / 4: -3 * log(2) - S.EulerGamma + S.Pi / 2, S(2) / 3: -3 * log(3) / 2 + S.Pi / 2 / sqrt(3) - S.EulerGamma, } if z > 0: n = floor(z) z0 = z - n if z0 in lookup: return lookup[z0] + Add(*[1 / (z0 + k) for k in range(n)]) elif z < 0: n = floor(1 - z) z0 = z + n if z0 in lookup: return lookup[z0] - Add(*[1 / (z0 - 1 - k) for k in range(n)]) elif z in (S.Infinity, S.NegativeInfinity): return S.Infinity else: t = z.extract_multiplicatively(S.ImaginaryUnit) if t in (S.Infinity, S.NegativeInfinity): return S.Infinity
def _eval_expand_log(self, deep=True, **hints): from sympy import unpolarify, expand_log from sympy.concrete import Sum, Product force = hints.get('force', False) if (len(self.args) == 2): return expand_log(self.func(*self.args), deep=deep, force=force) arg = self.args[0] if arg.is_Integer: # remove perfect powers p = perfect_power(int(arg)) if p is not False: return p[1]*self.func(p[0]) elif arg.is_Rational: return log(arg.p) - log(arg.q) elif arg.is_Mul: expr = [] nonpos = [] for x in arg.args: if force or x.is_positive or x.is_polar: a = self.func(x) if isinstance(a, log): expr.append(self.func(x)._eval_expand_log(**hints)) else: expr.append(a) elif x.is_negative: a = self.func(-x) expr.append(a) nonpos.append(S.NegativeOne) else: nonpos.append(x) return Add(*expr) + log(Mul(*nonpos)) elif arg.is_Pow or isinstance(arg, exp): if force or (arg.exp.is_real and (arg.base.is_positive or ((arg.exp+1) .is_positive and (arg.exp-1).is_nonpositive))) or arg.base.is_polar: b = arg.base e = arg.exp a = self.func(b) if isinstance(a, log): return unpolarify(e) * a._eval_expand_log(**hints) else: return unpolarify(e) * a elif isinstance(arg, Product): if arg.function.is_positive: return Sum(log(arg.function), *arg.limits) return self.func(arg)
def fdiff(self, argindex=2): from sympy import meijerg, unpolarify if argindex == 2: a, z = self.args return -C.exp(-unpolarify(z))*z**(a - 1) elif argindex == 1: a, z = self.args return uppergamma(a, z)*log(z) + meijerg([], [1, 1], [0, 0, a], [], z) else: raise ArgumentIndexError(self, argindex)
def eval(cls, nu, z): if nu.is_Integer: newz = z.extract_multiplicatively(I) if newz: # NOTE we don't want to change the function if z==0 return I**(-nu)*besselj(nu, -newz) # branch handling: from sympy import unpolarify, exp if nu.is_integer: newz = unpolarify(z) if newz != z: return besseli(nu, newz) else: newz, n = z.extract_branch_factor() if n != 0: return exp(2*n*pi*nu*I)*besseli(nu, newz) nnu = unpolarify(nu) if nu != nnu: return besseli(nnu, z)
def eval(cls, nu, z): from sympy import unpolarify, expand_mul, uppergamma, exp, gamma, factorial nu2 = unpolarify(nu) if nu != nu2: return expint(nu2, z) if nu.is_Integer and nu <= 0 or (not nu.is_Integer and (2 * nu).is_Integer): return unpolarify(expand_mul(z ** (nu - 1) * uppergamma(1 - nu, z))) # Extract branching information. This can be deduced from what is # explained in lowergamma.eval(). z, n = z.extract_branch_factor() if n == 0: return if nu.is_integer: if (nu > 0) is not True: return return expint(nu, z) - 2 * pi * I * n * (-1) ** (nu - 1) / factorial(nu - 1) * unpolarify(z) ** (nu - 1) else: return (exp(2 * I * pi * nu * n) - 1) * z ** (nu - 1) * gamma(1 - nu) + expint(nu, z)
def eval(cls, a, z): from sympy import unpolarify, I, expint if z.is_Number: if z is S.NaN: return S.NaN elif z is S.Infinity: return S.Zero elif z is S.Zero: # TODO: Holds only for Re(a) > 0: return gamma(a) # We extract branching information here. C/f lowergamma. nx, n = z.extract_branch_factor() if a.is_integer and (a > 0) == True: nx = unpolarify(z) if z != nx: return uppergamma(a, nx) elif a.is_integer and (a <= 0) == True: if n != 0: return -2*pi*I*n*(-1)**(-a)/factorial(-a) + uppergamma(a, nx) elif n != 0: return gamma(a)*(1 - exp(2*pi*I*n*a)) + exp(2*pi*I*n*a)*uppergamma(a, nx) # Special values. if a.is_Number: if a is S.One: return exp(-z) elif a is S.Half: return sqrt(pi)*erfc(sqrt(z)) elif a.is_Integer or (2*a).is_Integer: b = a - 1 if b.is_positive: if a.is_integer: return exp(-z) * factorial(b) * Add(*[z**k / factorial(k) for k in range(a)]) else: return gamma(a) * erfc(sqrt(z)) + (-1)**(a - S(3)/2) * exp(-z) * sqrt(z) * Add(*[gamma(-S.Half - k) * (-z)**k / gamma(1-a) for k in range(a - S.Half)]) elif b.is_Integer: return expint(-b, z)*unpolarify(z)**(b + 1) if not a.is_Integer: return (-1)**(S.Half - a) * pi*erfc(sqrt(z))/gamma(1-a) - z**a * exp(-z) * Add(*[z**k * gamma(a) / gamma(a+k+1) for k in range(S.Half - a)])
def _eval_rewrite_as_Ei(self, nu, z): from sympy import exp_polar, unpolarify, exp, factorial if nu == 1: return -Ei(z*exp_polar(-I*pi)) - I*pi elif nu.is_Integer and nu > 1: # DLMF, 8.19.7 x = -unpolarify(z) return x**(nu - 1)/factorial(nu - 1)*E1(z).rewrite(Ei) + \ exp(x)/factorial(nu - 1) * \ Add(*[factorial(nu - k - 2)*x**k for k in range(nu - 1)]) else: return self
def eval(cls, a, z): from sympy import unpolarify, I, factorial, exp, expint if z.is_Number: if z is S.NaN: return S.NaN elif z is S.Infinity: return S.Zero elif z is S.Zero: # TODO: Holds only for Re(a) > 0: return gamma(a) # We extract branching information here. C/f lowergamma. nx, n = z.extract_branch_factor() if a.is_integer and (a > 0) == True: nx = unpolarify(z) if z != nx: return uppergamma(a, nx) elif a.is_integer and (a <= 0) == True: if n != 0: return -2 * pi * I * n * (-1) ** (-a) / factorial(-a) + uppergamma(a, nx) elif n != 0: return gamma(a) * (1 - exp(2 * pi * I * n * a)) + exp(2 * pi * I * n * a) * uppergamma(a, nx) # Special values. if a.is_Number: # TODO this should be non-recursive if a is S.One: return C.exp(-z) elif a is S.Half: return sqrt(pi) * (1 - erf(sqrt(z))) # TODO could use erfc... elif a.is_Integer or (2 * a).is_Integer: b = a - 1 if b.is_positive: return b * cls(b, z) + z ** b * C.exp(-z) elif b.is_Integer: return expint(-b, z) * unpolarify(z) ** (b + 1) if not a.is_Integer: return (cls(a + 1, z) - z ** a * C.exp(-z)) / a
def eval(cls, a, z): from sympy import unpolarify, I, expint if z.is_Number: if z is S.NaN: return S.NaN elif z is S.Infinity: return S.Zero elif z is S.Zero: # TODO: Holds only for Re(a) > 0: return gamma(a) # We extract branching information here. C/f lowergamma. nx, n = z.extract_branch_factor() if a.is_integer and (a > 0) == True: nx = unpolarify(z) if z != nx: return uppergamma(a, nx) elif a.is_integer and (a <= 0) == True: if n != 0: return -2*pi*I*n*(-1)**(-a)/factorial(-a) + uppergamma(a, nx) elif n != 0: return gamma(a)*(1 - exp(2*pi*I*n*a)) + exp(2*pi*I*n*a)*uppergamma(a, nx) # Special values. if a.is_Number: # TODO this should be non-recursive if a is S.One: return exp(-z) elif a is S.Half: return sqrt(pi)*erfc(sqrt(z)) elif a.is_Integer or (2*a).is_Integer: b = a - 1 if b.is_positive: return b*cls(b, z) + z**b * exp(-z) elif b.is_Integer: return expint(-b, z)*unpolarify(z)**(b + 1) if not a.is_Integer: return (cls(a + 1, z) - z**a * exp(-z))/a
def eval(cls, n, z): n, z = map(sympify, (n, z)) from sympy import unpolarify if n.is_integer: if n.is_nonnegative: nz = unpolarify(z) if z != nz: return polygamma(n, nz) if n is S.NegativeOne: return loggamma(z) else: if z.is_Number: if z is S.NaN: return S.NaN elif z is S.Infinity: if n.is_Number: if n.is_zero: return S.Infinity else: return S.Zero if n.is_zero: return S.Infinity elif z.is_Integer: if z.is_nonpositive: return S.ComplexInfinity else: if n.is_zero: return -S.EulerGamma + harmonic(z - 1, 1) elif n.is_odd: return (-1)**(n + 1) * factorial(n) * zeta( n + 1, z) if n.is_zero: if z is S.NaN: return S.NaN elif z.is_Rational: p, q = z.as_numer_denom() # only expand for small denominators to avoid creating long expressions if q <= 5: return expand_func(polygamma(S.Zero, z, evaluate=False)) elif z in (S.Infinity, S.NegativeInfinity): return S.Infinity else: t = z.extract_multiplicatively(S.ImaginaryUnit) if t in (S.Infinity, S.NegativeInfinity): return S.Infinity
def _eval_expand_log(self, deep=True, **hints): from sympy import unpolarify from sympy.concrete import Sum, Product force = hints.get('force', False) arg = self.args[0] if arg.is_Integer: # remove perfect powers p = perfect_power(int(arg)) if p is not False: return p[1] * self.func(p[0]) elif arg.is_Mul: expr = [] nonpos = [] for x in arg.args: if force or x.is_positive or x.is_polar: a = self.func(x) if isinstance(a, log): expr.append(self.func(x)._eval_expand_log(**hints)) else: expr.append(a) else: nonpos.append(x) return Add(*expr) + log(Mul(*nonpos)) elif arg.is_Pow: if force or (arg.exp.is_real and arg.base.is_positive) or \ arg.base.is_polar: b = arg.base e = arg.exp a = self.func(b) if isinstance(a, log): return unpolarify(e) * a._eval_expand_log(**hints) else: return unpolarify(e) * a elif isinstance(arg, Product): if arg.function.is_positive: return Sum(log(arg.function), *arg.limits) return self.func(arg)
def _eval_expand_log(self, deep=True, **hints): from sympy import unpolarify from sympy.concrete import Sum, Product force = hints.get('force', False) arg = self.args[0] if arg.is_Integer: # remove perfect powers p = perfect_power(int(arg)) if p is not False: return p[1]*self.func(p[0]) elif arg.is_Mul: expr = [] nonpos = [] for x in arg.args: if force or x.is_positive or x.is_polar: a = self.func(x) if isinstance(a, log): expr.append(self.func(x)._eval_expand_log(**hints)) else: expr.append(a) else: nonpos.append(x) return Add(*expr) + log(Mul(*nonpos)) elif arg.is_Pow: if force or (arg.exp.is_real and arg.base.is_positive) or \ arg.base.is_polar: b = arg.base e = arg.exp a = self.func(b) if isinstance(a, log): return unpolarify(e) * a._eval_expand_log(**hints) else: return unpolarify(e) * a elif isinstance(arg, Product): if arg.function.is_positive: return Sum(log(arg.function), *arg.limits) return self.func(arg)
def eval(cls, nu, z): if nu.is_Integer: if nu < 0: return S(-1)**nu * besselj(-nu, z) if z.could_extract_minus_sign(): return S(-1)**nu * besselj(nu, -z) newz = z.extract_multiplicatively(I) if newz: # NOTE we don't want to change the function if z==0 return I**(nu) * besseli(nu, newz) # branch handling: from sympy import unpolarify, exp if nu.is_integer: newz = unpolarify(z) if newz != z: return besselj(nu, newz) else: newz, n = z.extract_branch_factor() if n != 0: return exp(2 * n * pi * nu * I) * besselj(nu, newz) nnu = unpolarify(nu) if nu != nnu: return besselj(nnu, z)
def eval(cls, nu, z): from sympy import (unpolarify, expand_mul, uppergamma, exp, gamma, factorial) nu2 = unpolarify(nu) if nu != nu2: return expint(nu2, z) if nu.is_Integer and nu <= 0 or (not nu.is_Integer and (2 * nu).is_Integer): return unpolarify(expand_mul(z**(nu - 1) * uppergamma(1 - nu, z))) # Extract branching information. This can be deduced from what is # explained in lowergamma.eval(). z, n = z.extract_branch_factor() if n == 0: return if nu.is_integer: if (nu > 0) is not True: return return expint(nu, z) \ - 2*pi*I*n*(-1)**(nu - 1)/factorial(nu - 1)*unpolarify(z)**(nu - 1) else: return (exp(2 * I * pi * nu * n) - 1) * z**(nu - 1) * gamma(1 - nu) + expint(nu, z)
def eval(cls, a, x): # For lack of a better place, we use this one to extract branching # information. The following can be # found in the literature (c/f references given above), albeit scattered: # 1) For fixed x != 0, lowergamma(s, x) is an entire function of s # 2) For fixed positive integers s, lowergamma(s, x) is an entire # function of x. # 3) For fixed non-positive integers s, # lowergamma(s, exp(I*2*pi*n)*x) = # 2*pi*I*n*(-1)**(-s)/factorial(-s) + lowergamma(s, x) # (this follows from lowergamma(s, x).diff(x) = x**(s-1)*exp(-x)). # 4) For fixed non-integral s, # lowergamma(s, x) = x**s*gamma(s)*lowergamma_unbranched(s, x), # where lowergamma_unbranched(s, x) is an entire function (in fact # of both s and x), i.e. # lowergamma(s, exp(2*I*pi*n)*x) = exp(2*pi*I*n*a)*lowergamma(a, x) from sympy import unpolarify, I if x is S.Zero: return S.Zero nx, n = x.extract_branch_factor() if a.is_integer and a.is_positive: nx = unpolarify(x) if nx != x: return lowergamma(a, nx) elif a.is_integer and a.is_nonpositive: if n != 0: return 2*pi*I*n*(-1)**(-a)/factorial(-a) + lowergamma(a, nx) elif n != 0: return exp(2*pi*I*n*a)*lowergamma(a, nx) # Special values. if a.is_Number: if a is S.One: return S.One - exp(-x) elif a is S.Half: return sqrt(pi)*erf(sqrt(x)) elif a.is_Integer or (2*a).is_Integer: b = a - 1 if b.is_positive: if a.is_integer: return factorial(b) - exp(-x) * factorial(b) * Add(*[x ** k / factorial(k) for k in range(a)]) else: return gamma(a)*(lowergamma(S.Half, x)/sqrt(pi) - exp(-x)*Add(*[x**(k - S.Half)/gamma(S.Half + k) for k in range(1, a + S.Half)])) if not a.is_Integer: return (-1)**(S.Half - a)*pi*erf(sqrt(x))/gamma(1 - a) + exp(-x)*Add(*[x**(k + a - 1)*gamma(a)/gamma(a + k) for k in range(1, Rational(3, 2) - a)]) if x.is_zero: return S.Zero
def eval(cls, s, z): s, z = sympify((s, z)) if z is S.One: return zeta(s) elif z is S.NegativeOne: return -dirichlet_eta(s) elif z is S.Zero: return S.Zero elif s == 2: if z == S.Half: return pi**2 / 12 - log(2)**2 / 2 elif z == 2: return pi**2 / 4 - I * pi * log(2) elif z == -(sqrt(5) - 1) / 2: return -pi**2 / 15 + log((sqrt(5) - 1) / 2)**2 / 2 elif z == -(sqrt(5) + 1) / 2: return -pi**2 / 10 - log((sqrt(5) + 1) / 2)**2 elif z == (3 - sqrt(5)) / 2: return pi**2 / 15 - log((sqrt(5) - 1) / 2)**2 elif z == (sqrt(5) - 1) / 2: return pi**2 / 10 - log((sqrt(5) - 1) / 2)**2 if z.is_zero: return S.Zero # Make an effort to determine if z is 1 to avoid replacing into # expression with singularity zone = z.equals(S.One) if zone: return zeta(s) elif zone is False: # For s = 0 or -1 use explicit formulas to evaluate, but # automatically expanding polylog(1, z) to -log(1-z) seems # undesirable for summation methods based on hypergeometric # functions if s is S.Zero: return z / (1 - z) elif s is S.NegativeOne: return z / (1 - z)**2 if s.is_zero: return z / (1 - z) # polylog is branched, but not over the unit disk from sympy.functions.elementary.complexes import (Abs, unpolarify, polar_lift) if z.has(exp_polar, polar_lift) and (zone or (Abs(z) <= S.One) == True): return cls(s, unpolarify(z))
def eval(cls, nu, z): if z.is_zero: if nu.is_zero: return S.One elif (nu.is_integer and nu.is_zero == False) or re(nu).is_positive: return S.Zero elif re(nu).is_negative and not (nu.is_integer == True): return S.ComplexInfinity elif nu.is_imaginary: return S.NaN if z.is_imaginary: if im(z) is S.Infinity or im(z) is S.NegativeInfinity: return S.Zero if z.could_extract_minus_sign(): return (z)**nu * (-z)**(-nu) * besseli(nu, -z) if nu.is_integer: if nu.could_extract_minus_sign(): return besseli(-nu, z) newz = z.extract_multiplicatively(I) if newz: # NOTE we don't want to change the function if z==0 return I**(-nu) * besselj(nu, -newz) # branch handling: from sympy import unpolarify, exp if nu.is_integer: newz = unpolarify(z) if newz != z: return besseli(nu, newz) else: newz, n = z.extract_branch_factor() if n != 0: return exp(2 * n * pi * nu * I) * besseli(nu, newz) nnu = unpolarify(nu) if nu != nnu: return besseli(nnu, z)
def eval(cls, n, z): n, z = map(sympify, (n, z)) from sympy import unpolarify if n.is_integer: if n.is_nonnegative: nz = unpolarify(z) if z != nz: return polygamma(n, nz) if n == -1: return loggamma(z) else: if z.is_Number: if z is S.NaN: return S.NaN elif z is S.Infinity: if n.is_Number: if n is S.Zero: return S.Infinity else: return S.Zero elif z.is_Integer: if z.is_nonpositive: return S.ComplexInfinity else: if n is S.Zero: return -S.EulerGamma + C.harmonic(z-1, 1) elif n.is_odd: return (-1)**(n+1)*C.factorial(n)*zeta(n+1, z) if n == 0 and z.is_Rational: # TODO actually *any* n/m can be done, but that is messy lookup = {S(1)/2: -2*log(2) - S.EulerGamma, S(1)/3: -S.Pi/2/sqrt(3) - 3*log(3)/2 - S.EulerGamma, S(1)/4: -S.Pi/2 - 3*log(2) - S.EulerGamma, S(3)/4: -3*log(2) - S.EulerGamma + S.Pi/2, S(2)/3: -3*log(3)/2 + S.Pi/2/sqrt(3) - S.EulerGamma} if z > 0: n = floor(z) z0 = z - n if z0 in lookup: return lookup[z0] + Add(*[1/(z0 + k) for k in range(n)]) elif z < 0: n = floor(1 - z) z0 = z + n if z0 in lookup: return lookup[z0] - Add(*[1/(z0 - 1 - k) for k in range(n)])
def eval(cls, n, z): n, z = list(map(sympify, (n, z))) from sympy import unpolarify if n.is_integer: if n.is_nonnegative: nz = unpolarify(z) if z != nz: return polygamma(n, nz) if n == -1: return loggamma(z) else: if z.is_Number: if z is S.NaN: return S.NaN elif z is S.Infinity: if n.is_Number: if n is S.Zero: return S.Infinity else: return S.Zero elif z.is_Integer: if z.is_nonpositive: return S.ComplexInfinity else: if n is S.Zero: return -S.EulerGamma + harmonic(z - 1, 1) elif n.is_odd: return (-1)**(n + 1)*factorial(n)*zeta(n + 1, z) if n == 0: if z is S.NaN: return S.NaN elif z.is_Rational: p, q = z.as_numer_denom() # only expand for small denominators to avoid creating long expressions if q <= 5: return expand_func(polygamma(n, z, evaluate=False)) elif z in (S.Infinity, S.NegativeInfinity): return S.Infinity else: t = z.extract_multiplicatively(S.ImaginaryUnit) if t in (S.Infinity, S.NegativeInfinity): return S.Infinity
def fdiff(self, argindex=2): from sympy import meijerg, unpolarify if argindex == 2: a, z = self.args return exp(-unpolarify(z)) * z ** (a - 1) elif argindex == 1: a, z = self.args return ( gamma(a) * digamma(a) - log(z) * uppergamma(a, z) - meijerg([], [1, 1], [0, 0, a], [], z) ) else: raise ArgumentIndexError(self, argindex)
def eval(cls, a, x): # For lack of a better place, we use this one to extract branching # information. The following can be # found in the literature (c/f references given above), albeit scattered: # 1) For fixed x != 0, lowergamma(s, x) is an entire function of s # 2) For fixed positive integers s, lowergamma(s, x) is an entire # function of x. # 3) For fixed non-positive integers s, # lowergamma(s, exp(I*2*pi*n)*x) = # 2*pi*I*n*(-1)**(-s)/factorial(-s) + lowergamma(s, x) # (this follows from lowergamma(s, x).diff(x) = x**(s-1)*exp(-x)). # 4) For fixed non-integral s, # lowergamma(s, x) = x**s*gamma(s)*lowergamma_unbranched(s, x), # where lowergamma_unbranched(s, x) is an entire function (in fact # of both s and x), i.e. # lowergamma(s, exp(2*I*pi*n)*x) = exp(2*pi*I*n*a)*lowergamma(a, x) from sympy import unpolarify, I if x == 0: return S.Zero nx, n = x.extract_branch_factor() if a.is_integer and a.is_positive: nx = unpolarify(x) if nx != x: return lowergamma(a, nx) elif a.is_integer and a.is_nonpositive: if n != 0: return 2*pi*I*n*(-1)**(-a)/factorial(-a) + lowergamma(a, nx) elif n != 0: return exp(2*pi*I*n*a)*lowergamma(a, nx) # Special values. if a.is_Number: if a is S.One: return S.One - exp(-x) elif a is S.Half: return sqrt(pi)*erf(sqrt(x)) elif a.is_Integer or (2*a).is_Integer: b = a - 1 if b.is_positive: if a.is_integer: return factorial(b) - exp(-x) * factorial(b) * Add(*[x ** k / factorial(k) for k in range(a)]) else: return gamma(a) * (lowergamma(S.Half, x)/sqrt(pi) - exp(-x) * Add(*[x**(k-S.Half) / gamma(S.Half+k) for k in range(1, a+S.Half)])) if not a.is_Integer: return (-1)**(S.Half - a) * pi*erf(sqrt(x)) / gamma(1-a) + exp(-x) * Add(*[x**(k+a-1)*gamma(a) / gamma(a+k) for k in range(1, S(3)/2-a)])
def test_expint(): from sympy import E1, expint, Max, re, lerchphi, Symbol, simplify, Si, Ci, Ei aneg = Symbol("a", negative=True) u = Symbol("u", polar=True) assert mellin_transform(E1(x), x, s) == (gamma(s) / s, (0, oo), True) assert inverse_mellin_transform(gamma(s) / s, s, x, (0, oo)).rewrite(expint).expand() == E1(x) assert mellin_transform(expint(a, x), x, s) == (gamma(s) / (a + s - 1), (Max(1 - re(a), 0), oo), True) # XXX IMT has hickups with complicated strips ... assert simplify( unpolarify( inverse_mellin_transform(gamma(s) / (aneg + s - 1), s, x, (1 - aneg, oo)).rewrite(expint).expand(func=True) ) ) == expint(aneg, x) assert mellin_transform(Si(x), x, s) == ( -2 ** s * sqrt(pi) * gamma(s / 2 + S(1) / 2) / (2 * s * gamma(-s / 2 + 1)), (-1, 0), True, ) assert inverse_mellin_transform( -2 ** s * sqrt(pi) * gamma((s + 1) / 2) / (2 * s * gamma(-s / 2 + 1)), s, x, (-1, 0) ) == Si(x) assert mellin_transform(Ci(sqrt(x)), x, s) == ( -2 ** (2 * s - 1) * sqrt(pi) * gamma(s) / (s * gamma(-s + S(1) / 2)), (0, 1), True, ) assert inverse_mellin_transform( -4 ** s * sqrt(pi) * gamma(s) / (2 * s * gamma(-s + S(1) / 2)), s, u, (0, 1) ).expand() == Ci(sqrt(u)) # TODO LT of Si, Shi, Chi is a mess ... assert laplace_transform(Ci(x), x, s) == (-log(1 + s ** 2) / 2 / s, 0, True) assert laplace_transform(expint(a, x), x, s) == (lerchphi(s * polar_lift(-1), 1, a), 0, S(0) < re(a)) assert laplace_transform(expint(1, x), x, s) == (log(s + 1) / s, 0, True) assert laplace_transform(expint(2, x), x, s) == ((s - log(s + 1)) / s ** 2, 0, True) assert inverse_laplace_transform(-log(1 + s ** 2) / 2 / s, s, u).expand() == Heaviside(u) * Ci(u) assert inverse_laplace_transform(log(s + 1) / s, s, x).rewrite(expint) == Heaviside(x) * E1(x) assert ( inverse_laplace_transform((s - log(s + 1)) / s ** 2, s, x).rewrite(expint).expand() == (expint(2, x) * Heaviside(x)).rewrite(Ei).rewrite(expint).expand() )
def eval(cls, a, x): # For lack of a better place, we use this one to extract branching # information. The following can be # found in the literature (c/f references given above), albeit scattered: # 1) For fixed x != 0, lowergamma(s, x) is an entire function of s # 2) For fixed positive integers s, lowergamma(s, x) is an entire # function of x. # 3) For fixed non-positive integers s, # lowergamma(s, exp(I*2*pi*n)*x) = # 2*pi*I*n*(-1)**(-s)/factorial(-s) + lowergamma(s, x) # (this follows from lowergamma(s, x).diff(x) = x**(s-1)*exp(-x)). # 4) For fixed non-integral s, # lowergamma(s, x) = x**s*gamma(s)*lowergamma_unbranched(s, x), # where lowergamma_unbranched(s, x) is an entire function (in fact # of both s and x), i.e. # lowergamma(s, exp(2*I*pi*n)*x) = exp(2*pi*I*n*a)*lowergamma(a, x) from sympy import unpolarify, I if x == 0: return S.Zero nx, n = x.extract_branch_factor() if a.is_integer and a.is_positive: nx = unpolarify(x) if nx != x: return lowergamma(a, nx) elif a.is_integer and a.is_nonpositive: if n != 0: return 2 * pi * I * n * (-1)**( -a) / factorial(-a) + lowergamma(a, nx) elif n != 0: return exp(2 * pi * I * n * a) * lowergamma(a, nx) # Special values. if a.is_Number: # TODO this should be non-recursive if a is S.One: return S.One - exp(-x) elif a is S.Half: return sqrt(pi) * erf(sqrt(x)) elif a.is_Integer or (2 * a).is_Integer: b = a - 1 if b.is_positive: return b * cls(b, x) - x**b * exp(-x) if not a.is_Integer: return (cls(a + 1, x) + x**a * exp(-x)) / a
def _prep_tuple(v): """ Turn an iterable argument V into a Tuple and unpolarify, since both hypergeometric and meijer g-functions are unbranched in their parameters. Examples ======== >>> from sympy.functions.special.hyper import _prep_tuple >>> _prep_tuple([1, 2, 3]) (1, 2, 3) >>> _prep_tuple((4, 5)) (4, 5) >>> _prep_tuple((7, 8, 9)) (7, 8, 9) """ from sympy import unpolarify return TupleArg(*[unpolarify(x) for x in v])
def _make_tuple(v): """ Turn an iterable argument V into a Tuple. Also unpolarify, since both hypergeometric and meijer g-functions are unbranched in their parameters. Examples: >>> from sympy.functions.special.hyper import _make_tuple as mt >>> from sympy.core.containers import Tuple >>> mt([1, 2, 3]) (1, 2, 3) >>> mt((4, 5)) (4, 5) >>> mt((7, 8, 9)) (7, 8, 9) """ from sympy import unpolarify return Tuple(*[unpolarify(sympify(x)) for x in v])
def test_expint(): from sympy import E1, expint, Max, re, lerchphi, Symbol, simplify, Si, Ci, Ei aneg = Symbol('a', negative=True) u = Symbol('u', polar=True) assert mellin_transform(E1(x), x, s) == (gamma(s) / s, (0, oo), True) assert inverse_mellin_transform(gamma(s) / s, s, x, (0, oo)).rewrite(expint).expand() == E1(x) assert mellin_transform(expint(a, x), x, s) == \ (gamma(s)/(a + s - 1), (Max(1 - re(a), 0), oo), True) # XXX IMT has hickups with complicated strips ... assert simplify(unpolarify( inverse_mellin_transform(gamma(s)/(aneg + s - 1), s, x, (1 - aneg, oo)).rewrite(expint).expand(func=True))) == \ expint(aneg, x) assert mellin_transform(Si(x), x, s) == \ (-2**s*sqrt(pi)*gamma(s/2 + S(1)/2)/( 2*s*gamma(-s/2 + 1)), (-1, 0), True) assert inverse_mellin_transform(-2**s*sqrt(pi)*gamma((s + 1)/2) /(2*s*gamma(-s/2 + 1)), s, x, (-1, 0)) \ == Si(x) assert mellin_transform(Ci(sqrt(x)), x, s) == \ (-2**(2*s - 1)*sqrt(pi)*gamma(s)/(s*gamma(-s + S(1)/2)), (0, 1), True) assert inverse_mellin_transform( -4**s * sqrt(pi) * gamma(s) / (2 * s * gamma(-s + S(1) / 2)), s, u, (0, 1)).expand() == Ci(sqrt(u)) # TODO LT of Si, Shi, Chi is a mess ... assert laplace_transform(Ci(x), x, s) == (-log(1 + s**2) / 2 / s, 0, True) assert laplace_transform(expint(a, x), x, s) == \ (lerchphi(s*polar_lift(-1), 1, a), 0, S(0) < re(a)) assert laplace_transform(expint(1, x), x, s) == (log(s + 1) / s, 0, True) assert laplace_transform(expint(2, x), x, s) == \ ((s - log(s + 1))/s**2, 0, True) assert inverse_laplace_transform(-log(1 + s**2)/2/s, s, u).expand() == \ Heaviside(u)*Ci(u) assert inverse_laplace_transform(log(s + 1)/s, s, x).rewrite(expint) == \ Heaviside(x)*E1(x) assert inverse_laplace_transform((s - log(s + 1))/s**2, s, x).rewrite(expint).expand() == \ (expint(2, x)*Heaviside(x)).rewrite(Ei).rewrite(expint).expand()
def eval(cls, a, x): # For lack of a better place, we use this one to extract branching # information. The following can be # found in the literature (c/f references given above), albeit scattered: # 1) For fixed x != 0, lowergamma(s, x) is an entire function of s # 2) For fixed positive integers s, lowergamma(s, x) is an entire # function of x. # 3) For fixed non-positive integers s, # lowergamma(s, exp(I*2*pi*n)*x) = # 2*pi*I*n*(-1)**(-s)/factorial(-s) + lowergamma(s, x) # (this follows from lowergamma(s, x).diff(x) = x**(s-1)*exp(-x)). # 4) For fixed non-integral s, # lowergamma(s, x) = x**s*gamma(s)*lowergamma_unbranched(s, x), # where lowergamma_unbranched(s, x) is an entire function (in fact # of both s and x), i.e. # lowergamma(s, exp(2*I*pi*n)*x) = exp(2*pi*I*n*a)*lowergamma(a, x) from sympy import unpolarify, I if x == 0: return S.Zero nx, n = x.extract_branch_factor() if a.is_integer and a.is_positive: nx = unpolarify(x) if nx != x: return lowergamma(a, nx) elif a.is_integer and a.is_nonpositive: if n != 0: return 2*pi*I*n*(-1)**(-a)/factorial(-a) + lowergamma(a, nx) elif n != 0: return exp(2*pi*I*n*a)*lowergamma(a, nx) # Special values. if a.is_Number: # TODO this should be non-recursive if a is S.One: return S.One - exp(-x) elif a is S.Half: return sqrt(pi)*erf(sqrt(x)) elif a.is_Integer or (2*a).is_Integer: b = a - 1 if b.is_positive: return b*cls(b, x) - x**b * exp(-x) if not a.is_Integer: return (cls(a + 1, x) + x**a * exp(-x))/a
def can_do_meijer(a1, a2, b1, b2, numeric=True): """ This helper function tries to hyperexpand() the meijer g-function corresponding to the parameters a1, a2, b1, b2. It returns False if this expansion still contains g-functions. If numeric is True, it also tests the so-obtained formula numerically (at random values) and returns False if the test fails. Else it returns True. """ from sympy import unpolarify, expand r = hyperexpand(meijerg(a1, a2, b1, b2, z)) if r.has(meijerg): return False # NOTE hyperexpand() returns a truly branched function, whereas numerical # evaluation only works on the main branch. Since we are evaluating on # the main branch, this should not be a problem, but expressions like # exp_polar(I*pi/2*x)**a are evaluated incorrectly. We thus have to get # rid of them. The expand heuristically does this... r = unpolarify( expand( r, force=True, power_base=True, power_exp=False, mul=False, log=False, multinomial=False, basic=False, )) if not numeric: return True repl = {} for n, ai in enumerate(meijerg(a1, a2, b1, b2, z).free_symbols - {z}): repl[ai] = randcplx(n) return tn(meijerg(a1, a2, b1, b2, z).subs(repl), r.subs(repl), z)
def test_unpolarify(): from sympy import (exp_polar, polar_lift, exp, unpolarify, principal_branch) from sympy import gamma, erf, sin, tanh, uppergamma, Eq, Ne from sympy.abc import x p = exp_polar(7 * I) + 1 u = exp(7 * I) + 1 assert unpolarify(1) == 1 assert unpolarify(p) == u assert unpolarify(p**2) == u**2 assert unpolarify(p**x) == p**x assert unpolarify(p * x) == u * x assert unpolarify(p + x) == u + x assert unpolarify(sqrt(sin(p))) == sqrt(sin(u)) # Test reduction to principal branch 2*pi. t = principal_branch(x, 2 * pi) assert unpolarify(t) == x assert unpolarify(sqrt(t)) == sqrt(t) # Test exponents_only. assert unpolarify(p**p, exponents_only=True) == p**u assert unpolarify(uppergamma(x, p**p)) == uppergamma(x, p**u) # Test functions. assert unpolarify(sin(p)) == sin(u) assert unpolarify(tanh(p)) == tanh(u) assert unpolarify(gamma(p)) == gamma(u) assert unpolarify(erf(p)) == erf(u) assert unpolarify(uppergamma(x, p)) == uppergamma(x, p) assert unpolarify(uppergamma(sin(p), sin(p + exp_polar(0)))) == \ uppergamma(sin(u), sin(u + 1)) assert unpolarify(uppergamma(polar_lift(0), 2*exp_polar(0))) == \ uppergamma(0, 2) assert unpolarify(Eq(p, 0)) == Eq(u, 0) assert unpolarify(Ne(p, 0)) == Ne(u, 0) assert unpolarify(polar_lift(x) > 0) == (x > 0) # Test bools assert unpolarify(True) is True
def _eval_expand_log(self, deep=True, **hints): from sympy import unpolarify, expand_log, factorint from sympy.concrete import Sum, Product from sympy.functions.elementary.complexes import Abs force = hints.get('force', False) factor = hints.get('factor', False) if (len(self.args) == 2): return expand_log(self.func(*self.args), deep=deep, force=force) arg = self.args[0] if arg.is_Integer: # remove perfect powers p = perfect_power(arg) logarg = None coeff = 1 if p is not False: arg, coeff = p logarg = self.func(arg) # expand as product of its prime factors if factor=True if factor: p = factorint(arg) if arg not in p.keys(): logarg = sum(n * log(val) for val, n in p.items()) if logarg is not None: return coeff * logarg elif arg.is_Rational: return log(arg.p) - log(arg.q) elif arg.is_Mul: expr = [] nonpos = [] for x in arg.args: if force or (x.is_real and not x.is_negative) or x.is_polar: a = self.func(x) if isinstance(a, log): expr.append(self.func(x)._eval_expand_log(**hints)) else: expr.append(a) elif x.is_negative: a = self.func(-x) expr.append(a) nonpos.append(S.NegativeOne) else: nonpos.append(x) return Add(*expr) + log(Mul(*nonpos)) elif arg.is_Pow or isinstance(arg, exp): # expanding log(b^e) b = arg.base e = arg.exp if e % 2 == 0 and b.is_real: # even power and real base obeys the power rule: log(b^e) = e log(Abs(b)) return e * self.func(Abs(b)) elif e % 2 == 1 and b.is_real: # odd power and real base obeys the power rule: log(b^e) = e log(b) return e * self.func(b) elif force or (e.is_extended_real and (b.is_positive or ((e + 1).is_positive and (e - 1).is_nonpositive))) or b.is_polar: a = self.func(b) if isinstance(a, log): return unpolarify(e) * a._eval_expand_log(**hints) else: return unpolarify(e) * a elif isinstance(arg, Product): if force or arg.function.is_positive: return Sum(log(arg.function), *arg.limits) return self.func(arg)
def eval(cls, arg, base=None): from sympy import unpolarify arg = sympify(arg) if base is not None: base = sympify(base) if base == 1: if arg == 1: return S.NaN else: return S.ComplexInfinity try: # handle extraction of powers of the base now # or else expand_log in Mul would have to handle this n = multiplicity(base, arg) if n: den = base**n if den.is_Integer: return n + log(arg // den) / log(base) else: return n + log(arg / den) / log(base) else: return log(arg)/log(base) except ValueError: pass if base is not S.Exp1: return cls(arg)/cls(base) else: return cls(arg) if arg.is_Number: if arg is S.Zero: return S.ComplexInfinity elif arg is S.One: return S.Zero elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.Infinity elif arg is S.NaN: return S.NaN elif arg.is_negative: return S.Pi * S.ImaginaryUnit + cls(-arg) elif arg.is_Rational: if arg.q != 1: return cls(arg.p) - cls(arg.q) elif arg is S.ComplexInfinity: return S.ComplexInfinity elif arg is S.Exp1: return S.One elif arg.func is exp and arg.args[0].is_real: return arg.args[0] elif arg.func is exp_polar: return unpolarify(arg.exp) #don't autoexpand Pow or Mul (see the issue 252): elif not arg.is_Add: coeff = arg.as_coefficient(S.ImaginaryUnit) if coeff is not None: if coeff is S.Infinity: return S.Infinity elif coeff is S.NegativeInfinity: return S.Infinity elif coeff.is_Rational: if coeff.is_nonnegative: return S.Pi * S.ImaginaryUnit * S.Half + cls(coeff) else: return -S.Pi * S.ImaginaryUnit * S.Half + cls(-coeff)
def test_unpolarify(): from sympy import (exp_polar, polar_lift, exp, unpolarify, principal_branch) from sympy import gamma, erf, sin, tanh, uppergamma, Eq, Ne from sympy.abc import x p = exp_polar(7*I) + 1 u = exp(7*I) + 1 assert unpolarify(1) == 1 assert unpolarify(p) == u assert unpolarify(p**2) == u**2 assert unpolarify(p**x) == p**x assert unpolarify(p*x) == u*x assert unpolarify(p + x) == u + x assert unpolarify(sqrt(sin(p))) == sqrt(sin(u)) # Test reduction to principal branch 2*pi. t = principal_branch(x, 2*pi) assert unpolarify(t) == x assert unpolarify(sqrt(t)) == sqrt(t) # Test exponents_only. assert unpolarify(p**p, exponents_only=True) == p**u assert unpolarify(uppergamma(x, p**p)) == uppergamma(x, p**u) # Test functions. assert unpolarify(sin(p)) == sin(u) assert unpolarify(tanh(p)) == tanh(u) assert unpolarify(gamma(p)) == gamma(u) assert unpolarify(erf(p)) == erf(u) assert unpolarify(uppergamma(x, p)) == uppergamma(x, p) assert unpolarify(uppergamma(sin(p), sin(p + exp_polar(0)))) == \ uppergamma(sin(u), sin(u + 1)) assert unpolarify(uppergamma(polar_lift(0), 2*exp_polar(0))) == \ uppergamma(0, 2) assert unpolarify(Eq(p, 0)) == Eq(u, 0) assert unpolarify(Ne(p, 0)) == Ne(u, 0) assert unpolarify(polar_lift(x) > 0) == (x > 0) # Test bools assert unpolarify(True) is True
def _eval_expand_func(self, **hints): from sympy import exp, I, floor, Add, Poly, Dummy, exp_polar, unpolarify z, s, a = self.args if z == 1: return zeta(s, a) if s.is_Integer and s <= 0: t = Dummy("t") p = Poly((t + a) ** (-s), t) start = 1 / (1 - t) res = S.Zero for c in reversed(p.all_coeffs()): res += c * start start = t * start.diff(t) return res.subs(t, z) if a.is_Rational: # See section 18 of # Kelly B. Roach. Hypergeometric Function Representations. # In: Proceedings of the 1997 International Symposium on Symbolic and # Algebraic Computation, pages 205-211, New York, 1997. ACM. # TODO should something be polarified here? add = S.Zero mul = S.One # First reduce a to the interaval (0, 1] if a > 1: n = floor(a) if n == a: n -= 1 a -= n mul = z ** (-n) add = Add(*[-(z ** (k - n)) / (a + k) ** s for k in range(n)]) elif a <= 0: n = floor(-a) + 1 a += n mul = z ** n add = Add(*[z ** (n - 1 - k) / (a - k - 1) ** s for k in range(n)]) m, n = S([a.p, a.q]) zet = exp_polar(2 * pi * I / n) root = z ** (1 / n) return add + mul * n ** (s - 1) * Add( *[ polylog(s, zet ** k * root)._eval_expand_func(**hints) / (unpolarify(zet) ** k * root) ** m for k in range(n) ] ) # TODO use minpoly instead of ad-hoc methods when issue 5888 is fixed if ( isinstance(z, exp) and (z.args[0] / (pi * I)).is_Rational or z in [-1, I, -I] ): # TODO reference? if z == -1: p, q = S([1, 2]) elif z == I: p, q = S([1, 4]) elif z == -I: p, q = S([-1, 4]) else: arg = z.args[0] / (2 * pi * I) p, q = S([arg.p, arg.q]) return Add( *[ exp(2 * pi * I * k * p / q) / q ** s * zeta(s, (k + a) / q) for k in range(q) ] ) return lerchphi(z, s, a)
def eval(cls, arg, base=None): from sympy import unpolarify from sympy.calculus import AccumBounds from sympy.sets.setexpr import SetExpr arg = sympify(arg) if base is not None: base = sympify(base) if base == 1: if arg == 1: return S.NaN else: return S.ComplexInfinity try: # handle extraction of powers of the base now # or else expand_log in Mul would have to handle this n = multiplicity(base, arg) if n: den = base**n if den.is_Integer: return n + log(arg // den) / log(base) else: return n + log(arg / den) / log(base) else: return log(arg)/log(base) except ValueError: pass if base is not S.Exp1: return cls(arg)/cls(base) else: return cls(arg) if arg.is_Number: if arg is S.Zero: return S.ComplexInfinity elif arg is S.One: return S.Zero elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.Infinity elif arg is S.NaN: return S.NaN elif arg.is_Rational and arg.p == 1: return -cls(arg.q) if arg is S.ComplexInfinity: return S.ComplexInfinity if isinstance(arg, exp) and arg.args[0].is_real: return arg.args[0] elif isinstance(arg, exp_polar): return unpolarify(arg.exp) elif isinstance(arg, AccumBounds): if arg.min.is_positive: return AccumBounds(log(arg.min), log(arg.max)) else: return elif isinstance(arg, SetExpr): return arg._eval_func(cls) if arg.is_number: if arg.is_negative: return S.Pi * S.ImaginaryUnit + cls(-arg) elif arg is S.ComplexInfinity: return S.ComplexInfinity elif arg is S.Exp1: return S.One # don't autoexpand Pow or Mul (see the issue 3351): if not arg.is_Add: coeff = arg.as_coefficient(S.ImaginaryUnit) if coeff is not None: if coeff is S.Infinity: return S.Infinity elif coeff is S.NegativeInfinity: return S.Infinity elif coeff.is_Rational: if coeff.is_nonnegative: return S.Pi * S.ImaginaryUnit * S.Half + cls(coeff) else: return -S.Pi * S.ImaginaryUnit * S.Half + cls(-coeff)
def fdiff(self, argindex=1): from sympy import unpolarify arg = unpolarify(self.args[0]) if argindex == 1: return self._trigfunc(arg)/arg
def eval(cls, ap, bq, z): from sympy import unpolarify if len(ap) <= len(bq) or (len(ap) == len(bq) + 1 and (Abs(z) <= 1) == True): nz = unpolarify(z) if z != nz: return hyper(ap, bq, nz)
def eval(cls, arg, base=None): from sympy import unpolarify arg = sympify(arg) if base is not None: base = sympify(base) if base == 1: if arg == 1: return S.NaN else: return S.ComplexInfinity try: if not (base.is_positive and arg.is_positive): raise ValueError n = multiplicity(base, arg) if n: den = base**n if den.is_Integer: return n + log(arg // den) / log(base) else: return n + log(arg / den) / log(base) else: return log(arg)/log(base) except ValueError: pass if base is not S.Exp1: return cls(arg)/cls(base) else: return cls(arg) if arg.is_Number: if arg is S.Zero: return S.ComplexInfinity elif arg is S.One: return S.Zero elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.Infinity elif arg is S.NaN: return S.NaN elif arg.is_negative: return S.Pi * S.ImaginaryUnit + cls(-arg) elif arg.is_Rational: if arg.q != 1: return cls(arg.p) - cls(arg.q) # remove perfect powers automatically p = perfect_power(int(arg)) if p is not False: return p[1]*cls(p[0]) elif arg is S.ComplexInfinity: return S.ComplexInfinity elif arg is S.Exp1: return S.One elif arg.func is exp and arg.args[0].is_real: return arg.args[0] elif arg.func is exp_polar: return unpolarify(arg.exp) #don't autoexpand Pow or Mul (see the issue 252): elif not arg.is_Add: coeff = arg.as_coefficient(S.ImaginaryUnit) if coeff is not None: if coeff is S.Infinity: return S.Infinity elif coeff is S.NegativeInfinity: return S.Infinity elif coeff.is_Rational: if coeff.is_nonnegative: return S.Pi * S.ImaginaryUnit * S.Half + cls(coeff) else: return -S.Pi * S.ImaginaryUnit * S.Half + cls(-coeff)
def mysimp(expr): return expand( unpolarify(simplify(expand(expand_func(expr.rewrite(besselj))))))
def unpolarify(x): return diffify(sympy.unpolarify(x))
def eval(cls, a, z): from sympy import unpolarify, I, expint if z.is_Number: if z is S.NaN: return S.NaN elif z is S.Infinity: return S.Zero elif z.is_zero: if re(a).is_positive: return gamma(a) # We extract branching information here. C/f lowergamma. nx, n = z.extract_branch_factor() if a.is_integer and a.is_positive: nx = unpolarify(z) if z != nx: return uppergamma(a, nx) elif a.is_integer and a.is_nonpositive: if n != 0: return -2 * pi * I * n * (-1) ** (-a) / factorial(-a) + uppergamma( a, nx ) elif n != 0: return gamma(a) * (1 - exp(2 * pi * I * n * a)) + exp( 2 * pi * I * n * a ) * uppergamma(a, nx) # Special values. if a.is_Number: if a is S.Zero and z.is_positive: return -Ei(-z) elif a is S.One: return exp(-z) elif a is S.Half: return sqrt(pi) * erfc(sqrt(z)) elif a.is_Integer or (2 * a).is_Integer: b = a - 1 if b.is_positive: if a.is_integer: return ( exp(-z) * factorial(b) * Add(*[z ** k / factorial(k) for k in range(a)]) ) else: return gamma(a) * erfc(sqrt(z)) + (-1) ** (a - S(3) / 2) * exp( -z ) * sqrt(z) * Add( *[ gamma(-S.Half - k) * (-z) ** k / gamma(1 - a) for k in range(a - S.Half) ] ) elif b.is_Integer: return expint(-b, z) * unpolarify(z) ** (b + 1) if not a.is_Integer: return (-1) ** (S.Half - a) * pi * erfc(sqrt(z)) / gamma( 1 - a ) - z ** a * exp(-z) * Add( *[ z ** k * gamma(a) / gamma(a + k + 1) for k in range(S.Half - a) ] ) if a.is_zero and z.is_positive: return -Ei(-z) if z.is_zero and re(a).is_positive: return gamma(a)
def test_issue_14216(): from sympy.functions.elementary.complexes import unpolarify A = MatrixSymbol("A", 2, 2) assert unpolarify(A[0, 0]) == A[0, 0] assert unpolarify(A[0, 0] * A[1, 0]) == A[0, 0] * A[1, 0]
def test_expint(): """ Test various exponential integrals. """ from sympy import ( expint, unpolarify, Symbol, Ci, Si, Shi, Chi, sin, cos, sinh, cosh, Ei, ) assert simplify( unpolarify( integrate(exp(-z * x) / x ** y, (x, 1, oo), meijerg=True, conds="none") .rewrite(expint) .expand(func=True) ) ) == expint(y, z) assert integrate(exp(-z * x) / x, (x, 1, oo), meijerg=True, conds="none").rewrite( expint ).expand() == expint(1, z) assert integrate( exp(-z * x) / x ** 2, (x, 1, oo), meijerg=True, conds="none" ).rewrite(expint).expand() == expint(2, z).rewrite(Ei).rewrite(expint) assert ( integrate(exp(-z * x) / x ** 3, (x, 1, oo), meijerg=True, conds="none") .rewrite(expint) .expand() == expint(3, z).rewrite(Ei).rewrite(expint).expand() ) t = Symbol("t", positive=True) assert integrate(-cos(x) / x, (x, t, oo), meijerg=True).expand() == Ci(t) assert integrate(-sin(x) / x, (x, t, oo), meijerg=True).expand() == Si(t) - pi / 2 assert integrate(sin(x) / x, (x, 0, z), meijerg=True) == Si(z) assert integrate(sinh(x) / x, (x, 0, z), meijerg=True) == Shi(z) assert integrate(exp(-x) / x, x, meijerg=True).expand().rewrite( expint ) == I * pi - expint(1, x) assert ( integrate(exp(-x) / x ** 2, x, meijerg=True).rewrite(expint).expand() == expint(1, x) - exp(-x) / x - I * pi ) u = Symbol("u", polar=True) assert integrate(cos(u) / u, u, meijerg=True).expand().as_independent(u)[1] == Ci(u) assert integrate(cosh(u) / u, u, meijerg=True).expand().as_independent(u)[1] == Chi( u ) assert integrate(expint(1, x), x, meijerg=True).rewrite( expint ).expand() == x * expint(1, x) - exp(-x) assert ( integrate(expint(2, x), x, meijerg=True).rewrite(expint).expand() == -(x ** 2) * expint(1, x) / 2 + x * exp(-x) / 2 - exp(-x) / 2 ) assert simplify( unpolarify( integrate(expint(y, x), x, meijerg=True).rewrite(expint).expand(func=True) ) ) == -expint(y + 1, x) assert integrate(Si(x), x, meijerg=True) == x * Si(x) + cos(x) assert integrate(Ci(u), u, meijerg=True).expand() == u * Ci(u) - sin(u) assert integrate(Shi(x), x, meijerg=True) == x * Shi(x) - cosh(x) assert integrate(Chi(u), u, meijerg=True).expand() == u * Chi(u) - sinh(u) assert integrate(Si(x) * exp(-x), (x, 0, oo), meijerg=True) == pi / 4 assert integrate(expint(1, x) * sin(x), (x, 0, oo), meijerg=True) == log(2) / 2
def eval(cls, arg, base=None): from sympy import unpolarify from sympy.calculus import AccumBounds from sympy.sets.setexpr import SetExpr from sympy.functions.elementary.complexes import Abs arg = sympify(arg) if base is not None: base = sympify(base) if base == 1: if arg == 1: return S.NaN else: return S.ComplexInfinity try: # handle extraction of powers of the base now # or else expand_log in Mul would have to handle this n = multiplicity(base, arg) if n: return n + log(arg / base**n) / log(base) else: return log(arg) / log(base) except ValueError: pass if base is not S.Exp1: return cls(arg) / cls(base) else: return cls(arg) if arg.is_Number: if arg.is_zero: return S.ComplexInfinity elif arg is S.One: return S.Zero elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.Infinity elif arg is S.NaN: return S.NaN elif arg.is_Rational and arg.p == 1: return -cls(arg.q) if arg.is_Pow and arg.base is S.Exp1 and arg.exp.is_extended_real: return arg.exp I = S.ImaginaryUnit if isinstance(arg, exp) and arg.exp.is_extended_real: return arg.exp elif isinstance(arg, exp) and arg.exp.is_number: r_, i_ = match_real_imag(arg.exp) if i_ and i_.is_comparable: i_ %= 2 * S.Pi if i_ > S.Pi: i_ -= 2 * S.Pi return r_ + expand_mul(i_ * I, deep=False) elif isinstance(arg, exp_polar): return unpolarify(arg.exp) elif isinstance(arg, AccumBounds): if arg.min.is_positive: return AccumBounds(log(arg.min), log(arg.max)) else: return elif isinstance(arg, SetExpr): return arg._eval_func(cls) if arg.is_number: if arg.is_negative: return S.Pi * I + cls(-arg) elif arg is S.ComplexInfinity: return S.ComplexInfinity elif arg is S.Exp1: return S.One if arg.is_zero: return S.ComplexInfinity # don't autoexpand Pow or Mul (see the issue 3351): if not arg.is_Add: coeff = arg.as_coefficient(I) if coeff is not None: if coeff is S.Infinity: return S.Infinity elif coeff is S.NegativeInfinity: return S.Infinity elif coeff.is_Rational: if coeff.is_nonnegative: return S.Pi * I * S.Half + cls(coeff) else: return -S.Pi * I * S.Half + cls(-coeff) if arg.is_number and arg.is_algebraic: # Match arg = coeff*(r_ + i_*I) with coeff>0, r_ and i_ real. coeff, arg_ = arg.as_independent(I, as_Add=False) if coeff.is_negative: coeff *= -1 arg_ *= -1 arg_ = expand_mul(arg_, deep=False) r_, i_ = arg_.as_independent(I, as_Add=True) i_ = i_.as_coefficient(I) if coeff.is_real and i_ and i_.is_real and r_.is_real: if r_.is_zero: if i_.is_positive: return S.Pi * I * S.Half + cls(coeff * i_) elif i_.is_negative: return -S.Pi * I * S.Half + cls(coeff * -i_) else: from sympy.simplify import ratsimp # Check for arguments involving rational multiples of pi t = (i_ / r_).cancel() t1 = (-t).cancel() atan_table = { # first quadrant only sqrt(3): S.Pi / 3, 1: S.Pi / 4, sqrt(5 - 2 * sqrt(5)): S.Pi / 5, sqrt(2) * sqrt(5 - sqrt(5)) / (1 + sqrt(5)): S.Pi / 5, sqrt(5 + 2 * sqrt(5)): S.Pi * Rational(2, 5), sqrt(2) * sqrt(sqrt(5) + 5) / (-1 + sqrt(5)): S.Pi * Rational(2, 5), sqrt(3) / 3: S.Pi / 6, sqrt(2) - 1: S.Pi / 8, sqrt(2 - sqrt(2)) / sqrt(sqrt(2) + 2): S.Pi / 8, sqrt(2) + 1: S.Pi * Rational(3, 8), sqrt(sqrt(2) + 2) / sqrt(2 - sqrt(2)): S.Pi * Rational(3, 8), sqrt(1 - 2 * sqrt(5) / 5): S.Pi / 10, (-sqrt(2) + sqrt(10)) / (2 * sqrt(sqrt(5) + 5)): S.Pi / 10, sqrt(1 + 2 * sqrt(5) / 5): S.Pi * Rational(3, 10), (sqrt(2) + sqrt(10)) / (2 * sqrt(5 - sqrt(5))): S.Pi * Rational(3, 10), 2 - sqrt(3): S.Pi / 12, (-1 + sqrt(3)) / (1 + sqrt(3)): S.Pi / 12, 2 + sqrt(3): S.Pi * Rational(5, 12), (1 + sqrt(3)) / (-1 + sqrt(3)): S.Pi * Rational(5, 12) } if t in atan_table: modulus = ratsimp(coeff * Abs(arg_)) if r_.is_positive: return cls(modulus) + I * atan_table[t] else: return cls(modulus) + I * (atan_table[t] - S.Pi) elif t1 in atan_table: modulus = ratsimp(coeff * Abs(arg_)) if r_.is_positive: return cls(modulus) + I * (-atan_table[t1]) else: return cls(modulus) + I * (S.Pi - atan_table[t1])
def eval(cls, ap, bq, z): from sympy import unpolarify if len(ap) <= len(bq): nz = unpolarify(z) if z != nz: return hyper(ap, bq, nz)
def eval(cls, arg, base=None): from sympy import unpolarify from sympy.calculus import AccumBounds from sympy.sets.setexpr import SetExpr arg = sympify(arg) if base is not None: base = sympify(base) if base == 1: if arg == 1: return S.NaN else: return S.ComplexInfinity try: # handle extraction of powers of the base now # or else expand_log in Mul would have to handle this n = multiplicity(base, arg) if n: den = base**n if den.is_Integer: return n + log(arg // den) / log(base) else: return n + log(arg / den) / log(base) else: return log(arg) / log(base) except ValueError: pass if base is not S.Exp1: return cls(arg) / cls(base) else: return cls(arg) if arg.is_Number: if arg is S.Zero: return S.ComplexInfinity elif arg is S.One: return S.Zero elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.Infinity elif arg is S.NaN: return S.NaN elif arg.is_Rational and arg.p == 1: return -cls(arg.q) if arg is S.ComplexInfinity: return S.ComplexInfinity if isinstance(arg, exp) and arg.args[0].is_real: return arg.args[0] elif isinstance(arg, exp_polar): return unpolarify(arg.exp) elif isinstance(arg, AccumBounds): if arg.min.is_positive: return AccumBounds(log(arg.min), log(arg.max)) else: return elif isinstance(arg, SetExpr): return arg._eval_func(cls) if arg.is_number: if arg.is_negative: return S.Pi * S.ImaginaryUnit + cls(-arg) elif arg is S.ComplexInfinity: return S.ComplexInfinity elif arg is S.Exp1: return S.One # don't autoexpand Pow or Mul (see the issue 3351): if not arg.is_Add: coeff = arg.as_coefficient(S.ImaginaryUnit) if coeff is not None: if coeff is S.Infinity: return S.Infinity elif coeff is S.NegativeInfinity: return S.Infinity elif coeff.is_Rational: if coeff.is_nonnegative: return S.Pi * S.ImaginaryUnit * S.Half + cls(coeff) else: return -S.Pi * S.ImaginaryUnit * S.Half + cls(-coeff)