def search(expr, test): if not isinstance(expr, Basic): try: return any(search(i, test) for i in expr) except TypeError: return False elif test(expr): return True else: return any(search(i, test) for i in expr.iter_basic_args())
def has(self, *patterns): """ Test whether any subexpression matches any of the patterns. Examples: >>> from sympy import sin, S >>> from sympy.abc import x, y, z >>> (x**2 + sin(x*y)).has(z) False >>> (x**2 + sin(x*y)).has(x, y, z) True >>> x.has(x) True Note that ``expr.has(*patterns)`` is exactly equivalent to ``any(expr.has(p) for p in patterns)``. In particular, ``False`` is returned when the list of patterns is empty. >>> x.has() False """ def search(expr, test): if not isinstance(expr, Basic): try: return any(search(i, test) for i in expr) except TypeError: return False elif test(expr): return True else: return any(search(i, test) for i in expr.iter_basic_args()) def _match(p): if isinstance(p, BasicType): return lambda w: isinstance(w, p) else: return lambda w: p.matches(w) is not None patterns = map(sympify, patterns) return any(search(self, _match(p)) for p in patterns)
def as_ordered_terms(self, order=None, data=False): """ Transform an expression to an ordered list of terms. **Examples** >>> from sympy import sin, cos >>> from sympy.abc import x, y >>> (sin(x)**2*cos(x) + sin(x)**2 + 1).as_ordered_terms() [sin(x)**2*cos(x), sin(x)**2, 1] """ from sympy.utilities import any key, reverse = self._parse_order(order) terms, gens = self.as_terms() if not any(term.is_Order for term, _ in terms): ordered = sorted(terms, key=key, reverse=not reverse) else: _terms, _order = [], [] for term, repr in terms: if not term.is_Order: _terms.append((term, repr)) else: _order.append((term, repr)) ordered = sorted(_terms, key=key) \ + sorted(_order, key=key) if data: return ordered, gens else: return [ term for term, _ in ordered ]
def as_ordered_terms(self, order=None, data=False): """ Transform an expression to an ordered list of terms. **Examples** >>> from sympy import sin, cos >>> from sympy.abc import x, y >>> (sin(x)**2*cos(x) + sin(x)**2 + 1).as_ordered_terms() [sin(x)**2*cos(x), sin(x)**2, 1] """ from sympy.utilities import any key, reverse = self._parse_order(order) terms, gens = self.as_terms() if not any(term.is_Order for term, _ in terms): ordered = sorted(terms, key=key, reverse=not reverse) else: _terms, _order = [], [] for term, repr in terms: if not term.is_Order: _terms.append((term, repr)) else: _order.append((term, repr)) ordered = sorted(_terms, key=key) \ + sorted(_order, key=key) if data: return ordered, gens else: return [term for term, _ in ordered]
def _eval_subs(self, old, new): from sympy import sign from sympy.simplify.simplify import powdenest if self == old: return new def fallback(): """Return this value when partial subs has failed.""" return self.__class__(*[s._eval_subs(old, new) for s in self.args]) def breakup(eq): """break up powers assuming (not checking) that eq is a Mul: b**(Rational*e) -> b**e, Rational commutatives come back as a dictionary {b**e: Rational} noncommutatives come back as a list [(b**e, Rational)] """ (c, nc) = (dict(), list()) for (i, a) in enumerate( Mul.make_args(eq) or [eq]): # remove or [eq] after 2114 accepted a = powdenest(a) (b, e) = a.as_base_exp() if not e is S.One: (co, _) = e.as_coeff_mul() b = Pow(b, e / co) e = co if a.is_commutative: if b in c: # handle I and -1 like things where b, e for I is -1, 1/2 c[b] += e else: c[b] = e else: nc.append([b, e]) return (c, nc) def rejoin(b, co): """ Put rational back with exponent; in general this is not ok, but since we took it from the exponent for analysis, it's ok to put it back. """ (b, e) = b.as_base_exp() return Pow(b, e * co) def ndiv(a, b): """if b divides a in an extractive way (like 1/4 divides 1/2 but not vice versa, and 2/5 does not divide 1/3) then return the integer number of times it divides, else return 0. """ if not b.q % a.q or not a.q % b.q: return int(a / b) return 0 if not old.is_Mul: return fallback() # handle the leading coefficient and use it to decide if anything # should even be started; we always know where to find the Rational # so it's a quick test coeff = S.One co_self = self.args[0] co_old = old.args[0] if co_old.is_Rational and co_self.is_Rational: co_xmul = co_self.extract_multiplicatively(co_old) elif co_old.is_Rational: co_xmul = None else: co_xmul = True if not co_xmul: return fallback() (c, nc) = breakup(self) (old_c, old_nc) = breakup(old) # update the coefficients if we had an extraction if getattr(co_xmul, 'is_Rational', False): c.pop(co_self) c[co_xmul] = S.One old_c.pop(co_old) # do quick tests to see if we can't succeed ok = True if ( # more non-commutative terms len(old_nc) > len(nc)): ok = False elif ( # more commutative terms len(old_c) > len(c)): ok = False elif ( # unmatched non-commutative bases set(_[0] for _ in old_nc).difference(set(_[0] for _ in nc))): ok = False elif ( # unmatched commutative terms set(old_c).difference(set(c))): ok = False elif ( # differences in sign any(sign(c[b]) != sign(old_c[b]) for b in old_c)): ok = False if not ok: return fallback() if not old_c: cdid = None else: rat = [] for (b, old_e) in old_c.items(): c_e = c[b] rat.append(ndiv(c_e, old_e)) if not rat[-1]: return fallback() cdid = min(rat) if not old_nc: ncdid = None for i in range(len(nc)): nc[i] = rejoin(*nc[i]) else: ncdid = 0 # number of nc replacements we did take = len(old_nc) # how much to look at each time limit = cdid or S.Infinity # max number that we can take failed = [] # failed terms will need subs if other terms pass i = 0 while limit and i + take <= len(nc): hit = False # the bases must be equivalent in succession, and # the powers must be extractively compatible on the # first and last factor but equal inbetween. rat = [] for j in range(take): if nc[i + j][0] != old_nc[j][0]: break elif j == 0: rat.append(ndiv(nc[i + j][1], old_nc[j][1])) elif j == take - 1: rat.append(ndiv(nc[i + j][1], old_nc[j][1])) elif nc[i + j][1] != old_nc[j][1]: break else: rat.append(1) j += 1 else: ndo = min(rat) if ndo: if take == 1: if cdid: ndo = min(cdid, ndo) nc[i] = Pow(new, ndo) * rejoin( nc[i][0], nc[i][1] - ndo * old_nc[0][1]) else: ndo = 1 # the left residual l = rejoin(nc[i][0], nc[i][1] - ndo * old_nc[0][1]) # eliminate all middle terms mid = new # the right residual (which may be the same as the middle if take == 2) ir = i + take - 1 r = (nc[ir][0], nc[ir][1] - ndo * old_nc[-1][1]) if r[1]: if i + take < len(nc): nc[i:i + take] = [l * mid, r] else: r = rejoin(*r) nc[i:i + take] = [l * mid * r] else: # there was nothing left on the right nc[i:i + take] = [l * mid] limit -= ndo ncdid += ndo hit = True if not hit: # do the subs on this failing factor failed.append(i) i += 1 else: if not ncdid: return fallback() # although we didn't fail, certain nc terms may have # failed so we rebuild them after attempting a partial # subs on them failed.extend(range(i, len(nc))) for i in failed: nc[i] = rejoin(*nc[i]).subs(old, new) # rebuild the expression if cdid is None: do = ncdid elif ncdid is None: do = cdid else: do = min(ncdid, cdid) margs = [] for b in c: if b in old_c: # calculate the new exponent e = c[b] - old_c[b] * do margs.append(rejoin(b, e)) else: margs.append(rejoin(b.subs(old, new), c[b])) if cdid and not ncdid: # in case we are replacing commutative with non-commutative, # we want the new term to come at the front just like the # rest of this routine margs = [Pow(new, cdid)] + margs return Mul(*margs) * Mul(*nc)
def _eval_subs(self, old, new): from sympy import sign from sympy.simplify.simplify import powdenest if self == old: return new def fallback(): """Return this value when partial subs has failed.""" return self.__class__(*[s._eval_subs(old, new) for s in self.args]) def breakup(eq): """break up powers assuming (not checking) that eq is a Mul: b**(Rational*e) -> b**e, Rational commutatives come back as a dictionary {b**e: Rational} noncommutatives come back as a list [(b**e, Rational)] """ (c, nc) = (dict(), list()) for (i, a) in enumerate(Mul.make_args(eq) or [eq]): # remove or [eq] after 2114 accepted a = powdenest(a) (b, e) = a.as_base_exp() if not e is S.One: (co, _) = e.as_coeff_mul() b = Pow(b, e/co) e = co if a.is_commutative: if b in c: # handle I and -1 like things where b, e for I is -1, 1/2 c[b] += e else: c[b] = e else: nc.append([b, e]) return (c, nc) def rejoin(b, co): """ Put rational back with exponent; in general this is not ok, but since we took it from the exponent for analysis, it's ok to put it back. """ (b, e) = b.as_base_exp() return Pow(b, e*co) def ndiv(a, b): """if b divides a in an extractive way (like 1/4 divides 1/2 but not vice versa, and 2/5 does not divide 1/3) then return the integer number of times it divides, else return 0. """ if not b.q % a.q or not a.q % b.q: return int(a/b) return 0 if not old.is_Mul: return fallback() # handle the leading coefficient and use it to decide if anything # should even be started; we always know where to find the Rational # so it's a quick test coeff = S.One co_self = self.args[0] co_old = old.args[0] if co_old.is_Rational and co_self.is_Rational: co_xmul = co_self.extract_multiplicatively(co_old) elif co_old.is_Rational: co_xmul = None else: co_xmul = True if not co_xmul: return fallback() (c, nc) = breakup(self) (old_c, old_nc) = breakup(old) # update the coefficients if we had an extraction if getattr(co_xmul, 'is_Rational', False): c.pop(co_self) c[co_xmul] = S.One old_c.pop(co_old) # do quick tests to see if we can't succeed ok = True if ( # more non-commutative terms len(old_nc) > len(nc)): ok = False elif ( # more commutative terms len(old_c) > len(c)): ok = False elif ( # unmatched non-commutative bases set(_[0] for _ in old_nc).difference(set(_[0] for _ in nc))): ok = False elif ( # unmatched commutative terms set(old_c).difference(set(c))): ok = False elif ( # differences in sign any(sign(c[b]) != sign(old_c[b]) for b in old_c)): ok = False if not ok: return fallback() if not old_c: cdid = None else: rat = [] for (b, old_e) in old_c.items(): c_e = c[b] rat.append(ndiv(c_e, old_e)) if not rat[-1]: return fallback() cdid = min(rat) if not old_nc: ncdid = None for i in range(len(nc)): nc[i] = rejoin(*nc[i]) else: ncdid = 0 # number of nc replacements we did take = len(old_nc) # how much to look at each time limit = cdid or S.Infinity # max number that we can take failed = [] # failed terms will need subs if other terms pass i = 0 while limit and i + take <= len(nc): hit = False # the bases must be equivalent in succession, and # the powers must be extractively compatible on the # first and last factor but equal inbetween. rat = [] for j in range(take): if nc[i + j][0] != old_nc[j][0]: break elif j == 0: rat.append(ndiv(nc[i + j][1], old_nc[j][1])) elif j == take - 1: rat.append(ndiv(nc[i + j][1], old_nc[j][1])) elif nc[i + j][1] != old_nc[j][1]: break else: rat.append(1) j += 1 else: ndo = min(rat) if ndo: if take == 1: if cdid: ndo = min(cdid, ndo) nc[i] = Pow(new, ndo)*rejoin(nc[i][0], nc[i][1] - ndo*old_nc[0][1]) else: ndo = 1 # the left residual l = rejoin(nc[i][0], nc[i][1] - ndo* old_nc[0][1]) # eliminate all middle terms mid = new # the right residual (which may be the same as the middle if take == 2) ir = i + take - 1 r = (nc[ir][0], nc[ir][1] - ndo* old_nc[-1][1]) if r[1]: if i + take < len(nc): nc[i:i + take] = [l*mid, r] else: r = rejoin(*r) nc[i:i + take] = [l*mid*r] else: # there was nothing left on the right nc[i:i + take] = [l*mid] limit -= ndo ncdid += ndo hit = True if not hit: # do the subs on this failing factor failed.append(i) i += 1 else: if not ncdid: return fallback() # although we didn't fail, certain nc terms may have # failed so we rebuild them after attempting a partial # subs on them failed.extend(range(i, len(nc))) for i in failed: nc[i] = rejoin(*nc[i]).subs(old, new) # rebuild the expression if cdid is None: do = ncdid elif ncdid is None: do = cdid else: do = min(ncdid, cdid) margs = [] for b in c: if b in old_c: # calculate the new exponent e = c[b] - old_c[b]*do margs.append(rejoin(b, e)) else: margs.append(rejoin(b.subs(old, new), c[b])) if cdid and not ncdid: # in case we are replacing commutative with non-commutative, # we want the new term to come at the front just like the # rest of this routine margs = [Pow(new, cdid)] + margs return Mul(*margs)*Mul(*nc)
def has(self, *patterns, **flags): """Return True if self has any of the patterns. If the `all` flag is True then return True if all of the patterns are present. >>> from sympy import sin, S >>> from sympy.abc import x, y, z >>> (x**2 + sin(x*y)).has(z) False >>> (x**2 + sin(x*y)).has(x, y, z) True When `all` is True then True is returned only if all of the patterns are present: >>> (x**2 + sin(x*y)).has(x, y, z, all=True) False If there are no patterns, False is always returned: "something doesn't have nothing" >>> (x).has() False >>> (S.One).has() False """ from sympy.core.symbol import Wild def search(expr, target, hit): if hasattr(expr, '__iter__') and hasattr(expr, '__len__'): # this 'if' clause is needed until all objects use # sympy containers for i in expr: if search(i, target, hit): return True elif not isinstance(expr, Basic): pass elif target(expr) and hit(expr): return True else: for term in expr.iter_basic_args(): if search(term, target, hit): return True return False def _has(p): p = sympify(p) if isinstance(p, BasicType): return search(self, lambda w: isinstance(w, p), lambda w: True) if p.is_Atom and not isinstance(p, Wild): return search(self, lambda w: isinstance(w, p.func), lambda w: w in [p]) return search(self, lambda w: p.matches(w) is not None, lambda w: True) if not patterns: return False # something doesn't have nothing patterns = set(patterns) if flags.get('all', False): return all(_has(p) for p in patterns) else: return any(_has(p) for p in patterns)