def as_coeff_exponent(self, x): """ c*x**e -> c,e where x can be any symbolic expression. """ x = sympify(x) wc = Wild('wc') we = Wild('we') p = wc*x**we from sympy import collect s = collect(self, x) d = s.match(p) if d is not None and we in d: return d[wc], d[we] return s, S.Zero
def as_coefficient(self, expr): """Extracts symbolic coefficient at the given expression. In other words, this functions separates 'self' into product of 'expr' and 'expr'-free coefficient. If such separation is not possible it will return None. >>> from sympy import E, pi, sin, I >>> from sympy.abc import x, y >>> E.as_coefficient(E) 1 >>> (2*E).as_coefficient(E) 2 >>> (2*E + x).as_coefficient(E) >>> (2*sin(E)*E).as_coefficient(E) >>> (2*pi*I).as_coefficient(pi*I) 2 >>> (2*I).as_coefficient(pi*I) """ if expr.is_Add: return None else: w = Wild('w') coeff = self.match(w * expr) if coeff is not None: if expr.is_Mul: args = expr.args else: args = [expr] if coeff[w].has(*args): return None else: return coeff[w] else: return None
def _eval_nseries(self, x, x0, n): def geto(e): "Returns the O(..) symbol, or None if there is none." if e.is_Order: return e if e.is_Add: for x in e.args: if x.is_Order: return x def getn(e): """ Returns the order of the expression "e". The order is determined either from the O(...) term. If there is no O(...) term, it returns None. Example: >>> getn(1+x+O(x**2)) 2 >>> getn(1+x) >>> """ o = geto(e) if o is None: return None else: o = o.expr if o.is_Symbol: return Integer(1) if o.is_Pow: return o.args[1] n, d = o.as_numer_denom() if isinstance(d, log): # i.e. o = x**2/log(x) if n.is_Symbol: return Integer(1) if n.is_Pow: return n.args[1] raise Exception("Unimplemented") base, exp = self.args if exp.is_Integer: if exp > 0: # positive integer powers are easy to expand, e.g.: # sin(x)**4 = (x-x**3/3+...)**4 = ... return (base.nseries(x, x0, n) ** exp).expand() elif exp == -1: # this is also easy to expand using the formula: # 1/(1 + x) = 1 + x + x**2 + x**3 ... # so we need to rewrite base to the form "1+x" from sympy import log if base.has(log(x)): # we need to handle the log(x) singularity: assert x0 == 0 y = Symbol("y", dummy=True) p = self.subs(log(x), -1/y) if not p.has(x): p = p.nseries(y, x0, n) p = p.subs(y, -1/log(x)) return p base = base.nseries(x, x0, n) if base.has(log(x)): # we need to handle the log(x) singularity: assert x0 == 0 y = Symbol("y", dummy=True) self0 = 1/base p = self0.subs(log(x), -1/y) if not p.has(x): p = p.nseries(y, x0, n) p = p.subs(y, -1/log(x)) return p prefactor = base.as_leading_term(x) # express "rest" as: rest = 1 + k*x**l + ... + O(x**n) rest = ((base-prefactor)/prefactor).expand() if rest == 0: # if prefactor == w**4 + x**2*w**4 + 2*x*w**4, we need to # factor the w**4 out using collect: from sympy import collect return 1/collect(prefactor, x) if rest.is_Order: return ((1+rest)/prefactor).expand() if not rest.has(x): return 1/(prefactor*(rest+1)) n2 = getn(rest) if n2 is not None: n = n2 term2 = rest.as_leading_term(x) k, l = Wild("k"), Wild("l") r = term2.match(k*x**l) k, l = r[k], r[l] if l.is_Integer: l = int(l) elif l.is_number: l = float(l) else: raise Exception("Not implemented") s = 1 m = 1 while l * m < n: s += ((-rest)**m).expand() m += 1 r = (s/prefactor).expand() if n2 is None: # Append O(...) because it is not included in "r" from sympy import O r += O(x**n) return r else: # negative powers are rewritten to the cases above, for example: # sin(x)**(-4) = 1/( sin(x)**4) = ... # and expand the denominator: denominator = (base**(-exp)).nseries(x, x0, n) if 1/denominator == self: return self # now we have a type 1/f(x), that we know how to expand return (1/denominator).nseries(x, x0, n) if exp.has(x): import sympy return sympy.exp(exp*sympy.log(base)).nseries(x, x0, n) if base == x: return self order = C.Order(x**n, x) x = order.symbols[0] e = self.exp b = self.base ln = C.log exp = C.exp if e.has(x): return exp(e * ln(b)).nseries(x, x0, n) if b==x: return self b0 = b.limit(x,0) if b0 is S.Zero or b0.is_unbounded: lt = b.as_leading_term(x) o = order * lt**(1-e) bs = b.nseries(x, x0, n-e) if bs.is_Add: bs = bs.removeO() if bs.is_Add: # bs -> lt + rest -> lt * (1 + (bs/lt - 1)) return (lt**e * ((bs/lt).expand()**e).nseries(x, x0, n-e)).expand() + order return bs**e+order o2 = order * (b0**-e) # b -> b0 + (b-b0) -> b0 * (1 + (b/b0-1)) z = (b/b0-1) #r = self._compute_oseries3(z, o2, self.taylor_term) x = o2.symbols[0] ln = C.log o = C.Order(z, x) if o is S.Zero: r = (1+z) else: if o.expr.is_number: e2 = ln(o2.expr*x)/ln(x) else: e2 = ln(o2.expr)/ln(o.expr) n = e2.limit(x,0) + 1 if n.is_unbounded: # requested accuracy gives infinite series, # order is probably nonpolynomial e.g. O(exp(-1/x), x). r = (1+z) else: 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 = self.taylor_term(i, z, g) g = g.nseries(x, x0, n) l.append(g) r = Add(*l) return r * b0**e + order
def _eval_nseries(self, x, n): from sympy import powsimp, collect, exp, log, O, ceiling b, e = self.args if e.is_Integer: if e > 0: # positive integer powers are easy to expand, e.g.: # sin(x)**4 = (x-x**3/3+...)**4 = ... return Pow(b._eval_nseries(x, n=n), e)._eval_expand_multinomial(deep=False) elif e is S.NegativeOne: # this is also easy to expand using the formula: # 1/(1 + x) = 1 + x + x**2 + x**3 ... # so we need to rewrite base to the form "1+x" if b.has(log(x)): # we need to handle the log(x) singularity: y = Dummy("y") p = self.subs(log(x), -1 / y) if not p.has(x): p = p._eval_nseries(y, n=n) p = p.subs(y, -1 / log(x)) return p b = b._eval_nseries(x, n=n) if b.has(log(x)): # we need to handle the log(x) singularity: y = Dummy("y") self0 = 1 / b p = self0.subs(log(x), -1 / y) if not p.has(x): p = p._eval_nseries(y, n=n) p = p.subs(y, -1 / log(x)) return p prefactor = b.as_leading_term(x) # express "rest" as: rest = 1 + k*x**l + ... + O(x**n) rest = ((b - prefactor) / prefactor)._eval_expand_mul() if rest == 0: # if prefactor == w**4 + x**2*w**4 + 2*x*w**4, we need to # factor the w**4 out using collect: return 1 / collect(prefactor, x) if rest.is_Order: return (1 + rest) / prefactor n2 = rest.getn() if n2 is not None: n = n2 term2 = collect(rest.as_leading_term(x), x) k, l = Wild("k"), Wild("l") r = term2.match(k * x**l) # if term2 is NaN then r will not contain l k = r.get(k, S.One) l = r.get(l, S.Zero) if l.is_Rational and l > 0: pass elif l.is_number and l > 0: l = l.evalf() else: raise NotImplementedError() terms = [1 / prefactor] for m in xrange(1, ceiling(n / l)): new_term = terms[-1] * (-rest) if new_term.is_Pow: new_term = new_term._eval_expand_multinomial( deep=False) else: new_term = new_term._eval_expand_mul(deep=False) terms.append(new_term) if n2 is None: # Append O(...) because it is not included in "r" terms.append(O(x**n)) return powsimp(Add(*terms), deep=True, combine='exp') else: # negative powers are rewritten to the cases above, for example: # sin(x)**(-4) = 1/( sin(x)**4) = ... # and expand the denominator: denominator = (b**(-e))._eval_nseries(x, n=n) if 1 / denominator == self: return self # now we have a type 1/f(x), that we know how to expand return (1 / denominator)._eval_nseries(x, n=n) if e.has(x): return exp(e * log(b))._eval_nseries(x, n=n) if b == x: return powsimp(self, deep=True, combine='exp') # work for b(x)**e where e is not an Integer and does not contain x # and hopefully has no other symbols def e2int(e): """return the integer value (if possible) of e and a flag indicating whether it is bounded or not.""" n = e.limit(x, 0) unbounded = n.is_unbounded if not unbounded: # XXX was int or floor intended? int used to behave like floor # so int(-Rational(1, 2)) returned -1 rather than int's 0 try: n = int(n) except TypeError: #well, the n is something more complicated (like 1+log(2)) try: n = int(n.evalf()) + 1 # XXX why is 1 being added? except TypeError: pass # hope that base allows this to be resolved n = _sympify(n) return n, unbounded order = O(x**n, x) ei, unbounded = e2int(e) b0 = b.limit(x, 0) if unbounded and (b0 is S.One or b0.has(Symbol)): # XXX what order if b0 is S.One: resid = (b - 1) if resid.is_positive: return S.Infinity elif resid.is_negative: return S.Zero raise ValueError('cannot determine sign of %s' % resid) return b0**ei if (b0 is S.Zero or b0.is_unbounded): if unbounded is not False: return b0**e # XXX what order if not ei.is_number: # if not, how will we proceed? raise ValueError('expecting numerical exponent but got %s' % ei) nuse = n - ei lt = b.as_leading_term(x) # XXX o is not used -- was this to be used as o and o2 below to compute a new e? o = order * lt**(1 - e) bs = b._eval_nseries(x, n=nuse) if bs.is_Add: bs = bs.removeO() if bs.is_Add: # bs -> lt + rest -> lt*(1 + (bs/lt - 1)) return ((Pow(lt, e) * Pow( (bs / lt).expand(), e).nseries(x, n=nuse)).expand() + order) return bs**e + order # either b0 is bounded but neither 1 nor 0 or e is unbounded # b -> b0 + (b-b0) -> b0 * (1 + (b/b0-1)) o2 = order * (b0**-e) z = (b / b0 - 1) o = O(z, x) #r = self._compute_oseries3(z, o2, self.taylor_term) if o is S.Zero or o2 is S.Zero: unbounded = True else: if o.expr.is_number: e2 = log(o2.expr * x) / log(x) else: e2 = log(o2.expr) / log(o.expr) n, unbounded = e2int(e2) if unbounded: # requested accuracy gives infinite series, # order is probably nonpolynomial e.g. O(exp(-1/x), x). r = 1 + z else: l = [] g = None for i in xrange(n + 2): g = self.taylor_term(i, z, g) g = g.nseries(x, n=n) l.append(g) r = Add(*l) return r * b0**e + order