예제 #1
0
def prde_no_cancel_b_large(b, Q, n, DE):
    """
    Parametric Poly Risch Differential Equation - No cancellation: deg(b) large enough.

    Given a derivation D on k[t], n in ZZ, and b, q1, ..., qm in k[t] with
    b != 0 and either D == d/dt or deg(b) > max(0, deg(D) - 1), returns
    h1, ..., hr in k[r] and a matrix A with coefficients in Const(k) such that
    if c1, ..., cm in Const(k) and q in k[t] satisfy deg(q) <= n and
    Dq + b*Q == Sum(ci*qi, (i, 1, m)), then q = Sum(dj*hj, (j, 1, r)), where
    d1, ..., dr in Const(k) and A*Matrix([[c1, ..., cm, d1, ..., dr]]).T == 0.
    """
    db = b.degree(DE.t)
    m = len(Q)
    H = [Poly(0, DE.t)]*m

    for N in range(n, -1, -1):  # [n, ..., 0]
        for i in range(m):
            si = Q[i].nth(N + db)/b.LC()
            sitn = Poly(si*DE.t**N, DE.t)
            H[i] = H[i] + sitn
            Q[i] = Q[i] - derivation(sitn, DE) - b*sitn

    if all(qi.is_zero for qi in Q):
        dc = -1
        M = zeros(0, 2)
    else:
        dc = max([qi.degree(t) for qi in Q])
        M = Matrix(dc + 1, m, lambda i, j: Q[j].nth(i))
    A, u = constant_system(M, zeros(dc + 1, 1), DE)
    c = eye(m)
    A = A.row_join(zeros(A.rows, m)).col_join(c.row_join(-c))

    return H, A
예제 #2
0
def limited_integrate(fa, fd, G, DE):
    """
    Solves the limited integration problem:  f = Dv + Sum(ci*wi, (i, 1, n))
    """
    fa, fd = fa*Poly(1/fd.LC(), DE.t), fd.monic()
    A, B, h, N, g, V = limited_integrate_reduce(fa, fd, G, DE)
    V = [g] + V
    g = A.gcd(B)
    A, B, V = A.quo(g), B.quo(g), [via.cancel(vid*g, include=True) for
        via, vid in V]
    Q, M = prde_linear_constraints(A, B, V, DE)
    M, _ = constant_system(M, zeros(M.rows, 1), DE)
    l = M.nullspace()
    if M == Matrix() or len(l) > 1:
        # Continue with param_rischDE()
        raise NotImplementedError("param_rischDE() is required to solve this "
            "integral.")
    elif len(l) == 0:
        raise NonElementaryIntegralException
    elif len(l) == 1:
        # The c1 == 1.  In this case, we can assume a normal Risch DE
        if l[0][0].is_zero:
            raise NonElementaryIntegralException
        else:
            l[0] *= 1/l[0][0]
            C = sum(Poly(i, DE.t)*q for (i, q) in zip(l[0], Q))
            # Custom version of rischDE() that uses the already computed
            # denominator and degree bound from above.
            B, C, m, alpha, beta = spde(A, B, C, N, DE)
            y = solve_poly_rde(B, C, m, DE)

            return (alpha*y + beta, h), list(l[0][1:])
    else:
        raise NotImplementedError
예제 #3
0
def no_cancel_b_large(b, c, n, DE):
    """
    Poly Risch Differential Equation - No cancellation: deg(b) large enough.

    Given a derivation D on k[t], n either an integer or +oo, and b, c
    in k[t] with b != 0 and either D == d/dt or
    deg(b) > max(0, deg(D) - 1), either raise NonElementaryIntegralException, in
    which case the equation Dq + b*q == c has no solution of degree at
    most n in k[t], or a solution q in k[t] of this equation with
    deg(q) < n.
    """
    q = Poly(0, DE.t)

    while not c.is_zero:
        m = c.degree(DE.t) - b.degree(DE.t)
        if not 0 <= m <= n:  # n < 0 or m < 0 or m > n
            raise NonElementaryIntegralException

        p = Poly(c.as_poly(DE.t).LC() / b.as_poly(DE.t).LC() * DE.t**m,
                 DE.t,
                 expand=False)
        q = q + p
        n = m - 1
        c = c - derivation(p, DE) - b * p

    return q
예제 #4
0
def _sqrt_symbolic_denest(a, b, r):
    """Given an expression, sqrt(a + b*sqrt(b)), return the denested
    expression or None.

    Algorithm:
    If r = ra + rb*sqrt(rr), try replacing sqrt(rr) in ``a`` with
    (y**2 - ra)/rb, and if the result is a quadratic, ca*y**2 + cb*y + cc, and
    (cb + b)**2 - 4*ca*cc is 0, then sqrt(a + b*sqrt(r)) can be rewritten as
    sqrt(ca*(sqrt(r) + (cb + b)/(2*ca))**2).

    Examples
    ========

    >>> from diofant.simplify.sqrtdenest import _sqrt_symbolic_denest, sqrtdenest
    >>> from diofant import sqrt, Symbol
    >>> from diofant.abc import x

    >>> a, b, r = 16 - 2*sqrt(29), 2, -10*sqrt(29) + 55
    >>> _sqrt_symbolic_denest(a, b, r)
    sqrt(-2*sqrt(29) + 11) + sqrt(5)

    If the expression is numeric, it will be simplified:

    >>> w = sqrt(sqrt(sqrt(3) + 1) + 1) + 1 + sqrt(2)
    >>> sqrtdenest(sqrt((w**2).expand()))
    1 + sqrt(2) + sqrt(1 + sqrt(1 + sqrt(3)))

    Otherwise, it will only be simplified if assumptions allow:

    >>> w = w.subs(sqrt(3), sqrt(x + 3))
    >>> sqrtdenest(sqrt((w**2).expand()))
    sqrt((sqrt(sqrt(sqrt(x + 3) + 1) + 1) + 1 + sqrt(2))**2)

    Notice that the argument of the sqrt is a square. If x is made positive
    then the sqrt of the square is resolved:

    >>> _.subs(x, Symbol('x', positive=True))
    sqrt(sqrt(sqrt(x + 3) + 1) + 1) + 1 + sqrt(2)
    """

    a, b, r = map(sympify, (a, b, r))
    rval = _sqrt_match(r)
    if not rval:
        return
    ra, rb, rr = rval
    if rb:
        y = Dummy('y', positive=True)
        try:
            newa = Poly(a.subs(sqrt(rr), (y**2 - ra) / rb), y)
        except PolynomialError:
            return
        if newa.degree() == 2:
            ca, cb, cc = newa.all_coeffs()
            cb += b
            if _mexpand(cb**2 - 4 * ca * cc).equals(0):
                z = sqrt(ca * (sqrt(r) + cb / (2 * ca))**2)
                if z.is_number:
                    z = _mexpand(Mul._from_args(z.as_content_primitive()))
                return z
