def _eval_expand_trig(self, **hints): from sympy import expand_mul arg = self.args[0] x = None if arg.is_Add: # TODO, implement more if deep stuff here # TODO: Do this more efficiently for more than two terms x, y = arg.as_two_terms() sx = sin(x, evaluate=False)._eval_expand_trig() sy = sin(y, evaluate=False)._eval_expand_trig() cx = cos(x, evaluate=False)._eval_expand_trig() cy = cos(y, evaluate=False)._eval_expand_trig() return sx * cy + sy * cx else: n, x = arg.as_coeff_Mul(rational=True) if n.is_Integer: # n will be positive because of .eval # canonicalization # See http://mathworld.wolfram.com/Multiple-AngleFormulas.html if n.is_odd: return (-1)**((n - 1) / 2) * C.chebyshevt(n, sin(x)) else: return expand_mul((-1)**(n / 2 - 1) * cos(x) * C.chebyshevu(n - 1, sin(x)), deep=False) pi_coeff = _pi_coeff(arg) if pi_coeff is not None: if pi_coeff.is_Rational: return self.rewrite(sqrt) return sin(arg)
def _eval_expand_trig(self, **hints): from sympy import expand_mul arg = self.args[0] x = None if arg.is_Add: # TODO, implement more if deep stuff here # TODO: Do this more efficiently for more than two terms x, y = arg.as_two_terms() sx = sin(x, evaluate=False)._eval_expand_trig() sy = sin(y, evaluate=False)._eval_expand_trig() cx = cos(x, evaluate=False)._eval_expand_trig() cy = cos(y, evaluate=False)._eval_expand_trig() return sx*cy + sy*cx else: n, x = arg.as_coeff_Mul(rational=True) if n.is_Integer: # n will be positive because of .eval # canonicalization # See http://mathworld.wolfram.com/Multiple-AngleFormulas.html if n.is_odd: return (-1)**((n - 1)/2)*C.chebyshevt(n, sin(x)) else: return expand_mul((-1)**(n/2 - 1)*cos(x)*C.chebyshevu(n - 1, sin(x)), deep=False) pi_coeff = _pi_coeff(arg) if pi_coeff is not None: if pi_coeff.is_Rational: return self.rewrite(sqrt) return sin(arg)
def _eval_expand_trig(self, *args): arg = self.args[0].expand() x = None if arg.is_Add: x = arg.args[0] y = C.Add(*arg.args[1:]) return (cos(x)*cos(y) - sin(y)*sin(x)).expand(trig=True) else: coeff, terms = arg.as_coeff_terms() if not (coeff is S.One) and coeff.is_Integer and terms: x = C.Mul(*terms) return C.chebyshevt(coeff, cos(x)) return cos(arg)
def _eval_expand_trig(self, *args): arg = self.args[0].expand() x = None if arg.is_Add: x = arg.args[0] y = C.Add(*arg.args[1:]) return (cos(x) * cos(y) - sin(y) * sin(x)).expand(trig=True) else: coeff, terms = arg.as_coeff_terms() if not (coeff is S.One) and coeff.is_Integer and terms: x = C.Mul(*terms) return C.chebyshevt(coeff, cos(x)) return cos(arg)
def _eval_expand_trig(self, deep=True, **hints): if deep: arg = self.args[0].expand() else: arg = self.args[0] x = None if arg.is_Add: # TODO, implement more if deep stuff here x, y = arg.as_two_terms() return (cos(x)*cos(y) - sin(y)*sin(x)).expand(trig=True) else: coeff, terms = arg.as_coeff_Mul(rational=True) if coeff is not S.One and coeff.is_Integer and terms is not S.One: return C.chebyshevt(coeff, cos(terms)) return cos(arg)
def _eval_expand_trig(self, deep=True, **hints): if deep: arg = self.args[0].expand() else: arg = self.args[0] x = None if arg.is_Add: # TODO, implement more if deep stuff here x, y = arg.as_two_terms() return (cos(x) * cos(y) - sin(y) * sin(x)).expand(trig=True) else: coeff, terms = arg.as_coeff_mul() if not (coeff is S.One) and coeff.is_Integer and terms: x = arg._new_rawargs(*terms) return C.chebyshevt(coeff, cos(x)) return cos(arg)
def _eval_expand_trig(self, deep=True, **hints): if deep: arg = self.args[0].expand() else: arg = self.args[0] x = None if arg.is_Add: # TODO, implement more if deep stuff here x, y = arg.as_two_terms() return (cos(x)*cos(y) - sin(y)*sin(x)).expand(trig=True) else: coeff, terms = arg.as_coeff_mul() if not (coeff is S.One) and coeff.is_Integer and terms: x = arg._new_rawargs(*terms) return C.chebyshevt(coeff, cos(x)) return cos(arg)
def _eval_expand_trig(self, **hints): arg = self.args[0] x = None if arg.is_Add: # TODO: Do this more efficiently for more than two terms x, y = arg.as_two_terms() sx = sin(x)._eval_expand_trig() sy = sin(y)._eval_expand_trig() cx = cos(x)._eval_expand_trig() cy = cos(y)._eval_expand_trig() return cx*cy - sx*sy else: coeff, terms = arg.as_coeff_Mul(rational=True) if coeff.is_Integer: return C.chebyshevt(coeff, cos(terms)) return cos(arg)
def _eval_expand_trig(self, **hints): arg = self.args[0] x = None if arg.is_Add: # TODO: Do this more efficiently for more than two terms x, y = arg.as_two_terms() sx = sin(x)._eval_expand_trig() sy = sin(y)._eval_expand_trig() cx = cos(x)._eval_expand_trig() cy = cos(y)._eval_expand_trig() return cx * cy - sx * sy else: coeff, terms = arg.as_coeff_Mul(rational=True) if coeff.is_Integer: return C.chebyshevt(coeff, cos(terms)) return cos(arg)
def _eval_expand_trig(self, **hints): arg = self.args[0] x = None if arg.is_Add: # TODO: Do this more efficiently for more than two terms x, y = arg.as_two_terms() sx = sin(x, evaluate=False)._eval_expand_trig() sy = sin(y, evaluate=False)._eval_expand_trig() cx = cos(x, evaluate=False)._eval_expand_trig() cy = cos(y, evaluate=False)._eval_expand_trig() return cx * cy - sx * sy else: coeff, terms = arg.as_coeff_Mul(rational=True) if coeff.is_Integer: return C.chebyshevt(coeff, cos(terms)) pi_coeff = _pi_coeff(arg) if pi_coeff is not None: if pi_coeff.is_Rational: return self.rewrite(sqrt) return cos(arg)
def _eval_expand_trig(self, **hints): arg = self.args[0] x = None if arg.is_Add: # TODO: Do this more efficiently for more than two terms x, y = arg.as_two_terms() sx = sin(x, evaluate=False)._eval_expand_trig() sy = sin(y, evaluate=False)._eval_expand_trig() cx = cos(x, evaluate=False)._eval_expand_trig() cy = cos(y, evaluate=False)._eval_expand_trig() return cx*cy - sx*sy else: coeff, terms = arg.as_coeff_Mul(rational=True) if coeff.is_Integer: return C.chebyshevt(coeff, cos(terms)) pi_coeff = _pi_coeff(arg) if pi_coeff is not None: if pi_coeff.is_Rational: return self.rewrite(sqrt) return cos(arg)
def _eval_rewrite_as_sqrt(self, arg): _EXPAND_INTS = False def migcdex(x): # recursive calcuation of gcd and linear combination # for a sequence of integers. # Given (x1, x2, x3) # Returns (y1, y1, y3, g) # such that g is the gcd and x1*y1+x2*y2+x3*y3 - g = 0 # Note, that this is only one such linear combination. if len(x) == 1: return (1, x[0]) if len(x) == 2: return igcdex(x[0], x[-1]) g = migcdex(x[1:]) u, v, h = igcdex(x[0], g[-1]) return tuple([u] + [v * i for i in g[0:-1]] + [h]) def ipartfrac(r, factors=None): if isinstance(r, int): return r assert isinstance(r, C.Rational) n = r.q if 2 > r.q * r.q: return r.q if None == factors: a = [n // x**y for x, y in factorint(r.q).iteritems()] else: a = [n // x for x in factors] if len(a) == 1: return [r] h = migcdex(a) ans = [r.p * C.Rational(i * j, r.q) for i, j in zip(h[:-1], a)] assert r == sum(ans) return ans pi_coeff = _pi_coeff(arg) if pi_coeff is None: return None assert not pi_coeff.is_integer, "should have been simplified already" if not pi_coeff.is_Rational: return None cst_table_some = { 3: S.Half, 5: (sqrt(5) + 1) / 4, 17: sqrt((15 + sqrt(17)) / 32 + sqrt(2) * (sqrt(17 - sqrt(17)) + sqrt( sqrt(2) * (-8 * sqrt(17 + sqrt(17)) - (1 - sqrt(17)) * sqrt(17 - sqrt(17))) + 6 * sqrt(17) + 34)) / 32) # 65537 and 257 are the only other known Fermat primes # Please add if you would like them } def fermatCoords(n): assert isinstance(n, int) assert n > 0 if n == 1 or 0 == n % 2: return False primes = dict([(p, 0) for p in cst_table_some]) assert 1 not in primes for p_i in primes: while 0 == n % p_i: n = n / p_i primes[p_i] += 1 if 1 != n: return False if max(primes.values()) > 1: return False return tuple([p for p in primes if primes[p] == 1]) if pi_coeff.q in cst_table_some: return C.chebyshevt(pi_coeff.p, cst_table_some[pi_coeff.q]).expand() if 0 == pi_coeff.q % 2: # recursively remove powers of 2 narg = (pi_coeff * 2) * S.Pi nval = cos(narg) if None == nval: return None nval = nval.rewrite(sqrt) if not _EXPAND_INTS: if (isinstance(nval, cos) or isinstance(-nval, cos)): return None x = (2 * pi_coeff + 1) / 2 sign_cos = (-1)**((-1 if x < 0 else 1) * int(abs(x))) return sign_cos * sqrt((1 + nval) / 2) FC = fermatCoords(pi_coeff.q) if FC: decomp = ipartfrac(pi_coeff, FC) X = [(x[1], x[0] * S.Pi) for x in zip(decomp, numbered_symbols('z'))] pcls = cos(sum([x[0] for x in X]))._eval_expand_trig().subs(X) return pcls.rewrite(sqrt) if _EXPAND_INTS: decomp = ipartfrac(pi_coeff) X = [(x[1], x[0] * S.Pi) for x in zip(decomp, numbered_symbols('z'))] pcls = cos(sum([x[0] for x in X]))._eval_expand_trig().subs(X) return pcls return None
def eval(cls, arg): if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Zero: return S.One elif arg is S.Infinity or arg is S.NegativeInfinity: # In this cases, it is unclear if we should # return S.NaN or leave un-evaluated. One # useful test case is how "limit(sin(x)/x,x,oo)" # is handled. # See test_sin_cos_with_infinity() an # Test for issue 209 # http://code.google.com/p/sympy/issues/detail?id=2097 # For now, we return un-evaluated. return if arg.could_extract_minus_sign(): return cls(-arg) i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return C.cosh(i_coeff) pi_coeff = _pi_coeff(arg) if pi_coeff is not None: if pi_coeff.is_integer: return (S.NegativeOne)**pi_coeff if not pi_coeff.is_Rational: narg = pi_coeff * S.Pi if narg != arg: return cls(narg) return None # cosine formula ##################### # http://code.google.com/p/sympy/issues/detail?id=2949 # explicit calculations are preformed for # cos(k pi / 8), cos(k pi /10), and cos(k pi / 12) # Some other exact values like cos(k pi/15) can be # calculated using a partial-fraction decomposition # by calling cos( X ).rewrite(sqrt) cst_table_some = { 3: S.Half, 5: (sqrt(5) + 1) / 4, } if pi_coeff.is_Rational: q = pi_coeff.q p = pi_coeff.p % (2 * q) if p > q: narg = (pi_coeff - 1) * S.Pi return -cls(narg) if 2 * p > q: narg = (1 - pi_coeff) * S.Pi return -cls(narg) # If nested sqrt's are worse than un-evaluation # you can require q in (1, 2, 3, 4, 6) # q <= 12 returns expressions with 2 or fewer nestings. if q > 12: return None if q in cst_table_some: cts = cst_table_some[pi_coeff.q] return C.chebyshevt(pi_coeff.p, cts).expand() if 0 == q % 2: narg = (pi_coeff * 2) * S.Pi nval = cls(narg) if None == nval: return None x = (2 * pi_coeff + 1) / 2 sign_cos = (-1)**((-1 if x < 0 else 1) * int(abs(x))) return sign_cos * sqrt((1 + nval) / 2) return None if arg.is_Add: x, m = _peeloff_pi(arg) if m: return cos(m) * cos(x) - sin(m) * sin(x) if arg.func is acos: return arg.args[0] if arg.func is atan: x = arg.args[0] return 1 / sqrt(1 + x**2) if arg.func is atan2: y, x = arg.args return x / sqrt(x**2 + y**2) if arg.func is asin: x = arg.args[0] return sqrt(1 - x**2) if arg.func is acot: x = arg.args[0] return 1 / sqrt(1 + 1 / x**2)
def _eval_rewrite_as_sqrt(self, arg): _EXPAND_INTS = False def migcdex(x): # recursive calcuation of gcd and linear combination # for a sequence of integers. # Given (x1, x2, x3) # Returns (y1, y1, y3, g) # such that g is the gcd and x1*y1+x2*y2+x3*y3 - g = 0 # Note, that this is only one such linear combination. if len(x) == 1: return (1, x[0]) if len(x) == 2: return igcdex(x[0], x[-1]) g = migcdex(x[1:]) u, v, h = igcdex(x[0], g[-1]) return tuple([u] + [v*i for i in g[0:-1] ] + [h]) def ipartfrac(r, factors=None): if isinstance(r, int): return r assert isinstance(r, C.Rational) n = r.q if 2 > r.q*r.q: return r.q if None == factors: a = [n/x**y for x, y in factorint(r.q).iteritems()] else: a = [n/x for x in factors] if len(a) == 1: return [ r ] h = migcdex(a) ans = [ r.p*C.Rational(i*j, r.q) for i, j in zip(h[:-1], a) ] assert r == sum(ans) return ans pi_coeff = _pi_coeff(arg) if pi_coeff is None: return None assert not pi_coeff.is_integer, "should have been simplified already" if not pi_coeff.is_Rational: return None cst_table_some = { 3: S.Half, 5: (sqrt(5) + 1)/4, 17: sqrt((15 + sqrt(17))/32 + sqrt(2)*(sqrt(17 - sqrt(17)) + sqrt(sqrt(2)*(-8*sqrt(17 + sqrt(17)) - (1 - sqrt(17)) *sqrt(17 - sqrt(17))) + 6*sqrt(17) + 34))/32) # 65537 and 257 are the only other known Fermat primes # Please add if you would like them } def fermatCoords(n): assert isinstance(n, int) assert n > 0 if n == 1 or 0 == n % 2: return False primes = dict( [(p, 0) for p in cst_table_some ] ) assert 1 not in primes for p_i in primes: while 0 == n % p_i: n = n/p_i primes[p_i] += 1 if 1 != n: return False if max(primes.values()) > 1: return False return tuple([ p for p in primes if primes[p] == 1]) if pi_coeff.q in cst_table_some: return C.chebyshevt(pi_coeff.p, cst_table_some[pi_coeff.q]).expand() if 0 == pi_coeff.q % 2: # recursively remove powers of 2 narg = (pi_coeff*2)*S.Pi nval = cos(narg) if None == nval: return None nval = nval.rewrite(sqrt) if not _EXPAND_INTS: if (isinstance(nval, cos) or isinstance(-nval, cos)): return None x = (2*pi_coeff + 1)/2 sign_cos = (-1)**((-1 if x < 0 else 1)*int(abs(x))) return sign_cos*sqrt( (1 + nval)/2 ) FC = fermatCoords(pi_coeff.q) if FC: decomp = ipartfrac(pi_coeff, FC) X = [(x[1], x[0]*S.Pi) for x in zip(decomp, numbered_symbols('z'))] pcls = cos(sum([x[0] for x in X]))._eval_expand_trig().subs(X) return pcls.rewrite(sqrt) if _EXPAND_INTS: decomp = ipartfrac(pi_coeff) X = [(x[1], x[0]*S.Pi) for x in zip(decomp, numbered_symbols('z'))] pcls = cos(sum([x[0] for x in X]))._eval_expand_trig().subs(X) return pcls return None
def eval(cls, arg): if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Zero: return S.One elif arg is S.Infinity or arg is S.NegativeInfinity: # In this cases, it is unclear if we should # return S.NaN or leave un-evaluated. One # useful test case is how "limit(sin(x)/x,x,oo)" # is handled. # See test_sin_cos_with_infinity() an # Test for issue 209 # http://code.google.com/p/sympy/issues/detail?id=2097 # For now, we return un-evaluated. return if arg.could_extract_minus_sign(): return cls(-arg) i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return C.cosh(i_coeff) pi_coeff = _pi_coeff(arg) if pi_coeff is not None: if pi_coeff.is_integer: return (S.NegativeOne)**pi_coeff if not pi_coeff.is_Rational: narg = pi_coeff*S.Pi if narg != arg: return cls(narg) return None # cosine formula ##################### # http://code.google.com/p/sympy/issues/detail?id=2949 # explicit calculations are preformed for # cos(k pi / 8), cos(k pi /10), and cos(k pi / 12) # Some other exact values like cos(k pi/15) can be # calculated using a partial-fraction decomposition # by calling cos( X ).rewrite(sqrt) cst_table_some = { 3: S.Half, 5: (sqrt(5) + 1)/4, } if pi_coeff.is_Rational: q = pi_coeff.q p = pi_coeff.p % (2*q) if p > q: narg = (pi_coeff - 1)*S.Pi return -cls(narg) if 2*p > q: narg = (1 - pi_coeff)*S.Pi return -cls(narg) # If nested sqrt's are worse than un-evaluation # you can require q in (1, 2, 3, 4, 6) # q <= 12 returns expressions with 2 or fewer nestings. if q > 12: return None if q in cst_table_some: cts = cst_table_some[pi_coeff.q] return C.chebyshevt(pi_coeff.p, cts).expand() if 0 == q % 2: narg = (pi_coeff*2)*S.Pi nval = cls(narg) if None == nval: return None x = (2*pi_coeff + 1)/2 sign_cos = (-1)**((-1 if x < 0 else 1)*int(abs(x))) return sign_cos*sqrt( (1 + nval)/2 ) return None if arg.is_Add: x, m = _peeloff_pi(arg) if m: return cos(m)*cos(x) - sin(m)*sin(x) if arg.func is acos: return arg.args[0] if arg.func is atan: x = arg.args[0] return 1 / sqrt(1 + x**2) if arg.func is atan2: y, x = arg.args return x / sqrt(x**2 + y**2) if arg.func is asin: x = arg.args[0] return sqrt(1 - x ** 2) if arg.func is acot: x = arg.args[0] return 1 / sqrt(1 + 1 / x**2)