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 _taylor(self, x, x0, n): l = [] g = None for i in xrange(n): g = self.taylor_term(i, self.args[0], g) g = g.nseries(x, x0, n) l.append(g) return C.Add(*l) + C.Order(x**n, x)
def _eval_expand_func(self, *args): arg = self.args[0].expand() if arg.is_Add: for i, coeff in enumerate(arg.args[:]): if arg.args[i].is_Number: terms = C.Add(*(arg.args[:i] + arg.args[i + 1:])) if coeff.is_Rational: if coeff.q != 1: terms += C.Rational(1, coeff.q) coeff = C.Integer(int(coeff)) else: continue return gamma(terms) * C.RisingFactorial(terms, coeff) return self.func(*self.args)
def _eval_nseries(self, x, x0, n): from sympy import powsimp arg = self.args[0] k, l = Wild("k"), Wild("l") r = arg.match(k * x**l) if r is not None: k, l = r[k], r[l] if l != 0 and not l.has(x) and not k.has(x): r = log(k) + l * log(x) return r order = C.Order(x**n, x) arg = self.args[0] x = order.symbols[0] ln = C.log use_lt = not C.Order(1, x).contains(arg) if not use_lt: arg0 = arg.limit(x, 0) use_lt = (arg0 is S.Zero) if use_lt: # singularity, #example: self = log(sin(x)) # arg = (arg / lt) * lt lt = arg.as_leading_term(x) # arg = sin(x); lt = x a = powsimp((arg / lt).expand(), deep=True, combine='exp') # a = sin(x)/x # the idea is to recursively call ln(a).series(), but one needs to # make sure that ln(sin(x)/x) doesn't get "simplified" to # -log(x)+ln(sin(x)) and an infinite recursion occurs, see also the # issue 252. obj = ln(lt) + ln(a)._eval_nseries(x, x0, n) else: # arg -> arg0 + (arg - arg0) -> arg0 * (1 + (arg/arg0 - 1)) z = (arg / arg0 - 1) x = order.symbols[0] ln = C.log o = C.Order(z, x) if o is S.Zero: return ln(1 + z) + ln(arg0) if o.expr.is_number: e = ln(order.expr * x) / ln(x) else: e = ln(order.expr) / ln(o.expr) n = e.limit(x, 0) + 1 if n.is_unbounded: # requested accuracy gives infinite series, # order is probably nonpolynomial e.g. O(exp(-1/x), x). return ln(1 + z) + ln(arg0) try: n = int(n) except TypeError: #well, the n is something more complicated (like 1+log(2)) n = int(n.evalf()) + 1 assert n >= 0, ` n ` l = [] g = None for i in xrange(n + 2): g = ln.taylor_term(i, z, g) g = g.nseries(x, x0, n) l.append(g) obj = C.Add(*l) + ln(arg0) obj2 = expand_log(powsimp(obj, deep=True, combine='exp')) if obj2 != obj: r = obj2.nseries(x, x0, n) else: r = obj if r == self: return self return r + order
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 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 _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 __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 _eval_integral(self, f, x): """Calculate the anti-derivative to the function f(x). This is a powerful function that should in theory be able to integrate everything that can be integrated. If you find something, that it doesn't, it is easy to implement it. (1) Simple heuristics (based on pattern matching and integral table): - most frequently used functions (e.g. polynomials) - functions non-integrable by any of the following algorithms (e.g. exp(-x**2)) (2) Integration of rational functions: (a) using apart() - apart() is full partial fraction decomposition procedure based on Bronstein-Salvy algorithm. It gives formal decomposition with no polynomial factorization at all (so it's fast and gives the most general results). However it needs much better implementation of RootsOf class (if fact any implementation). (b) using Trager's algorithm - possibly faster than (a) but needs implementation :) (3) Whichever implementation of pmInt (Mateusz, Kirill's or a combination of both). - this way we can handle efficiently huge class of elementary and special functions (4) Recursive Risch algorithm as described in Bronstein's integration tutorial. - this way we can handle those integrable functions for which (3) fails (5) Powerful heuristics based mostly on user defined rules. - handle complicated, rarely used cases """ # if it is a poly(x) then let the polynomial integrate itself (fast) # # It is important to make this check first, otherwise the other code # will return a sympy expression instead of a Polynomial. # # see Polynomial for details. if isinstance(f, Poly): return f.integrate(x) # Piecewise antiderivatives need to call special integrate. if f.func is Piecewise: return f._eval_integral(x) # let's cut it short if `f` does not depend on `x` if not f.has(x): return f * x # try to convert to poly(x) and then integrate if successful (fast) poly = f.as_poly(x) if poly is not None: return poly.integrate().as_basic() # since Integral(f=g1+g2+...) == Integral(g1) + Integral(g2) + ... # we are going to handle Add terms separately, # if `f` is not Add -- we only have one term parts = [] args = make_list(f, Add) for g in args: coeff, g = g.as_independent(x) # g(x) = const if g is S.One: parts.append(coeff * x) continue # c # g(x) = (a*x+b) if g.is_Pow and not g.exp.has(x): a = Wild('a', exclude=[x]) b = Wild('b', exclude=[x]) M = g.base.match(a * x + b) if M is not None: if g.exp == -1: h = C.log(g.base) else: h = g.base**(g.exp + 1) / (g.exp + 1) parts.append(coeff * h / M[a]) continue # poly(x) # g(x) = ------- # poly(x) if g.is_rational_function(x): parts.append(coeff * ratint(g, x)) continue # g(x) = Mul(trig) h = trigintegrate(g, x) if h is not None: parts.append(coeff * h) continue # g(x) has at least a DiracDelta term h = deltaintegrate(g, x) if h is not None: parts.append(coeff * h) continue # fall back to the more general algorithm h = heurisch(g, x, hints=[]) # if we failed maybe it was because we had # a product that could have been expanded, # so let's try an expansion of the whole # thing before giving up; we don't try this # out the outset because there are things # that cannot be solved unless they are # NOT expanded e.g., x**x*(1+log(x)). There # should probably be a checker somewhere in this # routine to look for such cases and try to do # collection on the expressions if they are already # in an expanded form if not h and len(args) == 1: f = f.expand(mul=True, deep=False) if f.is_Add: return self._eval_integral(f, x) if h is not None: parts.append(coeff * h) else: return None return C.Add(*parts)