예제 #5
0
def test_sympyissue_8438():
    p = Poly([1, y, -2, -3], x).as_expr()
    roots = roots_cubic(Poly(p, x), x)
    z = -Rational(3, 2) - 7*I/2  # this will fail in code given in commit msg
    post = [r.subs({y: z}) for r in roots]
    assert set(post) == set(roots_cubic(Poly(p.subs({y: z}), x)))
    # /!\ if p is not made an expression, this is *very* slow
    assert all(p.subs({y: z, x: i}).evalf(2, chop=True) == 0 for i in post)
예제 #6
0
def cancel_exp(b, c, n, DE):
    """
    Poly Risch Differential Equation - Cancellation: Hyperexponential case.

    Given a derivation D on k[t], n either an integer or +oo, b in k, and
    c in k[t] with Dt/t in k and b != 0, either raise
    NonElementaryIntegralException, in which case the equation Dq + b*q == c
    has no solution of degree at most n in k[t], or a solution q in k[t] of
    this equation with deg(q) <= n.
    """
    from diofant.integrals.prde import parametric_log_deriv

    eta = DE.d.quo(Poly(DE.t, DE.t)).as_expr()

    with DecrementLevel(DE):
        etaa, etad = frac_in(eta, DE.t)
        ba, bd = frac_in(b, DE.t)
        A = parametric_log_deriv(ba, bd, etaa, etad, DE)
        if A is not None:
            a, m, z = A
            if a == 1:
                raise NotImplementedError("is_deriv_in_field() is required to "
                                          "solve this problem.")
                # if c*z*t**m == Dp for p in k<t> and q = p/(z*t**m) in k[t] and
                # deg(q) <= n:
                #     return q
                # else:
                #     raise NonElementaryIntegralException

    if c.is_zero:
        return c  # return 0

    if n < c.degree(DE.t):
        raise NonElementaryIntegralException

    q = Poly(0, DE.t)
    while not c.is_zero:
        m = c.degree(DE.t)
        if n < m:
            raise NonElementaryIntegralException
        # a1 = b + m*Dt/t
        a1 = b.as_expr()
        with DecrementLevel(DE):
            # TODO: Write a dummy function that does this idiom
            a1a, a1d = frac_in(a1, DE.t)
            a1a = a1a * etad + etaa * a1d * Poly(m, DE.t)
            a1d = a1d * etad

            a2a, a2d = frac_in(c.LC(), DE.t)

            sa, sd = rischDE(a1a, a1d, a2a, a2d, DE)
        stm = Poly(sa.as_expr() / sd.as_expr() * DE.t**m, DE.t, expand=False)
        q += stm
        n = m - 1
        c -= b * stm + derivation(stm, DE)  # deg(c) becomes smaller
    return q
예제 #7
0
def test_sympyissue_8289():
    roots = (Poly(x**2 + 2) * Poly(x**4 + 2)).all_roots()
    assert roots == _nsort(roots)
    roots = Poly(x**6 + 3 * x**3 + 2, x).all_roots()
    assert roots == _nsort(roots)
    roots = Poly(x**6 - x + 1).all_roots()
    assert roots == _nsort(roots)
    # all imaginary roots
    roots = Poly(x**4 + 4 * x**2 + 4, x).all_roots()
    assert roots == _nsort(roots)
예제 #8
0
def test_roots_quartic():
    assert roots_quartic(Poly(x**4, x)) == [0, 0, 0, 0]
    assert roots_quartic(Poly(x**4 + x**3, x)) in [
        [-1, 0, 0, 0],
        [0, -1, 0, 0],
        [0, 0, -1, 0],
        [0, 0, 0, -1]
    ]
    assert roots_quartic(Poly(x**4 - x**3, x)) in [
        [1, 0, 0, 0],
        [0, 1, 0, 0],
        [0, 0, 1, 0],
        [0, 0, 0, 1]
    ]

    lhs = roots_quartic(Poly(x**4 + x, x))
    rhs = [Rational(1, 2) + I*sqrt(3)/2, Rational(1, 2) - I*sqrt(3)/2, 0, -1]

    assert sorted(lhs, key=hash) == sorted(rhs, key=hash)

    # test of all branches of roots quartic
    for i, (a, b, c, d) in enumerate([(1, 2, 3, 0),
                                      (3, -7, -9, 9),
                                      (1, 2, 3, 4),
                                      (1, 2, 3, 4),
                                      (-7, -3, 3, -6),
                                      (-3, 5, -6, -4),
                                      (6, -5, -10, -3)]):
        if i == 2:
            c = -a*(a**2/Integer(8) - b/Integer(2))
        elif i == 3:
            d = a*(a*(3*a**2/Integer(256) - b/Integer(16)) + c/Integer(4))
        eq = x**4 + a*x**3 + b*x**2 + c*x + d
        ans = roots_quartic(Poly(eq, x))
        assert all(eq.subs({x: ai}).evalf(chop=True) == 0 for ai in ans)

    # not all symbolic quartics are unresolvable
    eq = Poly(q*x + q/4 + x**4 + x**3 + 2*x**2 - Rational(1, 3), x)
    sol = roots_quartic(eq)
    assert all(verify_numerically(eq.subs({x: i}), 0) for i in sol)
    z = symbols('z', negative=True)
    eq = x**4 + 2*x**3 + 3*x**2 + x*(z + 11) + 5
    zans = roots_quartic(Poly(eq, x))
    assert all(verify_numerically(eq.subs({x: i, z: -1}), 0) for i in zans)
    # but some are (see also issue sympy/sympy#4989)
    # it's ok if the solution is not Piecewise, but the tests below should pass
    eq = Poly(y*x**4 + x**3 - x + z, x)
    ans = roots_quartic(eq)
    assert all(type(i) == Piecewise for i in ans)
    reps = ({y: -Rational(1, 3), z: -Rational(1, 4)},  # 4 real
            {y: -Rational(1, 3), z: -Rational(1, 2)},  # 2 real
            {y: -Rational(1, 3), z: -2})  # 0 real
    for rep in reps:
        sol = roots_quartic(Poly(eq.subs(rep), x))
        assert all(verify_numerically(w.subs(rep) - s, 0) for w, s in zip(ans, sol))
