def get_integer_part(expr, no, options, return_ints=False): """ With no = 1, computes ceiling(expr) With no = -1, computes floor(expr) Note: this function either gives the exact result or signals failure. """ # The expression is likely less than 2^30 or so assumed_size = 30 ire, iim, ire_acc, iim_acc = evalf(expr, assumed_size, options) # We now know the size, so we can calculate how much extra precision # (if any) is needed to get within the nearest integer if ire and iim: gap = max(fastlog(ire)-ire_acc, fastlog(iim)-iim_acc) elif ire: gap = fastlog(ire)-ire_acc elif iim: gap = fastlog(iim)-iim_acc else: # ... or maybe the expression was exactly zero return None, None, None, None margin = 10 if gap >= -margin: ire, iim, ire_acc, iim_acc = \ evalf(expr, margin+assumed_size+gap, options) # We can now easily find the nearest integer, but to find floor/ceil, we # must also calculate whether the difference to the nearest integer is # positive or negative (which may fail if very close). def calc_part(expr, nexpr): nint = int(to_int(nexpr, rnd)) expr = C.Add(expr, -nint, evaluate=False) x, _, x_acc, _ = evalf(expr, 10, options) try: check_target(expr, (x, None, x_acc, None), 3) except PrecisionExhausted: if not expr.equals(0): raise PrecisionExhausted x = fzero nint += int(no*(mpf_cmp(x or fzero, fzero) == no)) nint = from_int(nint) return nint, fastlog(nint) + 10 re, im, re_acc, im_acc = None, None, None, None if ire: re, re_acc = calc_part(C.re(expr, evaluate=False), ire) if iim: im, im_acc = calc_part(C.im(expr, evaluate=False), iim) if return_ints: return int(to_int(re or fzero)), int(to_int(im or fzero)) return re, im, re_acc, im_acc
def _eval_is_real(self): real_b = self.base.is_real if real_b is None: return real_e = self.exp.is_real if real_e is None: return if real_b and real_e: if self.base.is_positive: return True else: # negative or zero (or positive) if self.exp.is_integer: return True elif self.base.is_negative: if self.exp.is_Rational: return False im_b = self.base.is_imaginary im_e = self.exp.is_imaginary if im_b: if self.exp.is_integer: if self.exp.is_even: return True elif self.exp.is_odd: return False elif (self.exp in [S.ImaginaryUnit, -S.ImaginaryUnit] and self.base in [S.ImaginaryUnit, -S.ImaginaryUnit]): return True if real_b and im_e: c = self.exp.coeff(S.ImaginaryUnit) if c: ok = (c*C.log(self.base)/S.Pi).is_Integer if ok is not None: return ok
def evalf_log(expr, prec, options): arg = expr.args[0] workprec = prec + 10 xre, xim, xacc, _ = evalf(arg, workprec, options) if xim: # XXX: use get_abs etc instead re = evalf_log(C.log(C.Abs(arg, evaluate=False), evaluate=False), prec, options) im = mpf_atan2(xim, xre or fzero, prec) return re[0], im, re[2], prec imaginary_term = mpf_cmp(xre, fzero) < 0 re = mpf_log(mpf_abs(xre), prec, rnd) size = fastlog(re) if prec - size > workprec: # We actually need to compute 1+x accurately, not x arg = C.Add(S.NegativeOne, arg, evaluate=False) xre, xim, _, _ = evalf_add(arg, prec, options) prec2 = workprec - fastlog(xre) re = mpf_log(mpf_add(xre, fone, prec2), prec, rnd) re_acc = prec if imaginary_term: return re, mpf_pi(prec), re_acc, prec else: return re, None, re_acc, None
def _eval_subs(self, old, new): if old.func is self.func and self.base == old.base: coeff1, terms1 = self.exp.as_independent(C.Symbol, as_Add=False) coeff2, terms2 = old.exp.as_independent(C.Symbol, as_Add=False) if terms1 == terms2: pow = coeff1/coeff2 ok = False # True if int(pow) == pow OR self.base.is_positive try: pow = as_int(pow) ok = True except ValueError: ok = self.base.is_positive if ok: # issue 2081 return Pow(new, pow) # (x**(6*y)).subs(x**(3*y),z)->z**2 if old.func is C.exp and self.exp.is_real and self.base.is_positive: coeff1, terms1 = old.args[0].as_independent(C.Symbol, as_Add=False) # we can only do this when the base is positive AND the exponent # is real coeff2, terms2 = (self.exp*C.log(self.base)).as_independent( C.Symbol, as_Add=False) if terms1 == terms2: pow = coeff1/coeff2 if pow == int(pow) or self.base.is_positive: return Pow(new, pow) # (2**x).subs(exp(x*log(2)), z) -> z
def taylor_term(cls, n, x, *previous_terms): """General method for the taylor term. This method is slow, because it differentiates n-times. Subclasses can redefine it to make it faster by using the "previous_terms". """ x = sympify(x) return cls(x).diff(x, n).subs(x, 0) * x**n / C.factorial(n)
def as_real_imag(self, deep=True, **hints): from sympy.core.symbol import symbols from sympy.polys.polytools import poly from sympy.core.function import expand_multinomial if self.exp.is_Integer: exp = self.exp re, im = self.base.as_real_imag(deep=deep) if re.func == C.re or im.func == C.im: return self, S.Zero a, b = symbols('a b', cls=Dummy) if exp >= 0: if re.is_Number and im.is_Number: # We can be more efficient in this case expr = expand_multinomial(self.base**exp) return expr.as_real_imag() expr = poly((a + b)**exp) # a = re, b = im; expr = (a + b*I)**exp else: mag = re**2 + im**2 re, im = re/mag, -im/mag if re.is_Number and im.is_Number: # We can be more efficient in this case expr = expand_multinomial((re + im*S.ImaginaryUnit)**-exp) return expr.as_real_imag() expr = poly((a + b)**-exp) # Terms with even b powers will be real r = [i for i in expr.terms() if not i[0][1] % 2] re_part = Add(*[cc*a**aa*b**bb for (aa, bb), cc in r]) # Terms with odd b powers will be imaginary r = [i for i in expr.terms() if i[0][1] % 4 == 1] im_part1 = Add(*[cc*a**aa*b**bb for (aa, bb), cc in r]) r = [i for i in expr.terms() if i[0][1] % 4 == 3] im_part3 = Add(*[cc*a**aa*b**bb for (aa, bb), cc in r]) return (re_part.subs({a: re, b: S.ImaginaryUnit*im}), im_part1.subs({a: re, b: im}) + im_part3.subs({a: re, b: -im})) elif self.exp.is_Rational: # NOTE: This is not totally correct since for x**(p/q) with # x being imaginary there are actually q roots, but # only a single one is returned from here. re, im = self.base.as_real_imag(deep=deep) if re.func == C.re or im.func == C.im: return self, S.Zero r = Pow(Pow(re, 2) + Pow(im, 2), S.Half) t = C.atan2(im, re) rp, tp = Pow(r, self.exp), t*self.exp return (rp*C.cos(tp), rp*C.sin(tp)) else: if deep: hints['complex'] = False return (C.re(self.expand(deep, **hints)), C.im(self.expand(deep, **hints))) else: return (C.re(self), C.im(self))
def as_real_imag(self, deep=True): """Performs complex expansion on 'self' and returns a tuple containing collected both real and imaginary parts. This method can't be confused with re() and im() functions, which does not perform complex expansion at evaluation. However it is possible to expand both re() and im() functions and get exactly the same results as with a single call to this function. >>> from sympy import symbols, I >>> x, y = symbols('xy', real=True) >>> (x + y*I).as_real_imag() (x, y) >>> from sympy.abc import z, w >>> (z + w*I).as_real_imag() (-im(w) + re(z), im(z) + re(w)) """ return (C.re(self), C.im(self))
def _eval_subs(self, old, new): if old.func is self.func and self.base == old.base: coeff1, terms1 = self.exp.as_coeff_Mul() coeff2, terms2 = old.exp.as_coeff_Mul() if terms1 == terms2: pow = coeff1/coeff2 if pow == int(pow) or self.base.is_positive: # issue 2081 return Pow(new, pow) # (x**(6*y)).subs(x**(3*y),z)->z**2 if old.func is C.exp and self.exp.is_real and self.base.is_positive: coeff1, terms1 = old.args[0].as_coeff_Mul() # we can only do this when the base is positive AND the exponent # is real coeff2, terms2 = (self.exp*C.log(self.base)).as_coeff_Mul() if terms1 == terms2: pow = coeff1/coeff2 if pow == int(pow) or self.base.is_positive: return Pow(new, pow) # (2**x).subs(exp(x*log(2)), z) -> z
def _eval_subs(self, old, new): if self == old: return new if old.func is self.func and self.base == old.base: coeff1, terms1 = self.exp.as_coeff_mul() coeff2, terms2 = old.exp.as_coeff_mul() if terms1 == terms2: pow = coeff1/coeff2 if pow.is_Integer or self.base.is_commutative: return Pow(new, pow) # (x**(2*y)).subs(x**(3*y),z) -> z**(2/3) if old.func is C.exp: coeff1, terms1 = old.args[0].as_coeff_mul() coeff2, terms2 = (self.exp*C.log(self.base)).as_coeff_mul() if terms1 == terms2: pow = coeff1/coeff2 if pow.is_Integer or self.base.is_commutative: return Pow(new, pow) # (x**(2*y)).subs(x**(3*y),z) -> z**(2/3) return Pow(self.base._eval_subs(old, new), self.exp._eval_subs(old, new))
def _eval_subs(self, old, new): if self == old: return new if old.func is self.func and self.base == old.base: coeff1, terms1 = self.exp.as_coeff_mul() coeff2, terms2 = old.exp.as_coeff_mul() if terms1 == terms2: pow = coeff1/coeff2 if pow.is_Integer or self.base.is_commutative: return Pow(new, pow) # (x**(2*y)).subs(x**(3*y),z) -> z**(2/3) if old.func is C.exp: coeff1, terms1 = old.args[0].as_coeff_mul() coeff2, terms2 = (self.exp*C.log(self.base)).as_coeff_mul() if terms1 == terms2: pow = coeff1/coeff2 if pow.is_Integer or self.base.is_commutative: return Pow(new, pow) # (x**(2*y)).subs(x**(3*y),z) -> z**(2/3) b, e = self.base._eval_subs(old, new), self.exp._eval_subs(old, new) if not b and e.is_negative: # don't let subs create an infinity return S.NaN return Pow(b, e)
def _eval_derivative(self, s): dbase = self.base.diff(s) dexp = self.exp.diff(s) return self * (dexp * C.log(self.base) + dbase * self.exp/self.base)
def as_real_imag(self, deep=True, **hints): from sympy.core.symbol import symbols from sympy.polys.polytools import poly from sympy.core.function import expand_multinomial if self.exp.is_Integer: exp = self.exp re, im = self.base.as_real_imag(deep=deep) a, b = symbols('a b', cls=Dummy) if exp >= 0: if re.is_Number and im.is_Number: # We can be more efficient in this case expr = expand_multinomial(self.base**exp) return expr.as_real_imag() expr = poly( (a + b)**exp) # a = re, b = im; expr = (a + b*I)**exp else: mag = re**2 + im**2 re, im = re / mag, -im / mag if re.is_Number and im.is_Number: # We can be more efficient in this case expr = expand_multinomial( (re + im * S.ImaginaryUnit)**-exp) return expr.as_real_imag() expr = poly((a + b)**-exp) # Terms with even b powers will be real r = [i for i in expr.terms() if not i[0][1] % 2] re_part = Add(*[cc * a**aa * b**bb for (aa, bb), cc in r]) # Terms with odd b powers will be imaginary r = [i for i in expr.terms() if i[0][1] % 4 == 1] im_part1 = Add(*[cc * a**aa * b**bb for (aa, bb), cc in r]) r = [i for i in expr.terms() if i[0][1] % 4 == 3] im_part3 = Add(*[cc * a**aa * b**bb for (aa, bb), cc in r]) return (re_part.subs({ a: re, b: S.ImaginaryUnit * im }), im_part1.subs({ a: re, b: im }) + im_part3.subs({ a: re, b: -im })) elif self.exp.is_Rational: # NOTE: This is not totally correct since for x**(p/q) with # x being imaginary there are actually q roots, but # only a single one is returned from here. re, im = self.base.as_real_imag(deep=deep) r = Pow(Pow(re, 2) + Pow(im, 2), S.Half) t = C.atan2(im, re) rp, tp = Pow(r, self.exp), t * self.exp return (rp * C.cos(tp), rp * C.sin(tp)) else: if deep: hints['complex'] = False return (C.re(self.expand(deep, complex=False)), C.im(self.expand(deep, **hints))) else: return (C.re(self), C.im(self))
def _eval_expand_complex(self, deep=True, **hints): if deep: func = self.func(*[ a.expand(deep, **hints) for a in self.args ]) else: func = self.func(*self.args) return C.re(func) + S.ImaginaryUnit * C.im(func)
def _eval_power(self, exp): return C.exp(exp)
def as_real_imag(self, deep=True, **hints): if hints.get("ignore") == self: return None else: return (C.re(self), C.im(self))
def count_ops(self, symbolic=True): if symbolic: return Add(*[t.count_ops(symbolic) for t in self.args]) + C.Symbol('POW') return Add(*[t.count_ops(symbolic) for t in self.args]) + 1
def _eval_derivative(self, s): dbase = self.base.diff(s) dexp = self.exp.diff(s) return self * (dexp * C.log(self.base) + dbase * self.exp / self.base)
def __gt__(self, other): dif = self - other if dif.is_positive != dif.is_nonpositive: return dif.is_positive return C.StrictInequality(other, self)
def __ge__(self, other): dif = self - other if dif.is_nonnegative != dif.is_negative: return dif.is_nonnegative return C.Inequality(other, self)
def __abs__(self): return C.Abs(self)
def fdiff(self, *indices): # FIXME FApply -> ? return C.FApply(C.FDerivative(*indices), self)
def count_ops(expr, visual=False): """ Return a representation (integer or expression) of the operations in expr. If `visual` is False (default) then the sum of the coefficients of the visual expression will be returned. If `visual` is True then the number of each type of operation is shown with the core class types (or their virtual equivalent) multiplied by the number of times they occur. If expr is an iterable, the sum of the op counts of the items will be returned. Examples: >>> from sympy.abc import a, b, x, y >>> from sympy import sin, count_ops Although there isn't a SUB object, minus signs are interpreted as either negations or subtractions: >>> (x - y).count_ops(visual=True) SUB >>> (-x).count_ops(visual=True) NEG Here, there are two Adds and a Pow: >>> (1 + a + b**2).count_ops(visual=True) POW + 2*ADD In the following, an Add, Mul, Pow and two functions: >>> (sin(x)*x + sin(x)**2).count_ops(visual=True) ADD + MUL + POW + 2*SIN for a total of 5: >>> (sin(x)*x + sin(x)**2).count_ops(visual=False) 5 Note that "what you type" is not always what you get. The expression 1/x/y is translated by sympy into 1/(x*y) so it gives a DIV and MUL rather than two DIVs: >>> (1/x/y).count_ops(visual=True) DIV + MUL The visual option can be used to demonstrate the difference in operations for expressions in different forms. Here, the Horner representation is compared with the expanded form of a polynomial: >>> eq=x*(1 + x*(2 + x*(3 + x))) >>> count_ops(eq.expand(), visual=True) - count_ops(eq, visual=True) -MUL + 3*POW The count_ops function also handles iterables: >>> count_ops([x, sin(x), None, True, x + 2], visual=False) 2 >>> count_ops([x, sin(x), None, True, x + 2], visual=True) ADD + SIN >>> count_ops({x: sin(x), x + 2: y + 1}, visual=True) SIN + 2*ADD """ from sympy.simplify.simplify import fraction expr = sympify(expr) if isinstance(expr, Expr): ops = [] args = [expr] NEG = C.Symbol('NEG') DIV = C.Symbol('DIV') SUB = C.Symbol('SUB') ADD = C.Symbol('ADD') def isneg(a): c = a.as_coeff_mul()[0] return c.is_Number and c.is_negative while args: a = args.pop() if a.is_Rational: #-1/3 = NEG + DIV if a is not S.One: if a.p < 0: ops.append(NEG) if a.q != 1: ops.append(DIV) continue elif a.is_Mul: if isneg(a): ops.append(NEG) if a.args[0] is S.NegativeOne: a = a.as_two_terms()[1] else: a = -a n, d = fraction(a) if n.is_Integer: ops.append(DIV) if n < 0: ops.append(NEG) args.append(d) continue # won't be -Mul but could be Add elif d is not S.One: if not d.is_Integer: args.append(d) ops.append(DIV) args.append(n) continue # could be -Mul elif a.is_Add: aargs = list(a.args) negs = 0 for i, ai in enumerate(aargs): if isneg(ai): negs += 1 args.append(-ai) if i > 0: ops.append(SUB) else: args.append(ai) if i > 0: ops.append(ADD) if negs == len(aargs): # -x - y = NEG + SUB ops.append(NEG) elif isneg(aargs[0]): # -x + y = SUB, but we already recorded an ADD ops.append(SUB - ADD) continue if a.is_Pow and a.exp is S.NegativeOne: ops.append(DIV) args.append(a.base) # won't be -Mul but could be Add continue if (a.is_Mul or a.is_Pow or a.is_Function or isinstance(a, Derivative) or isinstance(a, C.Integral)): o = C.Symbol(a.func.__name__.upper()) # count the args if (a.is_Mul or isinstance(a, C.LatticeOp)): ops.append(o*(len(a.args) - 1)) else: ops.append(o) args.extend(a.args) elif type(expr) is dict: ops = [count_ops(k, visual=visual) + count_ops(v, visual=visual) for k, v in expr.iteritems()] elif hasattr(expr, '__iter__'): ops = [count_ops(i, visual=visual) for i in expr] elif not isinstance(expr, Basic): ops = [] else: # it's Basic not isinstance(expr, Expr): assert isinstance(expr, Basic) ops = [count_ops(a, visual=visual) for a in expr.args] if not ops: if visual: return S.Zero return 0 ops = Add(*ops) if visual: return ops if ops.is_Number: return int(ops) return sum(int((a.args or [1])[0]) for a in Add.make_args(ops))
def as_real_imag(self, deep=True, **hints): if hints.get('ignore') == self: return None else: return (C.re(self), C.im(self))
def taylor_term(self, n, x, *previous_terms): # of (1+x)**e if n < 0: return S.Zero x = _sympify(x) return C.Binomial(self.exp, n) * Pow(x, n)
def _eval_as_leading_term(self, x): if not self.exp.has(x): return Pow(self.base.as_leading_term(x), self.exp) return C.exp(self.exp * C.log(self.base)).as_leading_term(x)
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 = C.Wild("k"), C.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) if n.is_Integer: assert n.is_nonnegative 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
def taylor_term(self, n, x, *previous_terms): # of (1+x)**e if n < 0: return S.Zero x = _sympify(x) return C.binomial(self.exp, n) * Pow(x, n)
def series(self, x=None, x0=0, n=6, dir="+"): """ Series expansion of "self" around `x = x0` yielding either terms of the series one by one (the lazy series given when n=None), else all the terms at once when n != None. Note: when n != None, if an O() term is returned then the x in the in it and the entire expression reprsents x - x0, the displacement from x0. (If there is no O() term then the series was exact and x has it's normal meaning.) This is currently necessary since sympy's O() can only represent terms at x0=0. So instead of >> cos(x).series(x0=1, n=2) (1 - x)*sin(1) + cos(1) + O((x - 1)**2) which graphically looks like this: \ .|. . . . | \ . . ---+---------------------- | . . . . | \ x=0 the following is returned instead -x*sin(1) + cos(1) + O(x**2) whose graph is this \ | . .| . . . \ . . -----+\------------------. | . . . . | \ x=0 which is identical to cos(x + 1).series(n=2). Usage: Returns the series expansion of "self" around the point `x = x0` with respect to `x` up to O(x**n) (default n is 6). If `x=None` and `self` is univariate, the univariate symbol will be supplied, otherwise an error will be raised. >>> from sympy import cos, exp >>> from sympy.abc import x, y >>> cos(x).series() 1 - x**2/2 + x**4/24 + O(x**6) >>> cos(x).series(n=4) 1 - x**2/2 + O(x**4) >>> e = cos(x + exp(y)) >>> e.series(y, n=2) -y*sin(1 + x) + cos(1 + x) + O(y**2) >>> e.series(x, n=2) -x*sin(exp(y)) + cos(exp(y)) + O(x**2) If `n=None` then an iterator of the series terms will be returned. >>> term=cos(x).series(n=None) >>> [term.next() for i in range(2)] [1, -x**2/2] For `dir=+` (default) the series is calculated from the right and for `dir=-` the series from the left. For smooth functions this flag will not alter the results. >>> abs(x).series(dir="+") x >>> abs(x).series(dir="-") -x """ if x is None: syms = self.atoms(C.Symbol) if len(syms) > 1: raise ValueError('x must be given for multivariate functions.') x = syms.pop() if not self.has(x): if n is None: return (s for s in [self]) else: return self ## it seems like the following should be doable, but several failures ## then occur. Is this related to issue 1747 et al? See also XPOS below. #if x.is_positive is x.is_negative is None: # # replace x with an x that has a positive assumption # xpos = C.Dummy('x', positive=True) # rv = self.subs(x, xpos).series(xpos, x0, n, dir) # if n is None: # return (s.subs(xpos, x) for s in rv) # else: # return rv.subs(xpos, x) if len(dir) != 1 or dir not in '+-': raise ValueError("Dir must be '+' or '-'") if x0 in [S.Infinity, S.NegativeInfinity]: dir = {S.Infinity: '+', S.NegativeInfinity: '-'}[x0] s = self.subs(x, 1/x).series(x, n=n, dir=dir) if n is None: return (si.subs(x, 1/x) for si in s) # don't include the order term since it will eat the larger terms return s.removeO().subs(x, 1/x) # use rep to shift origin to x0 and change sign (if dir is negative) # and undo the process with rep2 if x0 or dir == '-': if dir == '-': rep = -x + x0 rep2 = -x rep2b = x0 else: rep = x + x0 rep2 = x rep2b = -x0 s = self.subs(x, rep).series(x, x0=0, n=n, dir='+') if n is None: # lseries... return (si.subs(x, rep2 + rep2b) for si in s) # nseries... o = s.getO() or S.Zero s = s.removeO() if o and x0: rep2b = 0 # when O() can handle x0 != 0 this can be removed return s.subs(x, rep2 + rep2b) + o # from here on it's x0=0 and dir='+' handling if n != None: # nseries handling s1 = self._eval_nseries(x, n=n) o = s1.getO() or S.Zero if o: # make sure the requested order is returned ngot = o.getn() if ngot > n: # leave o in its current form (e.g. with x*log(x)) so # it eats terms properly, then replace it below s1 += o.subs(x, x**C.Rational(n, ngot)) elif ngot < n: # increase the requested number of terms to get the desired # number keep increasing (up to 9) until the received order # is different than the original order and then predict how # many additional terms are needed for more in range(1, 9): s1 = self._eval_nseries(x, n=n + more) newn = s1.getn() if newn != ngot: ndo = n + (n - ngot)*more/(newn - ngot) s1 = self._eval_nseries(x, n=ndo) # if this assertion fails then our ndo calculation # needs modification assert s1.getn() == n break else: raise ValueError('Could not calculate %s terms for %s' % (str(n), self)) o = s1.getO() s1 = s1.removeO() else: o = C.Order(x**n) if (s1 + o).removeO() == s1: o = S.Zero return s1 + o else: # lseries handling def yield_lseries(s): """Return terms of lseries one at a time.""" for si in s: if not si.is_Add: yield si continue # yield terms 1 at a time if possible # by increasing order until all the # terms have been returned yielded = 0 o = C.Order(si)*x ndid = 0 ndo = len(si.args) while 1: do = (si - yielded + o).removeO() o *= x if not do or do.is_Order: continue if do.is_Add: ndid += len(do.args) else: ndid += 1 yield do if ndid == ndo: raise StopIteration yielded += do return yield_lseries(self.removeO()._eval_lseries(x))
def __lt__(self, other): dif = self - other if dif.is_negative != dif.is_nonnegative: return dif.is_negative return C.StrictInequality(self, other)
def _create_evalf_table(): global evalf_table evalf_table = { C.Symbol: evalf_symbol, C.Dummy: evalf_symbol, C.Float: lambda x, prec, options: (x._mpf_, None, prec, None), C.Rational: lambda x, prec, options: (from_rational(x.p, x.q, prec), None, prec, None), C.Integer: lambda x, prec, options: (from_int(x.p, prec), None, prec, None), C.Zero: lambda x, prec, options: (None, None, prec, None), C.One: lambda x, prec, options: (fone, None, prec, None), C.Half: lambda x, prec, options: (fhalf, None, prec, None), C.Pi: lambda x, prec, options: (mpf_pi(prec), None, prec, None), C.Exp1: lambda x, prec, options: (mpf_e(prec), None, prec, None), C.ImaginaryUnit: lambda x, prec, options: (None, fone, None, prec), C.NegativeOne: lambda x, prec, options: (fnone, None, prec, None), C.exp: lambda x, prec, options: evalf_pow( C.Pow(S.Exp1, x.args[0], evaluate=False), prec, options), C.cos: evalf_trig, C.sin: evalf_trig, C.Add: evalf_add, C.Mul: evalf_mul, C.Pow: evalf_pow, C.log: evalf_log, C.atan: evalf_atan, C.Abs: evalf_abs, C.re: evalf_re, C.im: evalf_im, C.floor: evalf_floor, C.ceiling: evalf_ceiling, C.Integral: evalf_integral, C.Sum: evalf_sum, C.Piecewise: evalf_piecewise, C.bernoulli: evalf_bernoulli, }
def as_real_imag(self, deep=True): return (C.re(self), C.im(self))
def do_integral(expr, prec, options): func = expr.args[0] x, xlow, xhigh = expr.args[1] orig = mp.prec oldmaxprec = options.get('maxprec', DEFAULT_MAXPREC) options['maxprec'] = min(oldmaxprec, 2 * prec) try: mp.prec = prec + 5 xlow = as_mpmath(xlow, prec + 15, options) xhigh = as_mpmath(xhigh, prec + 15, options) # Integration is like summation, and we can phone home from # the integrand function to update accuracy summation style # Note that this accuracy is inaccurate, since it fails # to account for the variable quadrature weights, # but it is better than nothing have_part = [False, False] max_real_term = [MINUS_INF] max_imag_term = [MINUS_INF] def f(t): re, im, re_acc, im_acc = evalf(func, mp.prec, {'subs': {x: t}}) have_part[0] = re or have_part[0] have_part[1] = im or have_part[1] max_real_term[0] = max(max_real_term[0], fastlog(re)) max_imag_term[0] = max(max_imag_term[0], fastlog(im)) if im: return mpc(re or fzero, im) return mpf(re or fzero) if options.get('quad') == 'osc': A = C.Wild('A', exclude=[x]) B = C.Wild('B', exclude=[x]) D = C.Wild('D') m = func.match(C.cos(A * x + B) * D) if not m: m = func.match(C.sin(A * x + B) * D) if not m: raise ValueError( "An integrand of the form sin(A*x+B)*f(x) " "or cos(A*x+B)*f(x) is required for oscillatory quadrature" ) period = as_mpmath(2 * S.Pi / m[A], prec + 15, options) result = quadosc(f, [xlow, xhigh], period=period) # XXX: quadosc does not do error detection yet quadrature_error = MINUS_INF else: result, quadrature_error = quadts(f, [xlow, xhigh], error=1) quadrature_error = fastlog(quadrature_error._mpf_) finally: options['maxprec'] = oldmaxprec mp.prec = orig if have_part[0]: re = result.real._mpf_ if re == fzero: re, re_acc = scaled_zero( min(-prec, -max_real_term[0], -quadrature_error)) re = scaled_zero(re) # handled ok in evalf_integral else: re_acc = -max(max_real_term[0] - fastlog(re) - prec, quadrature_error) else: re, re_acc = None, None if have_part[1]: im = result.imag._mpf_ if im == fzero: im, im_acc = scaled_zero( min(-prec, -max_imag_term[0], -quadrature_error)) im = scaled_zero(im) # handled ok in evalf_integral else: im_acc = -max(max_imag_term[0] - fastlog(im) - prec, quadrature_error) else: im, im_acc = None, None result = re, im, re_acc, im_acc return result
def do_integral(expr, prec, options): func = expr.args[0] x, xlow, xhigh = expr.args[1] orig = mp.prec oldmaxprec = options.get("maxprec", DEFAULT_MAXPREC) options["maxprec"] = min(oldmaxprec, 2 * prec) try: mp.prec = prec + 5 xlow = as_mpmath(xlow, prec + 15, options) xhigh = as_mpmath(xhigh, prec + 15, options) # Integration is like summation, and we can phone home from # the integrand function to update accuracy summation style # Note that this accuracy is inaccurate, since it fails # to account for the variable quadrature weights, # but it is better than nothing have_part = [False, False] max_real_term = [MINUS_INF] max_imag_term = [MINUS_INF] def f(t): re, im, re_acc, im_acc = evalf(func, mp.prec, {"subs": {x: t}}) have_part[0] = re or have_part[0] have_part[1] = im or have_part[1] max_real_term[0] = max(max_real_term[0], fastlog(re)) max_imag_term[0] = max(max_imag_term[0], fastlog(im)) if im: return mpc(re or fzero, im) return mpf(re or fzero) if options.get("quad") == "osc": A = C.Wild("A", exclude=[x]) B = C.Wild("B", exclude=[x]) D = C.Wild("D") m = func.match(C.cos(A * x + B) * D) if not m: m = func.match(C.sin(A * x + B) * D) if not m: raise ValueError( "An integrand of the form sin(A*x+B)*f(x) " "or cos(A*x+B)*f(x) is required for oscillatory quadrature" ) period = as_mpmath(2 * S.Pi / m[A], prec + 15, options) result = quadosc(f, [xlow, xhigh], period=period) # XXX: quadosc does not do error detection yet quadrature_error = MINUS_INF else: result, quadrature_error = quadts(f, [xlow, xhigh], error=1) quadrature_error = fastlog(quadrature_error._mpf_) finally: options["maxprec"] = oldmaxprec mp.prec = orig if have_part[0]: re = result.real._mpf_ if re == fzero: re, re_acc = scaled_zero(min(-prec, -max_real_term[0], -quadrature_error)) re = scaled_zero(re) # handled ok in evalf_integral else: re_acc = -max(max_real_term[0] - fastlog(re) - prec, quadrature_error) else: re, re_acc = None, None if have_part[1]: im = result.imag._mpf_ if im == fzero: im, im_acc = scaled_zero(min(-prec, -max_imag_term[0], -quadrature_error)) im = scaled_zero(im) # handled ok in evalf_integral else: im_acc = -max(max_imag_term[0] - fastlog(im) - prec, quadrature_error) else: im, im_acc = None, None result = re, im, re_acc, im_acc return result
def __le__(self, other): dif = self - other if dif.is_nonpositive != dif.is_positive: return dif.is_nonpositive return C.Inequality(self, other)