def _eval_subs(self, old, new): if self == old: return new arg = self.args[0] o = old if old.is_Pow: # handle (exp(3*log(x))).subs(x**2, z) -> z**(3/2) old = exp(old.exp * log(old.base)) if old.func is exp: # exp(a*expr) .subs( exp(b*expr), y ) -> y ** (a/b) a, expr_terms = self.args[0].as_coeff_terms() b, expr_terms_ = old.args[0].as_coeff_terms() if expr_terms == expr_terms_: return new**(a / b) if arg.is_Add: # exp(2*x+a).subs(exp(3*x),y) -> y**(2/3) * exp(a) # exp(exp(x) + exp(x**2)).subs(exp(exp(x)), w) -> w * exp(exp(x**2)) oarg = old.args[0] new_l = [] old_al = [] coeff2, terms2 = oarg.as_coeff_terms() for a in arg.args: a = a._eval_subs(old, new) coeff1, terms1 = a.as_coeff_terms() if terms1 == terms2: new_l.append(new**(coeff1 / coeff2)) else: old_al.append(a._eval_subs(old, new)) if new_l: new_l.append(self.func(C.Add(*old_al))) r = C.Mul(*new_l) return r old = o return Function._eval_subs(self, old, new)
def _eval_as_leading_term(self, x): arg = self.args[0] if arg.is_Add: return C.Mul(*[exp(f).as_leading_term(x) for f in arg.args]) arg = self.args[0].as_leading_term(x) if C.Order(1, x).contains(arg): return S.One return exp(arg)
def _print_Mul(self, expr): coeff, terms = expr.as_coeff_terms() if not coeff.is_negative: tex = "" else: coeff = -coeff tex = "- " numer, denom = fraction(C.Mul(*terms)) def convert(terms): product = [] if not terms.is_Mul: return str(self._print(terms)) else: for term in terms.args: pretty = self._print(term) if term.is_Add: product.append(r"\left(%s\right)" % pretty) else: product.append(str(pretty)) return r" ".join(product) if denom is S.One: if coeff is not S.One: tex += str(self._print(coeff)) + " " if numer.is_Add: tex += r"\left(%s\right)" % convert(numer) else: tex += r"%s" % convert(numer) else: if numer is S.One: if coeff.is_Integer: numer *= coeff.p elif coeff.is_Rational: if coeff.p != 1: numer *= coeff.p denom *= coeff.q elif coeff is not S.One: tex += str(self._print(coeff)) + " " else: if coeff.is_Rational and coeff.p == 1: denom *= coeff.q elif coeff is not S.One: tex += str(self._print(coeff)) + " " tex += r"\frac{%s}{%s}" % \ (convert(numer), convert(denom)) return tex
def parse_term(expr): """Parses expression expr and outputs tuple (sexpr, rat_expo, sym_expo, deriv) where: - sexpr is the base expression - rat_expo is the rational exponent that sexpr is raised to - sym_expo is the symbolic exponent that sexpr is raised to - deriv contains the derivatives the the expression for example, the output of x would be (x, 1, None, None) the output of 2**x would be (2, 1, x, None) """ rat_expo, sym_expo = S.One, None sexpr, deriv = expr, None if expr.is_Pow: if isinstance(expr.base, Derivative): sexpr, deriv = parse_derivative(expr.base) else: sexpr = expr.base if expr.exp.is_Rational: rat_expo = expr.exp elif expr.exp.is_Mul: coeff, tail = expr.exp.as_coeff_terms() if coeff.is_Rational: rat_expo, sym_expo = coeff, C.Mul(*tail) else: sym_expo = expr.exp else: sym_expo = expr.exp elif expr.func is C.exp: if expr.args[0].is_Rational: sexpr, rat_expo = S.Exp1, expr.args[0] elif expr.args[0].is_Mul: coeff, tail = expr.args[0].as_coeff_terms() if coeff.is_Rational: sexpr, rat_expo = C.exp(C.Mul(*tail)), coeff elif isinstance(expr, Derivative): sexpr, deriv = parse_derivative(expr) return sexpr, rat_expo, sym_expo, deriv
def separate(expr, deep=False): """Rewrite or separate a power of product to a product of powers but without any expanding, ie. rewriting products to summations. >>> from sympy import * >>> x, y, z = symbols('x', 'y', 'z') >>> separate((x*y)**2) x**2*y**2 >>> separate((x*(y*z)**3)**2) x**2*y**6*z**6 >>> separate((x*sin(x))**y + (x*cos(x))**y) x**y*cos(x)**y + x**y*sin(x)**y >>> separate((exp(x)*exp(y))**x) exp(x**2)*exp(x*y) >>> separate((sin(x)*cos(x))**y) cos(x)**y*sin(x)**y Notice that summations are left un touched. If this is not the requested behaviour, apply 'expand' to input expression before: >>> separate(((x+y)*z)**2) z**2*(x + y)**2 >>> separate((x*y)**(1+z)) x**(1 + z)*y**(1 + z) """ expr = sympify(expr) if expr.is_Pow: terms, expo = [], separate(expr.exp, deep) if expr.base.is_Mul: t = [separate(C.Pow(t, expo), deep) for t in expr.base.args] return C.Mul(*t) elif expr.base.func is C.exp: if deep == True: return C.exp(separate(expr.base[0], deep) * expo) else: return C.exp(expr.base[0] * expo) else: return C.Pow(separate(expr.base, deep), expo) elif expr.is_Add or expr.is_Mul: return type(expr)(*[separate(t, deep) for t in expr.args]) elif expr.is_Function and deep: return expr.func(*[separate(t) for t in expr.args]) else: return expr
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.One: return S.Exp1 elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.Zero elif arg.func is log: return arg.args[0] elif arg.is_Mul: coeff = arg.as_coefficient(S.Pi * S.ImaginaryUnit) if coeff is not None: if (2 * coeff).is_integer: if coeff.is_even: return S.One elif coeff.is_odd: return S.NegativeOne elif (coeff + S.Half).is_even: return -S.ImaginaryUnit elif (coeff + S.Half).is_odd: return S.ImaginaryUnit I = S.ImaginaryUnit oo = S.Infinity a = Wild("a", exclude=[I, oo]) r = arg.match(I * a * oo) if r and r[a] != 0: return S.NaN if arg.is_Add: args = arg.args else: args = [arg] included, excluded = [], [] for arg in args: coeff, terms = arg.as_coeff_terms() if coeff is S.Infinity: excluded.append(coeff**C.Mul(*terms)) else: coeffs, log_term = [coeff], None for term in terms: if term.func is log: if log_term is None: log_term = term.args[0] else: log_term = None break elif term.is_comparable: coeffs.append(term) else: log_term = None break if log_term is not None: excluded.append(log_term**C.Mul(*coeffs)) else: included.append(arg) if excluded: return C.Mul(*(excluded + [cls(C.Add(*included))]))
def as_base_exp(self): return S.Exp1, C.Mul(*self.args)
def powsimp(expr, deep=False, combine='all'): """ == Usage == Reduces expression by combining powers with similar bases and exponents. == Notes == If deep is True then powsimp() will also simplify arguments of functions. By default deep is set to False. You can make powsimp() only combine bases or only combine exponents by changing combine='base' or combine='exp'. By default, combine='all', which does both. combine='base' will only combine:: a a a 2x x x * y => (x*y) as well as things like 2 => 4 and combine='exp' will only combine :: a b (a + b) x * x => x combine='exp' will strictly only combine exponents in the way that used to be automatic. Also use deep=True if you need the old behavior. == Examples == >>> from sympy import * >>> x,n = map(Symbol, 'xn') >>> e = x**n * (x*n)**(-n) * n >>> powsimp(e) n**(1 - n) >>> powsimp(log(e)) log(n*x**n*(n*x)**(-n)) >>> powsimp(log(e), deep=True) log(n**(1 - n)) >>> powsimp(e, combine='exp') n*x**n*(n*x)**(-n) >>> powsimp(e, combine='base') n*(1/n)**n >>> y, z = symbols('yz') >>> a = x**y*x**z*n**z*n**y >>> powsimp(a, combine='exp') n**(y + z)*x**(y + z) >>> powsimp(a, combine='base') (n*x)**y*(n*x)**z >>> powsimp(a, combine='all') (n*x)**(y + z) """ if combine not in ['all', 'exp', 'base']: raise ValueError, "combine must be one of ('all', 'exp', 'base')." if combine in ('all', 'base'): expr = separate(expr, deep) y = Symbol('y', dummy=True) if expr.is_Pow: if deep: return powsimp(y*powsimp(expr.base, deep, combine)**powsimp(\ expr.exp, deep, combine), deep, combine)/y else: return powsimp(y * expr, deep, combine) / y # Trick it into being a Mul elif expr.is_Function: if expr.func == exp and deep: # Exp should really be like Pow return powsimp(y * exp(powsimp(expr.args[0], deep, combine)), deep, combine) / y elif expr.func == exp and not deep: return powsimp(y * expr, deep, combine) / y elif deep: return expr.func(*[powsimp(t, deep, combine) for t in expr.args]) else: return expr elif expr.is_Add: return C.Add(*[powsimp(t, deep, combine) for t in expr.args]) elif expr.is_Mul: if combine in ('exp', 'all'): # Collect base/exp data, while maintaining order in the # non-commutative parts of the product if combine is 'all' and deep and any( (t.is_Add for t in expr.args)): # Once we get to 'base', there is no more 'exp', so we need to # distribute here. return powsimp(expand_mul(expr, deep=False), deep, combine) c_powers = {} nc_part = [] newexpr = sympify(1) for term in expr.args: if term.is_Add and deep: newexpr *= powsimp(term, deep, combine) else: if term.is_commutative: b, e = term.as_base_exp() c_powers[b] = c_powers.get(b, 0) + e else: nc_part.append(term) newexpr = Mul(newexpr, Mul(*(Pow(b, e) for b, e in c_powers.items()))) if combine is 'exp': return Mul(newexpr, Mul(*nc_part)) else: # combine is 'all', get stuff ready for 'base' if deep: newexpr = expand_mul(newexpr, deep=False) if newexpr.is_Add: return powsimp(Mul(*nc_part), deep, combine='base') * Add( *(powsimp(i, deep, combine='base') for i in newexpr.args)) else: return powsimp(Mul(*nc_part), deep, combine='base')*\ powsimp(newexpr, deep, combine='base') else: # combine is 'base' if deep: expr = expand_mul(expr, deep=False) if expr.is_Add: return Add(*(powsimp(i, deep, combine) for i in expr.args)) else: # Build c_powers and nc_part. These must both be lists not # dicts because exp's are not combined. c_powers = [] nc_part = [] for term in expr.args: if term.is_commutative: c_powers.append(list(term.as_base_exp())) else: nc_part.append(term) # Pull out numerical coefficients from exponent # e.g., 2**(2*x) => 4**x for i in xrange(len(c_powers)): b, e = c_powers[i] exp_c, exp_t = e.as_coeff_terms() if not (exp_c is S.One) and exp_t: c_powers[i] = [C.Pow(b, exp_c), C.Mul(*exp_t)] # Combine bases whenever they have the same exponent which is # not numeric c_exp = {} for b, e in c_powers: if e in c_exp: c_exp[e].append(b) else: c_exp[e] = [b] # Merge back in the results of the above to form a new product for e in c_exp: bases = c_exp[e] if deep: simpe = powsimp(e, deep, combine) c_exp = {} for b, ex in c_powers: if ex in c_exp: c_exp[ex].append(b) else: c_exp[ex] = [b] del c_exp[e] c_exp[simpe] = bases else: simpe = e if len(bases) > 1: for b in bases: c_powers.remove([b, e]) new_base = Mul(*bases) in_c_powers = False for i in xrange(len(c_powers)): if c_powers[i][0] == new_base: if combine == 'all': c_powers[i][1] += simpe else: c_powers.append([new_base, simpe]) in_c_powers = True if not in_c_powers: c_powers.append([new_base, simpe]) c_part = [C.Pow(b, e) for b, e in c_powers] return C.Mul(*(c_part + nc_part)) else: return expr
def _together(expr): from sympy.core.function import Function if expr.is_Add: items, coeffs, basis = [], [], {} for elem in expr.args: numer, q = fraction(_together(elem)) denom = {} for term in make_list(q.expand(), Mul): expo = S.One coeff = S.One if term.is_Pow: if term.exp.is_Rational: term, expo = term.base, term.exp elif term.exp.is_Mul: coeff, tail = term.exp.as_coeff_terms() if coeff.is_Rational: tail = C.Mul(*tail) term, expo = Pow(term.base, tail), coeff coeff = S.One elif term.func is C.exp: if term.args[0].is_Rational: term, expo = S.Exp1, term.args[0] elif term.args[0].is_Mul: coeff, tail = term.args[0].as_coeff_terms() if coeff.is_Rational: tail = C.Mul(*tail) term, expo = C.exp(tail), coeff coeff = S.One elif term.is_Rational: coeff = Integer(term.q) term = Integer(term.p) if term in denom: denom[term] += expo else: denom[term] = expo if term in basis: total, maxi = basis[term] n_total = total + expo n_maxi = max(maxi, expo) basis[term] = (n_total, n_maxi) else: basis[term] = (expo, expo) coeffs.append(coeff) items.append((numer, denom)) numerator, denominator = [], [] for (term, (total, maxi)) in basis.iteritems(): basis[term] = (total, total - maxi) if term.func is C.exp: denominator.append(C.exp(maxi * term.args[0])) else: if maxi is S.One: denominator.append(term) else: denominator.append(Pow(term, maxi)) if all([c.is_integer for c in coeffs]): gcds = lambda x, y: igcd(int(x), int(y)) common = Rational(reduce(gcds, coeffs)) else: common = S.One product = Mul(*coeffs) / common for ((numer, denom), coeff) in zip(items, coeffs): expr, coeff = [], product / (coeff * common) for term in basis.iterkeys(): total, sub = basis[term] if term in denom: expo = total - denom[term] - sub else: expo = total - sub if term.func is C.exp: expr.append(C.exp(expo * term.args[0])) else: if expo is S.One: expr.append(term) else: expr.append(Pow(term, expo)) numerator.append(coeff * Mul(*([numer] + expr))) return Add(*numerator) / (product * Mul(*denominator)) elif expr.is_Mul or expr.is_Pow: return type(expr)(*[_together(t) for t in expr.args]) elif expr.is_Function and deep: return expr.func(*[_together(t) for t in expr.args]) else: return expr
def _eval_rewrite_as_Heaviside(self, *args): return C.Add(*[j*C.Mul(*[C.Heaviside(i-j) for i in args if i!=j]) \ for j in args])
def _print_Mul(self, expr): coeff, terms = expr.as_coeff_terms() if not coeff.is_negative: tex = "" else: coeff = -coeff tex = "- " numer, denom = fraction(C.Mul(*terms)) seperator = self._settings['mul_symbol_latex'] def convert(terms): if not terms.is_Mul: return str(self._print(terms)) else: _tex = last_term_tex = "" for term in terms.args: pretty = self._print(term) if term.is_Add: term_tex = (r"\left(%s\right)" % pretty) else: term_tex = str(pretty) # between two digits, \times must always be used, # to avoid confusion if seperator == " " and \ re.search("[0-9][} ]*$", last_term_tex) and \ re.match("[{ ]*[-+0-9]", term_tex): _tex += r" \times " elif _tex: _tex += seperator _tex += term_tex last_term_tex = term_tex return _tex if denom is S.One: if numer.is_Add: _tex = r"\left(%s\right)" % convert(numer) else: _tex = r"%s" % convert(numer) if coeff is not S.One: tex += str(self._print(coeff)) # between two digits, \times must always be used, to avoid # confusion if seperator == " " and re.search("[0-9][} ]*$", tex) and \ re.match("[{ ]*[-+0-9]", _tex): tex += r" \times " + _tex else: tex += seperator + _tex else: tex += _tex else: if numer is S.One: if coeff.is_Integer: numer *= coeff.p elif coeff.is_Rational: if coeff.p != 1: numer *= coeff.p denom *= coeff.q elif coeff is not S.One: tex += str(self._print(coeff)) + " " else: if coeff.is_Rational and coeff.p == 1: denom *= coeff.q elif coeff is not S.One: tex += str(self._print(coeff)) + " " tex += r"\frac{%s}{%s}" % \ (convert(numer), convert(denom)) return tex
def __new__(cls, expr, *symbols, **assumptions): expr = sympify(expr).expand() if expr is S.NaN: return S.NaN if symbols: symbols = map(sympify, symbols) else: symbols = list(expr.atoms(C.Symbol)) symbols.sort(Basic.compare) if expr.is_Order: new_symbols = list(expr.symbols) for s in symbols: if s not in new_symbols: new_symbols.append(s) if len(new_symbols)==len(expr.symbols): return expr symbols = new_symbols elif symbols: symbol_map = {} new_symbols = [] for s in symbols: if isinstance(s, C.Symbol): new_symbols.append(s) continue z = C.Symbol('z',dummy=True) x1,s1 = solve4linearsymbol(s, z) expr = expr.subs(x1,s1) symbol_map[z] = s new_symbols.append(z) if symbol_map: r = Order(expr, *new_symbols, **assumptions) expr = r.expr.subs(symbol_map) symbols = [] for s in r.symbols: if symbol_map.has_key(s): symbols.append(symbol_map[s]) else: symbols.append(s) else: if expr.is_Add: lst = expr.extract_leading_order(*symbols) expr = C.Add(*[f.expr for (e,f) in lst]) else: expr = expr.as_leading_term(*symbols) coeff, terms = expr.as_coeff_terms() if coeff is S.Zero: return coeff expr = C.Mul(*[t for t in terms if t.has(*symbols)]) elif expr is not S.Zero: expr = S.One if expr is S.Zero: return expr # create Order instance: obj = Expr.__new__(cls, expr, *symbols, **assumptions) return obj
def _print_Mul(self, expr): coeff, terms = expr.as_coeff_terms() if not coeff.is_negative: tex = "" else: coeff = -coeff tex = "- " numer, denom = fraction(C.Mul(*terms)) mul_symbol_table = { None: r" ", "ldot": r" \,.\, ", "dot": r" \cdot ", "times": r" \times " } seperator = mul_symbol_table[self._settings['mul_symbol']] def convert(terms): product = [] if not terms.is_Mul: return str(self._print(terms)) else: for term in terms.args: pretty = self._print(term) if term.is_Add: product.append(r"\left(%s\right)" % pretty) else: product.append(str(pretty)) return seperator.join(product) if denom is S.One: if coeff is not S.One: tex += str(self._print(coeff)) + seperator if numer.is_Add: tex += r"\left(%s\right)" % convert(numer) else: tex += r"%s" % convert(numer) else: if numer is S.One: if coeff.is_Integer: numer *= coeff.p elif coeff.is_Rational: if coeff.p != 1: numer *= coeff.p denom *= coeff.q elif coeff is not S.One: tex += str(self._print(coeff)) + " " else: if coeff.is_Rational and coeff.p == 1: denom *= coeff.q elif coeff is not S.One: tex += str(self._print(coeff)) + " " tex += r"\frac{%s}{%s}" % \ (convert(numer), convert(denom)) return tex