예제 #9
0
def test_roots_binomial():
    assert roots_binomial(Poly(5 * x, x)) == [0]
    assert roots_binomial(Poly(5 * x**4, x)) == [0, 0, 0, 0]
    assert roots_binomial(Poly(5 * x + 2, x)) == [-Rational(2, 5)]

    A = 10**Rational(3, 4) / 10

    assert roots_binomial(Poly(5*x**4 + 2, x)) == \
        [-A - A*I, -A + A*I, A - A*I, A + A*I]

    a1 = Symbol('a1', nonnegative=True)
    b1 = Symbol('b1', nonnegative=True)

    r0 = roots_quadratic(Poly(a1 * x**2 + b1, x))
    r1 = roots_binomial(Poly(a1 * x**2 + b1, x))

    assert powsimp(r0[0]) == powsimp(r1[0])
    assert powsimp(r0[1]) == powsimp(r1[1])
    for a, b, s, n in itertools.product((1, 2), (1, 2), (-1, 1), (2, 3, 4, 5)):
        if a == b and a != 1:  # a == b == 1 is sufficient
            continue
        p = Poly(a * x**n + s * b)
        ans = roots_binomial(p)
        assert ans == _nsort(ans)

    # issue sympy/sympy#8813
    assert roots(Poly(2 * x**3 - 16 * y**3, x)) == {
        2 * y * (-Rational(1, 2) - sqrt(3) * I / 2): 1,
        2 * y: 1,
        2 * y * (-Rational(1, 2) + sqrt(3) * I / 2): 1
    }
예제 #10
0
def test_nroots2():
    p = Poly(x**5 + 3 * x + 1, x)

    roots = p.nroots(n=3)
    # The order of roots matters. The roots are ordered by their real
    # components (if they agree, then by their imaginary components),
    # with real roots appearing first.
    assert [str(r) for r in roots] == \
        ['-0.332', '-0.839 - 0.944*I', '-0.839 + 0.944*I',
         '1.01 - 0.937*I', '1.01 + 0.937*I']

    roots = p.nroots(n=5)
    assert [str(r) for r in roots] == \
        ['-0.33199', '-0.83907 - 0.94385*I', '-0.83907 + 0.94385*I',
         '1.0051 - 0.93726*I', '1.0051 + 0.93726*I']
예제 #11
0
def test_nroots2():
    p = Poly(x**5 + 3*x + 1, x)

    roots = p.nroots(n=3)
    # The order of roots matters. The roots are ordered by their real
    # components (if they agree, then by their imaginary components),
    # with real roots appearing first.
    assert [str(r) for r in roots] == \
        ['-0.332', '-0.839 - 0.944*I', '-0.839 + 0.944*I',
         '1.01 - 0.937*I', '1.01 + 0.937*I']

    roots = p.nroots(n=5)
    assert [str(r) for r in roots] == \
        ['-0.33199', '-0.83907 - 0.94385*I', '-0.83907 + 0.94385*I',
         '1.0051 - 0.93726*I', '1.0051 + 0.93726*I']
예제 #12
0
def test_roots_cubic():
    assert roots_cubic(Poly(2 * x**3, x)) == [0, 0, 0]
    assert roots_cubic(Poly(x**3 - 3 * x**2 + 3 * x - 1, x)) == [1, 1, 1]

    assert roots_cubic(Poly(x**3 + 1, x)) == \
        [-1, Rational(1, 2) - I*sqrt(3)/2, Rational(1, 2) + I*sqrt(3)/2]
    assert roots_cubic(Poly(2*x**3 - 3*x**2 - 3*x - 1, x))[0] == \
        Rational(1, 2) + cbrt(3)/2 + 3**Rational(2, 3)/2
    eq = -x**3 + 2 * x**2 + 3 * x - 2
    assert roots(eq, trig=True, multiple=True) == \
        roots_cubic(Poly(eq, x), trig=True) == [
        Rational(2, 3) + 2*sqrt(13)*cos(acos(8*sqrt(13)/169)/3)/3,
        -2*sqrt(13)*sin(-acos(8*sqrt(13)/169)/3 + pi/6)/3 + Rational(2, 3),
        -2*sqrt(13)*cos(-acos(8*sqrt(13)/169)/3 + pi/3)/3 + Rational(2, 3),
    ]
예제 #13
0
def prde_normal_denom(fa, fd, G, DE):
    """
    Parametric Risch Differential Equation - Normal part of the denominator.

    Given a derivation D on k[t] and f, g1, ..., gm in k(t) with f weakly
    normalized with respect to t, return the tuple (a, b, G, h) such that
    a, h in k[t], b in k<t>, G = [g1, ..., gm] in k(t)^m, and for any solution
    c1, ..., cm in Const(k) and y in k(t) of Dy + f*y == Sum(ci*gi, (i, 1, m)),
    q == y*h in k<t> satisfies a*Dq + b*q == Sum(ci*Gi, (i, 1, m)).
    """
    dn, ds = splitfactor(fd, DE)
    Gas, Gds = list(zip(*G))
    gd = reduce(lambda i, j: i.lcm(j), Gds, Poly(1, DE.t))
    en, es = splitfactor(gd, DE)

    p = dn.gcd(en)
    h = en.gcd(en.diff(DE.t)).quo(p.gcd(p.diff(DE.t)))

    a = dn*h
    c = a*h

    ba = a*fa - dn*derivation(h, DE)*fd
    ba, bd = ba.cancel(fd, include=True)

    G = [(c*A).cancel(D, include=True) for A, D in G]

    return a, (ba, bd), G, h
