def _eval_expand_mul(self, deep=True, **hints): hit = False sargs, terms = self.args, [] for term in sargs: if term.is_Mul: old = term hints['mul'] = True targs = [t._eval_expand_mul(deep=deep, **hints) for t in term.args] hints['mul'] = False term = Mul(*targs) newterm = term._eval_expand_mul(deep=deep, **hints) hit = hit or newterm != old else: hints['mul'] = True newterm = term._eval_expand_mul(deep=deep, **hints) terms.append(newterm) hints['mul'] = True if not hit: return self return self.func(*terms)
def as_numer_denom(self): # clear rational denominator content, expr = self.primitive() ncon, dcon = content.as_numer_denom() # collect numerators and denominators of the terms nd = defaultdict(list) for f in expr.args: ni, di = f.as_numer_denom() nd[di].append(ni) # put infinity in the numerator if S.Zero in nd: n = nd.pop(S.Zero) assert len(n) == 1 n = n[0] nd[S.One].append(n / S.Zero) # check for quick exit if len(nd) == 1: d, n = nd.popitem() return Add(*[_keep_coeff(ncon, ni) for ni in n]), _keep_coeff(dcon, d) # sum up the terms having a common denominator for d, n in nd.iteritems(): if len(n) == 1: nd[d] = n[0] else: nd[d] = Add(*n) # assemble single numerator and denominator denoms, numers = [list(i) for i in zip(*nd.iteritems())] n, d = Add(*[ Mul(*(denoms[:i] + [numers[i]] + denoms[i + 1:])) for i in xrange(len(numers)) ]), Mul(*denoms) return _keep_coeff(ncon, n), _keep_coeff(dcon, d)
def _eval_expand_mul(self, deep=True, **hints): hit = False sargs, terms = self.args, [] for term in sargs: if term.is_Mul: old = term hints['mul'] = True targs = [ t._eval_expand_mul(deep=deep, **hints) for t in term.args ] hints['mul'] = False term = Mul(*targs) newterm = term._eval_expand_mul(deep=deep, **hints) hit = hit or newterm != old else: hints['mul'] = True newterm = term._eval_expand_mul(deep=deep, **hints) terms.append(newterm) hints['mul'] = True if not hit: return self return self.func(*terms)
def _eval_expand_power_exp(self, deep=True, *args, **hints): """a**(n+m) -> a**n*a**m""" if deep: b = self.base.expand(deep=deep, **hints) e = self.exp.expand(deep=deep, **hints) else: b = self.base e = self.exp if e.is_Add and e.is_commutative: expr = [] for x in e.args: if deep: x = x.expand(deep=deep, **hints) expr.append(Pow(self.base, x)) return Mul(*expr) return Pow(b, e)
def _eval_power(b, e): if (e is S.NaN): return S.NaN if isinstance(e, Number): if isinstance(e, Real): return b._eval_evalf(e._prec)**e if e.is_negative: # (3/4)**-2 -> (4/3)**2 ne = -e if (ne is S.One): return Rational(b.q, b.p) if b < 0: if e.q != 1: return -(S.NegativeOne)**( (e.p % e.q) / S(e.q)) * Rational(b.q, -b.p)**ne else: return S.NegativeOne**ne * Rational(b.q, -b.p)**ne else: return Rational(b.q, b.p)**ne if (e is S.Infinity): if b.p > b.q: # (3/2)**oo -> oo return S.Infinity if b.p < -b.q: # (-3/2)**oo -> oo + I*oo return S.Infinity + S.Infinity * S.ImaginaryUnit return S.Zero if isinstance(e, Integer): # (4/3)**2 -> 4**2 / 3**2 return Rational(b.p**e.p, b.q**e.p) if isinstance(e, Rational): if b.p != 1: # (4/3)**(5/6) -> 4**(5/6) * 3**(-5/6) return Integer(b.p)**e * Integer(b.q)**(-e) if b >= 0: return Integer(b.q)**Rational( e.p * (e.q - 1), e.q) / (Integer(b.q)**Integer(e.p)) else: return (-1)**e * (-b)**e c, t = b.as_coeff_terms() if e.is_even and isinstance(c, Number) and c < 0: return (-c * Mul(*t))**e return
def as_content_primitive(self, radical=False): """Return the tuple (R, self/R) where R is the positive Rational extracted from self. If radical is True (default is False) then common radicals will be removed and included as a factor of the primitive expression. **Examples** >>> from sympy import sqrt >>> (3 + 3*sqrt(2)).as_content_primitive() (3, 1 + sqrt(2)) Radical content can also be factored out of the primitive: >>> (2*sqrt(2) + 4*sqrt(10)).as_content_primitive(radical=True) (2, sqrt(2)*(1 + 2*sqrt(5))) See docstring of Expr.as_content_primitive for more examples. """ con, prim = Add(*[_keep_coeff(*a.as_content_primitive(radical=radical)) for a in self.args]).primitive() if radical and prim.is_Add: # look for common radicals that can be removed args = prim.args rads = [] common_q = None for m in args: term_rads = defaultdict(list) for ai in Mul.make_args(m): if ai.is_Pow: b, e = ai.as_base_exp() if e.is_Rational and b.is_Integer and b > 0: term_rads[e.q].append(int(b)**e.p) if not term_rads: break if common_q is None: common_q = set(term_rads.keys()) else: common_q = common_q & set(term_rads.keys()) if not common_q: break rads.append(term_rads) else: # process rads # keep only those in common_q for r in rads: for q in r.keys(): if q not in common_q: r.pop(q) for q in r: r[q] = prod(r[q]) # find the gcd of bases for each q G = [] for q in common_q: g = reduce(igcd, [r[q] for r in rads], 0) if g != 1: G.append(Pow(g, Rational(1, q))) if G: G = Mul(*G) args = [ai/G for ai in args] prim = G*Add(*args) return con, prim
def flatten(cls, seq): """ Takes the sequence "seq" of nested Adds and returns a flatten list. Returns: (commutative_part, noncommutative_part, order_symbols) Applies associativity, all terms are commutable with respect to addition. ** Developer Notes ** See Mul.flatten """ rv = None if len(seq) == 2: a, b = seq if b.is_Rational: a, b = b, a assert a if a.is_Rational: if b.is_Mul: # if it's an unevaluated 2-arg, expand it c, t = b.as_coeff_Mul() if t.is_Add: h, t = t.as_coeff_Add() bargs = [c*ti for ti in Add.make_args(t)] bargs.sort(key=hash) ch = c*h if ch: bargs.insert(0, ch) b = Add._from_args(bargs) if b.is_Add: bargs = list(b.args) if bargs[0].is_Number: bargs[0] += a if not bargs[0]: bargs.pop(0) else: bargs.insert(0, a) rv = bargs, [], None elif b.is_Mul: rv = [a, b], [], None if rv: if all(s.is_commutative for s in rv[0]): return rv return [], rv[0], None terms = {} # term -> coeff # e.g. x**2 -> 5 for ... + 5*x**2 + ... coeff = S.Zero # standalone term (Number or zoo will always be in slot 0) # e.g. 3 + ... order_factors = [] for o in seq: # O(x) if o.is_Order: for o1 in order_factors: if o1.contains(o): o = None break if o is None: continue order_factors = [o]+[o1 for o1 in order_factors if not o.contains(o1)] continue # 3 or NaN elif o.is_Number: if o is S.NaN or coeff is S.ComplexInfinity and o.is_bounded is False: # we know for sure the result will be nan return [S.NaN], [], None if coeff.is_Number: coeff += o if coeff is S.NaN: # we know for sure the result will be nan return [S.NaN], [], None continue elif o is S.ComplexInfinity: if coeff.is_bounded is False: # we know for sure the result will be nan return [S.NaN], [], None coeff = S.ComplexInfinity continue # Add([...]) elif o.is_Add: # NB: here we assume Add is always commutative seq.extend(o.args) # TODO zerocopy? continue # Mul([...]) elif o.is_Mul: c, s = o.as_coeff_Mul() # 3*... # unevaluated 2-arg Mul, but we always unfold it so # it can combine with other terms (just like is done # with the Pow below) if c.is_Number and s.is_Add: seq.extend([c*a for a in s.args]) continue # check for unevaluated Pow, e.g. 2**3 or 2**(-1/2) elif o.is_Pow: b, e = o.as_base_exp() if b.is_Number and (e.is_Integer or (e.is_Rational and e.is_negative)): seq.append(Pow(b, e)) continue c, s = S.One, o else: # everything else c = S.One s = o # now we have: # o = c*s, where # # c is a Number # s is an expression with number factor extracted # let's collect terms with the same s, so e.g. # 2*x**2 + 3*x**2 -> 5*x**2 if s in terms: terms[s] += c else: terms[s] = c # now let's construct new args: # [2*x**2, x**3, 7*x**4, pi, ...] newseq = [] noncommutative = False for s,c in terms.items(): # 0*s if c is S.Zero: continue # 1*s elif c is S.One: newseq.append(s) # c*s else: if s.is_Mul: # Mul, already keeps its arguments in perfect order. # so we can simply put c in slot0 and go the fast way. cs = s._new_rawargs(*((c,) + s.args)) newseq.append(cs) else: # alternatively we have to call all Mul's machinery (slow) newseq.append(Mul(c,s)) noncommutative = noncommutative or not s.is_commutative # oo, -oo if coeff is S.Infinity: newseq = [f for f in newseq if not (f.is_nonnegative or f.is_real and (f.is_bounded or f.is_finite or f.is_infinitesimal))] elif coeff is S.NegativeInfinity: newseq = [f for f in newseq if not (f.is_nonpositive or f.is_real and (f.is_bounded or f.is_finite or f.is_infinitesimal))] if coeff is S.ComplexInfinity: # zoo might be # unbounded_real + bounded_im # bounded_real + unbounded_im # unbounded_real + unbounded_im # addition of a bounded real or imaginary number won't be able to # change the zoo nature; if unbounded a NaN condition could result if # the unbounded symbol had sign opposite of the unbounded portion of zoo, # e.g. unbounded_real - unbounded_real newseq = [c for c in newseq if not (c.is_bounded and c.is_real is not None)] # process O(x) if order_factors: newseq2 = [] for t in newseq: for o in order_factors: # x + O(x) -> O(x) if o.contains(t): t = None break # x + O(x**2) -> x + O(x**2) if t is not None: newseq2.append(t) newseq = newseq2 + order_factors # 1 + O(1) -> O(1) for o in order_factors: if o.contains(coeff): coeff = S.Zero break # order args canonically # Currently we sort things using hashes, as it is quite fast. A better # solution is not to sort things at all - but this needs some more # fixing. NOTE: this is used in primitive, too, so if it changes # here it should be changed there. newseq.sort(key=hash) # current code expects coeff to be always in slot-0 if coeff is not S.Zero: newseq.insert(0, coeff) # we are done if noncommutative: return [], newseq, None else: return newseq, [], None
def __rdiv__(self, other): return Mul(other, Pow(self, S.NegativeOne))
def __div__(self, other): return Mul(self, Pow(other, S.NegativeOne))
def __rmul__(self, other): return Mul(other, self)
def _eval_power(b, e): """ Tries to do some simplifications on b ** e, where b is an instance of Integer Returns None if no further simplifications can be done When exponent is a fraction (so we have for example a square root), we try to find a simpler representation by factoring the argument up to factors of 2**15, e.g. - 4**Rational(1,2) becomes 2 - (-4)**Rational(1,2) becomes 2*I - (2**(3+7)*3**(6+7))**Rational(1,7) becomes 6*18**(3/7) Further simplification would require a special call to factorint on the argument which is not done here for sake of speed. """ from sympy import perfect_power if e is S.NaN: return S.NaN if b is S.One: return S.One if b is S.NegativeOne: return if e is S.Infinity: if b > S.One: return S.Infinity if b is S.NegativeOne: return S.NaN # cases for 0 and 1 are done in their respective classes return S.Infinity + S.ImaginaryUnit * S.Infinity if not isinstance(e, Number): # simplify when exp is even # (-2) ** k --> 2 ** k c, t = b.as_coeff_mul() if e.is_even and isinstance(c, Number) and c < 0: return (-c*Mul(*t))**e if not isinstance(e, Rational): return if e is S.Half and b < 0: # we extract I for this special case since everyone is doing so return S.ImaginaryUnit*Pow(-b, e) if e < 0: # invert base and change sign on exponent ne = -e if b < 0: if e.q != 1: return -(S.NegativeOne)**((e.p % e.q) / S(e.q)) * Rational(1, -b)**ne else: return (S.NegativeOne)**ne*Rational(1, -b)**ne else: return Rational(1, b)**ne # see if base is a perfect root, sqrt(4) --> 2 b_pos = int(abs(b)) x, xexact = integer_nthroot(b_pos, e.q) if xexact: # if it's a perfect root we've finished result = Integer(x ** abs(e.p)) if b < 0: result *= (-1)**e return result # The following is an algorithm where we collect perfect roots # from the factors of base. # if it's not an nth root, it still might be a perfect power p = perfect_power(b_pos) if p: dict = {p[0]: p[1]} else: dict = Integer(b_pos).factors(limit=2**15) # now process the dict of factors if b.is_negative: dict[-1] = 1 out_int = 1 sqr_int = 1 sqr_gcd = 0 sqr_dict = {} for prime, exponent in dict.iteritems(): exponent *= e.p div_e, div_m = divmod(exponent, e.q) if div_e > 0: out_int *= prime**div_e if div_m > 0: sqr_dict[prime] = div_m for p, ex in sqr_dict.iteritems(): if sqr_gcd == 0: sqr_gcd = ex else: sqr_gcd = igcd(sqr_gcd, ex) for k, v in sqr_dict.iteritems(): sqr_int *= k**(v//sqr_gcd) if sqr_int == b and out_int == 1: result = None else: result = out_int*Pow(sqr_int , Rational(sqr_gcd, e.q)) return result
def flatten(cls, seq): """ Takes the sequence "seq" of nested Adds and returns a flatten list. Returns: (commutative_part, noncommutative_part, order_symbols) Applies associativity, all terms are commutable with respect to addition. """ terms = {} # term -> coeff # e.g. x**2 -> 5 for ... + 5*x**2 + ... coeff = S.Zero # standalone term # e.g. 3 + ... order_factors = [] for o in seq: # O(x) if o.is_Order: for o1 in order_factors: if o1.contains(o): o = None break if o is None: continue order_factors = [o] + [ o1 for o1 in order_factors if not o.contains(o1) ] continue # 3 or NaN elif o.is_Number: if o is S.NaN or coeff is S.ComplexInfinity and o.is_bounded is False: # we know for sure the result will be nan return [S.NaN], [], None if coeff.is_Number: coeff += o if coeff is S.NaN: # we know for sure the result will be nan return [S.NaN], [], None continue elif o is S.ComplexInfinity: if coeff.is_bounded is False: # we know for sure the result will be nan return [S.NaN], [], None coeff = S.ComplexInfinity continue # Add([...]) elif o.is_Add: # NB: here we assume Add is always commutative seq.extend(o.args) # TODO zerocopy? continue # Mul([...]) elif o.is_Mul: c, s = o.as_coeff_Mul() # 3*... if c.is_Number: # unevaluated 2-arg Mul if s.is_Add and s.is_commutative: seq.extend([c * a for a in s.args]) continue # everything else else: c = S.One s = o # now we have: # o = c*s, where # # c is a Number # s is an expression with number factor extracted # let's collect terms with the same s, so e.g. # 2*x**2 + 3*x**2 -> 5*x**2 if s in terms: terms[s] += c else: terms[s] = c # now let's construct new args: # [2*x**2, x**3, 7*x**4, pi, ...] newseq = [] noncommutative = False for s, c in terms.items(): # 0*s if c is S.Zero: continue # 1*s elif c is S.One: newseq.append(s) # c*s else: if s.is_Mul: # Mul, already keeps its arguments in perfect order. # so we can simply put c in slot0 and go the fast way. cs = s._new_rawargs(*((c, ) + s.args)) newseq.append(cs) else: # alternatively we have to call all Mul's machinery (slow) newseq.append(Mul(c, s)) noncommutative = noncommutative or not s.is_commutative # oo, -oo if coeff is S.Infinity: newseq = [ f for f in newseq if not (f.is_nonnegative or f.is_real and (f.is_bounded or f.is_finite or f.is_infinitesimal)) ] elif coeff is S.NegativeInfinity: newseq = [ f for f in newseq if not (f.is_nonpositive or f.is_real and (f.is_bounded or f.is_finite or f.is_infinitesimal)) ] if coeff is S.ComplexInfinity: # zoo might be # unbounded_real + bounded_im # bounded_real + unbounded_im # unbounded_real + unbounded_im # addition of a bounded real or imaginary number won't be able to # change the zoo nature; if unbounded a NaN condition could result if # the unbounded symbol had sign opposite of the unbounded portion of zoo, # e.g. unbounded_real - unbounded_real newseq = [ c for c in newseq if not (c.is_bounded and c.is_real is not None) ] # process O(x) if order_factors: newseq2 = [] for t in newseq: for o in order_factors: # x + O(x) -> O(x) if o.contains(t): t = None break # x + O(x**2) -> x + O(x**2) if t is not None: newseq2.append(t) newseq = newseq2 + order_factors # 1 + O(1) -> O(1) for o in order_factors: if o.contains(coeff): coeff = S.Zero break # order args canonically # Currently we sort things using hashes, as it is quite fast. A better # solution is not to sort things at all - but this needs some more # fixing. newseq.sort(key=hash) # current code expects coeff to be always in slot-0 if coeff is not S.Zero: newseq.insert(0, coeff) # we are done if noncommutative: return [], newseq, None else: return newseq, [], None
def flatten(cls, seq): """ Takes the sequence "seq" of nested Adds and returns a flatten list. Returns: (commutative_part, noncommutative_part, order_symbols) Applies associativity, all terms are commutable with respect to addition. """ terms = {} # term -> coeff # e.g. x**2 -> 5 for ... + 5*x**2 + ... coeff = S.Zero # standalone term # e.g. 3 + ... order_factors = [] for o in seq: # O(x) if o.is_Order: for o1 in order_factors: if o1.contains(o): o = None break if o is None: continue order_factors = [o]+[o1 for o1 in order_factors if not o.contains(o1)] continue # 3 elif o.is_Number: coeff += o continue # Add([...]) elif o.is_Add: # NB: here we assume Add is always commutative seq.extend(o.args) # TODO zerocopy? continue # Mul([...]) elif o.is_Mul: c = o.args[0] # 3*... if c.is_Number: if c is S.One: s = o else: s = o.as_two_terms()[1] else: c = S.One s = o # everything else else: c = S.One s = o # now we have: # o = c*s, where # # c is a Number # s is an expression with number factor extracted # let's collect terms with the same s, so e.g. # 2*x**2 + 3*x**2 -> 5*x**2 if s in terms: terms[s] += c else: terms[s] = c # now let's construct new args: # [2*x**2, x**3, 7*x**4, pi, ...] newseq = [] noncommutative = False for s,c in terms.items(): # 0*s if c is S.Zero: continue # 1*s elif c is S.One: newseq.append(s) # c*s else: if s.is_Mul: # Mul, already keeps it's arguments in perfect order. # so we can simply put c in slot0 and go the fast way. cs = s._new_rawargs(*((c,) + s.args)) newseq.append(cs) else: # alternatively we have to call all Mul's machinery (slow) newseq.append(Mul(c,s)) noncommutative = noncommutative or not s.is_commutative # nan if coeff is S.NaN: # we know for sure the result will be nan return [S.NaN], [], None # oo, -oo elif (coeff is S.Infinity) or (coeff is S.NegativeInfinity): newseq = [f for f in newseq if not f.is_real] # process O(x) if order_factors: newseq2 = [] for t in newseq: for o in order_factors: # x + O(x) -> O(x) if o.contains(t): t = None break # x + O(x**2) -> x + O(x**2) if t is not None: newseq2.append(t) newseq = newseq2 + order_factors # 1 + O(1) -> O(1) for o in order_factors: if o.contains(coeff): coeff = S.Zero break # order args canonically # Currently we sort things using hashes, as it is quite fast. A better # solution is not to sort things at all - but this needs some more # fixing. newseq.sort(key=hash) # current code expects coeff to be always in slot-0 if coeff is not S.Zero: newseq.insert(0, coeff) # we are done if noncommutative: return [], newseq, None else: return newseq, [], None
def flatten(cls, seq): """ Takes the sequence "seq" of nested Adds and returns a flatten list. Returns: (commutative_part, noncommutative_part, order_symbols) Applies associativity, all terms are commutable with respect to addition. NB: the removal of 0 is already handled by AssocOp.__new__ See also ======== sympy.core.mul.Mul.flatten """ rv = None if len(seq) == 2: a, b = seq if b.is_Rational: a, b = b, a if a.is_Rational: if b.is_Mul: rv = [a, b], [], None if rv: if all(s.is_commutative for s in rv[0]): return rv return [], rv[0], None terms = {} # term -> coeff # e.g. x**2 -> 5 for ... + 5*x**2 + ... coeff = S.Zero # coefficient (Number or zoo) to always be in slot 0 # e.g. 3 + ... order_factors = [] for o in seq: # O(x) if o.is_Order: for o1 in order_factors: if o1.contains(o): o = None break if o is None: continue order_factors = [o] + [ o1 for o1 in order_factors if not o.contains(o1) ] continue # 3 or NaN elif o.is_Number: if (o is S.NaN or coeff is S.ComplexInfinity and o.is_bounded is False): # we know for sure the result will be nan return [S.NaN], [], None if coeff.is_Number: coeff += o if coeff is S.NaN: # we know for sure the result will be nan return [S.NaN], [], None continue elif o is S.ComplexInfinity: if coeff.is_bounded is False: # we know for sure the result will be nan return [S.NaN], [], None coeff = S.ComplexInfinity continue # Add([...]) elif o.is_Add: # NB: here we assume Add is always commutative seq.extend(o.args) # TODO zerocopy? continue # Mul([...]) elif o.is_Mul: c, s = o.as_coeff_Mul() # check for unevaluated Pow, e.g. 2**3 or 2**(-1/2) elif o.is_Pow: b, e = o.as_base_exp() if b.is_Number and (e.is_Integer or (e.is_Rational and e.is_negative)): seq.append(b**e) continue c, s = S.One, o else: # everything else c = S.One s = o # now we have: # o = c*s, where # # c is a Number # s is an expression with number factor extracted # let's collect terms with the same s, so e.g. # 2*x**2 + 3*x**2 -> 5*x**2 if s in terms: terms[s] += c else: terms[s] = c # now let's construct new args: # [2*x**2, x**3, 7*x**4, pi, ...] newseq = [] noncommutative = False for s, c in terms.items(): # 0*s if c is S.Zero: continue # 1*s elif c is S.One: newseq.append(s) # c*s else: if s.is_Mul: # Mul, already keeps its arguments in perfect order. # so we can simply put c in slot0 and go the fast way. cs = s._new_rawargs(*((c, ) + s.args)) newseq.append(cs) elif s.is_Add: # we just re-create the unevaluated Mul newseq.append(Mul(c, s, evaluate=False)) else: # alternatively we have to call all Mul's machinery (slow) newseq.append(Mul(c, s)) noncommutative = noncommutative or not s.is_commutative # oo, -oo if coeff is S.Infinity: newseq = [ f for f in newseq if not (f.is_nonnegative or f.is_real and (f.is_bounded or f.is_infinitesimal)) ] elif coeff is S.NegativeInfinity: newseq = [ f for f in newseq if not (f.is_nonpositive or f.is_real and (f.is_bounded or f.is_infinitesimal)) ] if coeff is S.ComplexInfinity: # zoo might be # unbounded_real + bounded_im # bounded_real + unbounded_im # unbounded_real + unbounded_im # addition of a bounded real or imaginary number won't be able to # change the zoo nature; if unbounded a NaN condition could result # if the unbounded symbol had sign opposite of the unbounded # portion of zoo, e.g., unbounded_real - unbounded_real. newseq = [ c for c in newseq if not (c.is_bounded and c.is_real is not None) ] # process O(x) if order_factors: newseq2 = [] for t in newseq: for o in order_factors: # x + O(x) -> O(x) if o.contains(t): t = None break # x + O(x**2) -> x + O(x**2) if t is not None: newseq2.append(t) newseq = newseq2 + order_factors # 1 + O(1) -> O(1) for o in order_factors: if o.contains(coeff): coeff = S.Zero break # order args canonically _addsort(newseq) # current code expects coeff to be first if coeff is not S.Zero: newseq.insert(0, coeff) # we are done if noncommutative: return [], newseq, None else: return newseq, [], None
def _eval_power(base, exp): """ Tries to do some simplifications on base ** exp, where base is an instance of Integer Returns None if no further simplifications can be done When exponent is a fraction (so we have for example a square root), we try to find the simplest possible representation, so that - 4**Rational(1,2) becomes 2 - (-4)**Rational(1,2) becomes 2*I We will """ if exp is S.NaN: return S.NaN if base is S.One: return S.One if base is S.NegativeOne: return if exp is S.Infinity: if base.p > S.One: return S.Infinity if base.p == -1: return S.NaN # cases 0, 1 are done in their respective classes return S.Infinity + S.ImaginaryUnit * S.Infinity if not isinstance(exp, Number): # simplify when exp is even # (-2) ** k --> 2 ** k c,t = base.as_coeff_terms() if exp.is_even and isinstance(c, Number) and c < 0: return (-c * Mul(*t)) ** exp if not isinstance(exp, Rational): return if exp is S.Half and base < 0: # we extract I for this special case since everyone is doing so return S.ImaginaryUnit * Pow(-base, exp) if exp < 0: # invert base and change sign on exponent if base < 0: return -(S.NegativeOne) ** ((exp.p % exp.q) / S(exp.q)) * Rational(1, -base) ** (-exp) else: return Rational(1, base.p) ** (-exp) # see if base is a perfect root, sqrt(4) --> 2 x, xexact = integer_nthroot(abs(base.p), exp.q) if xexact: # if it's a perfect root we've finished result = Integer(x ** abs(exp.p)) if exp < 0: result = 1/result if base < 0: result *= (-1)**exp return result # The following is an algorithm where we collect perfect roots # from the factors of base if base > 4294967296: # Prevent from factorizing too big integers return None dict = base.factors() out_int = 1 sqr_int = 1 sqr_gcd = 0 sqr_dict = {} for prime,exponent in dict.iteritems(): exponent *= exp.p div_e = exponent // exp.q div_m = exponent % exp.q if div_e > 0: out_int *= prime**div_e if div_m > 0: sqr_dict[prime] = div_m for p,ex in sqr_dict.iteritems(): if sqr_gcd == 0: sqr_gcd = ex else: sqr_gcd = igcd(sqr_gcd, ex) for k,v in sqr_dict.iteritems(): sqr_int *= k**(v // sqr_gcd) if sqr_int == base.p and out_int == 1: result = None else: result = out_int * Pow(sqr_int , Rational(sqr_gcd, exp.q)) return result
def __neg__(self): return Mul(S.NegativeOne, self)
def _eval_expand_power_base(self, **hints): """(a*b)**n -> a**n * b**n""" force = hints.get('force', False) b = self.base e = self.exp if not b.is_Mul: return self cargs, nc = b.args_cnc(split_1=False) # expand each term - this is top-level-only # expansion but we have to watch out for things # that don't have an _eval_expand method if nc: nc = [i._eval_expand_power_base(**hints) if hasattr(i, '_eval_expand_power_base') else i for i in nc] if e.is_Integer: if e.is_positive: rv = Mul(*nc*e) else: rv = 1/Mul(*nc*-e) if cargs: rv *= Mul(*cargs)**e return rv if not cargs: return Pow(Mul(*nc), e, evaluate=False) nc = [Mul(*nc)] # sift the commutative bases def pred(x): if x is S.ImaginaryUnit: return S.ImaginaryUnit polar = x.is_polar if polar: return True if polar is None: return fuzzy_bool(x.is_nonnegative) sifted = sift(cargs, pred) nonneg = sifted[True] other = sifted[None] neg = sifted[False] imag = sifted[S.ImaginaryUnit] if imag: I = S.ImaginaryUnit i = len(imag) % 4 if i == 0: pass elif i == 1: other.append(I) elif i == 2: if neg: nonn = -neg.pop() if nonn is not S.One: nonneg.append(nonn) else: neg.append(S.NegativeOne) else: if neg: nonn = -neg.pop() if nonn is not S.One: nonneg.append(nonn) else: neg.append(S.NegativeOne) other.append(I) del imag # bring out the bases that can be separated from the base if force or e.is_integer: # treat all commutatives the same and put nc in other cargs = nonneg + neg + other other = nc else: # this is just like what is happening automatically, except # that now we are doing it for an arbitrary exponent for which # no automatic expansion is done assert not e.is_Integer # handle negatives by making them all positive and putting # the residual -1 in other if len(neg) > 1: o = S.One if not other and neg[0].is_Number: o *= neg.pop(0) if len(neg) % 2: o = -o for n in neg: nonneg.append(-n) if o is not S.One: other.append(o) elif neg and other: if neg[0].is_Number and neg[0] is not S.NegativeOne: other.append(S.NegativeOne) nonneg.append(-neg[0]) else: other.extend(neg) else: other.extend(neg) del neg cargs = nonneg other += nc rv = S.One if cargs: rv *= Mul(*[Pow(b, e, evaluate=False) for b in cargs]) if other: rv *= Pow(Mul(*other), e, evaluate=False) return rv
def __mul__(self, other): return Mul(self, other)
def _eval_expand_power_base(self, deep=True, **hints): """(a*b)**n -> a**n * b**n""" force = hints.get('force', False) b, ewas = self.args if deep: e = self.exp.expand(deep=deep, **hints) else: e = self.exp if b.is_Mul: bargs = b.args if force or e.is_integer: nonneg = bargs other = [] elif ewas.is_Rational or len( bargs) == 2 and bargs[0] is S.NegativeOne: # the Rational exponent was already expanded automatically # if there is a negative Number * foo, foo must be unknown # or else it, too, would have automatically expanded; # sqrt(-Number*foo) -> sqrt(Number)*sqrt(-foo); then # sqrt(-foo) -> unchanged if foo is not positive else # -> I*sqrt(foo) # So...if we have a 2 arg Mul and the first is a Number # that number is -1 and there is nothing more than can # be done without the force=True hint nonneg = [] else: # this is just like what is happening automatically, except # that now we are doing it for an arbitrary exponent for which # no automatic expansion is done def pred(x): if x.is_polar is None: return x.is_nonnegative return x.is_polar sifted = sift(b.args, pred) nonneg = sifted[True] other = sifted[None] neg = sifted[False] # make sure the Number gets pulled out if neg and neg[0].is_Number and neg[0] is not S.NegativeOne: nonneg.append(-neg[0]) neg[0] = S.NegativeOne # leave behind a negative sign oddneg = len(neg) % 2 if oddneg: other.append(S.NegativeOne) # negate all negatives and append to nonneg nonneg += [-n for n in neg] if nonneg: # then there's a new expression to return d = sift(nonneg, lambda x: x.is_commutative is True) c = d[True] nc = d[False] if not e.is_Integer: other.extend(nc) nc = [] elif len(nc) == 1: c.extend(nc) nc = [] else: nc = [Mul._from_args(nc)] * e other = [Pow(Mul(*other), e)] + nc if deep: return Mul(*([Pow(b.expand(deep=deep, **hints), e)\ for b in c] + other)) else: return Mul(*([Pow(b, e) for b in c] + other)) return Pow(b, e)
def _eval_expand_multinomial(self, deep=True, **hints): """(a+b+..) ** n -> a**n + n*a**(n-1)*b + .., n is positive integer""" if deep: b = self.base.expand(deep=deep, **hints) e = self.exp.expand(deep=deep, **hints) else: b = self.base e = self.exp if b is None: base = self.base else: base = b if e is None: exp = self.exp else: exp = e if e is not None or b is not None: result = base**exp if result.is_Pow: base, exp = result.base, result.exp else: return result else: result = None if exp.is_Integer and exp.p > 0 and base.is_Add: n = int(exp) if base.is_commutative: order_terms, other_terms = [], [] for order in base.args: if order.is_Order: order_terms.append(order) else: other_terms.append(order) if order_terms: # (f(x) + O(x^n))^m -> f(x)^m + m*f(x)^{m-1} *O(x^n) f = Add(*other_terms) g = (f**(n-1)).expand() return (f*g).expand() + n*g*Add(*order_terms) if base.is_number: # Efficiently expand expressions of the form (a + b*I)**n # where 'a' and 'b' are real numbers and 'n' is integer. a, b = base.as_real_imag() if a.is_Rational and b.is_Rational: if not a.is_Integer: if not b.is_Integer: k = (a.q * b.q) ** n a, b = a.p*b.q, a.q*b.p else: k = a.q ** n a, b = a.p, a.q*b elif not b.is_Integer: k = b.q ** n a, b = a*b.q, b.p else: k = 1 a, b, c, d = int(a), int(b), 1, 0 while n: if n & 1: c, d = a*c-b*d, b*c+a*d n -= 1 a, b = a*a-b*b, 2*a*b n //= 2 I = S.ImaginaryUnit if k == 1: return c + I*d else: return Integer(c)/k + I*d/k p = other_terms # (x+y)**3 -> x**3 + 3*x**2*y + 3*x*y**2 + y**3 # in this particular example: # p = [x,y]; n = 3 # so now it's easy to get the correct result -- we get the # coefficients first: from sympy import multinomial_coefficients expansion_dict = multinomial_coefficients(len(p), n) # in our example: {(3, 0): 1, (1, 2): 3, (0, 3): 1, (2, 1): 3} # and now construct the expression. # An elegant way would be to use Poly, but unfortunately it is # slower than the direct method below, so it is commented out: #b = {} #for k in expansion_dict: # b[k] = Integer(expansion_dict[k]) #return Poly(b, *p).as_basic() from sympy.polys.polynomial import multinomial_as_basic result = multinomial_as_basic(expansion_dict, *p) return result else: if n == 2: return Add(*[f*g for f in base.args for g in base.args]) else: return Mul(base, Pow(base, n-1).expand()).expand() elif exp.is_Add and base.is_Number: # a + b a b # n --> n n , where n, a, b are Numbers coeff, tail = S.One, S.Zero for term in exp.args: if term.is_Number: coeff *= base**term else: tail += term return coeff * base**tail else: return result