def _find_opts(expr): if expr.is_Atom or expr.is_Order: return if iterable(expr): list(map(_find_opts, expr)) return if expr in seen_subexp: return expr seen_subexp.add(expr) list(map(_find_opts, expr.args)) if _coeff_isneg(expr): neg_expr = -expr if not neg_expr.is_Atom: opt_subs[expr] = Mul(S.NegativeOne, neg_expr, evaluate=False) seen_subexp.add(neg_expr) expr = neg_expr if expr.is_Mul: muls.add(expr) elif expr.is_Add: adds.add(expr) elif expr.is_Pow: if _coeff_isneg(expr.exp): opt_subs[expr] = Pow(Pow(expr.base, -expr.exp), S.NegativeOne, evaluate=False)
def as_numer_denom(self): if not self.is_commutative: return self, S.One base, exp = self.as_base_exp() n, d = base.as_numer_denom() if d is not S.One: if d.is_negative and n.is_negative: n, d = -n, -d if exp.is_Integer: if exp.is_negative: n, d = d, n exp = -exp return Pow(n, exp), Pow(d, exp) elif exp.is_Rational or d.is_positive: dneg = d.is_negative if dneg is not None: if dneg is True: n = -n d = -d elif dneg is False: n, d = d, n exp = -exp if _coeff_isneg(exp): n, d = d, n exp = -exp return Pow(n, exp), Pow(d, exp) # else we won't split up base but we check for neg expo below if _coeff_isneg(exp): return S.One, base**-exp # unprocessed float or NumberSymbol exponent # and Mul exp w/o negative sign return self, S.One
def _find_opts(expr): if not isinstance(expr, Basic): return if expr.is_Atom or expr.is_Order: return if iterable(expr): list(map(_find_opts, expr)) return if expr in seen_subexp: return expr seen_subexp.add(expr) list(map(_find_opts, expr.args)) if _coeff_isneg(expr): neg_expr = -expr if not neg_expr.is_Atom: opt_subs[expr] = Mul(S.NegativeOne, neg_expr, evaluate=False) seen_subexp.add(neg_expr) expr = neg_expr if isinstance(expr, (Mul, MatMul)): muls.add(expr) elif isinstance(expr, (Add, MatAdd)): adds.add(expr) elif isinstance(expr, (Pow, MatPow)): if _coeff_isneg(expr.exp): opt_subs[expr] = Pow(Pow(expr.base, -expr.exp), S.NegativeOne, evaluate=False)
def eval(cls, arg): from sympy import acos arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.Infinity elif arg is S.Zero: return S.Pi*S.ImaginaryUnit / 2 elif arg is S.One: return S.Zero elif arg is S.NegativeOne: return S.Pi*S.ImaginaryUnit if arg.is_number: cst_table = { S.ImaginaryUnit: log(S.ImaginaryUnit*(1 + sqrt(2))), -S.ImaginaryUnit: log(-S.ImaginaryUnit*(1 + sqrt(2))), S.Half: S.Pi/3, -S.Half: 2*S.Pi/3, sqrt(2)/2: S.Pi/4, -sqrt(2)/2: 3*S.Pi/4, 1/sqrt(2): S.Pi/4, -1/sqrt(2): 3*S.Pi/4, sqrt(3)/2: S.Pi/6, -sqrt(3)/2: 5*S.Pi/6, (sqrt(3) - 1)/sqrt(2**3): 5*S.Pi/12, -(sqrt(3) - 1)/sqrt(2**3): 7*S.Pi/12, sqrt(2 + sqrt(2))/2: S.Pi/8, -sqrt(2 + sqrt(2))/2: 7*S.Pi/8, sqrt(2 - sqrt(2))/2: 3*S.Pi/8, -sqrt(2 - sqrt(2))/2: 5*S.Pi/8, (1 + sqrt(3))/(2*sqrt(2)): S.Pi/12, -(1 + sqrt(3))/(2*sqrt(2)): 11*S.Pi/12, (sqrt(5) + 1)/4: S.Pi/5, -(sqrt(5) + 1)/4: 4*S.Pi/5 } if arg in cst_table: if arg.is_real: return cst_table[arg]*S.ImaginaryUnit return cst_table[arg] if arg is S.ComplexInfinity: return S.Infinity i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: if _coeff_isneg(i_coeff): return S.ImaginaryUnit * acos(i_coeff) return S.ImaginaryUnit * acos(-i_coeff) else: if _coeff_isneg(arg): return -cls(-arg)
def eval(cls, arg): from sympy import cot arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.One elif arg is S.NegativeInfinity: return S.NegativeOne elif arg is S.Zero: return S.ComplexInfinity elif arg.is_negative: return -cls(-arg) else: if arg is S.ComplexInfinity: return S.NaN i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: if _coeff_isneg(i_coeff): return S.ImaginaryUnit * cot(-i_coeff) return -S.ImaginaryUnit * cot(i_coeff) else: if _coeff_isneg(arg): return -cls(-arg) if arg.is_Add: x, m = _peeloff_ipi(arg) if m: cothm = coth(m) if cothm is S.ComplexInfinity: return coth(x) else: # cothm == 0 return tanh(x) if arg.func == asinh: x = arg.args[0] return sqrt(1 + x**2)/x if arg.func == acosh: x = arg.args[0] return x/(sqrt(x - 1) * sqrt(x + 1)) if arg.func == atanh: return 1/arg.args[0] if arg.func == acoth: return arg.args[0]
def eval(cls, arg): arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Zero elif arg is S.NegativeInfinity: return S.Zero elif arg is S.Zero: return S.Pi*S.ImaginaryUnit / 2 elif arg is S.One: return S.Infinity elif arg is S.NegativeOne: return S.NegativeInfinity elif arg.is_negative: return -cls(-arg) else: if arg is S.ComplexInfinity: return 0 i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return -S.ImaginaryUnit * C.acot(i_coeff) else: if _coeff_isneg(arg): return -cls(-arg)
def _set_function(f, self): expr = f.expr if not isinstance(expr, Expr): return if len(f.variables) > 1: return n = f.variables[0] # f(x) + c and f(-x) + c cover the same integers # so choose the form that has the fewest negatives c = f(0) fx = f(n) - c f_x = f(-n) - c neg_count = lambda e: sum(_coeff_isneg(_) for _ in Add.make_args(e)) if neg_count(f_x) < neg_count(fx): expr = f_x + c a = Wild('a', exclude=[n]) b = Wild('b', exclude=[n]) match = expr.match(a*n + b) if match and match[a]: # canonical shift expr = match[a]*n + match[b] % match[a] if expr != f.expr: return ImageSet(Lambda(n, expr), S.Integers)
def as_numer_denom(self): if not self.is_commutative: return self, S.One base, exp = self.as_base_exp() n, d = base.as_numer_denom() # this should be the same as ExpBase.as_numer_denom wrt # exponent handling neg_exp = exp.is_negative if not neg_exp and not (-exp).is_negative: neg_exp = _coeff_isneg(exp) int_exp = exp.is_integer # the denominator cannot be separated from the numerator if # its sign is unknown unless the exponent is an integer, e.g. # sqrt(a/b) != sqrt(a)/sqrt(b) when a=1 and b=-1. But if the # denominator is negative the numerator and denominator can # be negated and the denominator (now positive) separated. if not (d.is_real or int_exp): n = base d = S.One dnonpos = d.is_nonpositive if dnonpos: n, d = -n, -d elif dnonpos is None and not int_exp: n = base d = S.One if neg_exp: n, d = d, n exp = -exp return self.func(n, exp), self.func(d, exp)
def eval(cls, arg): from sympy import atan arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Zero: return S.Zero elif arg is S.One: return S.Infinity elif arg is S.NegativeOne: return S.NegativeInfinity elif arg is S.Infinity: return -S.ImaginaryUnit * atan(arg) elif arg is S.NegativeInfinity: return S.ImaginaryUnit * atan(-arg) elif arg.is_negative: return -cls(-arg) else: if arg is S.ComplexInfinity: from sympy.calculus.util import AccumBounds return S.ImaginaryUnit*AccumBounds(-S.Pi/2, S.Pi/2) i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return S.ImaginaryUnit * atan(i_coeff) else: if _coeff_isneg(arg): return -cls(-arg)
def _print_Mul(self, expr): if _coeff_isneg(expr): x = self.dom.createElement('apply') x.appendChild(self.dom.createElement('minus')) x.appendChild(self._print_Mul(-expr)) return x from sympy.simplify import fraction numer, denom = fraction(expr) if denom is not S.One: x = self.dom.createElement('apply') x.appendChild(self.dom.createElement('divide')) x.appendChild(self._print(numer)) x.appendChild(self._print(denom)) return x coeff, terms = expr.as_coeff_mul() if coeff is S.One and len(terms) == 1: # XXX since the negative coefficient has been handled, I don't # think a coeff of 1 can remain return self._print(terms[0]) if self.order != 'old': terms = Mul._from_args(terms).as_ordered_factors() x = self.dom.createElement('apply') x.appendChild(self.dom.createElement('times')) if(coeff != 1): x.appendChild(self._print(coeff)) for term in terms: x.appendChild(self._print(term)) return x
def _print_Add(self, expr, order=None): args = self._as_ordered_terms(expr, order=order) lastProcessed = self._print(args[0]) plusNodes = [] for arg in args[1:]: if _coeff_isneg(arg): # use minus x = self.dom.createElement('apply') x.appendChild(self.dom.createElement('minus')) x.appendChild(lastProcessed) x.appendChild(self._print(-arg)) # invert expression since this is now minused lastProcessed = x if(arg == args[-1]): plusNodes.append(lastProcessed) else: plusNodes.append(lastProcessed) lastProcessed = self._print(arg) if(arg == args[-1]): plusNodes.append(self._print(arg)) if len(plusNodes) == 1: return lastProcessed x = self.dom.createElement('apply') x.appendChild(self.dom.createElement('plus')) while len(plusNodes) > 0: x.appendChild(plusNodes.pop(0)) return x
def eval(cls, arg): from sympy import asin arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.NegativeInfinity elif arg is S.Zero: return S.Zero elif arg is S.One: return log(sqrt(2) + 1) elif arg is S.NegativeOne: return log(sqrt(2) - 1) elif arg.is_negative: return -cls(-arg) else: if arg is S.ComplexInfinity: return S.ComplexInfinity i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return S.ImaginaryUnit * asin(i_coeff) else: if _coeff_isneg(arg): return -cls(-arg)
def _print_Add(self, expr, order=None): if self.order == 'none': terms = list(expr.args) else: terms = self._as_ordered_terms(expr, order=order) pforms, indices = [], [] def pretty_negative(pform, index): """Prepend a minus sign to a pretty form. """ if index == 0: if pform.height() > 1: pform_neg = '- ' else: pform_neg = '-' else: pform_neg = ' - ' pform = stringPict.next(pform_neg, pform) return prettyForm(binding=prettyForm.NEG, *pform) for i, term in enumerate(terms): if term.is_Mul and _coeff_isneg(term): pform = self._print(-term) pforms.append(pretty_negative(pform, i)) elif term.is_Rational and term.q > 1: pforms.append(None) indices.append(i) elif term.is_Number and term < 0: pform = self._print(-term) pforms.append(pretty_negative(pform, i)) else: pforms.append(self._print(term)) if indices: large = True for pform in pforms: if pform is not None and pform.height() > 1: break else: large = False for i in indices: term, negative = terms[i], False if term < 0: term, negative = -term, True if large: pform = prettyForm(str(term.p))/prettyForm(str(term.q)) else: pform = self._print(term) if negative: pform = pretty_negative(pform, i) pforms[i] = pform return prettyForm.__add__(*pforms)
def _print_Add(self, expr): tex = str(self._print(expr.args[0])) for term in expr.args[1:]: if _coeff_isneg(term): tex += r" %s" % self._print(term) else: tex += r" + %s" % self._print(term) return tex
def eval(cls, arg): from sympy import tan arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.One elif arg is S.NegativeInfinity: return S.NegativeOne elif arg is S.Zero: return S.Zero elif arg.is_negative: return -cls(-arg) else: if arg is S.ComplexInfinity: return S.NaN i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: if _coeff_isneg(i_coeff): return -S.ImaginaryUnit * tan(-i_coeff) return S.ImaginaryUnit * tan(i_coeff) else: if _coeff_isneg(arg): return -cls(-arg) if arg.func == asinh: x = arg.args[0] return x / sqrt(1 + x ** 2) if arg.func == acosh: x = arg.args[0] return sqrt(x - 1) * sqrt(x + 1) / x if arg.func == atanh: return arg.args[0] if arg.func == acoth: return 1 / arg.args[0]
def _print_Add(self, expr, order=None): if self.order == "none": terms = list(expr.args) else: terms = self._as_ordered_terms(expr, order=order) tex = self._print(terms[0]) for term in terms[1:]: if not _coeff_isneg(term): tex += " +" tex += " " + self._print(term) return tex
def _print_Mul(self, expr): prec = precedence(expr) if _coeff_isneg(expr): expr = -expr sign = "-" else: sign = "" a = [] # items in the numerator b = [] # items that are in the denominator (if any) if self.order not in ('old', 'none'): args = expr.as_ordered_factors() else: # use make_args in case expr was something like -x -> x args = Mul.make_args(expr) # Gather args for numerator/denominator for item in args: if item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative: if item.exp != -1: b.append(Pow(item.base, -item.exp, evaluate=False)) else: b.append(Pow(item.base, -item.exp)) elif item.is_Rational and item is not S.Infinity: if item.p != 1: a.append(Rational(item.p)) if item.q != 1: b.append(Rational(item.q)) else: a.append(item) a = a or [S.One] a_str = map(lambda x:self.parenthesize(x, prec), a) b_str = map(lambda x:self.parenthesize(x, prec), b) if len(b) == 0: return sign + '*'.join(a_str) elif len(b) == 1: if len(a) == 1 and not (a[0].is_Atom or a[0].is_Add): return sign + "%s/"%a_str[0] + '*'.join(b_str) else: return sign + '*'.join(a_str) + "/%s"%b_str[0] else: return sign + '*'.join(a_str) + "/(%s)"%'*'.join(b_str)
def eval(cls, arg): from sympy import sin arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.NegativeInfinity elif arg is S.Zero: return S.Zero elif arg.is_negative: return -cls(-arg) else: if arg is S.ComplexInfinity: return S.NaN i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return S.ImaginaryUnit * sin(i_coeff) else: if _coeff_isneg(arg): return -cls(-arg) if arg.is_Add: x, m = _peeloff_ipi(arg) if m: return sinh(m)*cosh(x) + cosh(m)*sinh(x) if arg.func == asinh: return arg.args[0] if arg.func == acosh: x = arg.args[0] return sqrt(x - 1) * sqrt(x + 1) if arg.func == atanh: x = arg.args[0] return x/sqrt(1 - x**2) if arg.func == acoth: x = arg.args[0] return 1/(sqrt(x - 1) * sqrt(x + 1))
def _print_Mul(self, expr): def multiply(expr, mrow): from sympy.simplify import fraction numer, denom = fraction(expr) if denom is not S.One: frac = self.dom.createElement('mfrac') if self._settings["fold_short_frac"] and len(str(expr)) < 7: frac.setAttribute('bevelled', 'true') xnum = self._print(numer) xden = self._print(denom) frac.appendChild(xnum) frac.appendChild(xden) mrow.appendChild(frac) return mrow coeff, terms = expr.as_coeff_mul() if coeff is S.One and len(terms) == 1: mrow.appendChild(self._print(terms[0])) return mrow if self.order != 'old': terms = Mul._from_args(terms).as_ordered_factors() if coeff != 1: x = self._print(coeff) y = self.dom.createElement('mo') y.appendChild(self.dom.createTextNode(self.mathml_tag(expr))) mrow.appendChild(x) mrow.appendChild(y) for term in terms: x = self._print(term) mrow.appendChild(x) if not term == terms[-1]: y = self.dom.createElement('mo') y.appendChild(self.dom.createTextNode(self.mathml_tag(expr))) mrow.appendChild(y) return mrow mrow = self.dom.createElement('mrow') if _coeff_isneg(expr): x = self.dom.createElement('mo') x.appendChild(self.dom.createTextNode('-')) mrow.appendChild(x) mrow = multiply(-expr, mrow) else: mrow = multiply(expr, mrow) return mrow
def clear_coefficients(expr, rhs=S.Zero): """Return `p, r` where `p` is the expression obtained when Rational additive and multiplicative coefficients of `expr` have been stripped away in a naive fashion (i.e. without simplification). The operations needed to remove the coefficients will be applied to `rhs` and returned as `r`. Examples ======== >>> from sympy.simplify.simplify import clear_coefficients >>> from sympy.abc import x, y >>> from sympy import Dummy >>> expr = 4*y*(6*x + 3) >>> clear_coefficients(expr - 2) (y*(2*x + 1), 1/6) When solving 2 or more expressions like `expr = a`, `expr = b`, etc..., it is advantageous to provide a Dummy symbol for `rhs` and simply replace it with `a`, `b`, etc... in `r`. >>> rhs = Dummy('rhs') >>> clear_coefficients(expr, rhs) (y*(2*x + 1), _rhs/12) >>> _[1].subs(rhs, 2) 1/6 """ was = None free = expr.free_symbols if expr.is_Rational: return (S.Zero, rhs - expr) while expr and was != expr: was = expr m, expr = ( expr.as_content_primitive() if free else factor_terms(expr).as_coeff_Mul(rational=True)) rhs /= m c, expr = expr.as_coeff_Add(rational=True) rhs -= c expr = signsimp(expr, evaluate = False) if _coeff_isneg(expr): expr = -expr rhs = -rhs return expr, rhs
def _print_Add(self, expr, order=None): mrow = self.dom.createElement('mrow') args = self._as_ordered_terms(expr, order=order) mrow.appendChild(self._print(args[0])) for arg in args[1:]: if _coeff_isneg(arg): # use minus x = self.dom.createElement('mo') x.appendChild(self.dom.createTextNode('-')) y = self._print(-arg) # invert expression since this is now minused else: x = self.dom.createElement('mo') x.appendChild(self.dom.createTextNode('+')) y = self._print(arg) mrow.appendChild(x) mrow.appendChild(y) return mrow
def __new__(cls, b, e, evaluate=None): if evaluate is None: evaluate = global_evaluate[0] from sympy.functions.elementary.exponential import exp_polar b = _sympify(b) e = _sympify(e) if evaluate: if e is S.Zero: return S.One elif e is S.One: return b elif e.is_integer and _coeff_isneg(b): if e.is_even: b = -b elif e.is_odd: return -Pow(-b, e) if b is S.One: if e in (S.NaN, S.Infinity, -S.Infinity): return S.NaN return S.One elif S.NaN in (b, e): # XXX S.NaN**x -> S.NaN under assumption that x != 0 return S.NaN else: # recognize base as E if not e.is_Atom and b is not S.Exp1 and b.func is not exp_polar: from sympy import numer, denom, log, sign, im, factor_terms c, ex = factor_terms(e, sign=False).as_coeff_Mul() den = denom(ex) if den.func is log and den.args[0] == b: return S.Exp1**(c*numer(ex)) elif den.is_Add: s = sign(im(b)) if s.is_Number and s and den == \ log(-factor_terms(b, sign=False)) + s*S.ImaginaryUnit*S.Pi: return S.Exp1**(c*numer(ex)) obj = b._eval_power(e) if obj is not None: return obj obj = Expr.__new__(cls, b, e) obj.is_commutative = (b.is_commutative and e.is_commutative) return obj
def eval(cls, arg): arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Zero elif arg is S.NegativeInfinity: return S.Zero elif arg is S.Zero: return S.ComplexInfinity elif arg is S.One: return log(1 + sqrt(2)) elif arg is S.NegativeOne: return - log(1 + sqrt(2)) if arg.is_number: cst_table = { S.ImaginaryUnit: -S.Pi / 2, S.ImaginaryUnit*(sqrt(2) + sqrt(6)): -S.Pi / 12, S.ImaginaryUnit*(1 + sqrt(5)): -S.Pi / 10, S.ImaginaryUnit*2 / sqrt(2 - sqrt(2)): -S.Pi / 8, S.ImaginaryUnit*2: -S.Pi / 6, S.ImaginaryUnit*sqrt(2 + 2/sqrt(5)): -S.Pi / 5, S.ImaginaryUnit*sqrt(2): -S.Pi / 4, S.ImaginaryUnit*(sqrt(5)-1): -3*S.Pi / 10, S.ImaginaryUnit*2 / sqrt(3): -S.Pi / 3, S.ImaginaryUnit*2 / sqrt(2 + sqrt(2)): -3*S.Pi / 8, S.ImaginaryUnit*sqrt(2 - 2/sqrt(5)): -2*S.Pi / 5, S.ImaginaryUnit*(sqrt(6) - sqrt(2)): -5*S.Pi / 12, S(2): -S.ImaginaryUnit*log((1+sqrt(5))/2), } if arg in cst_table: return cst_table[arg]*S.ImaginaryUnit if arg is S.ComplexInfinity: return S.Zero if _coeff_isneg(arg): return -cls(-arg)
def _print_Add(self, expr, order=None): if(self._settings['use_operators']): return CodePrinter._print_Add(self, expr, order=order) terms = expr.as_ordered_terms() def partition(p,l): return reduce(lambda x, y: (x[0]+[y], x[1]) if p(y) else (x[0], x[1]+[y]), l, ([], [])) def add(a,b): return self._print_Function_with_args('add', (a, b)) # return self.known_functions['add']+'(%s, %s)' % (a,b) neg, pos = partition(lambda arg: _coeff_isneg(arg), terms) s = pos = reduce(lambda a,b: add(a,b), map(lambda t: self._print(t),pos)) if(len(neg) > 0): # sum the absolute values of the negative terms neg = reduce(lambda a,b: add(a,b), map(lambda n: self._print(-n),neg)) # then subtract them from the positive terms s = self._print_Function_with_args('sub', (pos,neg)) # s = self.known_functions['sub']+'(%s, %s)' % (pos,neg) return s
def eval(cls, arg): arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.Infinity elif arg is S.Zero: return S.One elif arg.is_negative: return cls(-arg) else: if arg is S.ComplexInfinity: return S.NaN i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return C.cos(i_coeff) else: if _coeff_isneg(arg): return cls(-arg) if arg.func == asinh: return sqrt(1+arg.args[0]**2) if arg.func == acosh: return arg.args[0] if arg.func == atanh: return 1/sqrt(1-arg.args[0]**2) if arg.func == acoth: x = arg.args[0] return x/(sqrt(x-1) * sqrt(x+1))
def as_numer_denom(self): """ Returns this with a positive exponent as a 2-tuple (a fraction). Examples ======== >>> from sympy.functions import exp >>> from sympy.abc import x >>> exp(-x).as_numer_denom() (1, exp(x)) >>> exp(x).as_numer_denom() (exp(x), 1) """ # this should be the same as Pow.as_numer_denom wrt # exponent handling exp = self.exp neg_exp = exp.is_negative if not neg_exp and not (-exp).is_negative: neg_exp = _coeff_isneg(exp) if neg_exp: return S.One, self.func(-exp) return self, S.One
def _print_Mul(self, expr): prec = precedence(expr) # Check for unevaluated Mul. In this case we need to make sure the # identities are visible, multiple Rational factors are not combined # etc so we display in a straight-forward form that fully preserves all # args and their order. args = expr.args if args[0] is S.One or any( isinstance(a, Number) or a.is_Pow and all(ai.is_Integer for ai in a.args) for a in args[1:]): d, n = sift(args, lambda x: isinstance(x, Pow) and bool( x.exp.as_coeff_Mul()[0] < 0), binary=True) for i, di in enumerate(d): if di.exp.is_Number: e = -di.exp else: dargs = list(di.exp.args) dargs[0] = -dargs[0] e = Mul._from_args(dargs) d[i] = Pow(di.base, e, evaluate=False) if e - 1 else di.base # don't parenthesize first factor if negative if _coeff_isneg(n[0]): pre = [str(n.pop(0))] else: pre = [] nfactors = pre + [ self.parenthesize(a, prec, strict=False) for a in n ] # don't parenthesize first of denominator unless singleton if len(d) > 1 and _coeff_isneg(d[0]): pre = [str(d.pop(0))] else: pre = [] dfactors = pre + [ self.parenthesize(a, prec, strict=False) for a in d ] n = '*'.join(nfactors) d = '*'.join(dfactors) if len(dfactors) > 1: return '%s/(%s)' % (n, d) elif dfactors: return '%s/%s' % (n, d) return n c, e = expr.as_coeff_Mul() if c < 0: expr = _keep_coeff(-c, e) sign = "-" else: sign = "" a = [] # items in the numerator b = [] # items that are in the denominator (if any) pow_paren = [ ] # Will collect all pow with more than one base element and exp = -1 if self.order not in ('old', 'none'): args = expr.as_ordered_factors() else: # use make_args in case expr was something like -x -> x args = Mul.make_args(expr) # Gather args for numerator/denominator def apow(i): b, e = i.as_base_exp() eargs = list(Mul.make_args(e)) if eargs[0] is S.NegativeOne: eargs = eargs[1:] else: eargs[0] = -eargs[0] e = Mul._from_args(eargs) if isinstance(i, Pow): return i.func(b, e, evaluate=False) return i.func(e, evaluate=False) for item in args: if (item.is_commutative and isinstance(item, Pow) and bool(item.exp.as_coeff_Mul()[0] < 0)): if item.exp is not S.NegativeOne: b.append(apow(item)) else: if (len(item.args[0].args) != 1 and isinstance(item.base, (Mul, Pow))): # To avoid situations like #14160 pow_paren.append(item) b.append(item.base) elif item.is_Rational and item is not S.Infinity: if item.p != 1: a.append(Rational(item.p)) if item.q != 1: b.append(Rational(item.q)) else: a.append(item) a = a or [S.One] a_str = [self.parenthesize(x, prec, strict=False) for x in a] b_str = [self.parenthesize(x, prec, strict=False) for x in b] # To parenthesize Pow with exp = -1 and having more than one Symbol for item in pow_paren: if item.base in b: b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)] if not b: return sign + '*'.join(a_str) elif len(b) == 1: return sign + '*'.join(a_str) + "/" + b_str[0] else: return sign + '*'.join(a_str) + "/(%s)" % '*'.join(b_str)
def cse(exprs, symbols=None, optimizations=None, postprocess=None): """ Perform common subexpression elimination on an expression. Parameters ========== exprs : list of sympy expressions, or a single sympy expression The expressions to reduce. symbols : infinite iterator yielding unique Symbols The symbols used to label the common subexpressions which are pulled out. The ``numbered_symbols`` generator is useful. The default is a stream of symbols of the form "x0", "x1", etc. This must be an infinite iterator. optimizations : list of (callable, callable) pairs, optional The (preprocessor, postprocessor) pairs. If not provided, ``sympy.simplify.cse.cse_optimizations`` is used. postprocess : a function which accepts the two return values of cse and returns the desired form of output from cse, e.g. if you want the replacements reversed the function might be the following lambda: lambda r, e: return reversed(r), e Returns ======= replacements : list of (Symbol, expression) pairs All of the common subexpressions that were replaced. Subexpressions earlier in this list might show up in subexpressions later in this list. reduced_exprs : list of sympy expressions The reduced expressions with all of the replacements above. """ from sympy.matrices import Matrix from sympy.simplify.simplify import fraction if symbols is None: symbols = numbered_symbols() else: # In case we get passed an iterable with an __iter__ method instead of # an actual iterator. symbols = iter(symbols) seen_subexp = set() muls = set() adds = set() to_eliminate = [] to_eliminate_ops_count = [] if optimizations is None: # Pull out the default here just in case there are some weird # manipulations of the module-level list in some other thread. optimizations = list(cse_optimizations) # Handle the case if just one expression was passed. if isinstance(exprs, Basic): exprs = [exprs] # Preprocess the expressions to give us better optimization opportunities. reduced_exprs = [preprocess_for_cse(e, optimizations) for e in exprs] # Find all of the repeated subexpressions. def insert(subtree): '''This helper will insert the subtree into to_eliminate while maintaining the ordering by op count and will skip the insertion if subtree is already present.''' ops_count = (subtree.count_ops(), subtree.is_Mul) # prefer non-Mul to Mul index_to_insert = bisect.bisect(to_eliminate_ops_count, ops_count) # all i up to this index have op count <= the current op count # so check that subtree is not yet present from this index down # (if necessary) to zero. for i in xrange(index_to_insert - 1, -1, -1): if to_eliminate_ops_count[i] == ops_count and \ subtree == to_eliminate[i]: return # already have it to_eliminate_ops_count.insert(index_to_insert, ops_count) to_eliminate.insert(index_to_insert, subtree) for expr in reduced_exprs: if not isinstance(expr, Basic): continue pt = preorder_traversal(expr, key=default_sort_key) for subtree in pt: inv = 1/subtree if subtree.is_Pow else None if subtree.is_Atom or iterable(subtree) or inv and inv.is_Atom: # Exclude atoms, since there is no point in renaming them. continue if subtree in seen_subexp: if inv and _coeff_isneg(subtree.exp): # save the form with positive exponent subtree = inv insert(subtree) pt.skip() continue if inv and inv in seen_subexp: if _coeff_isneg(subtree.exp): # save the form with positive exponent subtree = inv insert(subtree) pt.skip() continue elif subtree.is_Mul: muls.add(subtree) elif subtree.is_Add: adds.add(subtree) seen_subexp.add(subtree) # process adds - any adds that weren't repeated might contain # subpatterns that are repeated, e.g. x+y+z and x+y have x+y in common adds = [set(a.args) for a in adds] for i in xrange(len(adds)): for j in xrange(i + 1, len(adds)): com = adds[i].intersection(adds[j]) if len(com) > 1: insert(Add(*com)) # remove this set of symbols so it doesn't appear again adds[i] = adds[i].difference(com) adds[j] = adds[j].difference(com) for k in xrange(j + 1, len(adds)): if not com.difference(adds[k]): adds[k] = adds[k].difference(com) # process muls - any muls that weren't repeated might contain # subpatterns that are repeated, e.g. x*y*z and x*y have x*y in common # use SequenceMatcher on the nc part to find the longest common expression # in common between the two nc parts sm = difflib.SequenceMatcher() muls = [a.args_cnc(cset=True) for a in muls] for i in xrange(len(muls)): if muls[i][1]: sm.set_seq1(muls[i][1]) for j in xrange(i + 1, len(muls)): # the commutative part in common ccom = muls[i][0].intersection(muls[j][0]) # the non-commutative part in common if muls[i][1] and muls[j][1]: # see if there is any chance of an nc match ncom = set(muls[i][1]).intersection(set(muls[j][1])) if len(ccom) + len(ncom) < 2: continue # now work harder to find the match sm.set_seq2(muls[j][1]) i1, _, n = sm.find_longest_match(0, len(muls[i][1]), 0, len(muls[j][1])) ncom = muls[i][1][i1:i1 + n] else: ncom = [] com = list(ccom) + ncom if len(com) < 2: continue insert(Mul(*com)) # remove ccom from all if there was no ncom; to update the nc part # would require finding the subexpr and then replacing it with a # dummy to keep bounding nc symbols from being identified as a # subexpr, e.g. removing B*C from A*B*C*D might allow A*D to be # identified as a subexpr which would not be right. if not ncom: muls[i][0] = muls[i][0].difference(ccom) for k in xrange(j, len(muls)): if not ccom.difference(muls[k][0]): muls[k][0] = muls[k][0].difference(ccom) # Substitute symbols for all of the repeated subexpressions. replacements = [] reduced_exprs = list(reduced_exprs) hit = True for i, subtree in enumerate(to_eliminate): if hit: sym = symbols.next() hit = False if subtree.is_Pow and subtree.exp.is_Rational: update = lambda x: x.xreplace({subtree: sym, 1/subtree: 1/sym}) else: update = lambda x: x.subs(subtree, sym) # Make the substitution in all of the target expressions. for j, expr in enumerate(reduced_exprs): old = reduced_exprs[j] reduced_exprs[j] = update(expr) hit = hit or (old != reduced_exprs[j]) # Make the substitution in all of the subsequent substitutions. for j in range(i+1, len(to_eliminate)): old = to_eliminate[j] to_eliminate[j] = update(to_eliminate[j]) hit = hit or (old != to_eliminate[j]) if hit: replacements.append((sym, subtree)) # Postprocess the expressions to return the expressions to canonical form. for i, (sym, subtree) in enumerate(replacements): subtree = postprocess_for_cse(subtree, optimizations) replacements[i] = (sym, subtree) reduced_exprs = [postprocess_for_cse(e, optimizations) for e in reduced_exprs] if isinstance(exprs, Matrix): reduced_exprs = [Matrix(exprs.rows, exprs.cols, reduced_exprs)] if postprocess is None: return replacements, reduced_exprs return postprocess(replacements, reduced_exprs)
def precedence_Mul(item): if _coeff_isneg(item): return PRECEDENCE["Add"] return PRECEDENCE["Mul"]
def _print_Add(self, expr, order=None): """Print a Add object. :param expr: The expression. :rtype : bce.dom.mathml.all.Base :return: The printed MathML object. """ assert isinstance(expr, _sympy.Add) args = self._as_ordered_terms(expr, order=order) PREC = _sympy_precedence.precedence(expr) dt = _mathml.RowComponent() args_len = len(args) # Iterator each part. for arg_id in range(0, args_len): cur_arg = args[arg_id] if cur_arg.is_negative: # Get the negative number. neg_arg = -cur_arg # Get the precedence. CUR_PREC = _sympy_precedence.precedence(neg_arg) # Add a '-' operator. dt.append_object( _mathml.OperatorComponent(_mathml.OPERATOR_MINUS)) # noinspection PyProtectedMember if CUR_PREC < PREC or (_coeff_isneg(neg_arg) and arg_id != 0): # Insert the argument with parentheses around. dt.append_object( _mathml.OperatorComponent( _mathml.OPERATOR_LEFT_PARENTHESIS)) dt.append_object(self._print(neg_arg)) dt.append_object( _mathml.OperatorComponent( _mathml.OPERATOR_RIGHT_PARENTHESIS)) else: # Insert the argument only. dt.append_object(self._print(neg_arg)) else: # Add a '+' operator if the argument is not the first one. if arg_id != 0: dt.append_object( _mathml.OperatorComponent(_mathml.OPERATOR_PLUS)) # Get the precedence. CUR_PREC = _sympy_precedence.precedence(cur_arg) # noinspection PyProtectedMember if CUR_PREC < PREC or (_coeff_isneg(cur_arg) and arg_id != 0): # Insert the argument with parentheses around. dt.append_object( _mathml.OperatorComponent( _mathml.OPERATOR_LEFT_PARENTHESIS)) dt.append_object(self._print(cur_arg)) dt.append_object( _mathml.OperatorComponent( _mathml.OPERATOR_RIGHT_PARENTHESIS)) else: # Insert the argument only. dt.append_object(self._print(cur_arg)) return dt
def _print_Mul(self, expr): """Print a Mul object. :param expr: The expression. :rtype : bce.dom.mathml.all.Base :return: The printed MathML object. """ assert isinstance(expr, _sympy.Mul) # noinspection PyProtectedMember if _coeff_isneg(expr): x = _mathml.RowComponent() x.append_object(_mathml.OperatorComponent(_mathml.OPERATOR_MINUS)) x.append_object(self._print(-expr)) return x PREC = _sympy_precedence.precedence(expr) from sympy.simplify import fraction numer, denom = fraction(expr) if denom is not _sympy.S.One: return _mathml.FractionComponent(self._print(numer), self._print(denom)) coeff, terms = expr.as_coeff_mul() if coeff is _sympy.S.One and len(terms) == 1: # Since the negative coefficient has been handled, I don't # thing a coeff of 1 can remain if _sympy_precedence.precedence(terms[0]) < PREC: # Return the argument with parentheses around. tmp_node = _mathml.RowComponent() tmp_node.append_object( _mathml.OperatorComponent( _mathml.OPERATOR_LEFT_PARENTHESIS)) tmp_node.append_object(self._print(terms[0])) tmp_node.append_object( _mathml.OperatorComponent( _mathml.OPERATOR_RIGHT_PARENTHESIS)) return tmp_node else: # Return the argument only. return self._print(terms[0]) if self.order != "old": # noinspection PyProtectedMember terms = _sympy.Mul._from_args(terms).as_ordered_factors() # Build result row element(node). x = _mathml.RowComponent() if coeff != 1: if _sympy_precedence.precedence(coeff) < PREC: # Insert the coefficient number with parentheses around. x.append_object( _mathml.OperatorComponent( _mathml.OPERATOR_LEFT_PARENTHESIS)) x.append_object(self._print(coeff)) x.append_object( _mathml.OperatorComponent( _mathml.OPERATOR_RIGHT_PARENTHESIS)) else: # Insert the coefficient number only. x.append_object(self._print(coeff)) # Insert a multiply operator. if not terms[0].is_Symbol: x.append_object( _mathml.OperatorComponent(_mathml.OPERATOR_MULTIPLY)) terms_len = len(terms) for term_id in range(0, terms_len): cur_term = terms[term_id] if _sympy_precedence.precedence(cur_term) < PREC: x.append_object( _mathml.OperatorComponent( _mathml.OPERATOR_LEFT_PARENTHESIS)) x.append_object(self._print(cur_term)) x.append_object( _mathml.OperatorComponent( _mathml.OPERATOR_RIGHT_PARENTHESIS)) else: x.append_object(self._print(cur_term)) if term_id + 1 != terms_len and not cur_term.is_Symbol: x.append_object( _mathml.OperatorComponent(_mathml.OPERATOR_MULTIPLY)) return x