예제 #14
0
def prde_linear_constraints(a, b, G, DE):
    """
    Parametric Risch Differential Equation - Generate linear constraints on the constants.

    Given a derivation D on k[t], a, b, in k[t] with gcd(a, b) == 1, and
    G = [g1, ..., gm] in k(t)^m, return Q = [q1, ..., qm] in k[t]^m and a
    matrix M with entries in k(t) such that for any solution c1, ..., cm in
    Const(k) and p in k[t] of a*Dp + b*p == Sum(ci*gi, (i, 1, m)),
    (c1, ..., cm) is a solution of Mx == 0, and p and the ci satisfy
    a*Dp + b*p == Sum(ci*qi, (i, 1, m)).

    Because M has entries in k(t), and because Matrix doesn't play well with
    Poly, M will be a Matrix of Basic expressions.
    """
    m = len(G)

    Gns, Gds = list(zip(*G))
    d = reduce(lambda i, j: i.lcm(j), Gds)
    d = Poly(d, field=True)
    Q = [(ga*(d).quo(gd)).div(d) for ga, gd in G]

    if not all([ri.is_zero for _, ri in Q]):
        N = max([ri.degree(DE.t) for _, ri in Q])
        M = Matrix(N + 1, m, lambda i, j: Q[j][1].nth(i))
    else:
        M = Matrix()  # No constraints, return the empty matrix.

    qs, _ = list(zip(*Q))
    return qs, M
예제 #15
0
def cancel_primitive(b, c, n, DE):
    """
    Poly Risch Differential Equation - Cancellation: Primitive case.

    Given a derivation D on k[t], n either an integer or +oo, b in k, and
    c in k[t] with Dt in k and b != 0, either raise
    NonElementaryIntegralException, in which case the equation Dq + b*q == c
    has no solution of degree at most n in k[t], or a solution q in k[t] of
    this equation with deg(q) <= n.
    """
    from diofant.integrals.prde import is_log_deriv_k_t_radical_in_field

    with DecrementLevel(DE):
        ba, bd = frac_in(b, DE.t)
        A = is_log_deriv_k_t_radical_in_field(ba, bd, DE)
        if A is not None:
            n, z = A
            if n == 1:  # b == Dz/z
                raise NotImplementedError("is_deriv_in_field() is required to "
                                          " solve this problem.")
                # if z*c == Dp for p in k[t] and deg(p) <= n:
                #     return p/z
                # else:
                #     raise NonElementaryIntegralException

    if c.is_zero:
        return c  # return 0

    if n < c.degree(DE.t):
        raise NonElementaryIntegralException

    q = Poly(0, DE.t)
    while not c.is_zero:
        m = c.degree(DE.t)
        if n < m:
            raise NonElementaryIntegralException
        with DecrementLevel(DE):
            a2a, a2d = frac_in(c.LC(), DE.t)
            sa, sd = rischDE(ba, bd, a2a, a2d, DE)
        stm = Poly(sa.as_expr() / sd.as_expr() * DE.t**m, DE.t, expand=False)
        q += stm
        n = m - 1
        c -= b * stm + derivation(stm, DE)

    return q
예제 #16
0
def test_roots_quadratic():
    assert roots_quadratic(Poly(2*x**2, x)) == [0, 0]
    assert roots_quadratic(Poly(2*x**2 + 3*x, x)) == [-Rational(3, 2), 0]
    assert roots_quadratic(Poly(2*x**2 + 3, x)) == [-I*sqrt(6)/2, I*sqrt(6)/2]
    assert roots_quadratic(Poly(2*x**2 + 4*x + 3, x)) == [-1 - I*sqrt(2)/2, -1 + I*sqrt(2)/2]

    f = x**2 + (2*a*e + 2*c*e)/(a - c)*x + (d - b + a*e**2 - c*e**2)/(a - c)
    assert (roots_quadratic(Poly(f, x)) ==
            [-e*(a + c)/(a - c) - sqrt((a*b + 4*a*c*e**2 -
                                        a*d - b*c + c*d)/(a - c)**2),
             -e*(a + c)/(a - c) + sqrt((a*b + 4*a*c*e**2 -
                                        a*d - b*c + c*d)/(a - c)**2)])

    # check for simplification
    f = Poly(y*x**2 - 2*x - 2*y, x)
    assert roots_quadratic(f) == [-sqrt((2*y**2 + 1)/y**2) + 1/y,
                                  sqrt((2*y**2 + 1)/y**2) + 1/y]
    f = Poly(x**2 + (-y**2 - 2)*x + y**2 + 1, x)
    assert roots_quadratic(f) == [y**2/2 - sqrt(y**4)/2 + 1,
                                  y**2/2 + sqrt(y**4)/2 + 1]

    f = Poly(sqrt(2)*x**2 - 1, x)
    r = roots_quadratic(f)
    assert r == _nsort(r)

    # issue sympy/sympy#8255
    f = Poly(-24*x**2 - 180*x + 264)
    assert [w.evalf(2) for w in f.all_roots(radicals=True)] == \
           [w.evalf(2) for w in f.all_roots(radicals=False)]
    for _a, _b, _c in itertools.product((-2, 2), (-2, 2), (0, -1)):
        f = Poly(_a*x**2 + _b*x + _c)
        roots = roots_quadratic(f)
        assert roots == _nsort(roots)
