Example #1
0
def test_apart():
    assert apart(1 / (x + 2) / (x + 1), x) == 1 / (1 + x) - 1 / (2 + x)
    assert apart(1 / (x + 1) / (x + 5), x) == -1 / (5 + x) / 4 + 1 / (1 + x) / 4

    f = apart(1 / (x - y) / (x - z), x)

    assert f.subs({y: 1, z: 2}) == apart(1 / (x - 1) / (x - 2), x)

    assert apart((E * x + 2) / (x - pi) * (x - 1), x) in [
        2 - E + E * pi + E * x - 1 / (x - pi) * (2 - 2 * pi + E * pi - E * pi ** 2),
        2 - E + E * pi + E * x + 1 / (x - pi) * (-2 + 2 * pi - E * pi + E * pi ** 2),
    ]

    M = Matrix(2, 2, lambda i, j: 1 / (x - (i + 1)) / (x - (1 - j)))

    assert apart(M, x) in [
        Matrix([[(x - 1) ** (-2), -1 / x - 1 / (1 - x)], [1 / (1 - x) - 1 / (2 - x), -S.Half / x - S.Half / (2 - x)]]),
        Matrix(
            [[(-1 + x) ** (-2), -1 / x + 1 / (-1 + x)], [-1 / (-1 + x) + 1 / (-2 + x), -S.Half / x + S.Half / (-2 + x)]]
        ),
    ]

    assert apart(Eq((x ** 2 + 1) / (x + 1), sin(x)), x) == Eq(x - 1 + 2 / (x + 1), sin(x))

    assert str(apart(1 / (1 + x ** 5), x, evaluate=False)) in [
        "RootSum(Lambda(_a, -1/5/(x - _a)*_a), x**5 + 1, x)",
        "RootSum(Lambda(_a, -_a/(5*(x - _a))), x**5 + 1, x)",
    ]
Example #2
0
def test_apart():
    raises(ValueError, "apart(1/(x+1)/(y+2))")

    assert apart(1) == 1
    assert apart(1, x) == 1

    assert apart(1 / (x + 2) / (x + 1)) == 1 / (1 + x) - 1 / (2 + x)
    assert apart(1 / (x + 1) / (x + 5)) == -1 / (5 + x) / 4 + 1 / (1 + x) / 4

    f = apart(1 / (x - y) / (x - z), x)

    assert f.subs({y: 1, z: 2}) == apart(1 / (x - 1) / (x - 2), x)

    assert apart((E * x + 2) / (x - pi) * (x - 1), x) in [
        2 - E + E * pi + E * x - 1 / (x - pi) *
        (2 - 2 * pi + E * pi - E * pi**2),
        2 - E + E * pi + E * x + 1 / (x - pi) *
        (-2 + 2 * pi - E * pi + E * pi**2),
    ]

    M = Matrix(2, 2, lambda i, j: 1 / (x - (i + 1)) / (x - (1 - j)))

    assert apart(M, x) in [
        Matrix([
            [(x - 1)**(-2), -1 / x - 1 / (1 - x)],
            [1 / (1 - x) - 1 / (2 - x), -S.Half / x - S.Half / (2 - x)],
        ]),
        Matrix([
            [(-1 + x)**(-2), -1 / x + 1 / (-1 + x)],
            [-1 / (-1 + x) + 1 / (-2 + x), -S.Half / x + S.Half / (-2 + x)],
        ]),
    ]

    assert apart(Eq((x**2+1)/(x+1), sin(x)), x) == \
        Eq(x - 1 + 2/(x+1), sin(x))

    assert str(apart(1 / (1 + x**5), x, evaluate=False)) in [
        "RootSum(Lambda(_a, -1/5/(x - _a)*_a), x**5 + 1, x, domain='ZZ')",
        "RootSum(Lambda(_a, -_a/(5*(x - _a))), x**5 + 1, x, domain='ZZ')"
    ]
Example #3
0
 def apart(self, z=None, **args):
     """See the apart function in sympy.simplify"""
     from sympy.simplify import apart
     return apart(self, z=None, **args)
Example #4
0
 def apart(self, z=None, **args):
     """See the apart function in sympy.simplify"""
     from sympy.simplify import apart
     return apart(self, z=None, **args)
