def _eval_nseries(self, x, x0, n): assert len(self.args) == 1 arg = self.args[0] arg0 = arg.limit(x, 0) from sympy import oo if arg0 in [-oo, oo]: raise PoleError("Cannot expand around %s" % (arg)) if arg0 is not S.Zero: e = self.func(arg) e1 = e.expand() if e == e1: #for example when e = sin(x+1) or e = sin(cos(x)) #let's try the general algorithm term = e.subs(x, S.Zero) series = term fact = S.One for i in range(n - 1): i += 1 fact *= Rational(i) e = e.diff(x) term = e.subs(x, S.Zero) * (x**i) / fact term = term.expand() series += term return series + C.Order(x**n, x) return self.nseries(x, x0, n) l = [] g = None for i in xrange(n + 2): g = self.taylor_term(i, arg, g) g = g.nseries(x, x0, n) l.append(g) return Add(*l) + C.Order(x**n, x)
def extract_leading_order(self, *symbols): """ Returns the leading term and it's order. Examples: >>> (x+1+1/x**5).extract_leading_order(x) ((1/x**5, O(1/x**5)),) >>> (1+x).extract_leading_order(x) ((1, O(1, x)),) >>> (x+x**2).extract_leading_order(x) ((x, O(x)),) """ lst = [] seq = [(f, C.Order(f, *symbols)) for f in self.args] for ef,of in seq: for e,o in lst: if o.contains(of) and o != of: of = None break if of is None: continue new_lst = [(ef,of)] for e,o in lst: if of.contains(o) and o != of: continue new_lst.append((e,o)) lst = new_lst return tuple(lst)
def _eval_as_leading_term(self, x): """General method for the leading term""" arg = self.args[0].as_leading_term(x) if C.Order(1, x).contains(arg): return arg else: return self.func(arg)
def _eval_as_leading_term(self, x): coeff, factors = self.as_coeff_factors(x) has_unbounded = bool([f for f in self.args if f.is_unbounded]) if has_unbounded: if isinstance(factors, Basic): factors = factors.args factors = [f for f in factors if not f.is_bounded] if coeff is not S.Zero: o = C.Order(x) else: o = C.Order(factors[0]*x,x) n = 1 s = self.nseries(x, 0, n) while s.is_Order: n +=1 s = self.nseries(x, 0, n) if s.is_Add: s = s.removeO() if s.is_Add: lst = s.extract_leading_order(x) return Add(*[e for (e,f) in lst]) return s.as_leading_term(x)
def __new__(cls, *args, **assumptions): if assumptions.get('evaluate') is False: return Basic.__new__(cls, *map(_sympify, args), **assumptions) if len(args)==0: return cls.identity() if len(args)==1: return _sympify(args[0]) c_part, nc_part, order_symbols = cls.flatten(map(_sympify, args)) if len(c_part) + len(nc_part) <= 1: if c_part: obj = c_part[0] elif nc_part: obj = nc_part[0] else: obj = cls.identity() else: obj = Basic.__new__(cls, *(c_part + nc_part), **assumptions) obj.is_commutative = not nc_part if order_symbols is not None: obj = C.Order(obj, *order_symbols) return obj
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_order(self, *symbols): # Order(5, x, y) -> Order(1,x,y) return C.Order(S.One, *symbols)