예제 #17
0
def no_cancel_b_small(b, c, n, DE):
    """
    Poly Risch Differential Equation - No cancellation: deg(b) small enough.

    Given a derivation D on k[t], n either an integer or +oo, and b, c
    in k[t] with deg(b) < deg(D) - 1 and either D == d/dt or
    deg(D) >= 2, either raise NonElementaryIntegralException, in which case the
    equation Dq + b*q == c has no solution of degree at most n in k[t],
    or a solution q in k[t] of this equation with deg(q) <= n, or the
    tuple (h, b0, c0) such that h in k[t], b0, c0, in k, and for any
    solution q in k[t] of degree at most n of Dq + bq == c, y == q - h
    is a solution in k of Dy + b0*y == c0.
    """
    q = Poly(0, DE.t)

    while not c.is_zero:
        if n == 0:
            m = 0
        else:
            m = c.degree(DE.t) - DE.d.degree(DE.t) + 1

        if not 0 <= m <= n:  # n < 0 or m < 0 or m > n
            raise NonElementaryIntegralException

        if m > 0:
            p = Poly(c.as_poly(DE.t).LC() / (m * DE.d.as_poly(DE.t).LC()) *
                     DE.t**m,
                     DE.t,
                     expand=False)
        else:
            if b.degree(DE.t) != c.degree(DE.t):
                raise NonElementaryIntegralException
            if b.degree(DE.t) == 0:
                return (q, b.as_poly(DE.T[DE.level - 1]),
                        c.as_poly(DE.T[DE.level - 1]))
            p = Poly(c.as_poly(DE.t).LC() / b.as_poly(DE.t).LC(),
                     DE.t,
                     expand=False)

        q = q + p
        n = m - 1
        c = c - derivation(p, DE) - b * p

    return q
예제 #18
0
def spde(a, b, c, n, DE):
    """
    Rothstein's Special Polynomial Differential Equation algorithm.

    Given a derivation D on k[t], an integer n and a, b, c in k[t] with
    a != 0, either raise NonElementaryIntegralException, in which case the
    equation a*Dq + b*q == c has no solution of degree at most n in
    k[t], or return the tuple (B, C, m, alpha, beta) such that B, C,
    alpha, beta in k[t], m in ZZ, and any solution q in k[t] of degree
    at most n of a*Dq + b*q == c must be of the form
    q == alpha*h + beta, where h in k[t], deg(h) <= m, and Dh + B*h == C.

    This constitutes step 4 of the outline given in the rde.py docstring.
    """
    zero = Poly(0, DE.t)

    alpha = Poly(1, DE.t)
    beta = Poly(0, DE.t)

    while True:
        if c.is_zero:
            return zero, zero, 0, zero, beta  # -1 is more to the point
        if (n < 0) is True:
            raise NonElementaryIntegralException

        g = a.gcd(b)
        if not c.rem(g).is_zero:  # g does not divide c
            raise NonElementaryIntegralException

        a, b, c = a.quo(g), b.quo(g), c.quo(g)

        if a.degree(DE.t) == 0:
            b = b.to_field().quo(a)
            c = c.to_field().quo(a)
            return b, c, n, alpha, beta

        r, z = gcdex_diophantine(b, a, c)
        b += derivation(a, DE)
        c = z - derivation(r, DE)
        n -= a.degree(DE.t)

        beta += alpha * r
        alpha *= a
예제 #19
0
def test_root_factors():
    assert root_factors(Poly(1, x)) == [Poly(1, x)]
    assert root_factors(Poly(x, x)) == [Poly(x, x)]

    assert root_factors(x**2 - 1, x) == [x + 1, x - 1]
    assert root_factors(x**2 - y, x) == [x - sqrt(y), x + sqrt(y)]

    assert root_factors((x**4 - 1)**2) == \
        [x + 1, x + 1, x - 1, x - 1, x - I, x - I, x + I, x + I]

    assert root_factors(Poly(x**4 - 1, x), filter='Z') == \
        [Poly(x + 1, x), Poly(x - 1, x), Poly(x**2 + 1, x)]
    assert root_factors(8*x**2 + 12*x**4 + 6*x**6 + x**8, x, filter='Q') == \
        [x, x, x**6 + 6*x**4 + 12*x**2 + 8]

    pytest.raises(ValueError, lambda: root_factors(Poly(x * y)))
예제 #20
0
def no_cancel_equal(b, c, n, DE):
    """
    Poly Risch Differential Equation - No cancellation: deg(b) == deg(D) - 1

    Given a derivation D on k[t] with deg(D) >= 2, n either an integer
    or +oo, and b, c in k[t] with deg(b) == deg(D) - 1, either raise
    NonElementaryIntegralException, in which case the equation Dq + b*q == c has
    no solution of degree at most n in k[t], or a solution q in k[t] of
    this equation with deg(q) <= n, or the tuple (h, m, C) such that h
    in k[t], m in ZZ, and C in k[t], and for any solution q in k[t] of
    degree at most n of Dq + b*q == c, y == q - h is a solution in k[t]
    of degree at most m of Dy + b*y == C.
    """
    q = Poly(0, DE.t)
    lc = cancel(-b.as_poly(DE.t).LC() / DE.d.as_poly(DE.t).LC())
    if lc.is_Integer and lc.is_positive:
        M = lc
    else:
        M = -1

    while not c.is_zero:
        m = max(M, c.degree(DE.t) - DE.d.degree(DE.t) + 1)

        if not 0 <= m <= n:  # n < 0 or m < 0 or m > n
            raise NonElementaryIntegralException

        u = cancel(m * DE.d.as_poly(DE.t).LC() + b.as_poly(DE.t).LC())
        if u.is_zero:
            return q, m, c
        if m > 0:
            p = Poly(c.as_poly(DE.t).LC() / u * DE.t**m, DE.t, expand=False)
        else:
            if c.degree(DE.t) != DE.d.degree(DE.t) - 1:
                raise NonElementaryIntegralException
            else:
                p = c.as_poly(DE.t).LC() / b.as_poly(DE.t).LC()

        q = q + p
        n = m - 1
        c = c - derivation(p, DE) - b * p

    return q