Example #5
0
    def _eval_integral(self, f, x):
        """Calculate the antiderivative to the function f(x).

        This is a powerful function that should in theory be able to integrate
        everything that can be integrated. If you find something, that it
        doesn't, it is easy to implement it.

        (1) Simple heuristics (based on pattern matching and integral table):

         - most frequently used functions (eg. polynomials)
         - functions non-integrable by any of the following algorithms (eg.
           exp(-x**2))

        (2) Integration of rational functions:

         (a) using apart() - apart() is full partial fraction decomposition
         procedure based on Bronstein-Salvy algorithm. It gives formal
         decomposition with no polynomial factorization at all (so it's fast
         and gives the most general results). However it needs much better
         implementation of RootsOf class (if fact any implementation).
         (b) using Trager's algorithm - possibly faster than (a) but needs
         implementation :)

        (3) Whichever implementation of pmInt (Mateusz, Kirill's or a
        combination of both).

          - this way we can handle efficiently huge class of elementary and
            special functions

        (4) Recursive Risch algorithm as described in Bronstein's integration
        tutorial.

          - this way we can handle those integrable functions for which (3)
            fails

        (5) Powerful heuristics based mostly on user defined rules.

         - handle complicated, rarely used cases
        """

        # if it is a poly(x) then let the polynomial integrate itself (fast)
        #
        # It is important to make this check first, otherwise the other code
        # will return a sympy expression instead of a Polynomial.
        #
        # see Polynomial for details.
        if isinstance(f, Poly):
            return f.integrate(x)

        # Piecewise antiderivatives need to call special integrate.
        if isinstance(f,Piecewise):
            return f._eval_integral(x)

        # let's cut it short if `f` does not depend on `x`
        if not f.has(x):
            return f*x

        # try to convert to poly(x) and then integrate if successful (fast)
        poly = f.as_poly(x)

        if poly is not None:
            return poly.integrate(x).as_basic()

        # since Integral(f=g1+g2+...) == Integral(g1) + Integral(g2) + ...
        # we are going to handle Add terms separately,
        # if `f` is not Add -- we only have one term
        if not f.is_Add:
            f = [f]

        parts = []

        if isinstance(f, Basic):
            f = f.args
        for g in f:
            coeff, g = g.as_independent(x)

            # g(x) = const
            if g is S.One:
                parts.append(coeff * x)
                continue

            #               c
            # g(x) = (a*x+b)
            if g.is_Pow and not g.exp.has(x):
                a = Wild('a', exclude=[x])
                b = Wild('b', exclude=[x])

                M = g.base.match(a*x + b)

                if M is not None:
                    if g.exp == -1:
                        h = C.log(g.base)
                    else:
                        h = g.base**(g.exp+1) / (g.exp+1)

                    parts.append(coeff * h / M[a])
                    continue

            #        poly(x)
            # g(x) = -------
            #        poly(x)
            if g.is_fraction(x):
                h = self._eval_integral(apart(g, x), x)
                parts.append(coeff * h)
                continue

            # g(x) = Mul(trig)
            h = trigintegrate(g, x)
            if h is not None:
                parts.append(coeff * h)
                continue

            # g(x) has at least a DiracDelta term
            h = deltaintegrate(g,x)
            if h is not None:
                parts.append(coeff * h)
                continue

            # fall back to the more general algorithm
            h = heurisch(g, x, hints=[])

            if h is not None:
                parts.append(coeff * h)
            else:
                return None

        return C.Add(*parts)
Example #6
0
    def _eval_integral(self, f, x):
        """Calculate the antiderivative to the function f(x).

        This is a powerful function that should in theory be able to integrate
        everything that can be integrated. If you find something, that it
        doesn't, it is easy to implement it.

        (1) Simple heuristics (based on pattern matching and integral table):

         - most frequently used functions (eg. polynomials)
         - functions non-integrable by any of the following algorithms (eg.
           exp(-x**2))

        (2) Integration of rational functions:

         (a) using apart() - apart() is full partial fraction decomposition
         procedure based on Bronstein-Salvy algorithm. It gives formal
         decomposition with no polynomial factorization at all (so it's fast
         and gives the most general results). However it needs much better
         implementation of RootsOf class (if fact any implementation).
         (b) using Trager's algorithm - possibly faster than (a) but needs
         implementation :)

        (3) Whichever implementation of pmInt (Mateusz, Kirill's or a
        combination of both).

          - this way we can handle efficiently huge class of elementary and
            special functions

        (4) Recursive Risch algorithm as described in Bronstein's integration
        tutorial.

          - this way we can handle those integrable functions for which (3)
            fails

        (5) Powerful heuristics based mostly on user defined rules.

         - handle complicated, rarely used cases
        """

        # if it is a poly(x) then let the polynomial integrate itself (fast)
        #
        # It is important to make this check first, otherwise the other code
        # will return a sympy expression instead of a Polynomial.
        #
        # see Polynomial for details.
        if isinstance(f, Poly):
            return f.integrate(x)

        # Piecewise antiderivatives need to call special integrate.
        if isinstance(f, Piecewise):
            return f._eval_integral(x)

        # let's cut it short if `f` does not depend on `x`
        if not f.has(x):
            return f * x

        # try to convert to poly(x) and then integrate if successful (fast)
        poly = f.as_poly(x)

        if poly is not None:
            return poly.integrate(x).as_basic()

        # since Integral(f=g1+g2+...) == Integral(g1) + Integral(g2) + ...
        # we are going to handle Add terms separately,
        # if `f` is not Add -- we only have one term
        if not f.is_Add:
            f = [f]

        parts = []

        if isinstance(f, Basic):
            f = f.args
        for g in f:
            coeff, g = g.as_independent(x)

            # g(x) = const
            if g is S.One:
                parts.append(coeff * x)
                continue

            #               c
            # g(x) = (a*x+b)
            if g.is_Pow and not g.exp.has(x):
                a = Wild('a', exclude=[x])
                b = Wild('b', exclude=[x])

                M = g.base.match(a * x + b)

                if M is not None:
                    if g.exp == -1:
                        h = C.log(g.base)
                    else:
                        h = g.base**(g.exp + 1) / (g.exp + 1)

                    parts.append(coeff * h / M[a])
                    continue

            #        poly(x)
            # g(x) = -------
            #        poly(x)
            if g.is_fraction(x):
                h = self._eval_integral(apart(g, x), x)
                parts.append(coeff * h)
                continue

            # g(x) = Mul(trig)
            h = trigintegrate(g, x)
            if h is not None:
                parts.append(coeff * h)
                continue

            # g(x) has at least a DiracDelta term
            h = deltaintegrate(g, x)
            if h is not None:
                parts.append(coeff * h)
                continue

            # fall back to the more general algorithm
            h = heurisch(g, x, hints=[])

            if h is not None:
                parts.append(coeff * h)
            else:
                return None

        return C.Add(*parts)