Beispiel #1
0
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
Beispiel #2
0
 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
Beispiel #3
0
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
Beispiel #4
0
 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
Beispiel #5
0
    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)
Beispiel #6
0
    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))
Beispiel #7
0
    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))
Beispiel #8
0
 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
Beispiel #9
0
 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))
Beispiel #10
0
 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)
Beispiel #11
0
 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)
Beispiel #12
0
    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))
Beispiel #13
0
 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)
Beispiel #14
0
 def _eval_power(self, exp):
     return C.exp(exp)
Beispiel #15
0
 def as_real_imag(self, deep=True, **hints):
     if hints.get("ignore") == self:
         return None
     else:
         return (C.re(self), C.im(self))
Beispiel #16
0
 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
Beispiel #17
0
 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)
Beispiel #18
0
 def __gt__(self, other):
     dif = self - other
     if dif.is_positive !=  dif.is_nonpositive:
         return dif.is_positive
     return C.StrictInequality(other, self)
Beispiel #19
0
 def __ge__(self, other):
     dif = self - other
     if dif.is_nonnegative != dif.is_negative:
         return dif.is_nonnegative
     return C.Inequality(other, self)
Beispiel #20
0
 def __abs__(self):
     return C.Abs(self)
Beispiel #21
0
 def fdiff(self, *indices):
     # FIXME FApply -> ?
     return C.FApply(C.FDerivative(*indices), self)
Beispiel #22
0
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))
Beispiel #23
0
 def as_real_imag(self, deep=True, **hints):
     if hints.get('ignore') == self:
         return None
     else:
         return (C.re(self), C.im(self))
Beispiel #24
0
 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)
Beispiel #25
0
 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)
Beispiel #26
0
    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
Beispiel #27
0
 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)
Beispiel #28
0
    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))
Beispiel #29
0
 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)
Beispiel #30
0
 def __lt__(self, other):
     dif = self - other
     if dif.is_negative != dif.is_nonnegative:
         return dif.is_negative
     return C.StrictInequality(self, other)
Beispiel #31
0
 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)
Beispiel #32
0
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,
    }
Beispiel #33
0
 def as_real_imag(self, deep=True):
     return (C.re(self), C.im(self))
Beispiel #34
0
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
Beispiel #35
0
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
Beispiel #36
0
 def __le__(self, other):
     dif = self - other
     if dif.is_nonpositive != dif.is_positive:
         return dif.is_nonpositive
     return C.Inequality(self, other)