예제 #21
0
def test_roots_cubic():
    assert roots_cubic(Poly(2 * x**3, x)) == [0, 0, 0]
    assert roots_cubic(Poly(x**3 - 3 * x**2 + 3 * x - 1, x)) == [1, 1, 1]

    assert roots_cubic(Poly(x**3 + 1, x)) == \
        [-1, Rational(1, 2) - I*sqrt(3)/2, Rational(1, 2) + I*sqrt(3)/2]
    assert roots_cubic(Poly(2*x**3 - 3*x**2 - 3*x - 1, x))[0] == \
        Rational(1, 2) + cbrt(3)/2 + 3**Rational(2, 3)/2
    eq = -x**3 + 2 * x**2 + 3 * x - 2
    assert roots(eq, trig=True, multiple=True) == \
        roots_cubic(Poly(eq, x), trig=True) == [
        Rational(2, 3) + 2*sqrt(13)*cos(acos(8*sqrt(13)/169)/3)/3,
        -2*sqrt(13)*sin(-acos(8*sqrt(13)/169)/3 + pi/6)/3 + Rational(2, 3),
        -2*sqrt(13)*cos(-acos(8*sqrt(13)/169)/3 + pi/3)/3 + Rational(2, 3),
    ]
    res = roots_cubic(Poly(x**3 + 2 * a / 27, x))
    assert res == [
        -root(a + sqrt(a**2), 3) / 3,
        Mul(Rational(-1, 3),
            Rational(-1, 2) + sqrt(3) * I / 2,
            root(a + sqrt(a**2), 3),
            evaluate=False),
        Mul(Rational(-1, 3),
            Rational(-1, 2) - sqrt(3) * I / 2,
            root(a + sqrt(a**2), 3),
            evaluate=False)
    ]
예제 #22
0
def prde_no_cancel_b_small(b, Q, n, DE):
    """
    Parametric Poly Risch Differential Equation - No cancellation: deg(b) small enough.

    Given a derivation D on k[t], n in ZZ, and b, q1, ..., qm in k[t] with
    deg(b) < deg(D) - 1 and either D == d/dt or deg(D) >= 2, returns
    h1, ..., hr in k[t] and a matrix A with coefficients in Const(k) such that
    if c1, ..., cm in Const(k) and q in k[t] satisfy deg(q) <= n and
    Dq + b*q == Sum(ci*qi, (i, 1, m)) then q = Sum(dj*hj, (j, 1, r)) where
    d1, ..., dr in Const(k) and A*Matrix([[c1, ..., cm, d1, ..., dr]]).T == 0.
    """
    m = len(Q)
    H = [Poly(0, DE.t)]*m

    for N in range(n, 0, -1):  # [n, ..., 1]
        for i in range(m):
            si = Q[i].nth(N + DE.d.degree(DE.t) - 1)/(N*DE.d.LC())
            sitn = Poly(si*DE.t**N, DE.t)
            H[i] = H[i] + sitn
            Q[i] = Q[i] - derivation(sitn, DE) - b*sitn

    if b.degree(DE.t) > 0:
        for i in range(m):
            si = Poly(Q[i].nth(b.degree(DE.t))/b.LC(), DE.t)
            H[i] = H[i] + si
            Q[i] = Q[i] - derivation(si, DE) - b*si
        if all(qi.is_zero for qi in Q):
            dc = -1
            M = Matrix()
        else:
            dc = max([qi.degree(DE.t) for qi in Q])
            M = Matrix(dc + 1, m, lambda i, j: Q[j].nth(i))
        A, u = constant_system(M, zeros(dc + 1, 1), DE)
        c = eye(m)
        A = A.row_join(zeros(A.rows, m)).col_join(c.row_join(-c))
        return H, A
    else:
        # TODO: implement this (requires recursive param_rischDE() call)
        raise NotImplementedError
예제 #23
0
def order_at(a, p, t):
    """
    Computes the order of a at p, with respect to t.

    For a, p in k[t], the order of a at p is defined as nu_p(a) = max({n
    in Z+ such that p**n|a}), where a != 0.  If a == 0, nu_p(a) = +oo.

    To compute the order at a rational function, a/b, use the fact that
    nu_p(a/b) == nu_p(a) - nu_p(b).
    """
    if a.is_zero:
        return oo
    if p == Poly(t, t):
        return a.as_poly(t).ET()[0][0]

    # Uses binary search for calculating the power. power_list collects the tuples
    # (p^k,k) where each k is some power of 2. After deciding the largest k
    # such that k is power of 2 and p^k|a the loop iteratively calculates
    # the actual power.
    power_list = []
    p1 = p
    r = a.rem(p1)
    tracks_power = 1
    while r.is_zero:
        power_list.append((p1, tracks_power))
        p1 = p1 * p1
        tracks_power *= 2
        r = a.rem(p1)
    n = 0
    product = Poly(1, t)
    while len(power_list) != 0:
        final = power_list.pop()
        productf = product * final[0]
        r = a.rem(productf)
        if r.is_zero:
            n += final[1]
            product = productf
    return n
예제 #24
0
def test_printing():
    f, g = [dmp_normal([], 0, EX)] * 2
    e = PolynomialDivisionFailed(f, g, EX)
    assert str(e)[:57] == ("couldn't reduce degree in a polynomial "
                           "division algorithm")
    assert str(e)[-140:][:57] == ("You may want to use a different "
                                  "simplification algorithm.")

    f, g = [dmp_normal([], 0, RR)] * 2
    e = PolynomialDivisionFailed(f, g, RR)
    assert str(e)[-139:][:74] == ("Your working precision or tolerance of "
                                  "computations may be set improperly.")

    f, g = [dmp_normal([], 0, ZZ)] * 2
    e = PolynomialDivisionFailed(f, g, ZZ)
    assert str(e)[-168:][:80] == (
        "Zero detection is guaranteed in this "
        "coefficient domain. This may indicate a bug")

    e = OperationNotSupported(Poly(x), 'spam')
    assert str(e).find('spam') >= 0
    assert str(e).find('operation not supported') >= 0

    exc = PolificationFailed(1, x, x**2)
    assert str(exc).find("can't construct a polynomial from x") >= 0
    exc = PolificationFailed(1, [x], [x**2], True)
    assert str(exc).find("can't construct polynomials from x") >= 0

    e = ComputationFailed('LT', 1, exc)
    assert str(e).find('failed without generators') >= 0
    assert str(e).find('x**2') >= 0

    e = ExactQuotientFailed(Poly(x), Poly(x**2))
    assert str(e).find('does not divide') >= 0
    assert str(e).find('x**2') >= 0
    assert str(e).find('in ZZ') < 0
    e = ExactQuotientFailed(Poly(x), Poly(x**2), ZZ)
    assert str(e).find('in ZZ') >= 0
예제 #25
0
def test_sympyissue_8438():
    p = Poly([1, y, -2, -3], x).as_expr()
    roots = roots_cubic(Poly(p, x), x)
    z = -Rational(3,
                  2) - 7 * I / 2  # this will fail in code given in commit msg
    post = [r.subs({y: z}) for r in roots]
    assert set(post) == set(roots_cubic(Poly(p.subs({y: z}), x)))
    # /!\ if p is not made an expression, this is *very* slow
    assert all(p.subs({y: z, x: i}).evalf(2, chop=True) == 0 for i in post)
예제 #26
0
def weak_normalizer(a, d, DE, z=None):
    """
    Weak normalization.

    Given a derivation D on k[t] and f == a/d in k(t), return q in k[t]
    such that f - Dq/q is weakly normalized with respect to t.

    f in k(t) is said to be "weakly normalized" with respect to t if
    residue_p(f) is not a positive integer for any normal irreducible p
    in k[t] such that f is in R_p (Definition 6.1.1).  If f has an
    elementary integral, this is equivalent to no logarithm of
    integral(f) whose argument depends on t has a positive integer
    coefficient, where the arguments of the logarithms not in k(t) are
    in k[t].

    Returns (q, f - Dq/q)
    """
    z = z or Dummy('z')
    dn, ds = splitfactor(d, DE)

    # Compute d1, where dn == d1*d2**2*...*dn**n is a square-free
    # factorization of d.
    g = gcd(dn, dn.diff(DE.t))
    d_sqf_part = dn.quo(g)
    d1 = d_sqf_part.quo(gcd(d_sqf_part, g))

    a1, b = gcdex_diophantine(
        d.quo(d1).as_poly(DE.t), d1.as_poly(DE.t), a.as_poly(DE.t))
    r = (a - Poly(z, DE.t) * derivation(d1, DE)).as_poly(DE.t).resultant(
        d1.as_poly(DE.t))
    r = Poly(r, z)

    if not r.has(z):
        return Poly(1, DE.t), (a, d)

    N = [i for i in r.real_roots() if i in ZZ and i > 0]

    q = reduce(mul,
               [gcd(a - Poly(n, DE.t) * derivation(d1, DE), d1) for n in N],
               Poly(1, DE.t))

    dq = derivation(q, DE)
    sn = q * a - d * dq
    sd = q * d
    sn, sd = sn.cancel(sd, include=True)

    return q, (sn, sd)
예제 #27
0
def solve_biquadratic(f, g, opt):
    """Solve a system of two bivariate quadratic polynomial equations.

    Examples
    ========

    >>> from diofant.polys import Options, Poly
    >>> from diofant.abc import x, y
    >>> from diofant.solvers.polysys import solve_biquadratic
    >>> NewOption = Options((x, y), {'domain': 'ZZ'})

    >>> a = Poly(y**2 - 4 + x, y, x, domain='ZZ')
    >>> b = Poly(y*2 + 3*x - 7, y, x, domain='ZZ')
    >>> solve_biquadratic(a, b, NewOption)
    [(1/3, 3), (41/27, 11/9)]

    >>> a = Poly(y + x**2 - 3, y, x, domain='ZZ')
    >>> b = Poly(-y + x - 4, y, x, domain='ZZ')
    >>> solve_biquadratic(a, b, NewOption)
    [(-sqrt(29)/2 + 7/2, -sqrt(29)/2 - 1/2), (sqrt(29)/2 + 7/2, -1/2 + \
      sqrt(29)/2)]
    """
    G = groebner([f, g])

    if len(G) == 1 and G[0].is_ground:
        return

    if len(G) != 2:
        raise SolveFailed

    p, q = G
    x, y = opt.gens

    p = Poly(p, x, expand=False)
    q = q.ltrim(-1)

    p_roots = [ rcollect(expr, y) for expr in roots(p).keys() ]
    q_roots = list(roots(q).keys())

    solutions = []

    for q_root in q_roots:
        for p_root in p_roots:
            solution = (p_root.subs(y, q_root), q_root)
            solutions.append(solution)

    return sorted(solutions, key=default_sort_key)
예제 #28
0
def test_sympyissue_8285():
    roots = (Poly(4 * x**8 - 1, x) * Poly(x**2 + 1)).all_roots()
    assert roots == _nsort(roots)
    f = Poly(x**4 + 5 * x**2 + 6, x)
    ro = [RootOf(f, i) for i in range(4)]
    roots = Poly(x**4 + 5 * x**2 + 6, x).all_roots()
    assert roots == ro
    assert roots == _nsort(roots)
    # more than 2 complex roots from which to identify the
    # imaginary ones
    roots = Poly(2 * x**8 - 1).all_roots()
    assert roots == _nsort(roots)
    assert len(Poly(2 * x**10 - 1).all_roots()) == 10  # doesn't fail
예제 #29
0
def test_roots1():
    assert roots(1) == {}
    assert roots(1, multiple=True) == []
    q = Symbol('q', real=True)
    assert roots(x**3 - q, x) == {
        cbrt(q): 1,
        -cbrt(q) / 2 - sqrt(3) * I * cbrt(q) / 2: 1,
        -cbrt(q) / 2 + sqrt(3) * I * cbrt(q) / 2: 1
    }
    assert roots_cubic(Poly(x**3 - 1)) == [
        1,
        Rational(-1, 2) + sqrt(3) * I / 2,
        Rational(-1, 2) - sqrt(3) * I / 2
    ]

    assert roots([1, x, y]) == {
        -x / 2 - sqrt(x**2 - 4 * y) / 2: 1,
        -x / 2 + sqrt(x**2 - 4 * y) / 2: 1
    }
    pytest.raises(ValueError, lambda: roots([1, x, y], z))
예제 #30
0
def apart_undetermined_coeffs(P, Q):
    """Partial fractions via method of undetermined coefficients. """
    X = numbered_symbols(cls=Dummy)
    partial, symbols = [], []

    _, factors = Q.factor_list()

    for f, k in factors:
        n, q = f.degree(), Q

        for i in range(1, k + 1):
            coeffs, q = take(X, n), q.quo(f)
            partial.append((coeffs, q, f, i))
            symbols.extend(coeffs)

    dom = Q.get_domain().inject(*symbols)
    F = Poly(0, Q.gen, domain=dom)

    for i, (coeffs, q, f, k) in enumerate(partial):
        h = Poly(coeffs, Q.gen, domain=dom)
        partial[i] = (h, f, k)
        q = q.set_domain(dom)
        F += h * q

    system, result = [], Integer(0)

    for (k, ), coeff in F.terms():
        system.append(coeff - P.nth(k))

    from diofant.solvers import solve
    solution = solve(system, symbols)

    for h, f, k in partial:
        h = h.as_expr().subs(solution)
        result += h / f.as_expr()**k

    return result
예제 #31
0
def dispersionset(p, q=None, *gens, **args):
    r"""Compute the *dispersion set* of two polynomials.

    For two polynomials `f(x)` and `g(x)` with `\deg f > 0`
    and `\deg g > 0` the dispersion set `\operatorname{J}(f, g)` is defined as:

    .. math::
        \operatorname{J}(f, g)
        & := \{a \in \mathbb{N}_0 | \gcd(f(x), g(x+a)) \neq 1\} \\
        &  = \{a \in \mathbb{N}_0 | \deg \gcd(f(x), g(x+a)) \geq 1\}

    For a single polynomial one defines `\operatorname{J}(f) := \operatorname{J}(f, f)`.

    Examples
    ========

    >>> from diofant import poly
    >>> from diofant.abc import x

    Dispersion set and dispersion of a simple polynomial:

    >>> fp = poly((x - 3)*(x + 3), x)
    >>> sorted(dispersionset(fp))
    [0, 6]
    >>> dispersion(fp)
    6

    Note that the definition of the dispersion is not symmetric:

    >>> fp = poly(x**4 - 3*x**2 + 1, x)
    >>> gp = fp.shift(-3)
    >>> sorted(dispersionset(fp, gp))
    [2, 3, 4]
    >>> dispersion(fp, gp)
    4
    >>> sorted(dispersionset(gp, fp))
    []
    >>> dispersion(gp, fp)
    -oo

    Computing the dispersion also works over field extensions:

    >>> from diofant import sqrt
    >>> fp = poly(x**2 + sqrt(5)*x - 1, x, domain='QQ<sqrt(5)>')
    >>> gp = poly(x**2 + (2 + sqrt(5))*x + sqrt(5), x, domain='QQ<sqrt(5)>')
    >>> sorted(dispersionset(fp, gp))
    [2]
    >>> sorted(dispersionset(gp, fp))
    [1, 4]

    We can even perform the computations for polynomials
    having symbolic coefficients:

    >>> from diofant.abc import a
    >>> fp = poly(4*x**4 + (4*a + 8)*x**3 + (a**2 + 6*a + 4)*x**2 + (a**2 + 2*a)*x, x)
    >>> sorted(dispersionset(fp))
    [0, 1]

    See Also
    ========

    diofant.polys.dispersion.dispersion

    References
    ==========

    .. [1] [ManWright94]_
    .. [2] [Koepf98]_
    .. [3] [Abramov71]_
    .. [4] [Man93]_
    """
    # Check for valid input
    same = False if q is not None else True
    if same:
        q = p

    p = Poly(p, *gens, **args)
    q = Poly(q, *gens, **args)

    if not p.is_univariate or not q.is_univariate:
        raise ValueError("Polynomials need to be univariate")

    # The generator
    if not p.gen == q.gen:
        raise ValueError("Polynomials must have the same generator")
    gen = p.gen

    # We define the dispersion of constant polynomials to be zero
    if p.degree() < 1 or q.degree() < 1:
        return {0}

    # Factor p and q over the rationals
    fp = p.factor_list()
    fq = q.factor_list() if not same else fp

    # Iterate over all pairs of factors
    J = set()
    for s, unused in fp[1]:
        for t, unused in fq[1]:
            m = s.degree()
            n = t.degree()
            if n != m:
                continue
            an = s.LC()
            bn = t.LC()
            if not (an - bn).is_zero:
                continue
            # Note that the roles of `s` and `t` below are switched
            # w.r.t. the original paper. This is for consistency
            # with the description in the book of W. Koepf.
            anm1 = s.coeff_monomial(gen**(m - 1))
            bnm1 = t.coeff_monomial(gen**(n - 1))
            alpha = (anm1 - bnm1) / (n * bn)
            if not alpha.is_Integer:
                continue
            if alpha < 0 or alpha in J:
                continue
            if n > 1 and not (s - t.shift(alpha)).is_zero:
                continue
            J.add(alpha)

    return J
예제 #32
0
def test_RootOf():
    p = Poly(x**3 + y*x + 1, x)
    assert mcode(RootOf(p, 0)) == 'Root[#^3 + #*y + 1 &, 1]'
예제 #33
0
def test_sympyissue_14291():
    p = Poly(((x - 1)**2 + 1) * ((x - 1)**2 + 2) * (x - 1))
    assert set(
        p.all_roots()) == {1, 1 - I, 1 + I, 1 - I * sqrt(2), 1 + sqrt(2) * I}
예제 #34
0
def test_sympyissue_7724():
    e = x**4 * I + x**2 + I
    r1, r2 = roots(e, x), Poly(e, x).all_roots()
    assert len(r1) == 4
    assert {_.evalf() for _ in r1} == {_.evalf() for _ in r2}
예제 #35
0
def test_sympyissue_14291():
    p = Poly(((x - 1)**2 + 1)*((x - 1)**2 + 2)*(x - 1))
    assert set(p.all_roots()) == {1, 1 - I, 1 + I, 1 - I*sqrt(2), 1 + sqrt(2)*I}