Beispiel #1
0
def test_issue_5526():
    assert reduce_inequalities(S(0) <= x + Integral(y**2, (y, 1, 3)) - 1, True, [x]) == \
        (-Integral(y**2, (y, 1, 3)) + 1 <= x)
    f = Function('f')
    e = Sum(f(x), (x, 1, 3))
    assert reduce_inequalities(S(0) <= x + e + y**2, True, [x]) == \
        (-y**2 - Sum(f(x), (x, 1, 3)) <= x)
Beispiel #2
0
def test_issue_5526():
    assert reduce_inequalities(S(0) <= x + Integral(y**2, (y, 1, 3)) - 1, True, [x]) == \
        (-Integral(y**2, (y, 1, 3)) + 1 <= x)
    f = Function('f')
    e = Sum(f(x), (x, 1, 3))
    assert reduce_inequalities(S(0) <= x + e + y**2, True, [x]) == \
        (-y**2 - Sum(f(x), (x, 1, 3)) <= x)
def test_reduce_inequalities_errors():
    x = Symbol('x')
    y = Symbol('y')

    raises(NotImplementedError, lambda: reduce_inequalities(Ge(sin(x) + x, 1)))
    raises(NotImplementedError, lambda: reduce_inequalities(Ge(x**2*y + y, 1)))
    raises(NotImplementedError, lambda: reduce_inequalities(Ge(sqrt(2)*x, 1)))
Beispiel #4
0
def test_issue_5526():
    assert reduce_inequalities(0 <=
        x + Integral(y**2, (y, 1, 3)) - 1, [x]) == \
        (x >= -Integral(y**2, (y, 1, 3)) + 1)
    f = Function('f')
    e = Sum(f(x), (x, 1, 3))
    assert reduce_inequalities(0 <= x + e + y**2, [x]) == \
        (x >= -y**2 - Sum(f(x), (x, 1, 3)))
def test_reduce_inequalities_errors():
    x = Symbol('x')
    y = Symbol('y')

    raises(NotImplementedError, lambda: reduce_inequalities(Ge(sin(x) + x, 1)))
    raises(NotImplementedError,
           lambda: reduce_inequalities(Ge(x**2 * y + y, 1)))
    raises(NotImplementedError,
           lambda: reduce_inequalities(Ge(sqrt(2) * x, 1)))
Beispiel #6
0
def test_reduce_abs_inequalities():
    real = Q.real(x)

    assert reduce_inequalities(abs(x - 5) < 3, assume=real) == And(Gt(x, 2), Lt(x, 8))
    assert reduce_inequalities(abs(2*x + 3) >= 8, assume=real) == Or(Le(x, -S(11)/2), Ge(x, S(5)/2))
    assert reduce_inequalities(abs(x - 4) + abs(3*x - 5) < 7, assume=real) == And(Gt(x, S(1)/2), Lt(x, 4))
    assert reduce_inequalities(abs(x - 4) + abs(3*abs(x) - 5) < 7, assume=real) == Or(And(-2 < x, x < -1), And(S(1)/2 < x, x < 4))

    raises(NotImplementedError, "reduce_inequalities(abs(x - 5) < 3)")
Beispiel #7
0
def test_issue_10198():
    assert reduce_inequalities(-1 + 1 / abs(1 / x - 1) < 0) == Or(
        And(-oo < x, x < 0), And(S.Zero < x, x < S.Half))
    assert reduce_inequalities(abs(1 / sqrt(x)) - 1, x) == Eq(x, 1)
    assert reduce_abs_inequality(-3 + 1/abs(1 - 1/x), '<', x) == \
        Or(And(-oo < x, x < 0),
        And(S.Zero < x, x < Rational(3, 4)), And(Rational(3, 2) < x, x < oo))
    raises(
        ValueError,
        lambda: reduce_abs_inequality(-3 + 1 / abs(1 - 1 / sqrt(x)), '<', x))
Beispiel #8
0
def test_issue_10198():
    assert reduce_inequalities(-1 + 1 / abs(1 / x - 1) < 0) == Or(
        And(-oo < x, x < 0), And(S(0) < x, x < S(1) / 2))
    assert reduce_inequalities(abs(1 / sqrt(x)) - 1, x) == Eq(x, 1)
    assert reduce_abs_inequality(-3 + 1/abs(1 - 1/x), '<', x) == \
        Or(And(-oo < x, x < 0),
        And(S(0) < x, x < S(3)/4), And(S(3)/2 < x, x < oo))
    raises(
        ValueError,
        lambda: reduce_abs_inequality(-3 + 1 / abs(1 - 1 / sqrt(x)), '<', x))
Beispiel #9
0
def test_issue_10198():
    assert reduce_inequalities(
        -1 + 1/abs(1/x - 1) < 0) == Or(
        And(-oo < x, x < 0), And(S(0) < x, x < S(1)/2)
        )
    assert reduce_inequalities(abs(1/sqrt(x)) - 1, x) == Eq(x, 1)
    assert reduce_abs_inequality(-3 + 1/abs(1 - 1/x), '<', x) == \
        Or(And(-oo < x, x < 0),
        And(S(0) < x, x < S(3)/4), And(S(3)/2 < x, x < oo))
    raises(ValueError,lambda: reduce_abs_inequality(-3 + 1/abs(
        1 - 1/sqrt(x)), '<', x))
Beispiel #10
0
def test_reduce_abs_inequalities():
    real = Q.real(x)

    assert reduce_inequalities(
        abs(x - 5) < 3, assume=real) == And(Lt(2, x), Lt(x, 8))
    assert reduce_inequalities(
        abs(2*x + 3) >= 8, assume=real) == Or(And(Le(S(5)/2, x), Lt(x, oo)), And(Le(x, -S(11)/2), Lt(-oo, x)))
    assert reduce_inequalities(abs(x - 4) + abs(
        3*x - 5) < 7, assume=real) == And(Lt(S(1)/2, x), Lt(x, 4))
    assert reduce_inequalities(abs(x - 4) + abs(3*abs(x) - 5) < 7, assume=real) == Or(And(S(-2) < x, x < -1), And(S(1)/2 < x, x < 4))

    raises(NotImplementedError, lambda: reduce_inequalities(abs(x - 5) < 3))
Beispiel #11
0
def test_reduce_abs_inequalities():
    x = Symbol('x', real=True)

    assert reduce_inequalities(abs(x - 5) < 3) == And(Lt(2, x), Lt(x, 8))
    assert reduce_inequalities(
        abs(2*x + 3) >= 8) == Or(And(Le(S(5)/2, x), Lt(x, oo)), And(Le(x, -S(11)/2), Lt(-oo, x)))
    assert reduce_inequalities(abs(x - 4) + abs(
        3*x - 5) < 7) == And(Lt(S(1)/2, x), Lt(x, 4))
    assert reduce_inequalities(abs(x - 4) + abs(3*abs(x) - 5) < 7) == \
        Or(And(S(-2) < x, x < -1), And(S(1)/2 < x, x < 4))

    x = Symbol('x')
    raises(NotImplementedError, lambda: reduce_inequalities(abs(x - 5) < 3))
def test_reduce_abs_inequalities():
    x = Symbol('x', real=True)

    assert reduce_inequalities(abs(x - 5) < 3) == And(Lt(2, x), Lt(x, 8))
    assert reduce_inequalities(abs(2 * x + 3) >= 8) == Or(
        And(Le(S(5) / 2, x), Lt(x, oo)), And(Le(x, -S(11) / 2), Lt(-oo, x)))
    assert reduce_inequalities(abs(x - 4) + abs(3 * x - 5) < 7) == And(
        Lt(S(1) / 2, x), Lt(x, 4))
    assert reduce_inequalities(abs(x - 4) + abs(3*abs(x) - 5) < 7) == \
        Or(And(S(-2) < x, x < -1), And(S(1)/2 < x, x < 4))

    x = Symbol('x')
    raises(NotImplementedError, lambda: reduce_inequalities(abs(x - 5) < 3))
Beispiel #13
0
def test_reduce_abs_inequalities():
    real = Q.real(x)

    assert reduce_inequalities(abs(x - 5) < 3,
                               assume=real) == And(Lt(2, x), Lt(x, 8))
    assert reduce_inequalities(abs(2 * x + 3) >= 8, assume=real) == Or(
        And(Le(S(5) / 2, x), Lt(x, oo)), And(Le(x, -S(11) / 2), Lt(-oo, x)))
    assert reduce_inequalities(abs(x - 4) + abs(3 * x - 5) < 7,
                               assume=real) == And(Lt(S(1) / 2, x), Lt(x, 4))
    assert reduce_inequalities(abs(x - 4) + abs(3 * abs(x) - 5) < 7,
                               assume=real) == Or(And(S(-2) < x, x < -1),
                                                  And(S(1) / 2 < x, x < 4))

    raises(NotImplementedError, lambda: reduce_inequalities(abs(x - 5) < 3))
def test_issue_8545():
    from sympy import refine
    eq = 1 - x - abs(1 - x)
    ans = And(Lt(1, x), Lt(x, oo))
    assert reduce_abs_inequality(eq, '<', x) == ans
    eq = 1 - x - sqrt((1 - x)**2)
    assert reduce_inequalities(refine(eq) < 0) == ans
Beispiel #15
0
def test_issue_8235():
    x = Symbol('x', real=True)
    assert reduce_inequalities(x**2 - 1 < 0) == \
        And(S(-1) < x, x < S(1))
    assert reduce_inequalities(x**2 - 1 <= 0) == \
        And(S(-1) <= x, x <= 1)
    assert reduce_inequalities(x**2 - 1 > 0) == \
        Or(And(-oo < x, x < -1), And(x < oo, S(1) < x))
    assert reduce_inequalities(x**2 - 1 >= 0) == \
        Or(And(-oo < x, x <= S(-1)), And(S(1) <= x, x < oo))

    eq = x**8 + x**2 - 9
    sol = solve(eq >= 0)
    known_sol = Or(And(-oo < x, RootOf(x**8 + x**2 - 9, 1) <= x, x < oo), \
            And(-oo < x, x < oo, x <= RootOf(x**8 + x**2 - 9, 0)))
    assert sol == known_sol
Beispiel #16
0
def test_issue_8545():
    from sympy import refine
    eq = 1 - x - abs(1 - x)
    ans = And(Lt(1, x), Lt(x, oo))
    assert reduce_abs_inequality(eq, '<', x) == ans
    eq = 1 - x - sqrt((1 - x)**2)
    assert reduce_inequalities(refine(eq) < 0) == ans
def test_issue_8235():
    x = Symbol('x', real=True)
    assert reduce_inequalities(x**2 - 1 < 0) == \
        And(S(-1) < x, x < S(1))
    assert reduce_inequalities(x**2 - 1 <= 0) == \
        And(S(-1) <= x, x <= 1)
    assert reduce_inequalities(x**2 - 1 > 0) == \
        Or(And(-oo < x, x < -1), And(x < oo, S(1) < x))
    assert reduce_inequalities(x**2 - 1 >= 0) == \
        Or(And(-oo < x, x <= S(-1)), And(S(1) <= x, x < oo))

    eq = x**8 + x**2 - 9
    sol = solve(eq >= 0)
    known_sol = Or(And(-oo < x, RootOf(x**8 + x**2 - 9, 1) <= x, x < oo), \
            And(-oo < x, x < oo, x <= RootOf(x**8 + x**2 - 9, 0)))
    assert sol == known_sol
def test_reduce_inequalities_multivariate():
    x = Symbol('x')
    y = Symbol('y')

    assert reduce_inequalities([Ge(x**2, 1), Ge(y**2, 1)]) == \
        And(Eq(im(x), 0), Eq(im(y), 0), Or(And(Le(1, re(x)), Lt(re(x), oo)),
                                           And(Le(re(x), -1), Lt(-oo, re(x)))),
            Or(And(Le(1, re(y)), Lt(re(y), oo)), And(Le(re(y), -1), Lt(-oo, re(y)))))
Beispiel #19
0
def test_issue_8235():
    assert reduce_inequalities(x**2 - 1 < 0) == \
        And(S(-1) < x, x < S(1))
    assert reduce_inequalities(x**2 - 1 <= 0) == \
        And(S(-1) <= x, x <= 1)
    assert reduce_inequalities(x**2 - 1 > 0) == \
        Or(And(-oo < x, x < -1), And(x < oo, S(1) < x))
    assert reduce_inequalities(x**2 - 1 >= 0) == \
        Or(And(-oo < x, x <= S(-1)), And(S(1) <= x, x < oo))

    eq = x**8 + x - 9  # we want CRootOf solns here
    sol = solve(eq >= 0)
    tru = Or(And(rootof(eq, 1) <= x, x < oo), And(-oo < x, x <= rootof(eq, 0)))
    assert sol == tru

    # recast vanilla as real
    assert solve(sqrt((-x + 1)**2) < 1) == And(S(0) < x, x < 2)
Beispiel #20
0
def test_reduce_inequalities_multivariate():
    x = Symbol('x')
    y = Symbol('y')

    assert reduce_inequalities([Ge(x**2, 1), Ge(y**2, 1)]) == \
        And(Eq(im(x), 0), Eq(im(y), 0), Or(And(Le(1, re(x)), Lt(re(x), oo)),
                                           And(Le(re(x), -1), Lt(-oo, re(x)))),
            Or(And(Le(1, re(y)), Lt(re(y), oo)), And(Le(re(y), -1), Lt(-oo, re(y)))))
Beispiel #21
0
def test_issue_8235():
    assert reduce_inequalities(x**2 - 1 < 0) == \
        And(S(-1) < x, x < S(1))
    assert reduce_inequalities(x**2 - 1 <= 0) == \
        And(S(-1) <= x, x <= 1)
    assert reduce_inequalities(x**2 - 1 > 0) == \
        Or(And(-oo < x, x < -1), And(x < oo, S(1) < x))
    assert reduce_inequalities(x**2 - 1 >= 0) == \
        Or(And(-oo < x, x <= S(-1)), And(S(1) <= x, x < oo))

    eq = x**8 + x - 9  # we want CRootOf solns here
    sol = solve(eq >= 0)
    tru = Or(And(rootof(eq, 1) <= x, x < oo), And(-oo < x, x <= rootof(eq, 0)))
    assert sol == tru

    # recast vanilla as real
    assert solve(sqrt((-x + 1)**2) < 1) == And(S(0) < x, x < 2)
Beispiel #22
0
def test_reduce_abs_inequalities():
    e = abs(x - 5) < 3
    ans = And(Lt(2, x), Lt(x, 8))
    assert reduce_inequalities(e) == ans
    assert reduce_inequalities(e, x) == ans
    assert reduce_inequalities(abs(x - 5)) == Eq(x, 5)
    assert reduce_inequalities(abs(2 * x + 3) >= 8) == Or(
        And(Le(S(5) / 2, x), Lt(x, oo)), And(Le(x, -S(11) / 2), Lt(-oo, x)))
    assert reduce_inequalities(abs(x - 4) + abs(3 * x - 5) < 7) == And(
        Lt(S(1) / 2, x), Lt(x, 4))
    assert reduce_inequalities(abs(x - 4) + abs(3*abs(x) - 5) < 7) == \
        Or(And(S(-2) < x, x < -1), And(S(1)/2 < x, x < 4))

    nr = Symbol('nr', extended_real=False)
    raises(TypeError, lambda: reduce_inequalities(abs(nr - 5) < 3))
    assert reduce_inequalities(x < 3, symbols=[x, nr]) == And(-oo < x, x < 3)
Beispiel #23
0
def test_reduce_abs_inequalities():
    e = abs(x - 5) < 3
    ans = And(Lt(2, x), Lt(x, 8))
    assert reduce_inequalities(e) == ans
    assert reduce_inequalities(e, x) == ans
    assert reduce_inequalities(abs(x - 5)) == Eq(x, 5)
    assert reduce_inequalities(
        abs(2*x + 3) >= 8) == Or(And(Le(S(5)/2, x), Lt(x, oo)),
        And(Le(x, -S(11)/2), Lt(-oo, x)))
    assert reduce_inequalities(abs(x - 4) + abs(
        3*x - 5) < 7) == And(Lt(S(1)/2, x), Lt(x, 4))
    assert reduce_inequalities(abs(x - 4) + abs(3*abs(x) - 5) < 7) == \
        Or(And(S(-2) < x, x < -1), And(S(1)/2 < x, x < 4))

    nr = Symbol('nr', real=False)
    raises(TypeError, lambda: reduce_inequalities(abs(nr - 5) < 3))
    assert reduce_inequalities(x < 3, symbols=[x, nr]) == And(-oo < x, x < 3)
Beispiel #24
0
def test_reduce_abs_inequalities():
    e = abs(x - 5) < 3
    ans = And(Lt(2, x), Lt(x, 8))
    assert reduce_inequalities(e) == ans
    assert reduce_inequalities(e, x) == ans
    assert reduce_inequalities(abs(x - 5)) == Eq(x, 5)
    assert reduce_inequalities(abs(2 * x + 3) >= 8) == Or(
        And(Le(Rational(5, 2), x), Lt(x, oo)), And(Le(x, Rational(-11, 2)), Lt(-oo, x))
    )
    assert reduce_inequalities(abs(x - 4) + abs(3 * x - 5) < 7) == And(
        Lt(S.Half, x), Lt(x, 4)
    )
    assert reduce_inequalities(abs(x - 4) + abs(3 * abs(x) - 5) < 7) == Or(
        And(S(-2) < x, x < -1), And(S.Half < x, x < 4)
    )

    nr = Symbol("nr", extended_real=False)
    raises(TypeError, lambda: reduce_inequalities(abs(nr - 5) < 3))
    assert reduce_inequalities(x < 3, symbols=[x, nr]) == And(-oo < x, x < 3)
Beispiel #25
0
def test_reduce_inequalities_boolean():
    assert reduce_inequalities(
        [Eq(x**2, 0), True]) == Eq(x, 0)
    assert reduce_inequalities([Eq(x**2, 0), False]) == False
    assert reduce_inequalities(x**2 >= 0) is S.true  # issue 10196
Beispiel #26
0
def test_reduce_inequalities_general():
    assert reduce_inequalities(Ge(sqrt(2)*x, 1)) == And(sqrt(2)/2 <= x, x < oo)
    assert reduce_inequalities(PurePoly(x + 1, x) > 0) == And(S(-1) < x, x < oo)
Beispiel #27
0
def test_N2():
    with assuming(Q.real(x)):
        assert reduce_inequalities(x**4 - x + 1 > 0) is True
        assert reduce_inequalities(x**4 - x + 1 > 1) is Or(Lt(1, x), Lt(x, 0))
Beispiel #28
0
def _solve(f, *symbols, **flags):
    """Solves equations and systems of equations.

       Currently supported are univariate polynomial, transcendental
       equations, piecewise combinations thereof and systems of linear
       and polynomial equations.  Input is formed as a single expression
       or an equation,  or an iterable container in case of an equation
       system.  The type of output may vary and depends heavily on the
       input. For more details refer to more problem specific functions.

       By default all solutions are simplified to make the output more
       readable. If this is not the expected behavior (e.g., because of
       speed issues) set simplified=False in function arguments.

       To solve equations and systems of equations like recurrence relations
       or differential equations, use rsolve() or dsolve(), respectively.

       >>> from sympy import I, solve
       >>> from sympy.abc import x, y

       Solve a polynomial equation:

       >>> solve(x**4-1, x)
       [1, -1, -I, I]

       Solve a linear system:

       >>> solve((x+5*y-2, -3*x+6*y-15), x, y)
       {x: -3, y: 1}

    """

    def sympified_list(w):
        return map(sympify, iff(isinstance(w,(list, tuple, set)), w, [w]))
    # make f and symbols into lists of sympified quantities
    # keeping track of how f was passed since if it is a list
    # a dictionary of results will be returned.
    bare_f = not iterable(f)
    f, symbols = (sympified_list(w) for w in [f, symbols])

    for i, fi in enumerate(f):
        if isinstance(fi, Equality):
            f[i] = fi.lhs - fi.rhs
        elif isinstance(fi, Poly):
            f[i] = fi.as_expr()
        elif isinstance(fi, bool) or fi.is_Relational:
            return reduce_inequalities(f, assume=flags.get('assume'))

    if not symbols:
        #get symbols from equations or supply dummy symbols since
        #solve(3,x) returns []...though it seems that it should raise some sort of error TODO
        symbols = set([])
        for fi in f:
            symbols |= fi.free_symbols or set([Dummy('x')])
        symbols = list(symbols)
        symbols.sort(key=Basic.sort_key)

    if len(symbols) == 1:
        if isinstance(symbols[0], (list, tuple, set)):
            symbols = symbols[0]

    result = list()

    # Begin code handling for Function and Derivative instances
    # Basic idea:  store all the passed symbols in symbols_passed, check to see
    # if any of them are Function or Derivative types, if so, use a dummy
    # symbol in their place, and set symbol_swapped = True so that other parts
    # of the code can be aware of the swap.  Once all swapping is done, the
    # continue on with regular solving as usual, and swap back at the end of
    # the routine, so that whatever was passed in symbols is what is returned.
    symbols_new = []
    symbol_swapped = False

    symbols_passed = list(symbols)

    for i, s in enumerate(symbols):
        if s.is_Symbol:
            s_new = s
        elif s.is_Function:
            symbol_swapped = True
            s_new = Dummy('F%d' % i)
        elif s.is_Derivative:
            symbol_swapped = True
            s_new = Dummy('D%d' % i)
        else:
            raise TypeError('not a Symbol or a Function')
        symbols_new.append(s_new)

        if symbol_swapped:
            swap_back_dict = dict(zip(symbols_new, symbols))
    # End code for handling of Function and Derivative instances

    if bare_f:
        f = f[0]

        # Create a swap dictionary for storing the passed symbols to be solved
        # for, so that they may be swapped back.
        if symbol_swapped:
            swap_dict = zip(symbols, symbols_new)
            f = f.subs(swap_dict)
            symbols = symbols_new

        # Any embedded piecewise functions need to be brought out to the
        # top level so that the appropriate strategy gets selected.
        f = piecewise_fold(f)

        if len(symbols) != 1:
            soln = None
            free = f.free_symbols
            ex = free - set(symbols)
            if len(ex) == 1:
                ex = ex.pop()
                try:
                    # may come back as dict or list (if non-linear)
                    soln = solve_undetermined_coeffs(f, symbols, ex)
                except NotImplementedError:
                    pass
            if soln is None:
                n, d = solve_linear(f, x=symbols)
                if n.is_Symbol:
                    soln = {n: cancel(d)}
            if soln:
                if symbol_swapped and isinstance(soln, dict):
                    return dict([(swap_back_dict[k],
                                  v.subs(swap_back_dict))
                                  for k, v in soln.iteritems()])
                return soln

        symbol = symbols[0]

        # first see if it really depends on symbol and whether there
        # is a linear solution
        f_num, sol = solve_linear(f, x=symbols)
        if not symbol in f_num.free_symbols:
            return []
        elif f_num.is_Symbol:
            return [cancel(sol)]

        strategy = guess_solve_strategy(f, symbol)
        result = False # no solution was obtained

        if strategy == GS_POLY:
            poly = f.as_poly(symbol)
            if poly is None:
                msg = "Cannot solve equation %s for %s" % (f, symbol)
            else:
                # for cubics and quartics, if the flag wasn't set, DON'T do it
                # by default since the results are quite long. Perhaps one could
                # base this decision on a certain crtical length of the roots.
                if poly.degree() > 2:
                    flags['simplified'] = flags.get('simplified', False)
                result = roots(poly, cubics=True, quartics=True).keys()

        elif strategy == GS_RATIONAL:
            P, _ = f.as_numer_denom()
            dens = denoms(f, x=symbols)
            # reject any result that makes Q affirmatively 0;
            # if in doubt, keep it
            try:
                soln = _solve(P, symbol, **flags)
            except NotImplementedError:
                msg = "Cannot solve equation %s for %s" % (P, symbol)
                result = []
            else:
                if dens:
                    result = [s for s in soln if all(not checksol(den, {symbol: s}) for den in dens)]
                else:
                    result = soln

        elif strategy == GS_POLY_CV_1:
            args = list(f.args)
            if isinstance(f, Pow):
                result = _solve(args[0], symbol, **flags)
            elif isinstance(f, Add):
                # we must search for a suitable change of variables
                # collect exponents
                exponents_denom = list()
                for arg in args:
                    if isinstance(arg, Pow):
                        exponents_denom.append(arg.exp.q)
                    elif isinstance(arg, Mul):
                        for mul_arg in arg.args:
                            if isinstance(mul_arg, Pow):
                                exponents_denom.append(mul_arg.exp.q)
                assert len(exponents_denom) > 0
                if len(exponents_denom) == 1:
                    m = exponents_denom[0]
                else:
                    # get the LCM of the denominators
                    m = reduce(ilcm, exponents_denom)
                # x -> y**m.
                # we assume positive for simplification purposes
                t = Dummy('t', positive=True)
                f_ = f.subs(symbol, t**m)
                if guess_solve_strategy(f_, t) != GS_POLY:
                    msg = "Could not convert to a polynomial equation: %s" % f_
                    result = []
                else:
                    soln = [s**m for s in _solve(f_, t)]
                    # we might have introduced solutions from another branch
                    # when changing variables; check and keep solutions
                    # unless they definitely aren't a solution
                    result = [s for s in soln if checksol(f, {symbol: s}) is not False]

            elif isinstance(f, Mul):
                result = []
                for m in f.args:
                    result.extend(_solve(m, symbol, **flags) or [])

        elif strategy == GS_POLY_CV_2:
            m = 0
            args = list(f.args)
            if isinstance(f, Add):
                for arg in args:
                    if isinstance(arg, Pow):
                        m = min(m, arg.exp)
                    elif isinstance(arg, Mul):
                        for mul_arg in arg.args:
                            if isinstance(mul_arg, Pow):
                                m = min(m, mul_arg.exp)
            elif isinstance(f, Mul):
                for mul_arg in args:
                    if isinstance(mul_arg, Pow):
                        m = min(m, mul_arg.exp)

            if m and m != 1:
                f_ = simplify(f*symbol**(-m))
                try:
                    sols = _solve(f_, symbol)
                except NotImplementedError:
                    msg = 'Could not solve %s for %s' % (f_, symbol)
                else:
                    # we might have introduced unwanted solutions
                    # when multiplying by x**-m; check and keep solutions
                    # unless they definitely aren't a solution
                    if sols:
                        result = [s for s in sols if checksol(f, {symbol: s}) is not False]
            else:
                msg = 'CV_2 calculated %d but it should have been other than 0 or 1' % m

        elif strategy == GS_PIECEWISE:
            result = set()
            for expr, cond in f.args:
                candidates = _solve(expr, *symbols)
                if isinstance(cond, bool) or cond.is_Number:
                    if not cond:
                        continue

                    # Only include solutions that do not match the condition
                    # of any of the other pieces.
                    for candidate in candidates:
                        matches_other_piece = False
                        for other_expr, other_cond in f.args:
                            if isinstance(other_cond, bool) \
                               or other_cond.is_Number:
                                continue
                            if bool(other_cond.subs(symbol, candidate)):
                                matches_other_piece = True
                                break
                        if not matches_other_piece:
                            result.add(candidate)
                else:
                    for candidate in candidates:
                        if bool(cond.subs(symbol, candidate)):
                            result.add(candidate)

            result = list(result)

        elif strategy == -1:
            raise ValueError('Could not parse expression %s' % f)

        # this is the fallback for not getting any other solution
        if result is False or strategy == GS_TRANSCENDENTAL:
            # reject any result that makes any dens affirmatively 0,
            # if in doubt, keep it
            soln = tsolve(f_num, symbol)
            dens = denoms(f, x=symbols)
            if not dens:
                result = soln
            else:
                result = [s for s in soln if all(not checksol(den, {symbol: s}) for den in dens)]

        if result is False:
            raise NotImplementedError(msg + "\nNo algorithms are implemented to solve equation %s" % f)

        if flags.get('simplified', True) and strategy != GS_RATIONAL:
            result = map(simplify, result)

        return result
    else:
        if not f:
            return []
        else:
            # Create a swap dictionary for storing the passed symbols to be
            # solved for, so that they may be swapped back.
            if symbol_swapped:
                swap_dict = zip(symbols, symbols_new)
                f = [fi.subs(swap_dict) for fi in f]
                symbols = symbols_new

            polys = []

            for g in f:

                poly = g.as_poly(*symbols, extension=True)

                if poly is not None:
                    polys.append(poly)
                else:
                    raise NotImplementedError()

            if all(p.is_linear for p in polys):
                n, m = len(f), len(symbols)
                matrix = zeros((n, m + 1))

                for i, poly in enumerate(polys):
                    for monom, coeff in poly.terms():
                        try:
                            j = list(monom).index(1)
                            matrix[i, j] = coeff
                        except ValueError:
                            matrix[i, m] = -coeff

                # a dictionary of symbols: values or None
                soln = solve_linear_system(matrix, *symbols, **flags)
                # Use swap_dict to ensure we return the same type as what was
                # passed; this is not necessary in the poly-system case which
                # only supports zero-dimensional systems
                if symbol_swapped and soln:
                        soln = dict([(swap_back_dict[k],
                                      v.subs(swap_back_dict))
                                      for k, v in soln.iteritems()])
                return soln
            else:
                # a list of tuples, T, where T[i] [j] corresponds to the ith solution for symbols[j]
                return solve_poly_system(polys)
Beispiel #29
0
def test_hacky_inequalities():
    assert reduce_inequalities(x + y < 1, symbols=[x]) == (x < 1 - y)
    assert reduce_inequalities(x + y >= 1, symbols=[x]) == (x >= 1 - y)
    assert reduce_inequalities(Eq(0, x - y), symbols=[x]) == Eq(x, y)
    assert reduce_inequalities(Ne(0, x - y), symbols=[x]) == Ne(x, y)
Beispiel #30
0
def test_reduce_inequalities_multivariate():
    assert reduce_inequalities([Ge(x**2, 1), Ge(y**2, 1)]) == \
        And(And(Or(Le(re(x), -1), Le(1, re(x))), Eq(im(x), 0)),
            And(Or(Le(re(y), -1), Le(1, re(y))), Eq(im(y), 0)))
Beispiel #31
0
def test_reduce_inequalities_assume():
    assert reduce_inequalities(
        [Le(x**2, 1), Q.real(x)]) == And(Le(-1, x), Le(x, 1))
    assert reduce_inequalities(
        [Le(x**2, 1)], Q.real(x)) == And(Le(-1, x), Le(x, 1))
Beispiel #32
0
def test_reduce_inequalities_general():
    assert reduce_inequalities(Ge(sqrt(2) * x,
                                  1)) == And(sqrt(2) / 2 <= x, x < oo)
    assert reduce_inequalities(PurePoly(x + 1, x) > 0) == And(
        S(-1) < x, x < oo)
Beispiel #33
0
def solve(f, *symbols, **flags):
    """
    Algebraically solves equations and systems of equations.

        Currently supported are:
            - univariate polynomial,
            - transcendental
            - piecewise combinations of the above
            - systems of linear and polynomial equations
            - sytems containing relational expressions.

        Input is formed as:
            f
                - a single Expr or Poly that must be zero,
                - an Equality
                - a Relational expression or boolean
                - iterable of one or more of the above

            symbols (Symbol, Function or Derivative) specified as
                - none given (all free symbols will be used)
                - single symbol
                - denested list of symbols
                  e.g. solve(f, x, y)
                - ordered iterable of symbols
                  e.g. solve(f, [x, y])

            flags
                - ``simplified``, when False, will not simplify solutions
                                 (default=True except for polynomials of
                                  order 3 or greater)
                - ``warning``, when True, will warn every time a solution can
                               not be checked, or assumptions about a variable
                               can't be verified for a solution.

        The output varies according to the input and can be seen by example:

            >>> from sympy import solve, Poly, Eq, Function, exp
            >>> from sympy.abc import x, y, z, a, b

            o boolean or univariate Relational

                >>> solve(x < 3)
                And(im(x) == 0, re(x) < 3)

            o single expression and single symbol that is in the expression

                >>> solve(x - y, x)
                [y]
                >>> solve(x - 3, x)
                [3]
                >>> solve(Eq(x, 3), x)
                [3]
                >>> solve(Poly(x - 3), x)
                [3]
                >>> solve(x**2 - y**2, x)
                [y, -y]
                >>> solve(x**4 - 1, x)
                [1, -1, -I, I]

            o single expression with no symbol that is in the expression

                >>> solve(3, x)
                []
                >>> solve(x - 3, y)
                []

            o when no symbol is given then all free symbols will be used
              and sorted with default_sort_key and the result will be the
              same as above as if those symbols had been supplied

                >>> solve(x - 3)
                [3]
                >>> solve(x**2 - y**2)
                [y, -y]

            o when a Function or Derivative is given as a symbol, it is isolated
              algebraically and an implicit solution may be obtained

                >>> f = Function('f')
                >>> solve(f(x) - x, f(x))
                [x]
                >>> solve(f(x).diff(x) - f(x) - x, f(x).diff(x))
                [x + f(x)]

            o single expression and more than 1 symbol

                when there is a linear solution
                    >>> solve(x - y**2, x, y)
                    {x: y**2}
                    >>> solve(x**2 - y, x, y)
                    {y: x**2}

                when undetermined coefficients are identified
                    that are linear
                        >>> solve((a + b)*x - b + 2, a, b)
                        {a: -2, b: 2}

                    that are nonlinear
                        >>> solve((a + b)*x - b**2 + 2, a, b)
                        [(-2**(1/2), 2**(1/2)), (2**(1/2), -2**(1/2))]

                if there is no linear solution then the first successful
                attempt for a nonlinear solution will be returned
                    >>> solve(x**2 - y**2, x, y)
                    [y, -y]
                    >>> solve(x**2 - y**2/exp(x), x, y)
                    [x*exp(x/2), -x*exp(x/2)]

            o iterable of one or more of the above

                involving relationals or bools
                    >>> solve([x < 3, x - 2])
                    And(im(x) == 0, re(x) == 2)
                    >>> solve([x > 3, x - 2])
                    False

                when the system is linear
                    with a solution
                        >>> solve([x - 3], x)
                        {x: 3}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y)
                        {x: -3, y: 1}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y, z)
                        {x: -3, y: 1}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - z), z, x, y)
                        {x: -5*y + 2, z: 21*y - 6}

                    without a solution
                        >>> solve([x + 3, x - 3])

                when the system is not linear
                    >>> solve([x**2 + y -2, y**2 - 4], x, y)
                    [(-2, -2), (0, 2), (0, 2), (2, -2)]

                Warning: there is a possibility of obtaining ambiguous results
                if no symbols are given for a nonlinear system of equations or
                are given as a set since the symbols are not presently reported
                with the solution. A warning will be issued in this situation.
                    >>> solve([x - 2, x**2 + y])
                    <BLANKLINE>
                        For nonlinear systems of equations, symbols should be
                        given as a list so as to avoid ambiguity in the results.
                        solve sorted the symbols as [x, y]
                    [(2, -4)]

                    >>> solve([x - 2, x**2 + f(x)], set([f(x), x]))
                    <BLANKLINE>
                        For nonlinear systems of equations, symbols should be
                        given as a list so as to avoid ambiguity in the results.
                        solve sorted the symbols as [x, f(x)]
                    [(2, -4)]

                If two variables (or more) don't appear in the result, the assumptions
                can't be checked.
                    >>> solve(z**2*x**2 - z**2*y**2/exp(x), x, y, z, warning=True)
                    <BLANKLINE>
                        Warning: assumptions can't be checked
                        (can't find for which variable equation was solved).
                    [x*exp(x/2), -x*exp(x/2)]

                Presently, assumptions aren't checked either when `solve()` input
                involves relationals or bools.

       See also:
          rsolve() for solving recurrence relationships
          dsolve() for solving differential equations

    """
    # make f and symbols into lists of sympified quantities
    # keeping track of how f was passed since if it is a list
    # a dictionary of results will be returned.
    ###########################################################################
    def sympified_list(w):
        return map(sympify, w if iterable(w) else [w])
    bare_f = not iterable(f)
    ordered_symbols = (symbols and
                       symbols[0] and
                       (isinstance(symbols[0], Symbol) or
                        is_sequence(symbols[0], include=GeneratorType)
                       )
                      )
    f, symbols = (sympified_list(w) for w in [f, symbols])

    # preprocess equation(s)
    ###########################################################################
    for i, fi in enumerate(f):
        if isinstance(fi, Equality):
            f[i] = fi.lhs - fi.rhs
        elif isinstance(fi, Poly):
            f[i] = fi.as_expr()
        elif isinstance(fi, bool) or fi.is_Relational:
            return reduce_inequalities(f, assume=flags.get('assume'))
        # Any embedded piecewise functions need to be brought out to the
        # top level so that the appropriate strategy gets selected.
        f[i] = piecewise_fold(f[i])

    # preprocess symbol(s)
    ###########################################################################
    if not symbols:
        # get symbols from equations or supply dummy symbols so solve(3) behaves
        # like solve(3, x).
        symbols = set([])
        for fi in f:
            symbols |= fi.free_symbols or set([Dummy()])
        ordered_symbols = False
    elif len(symbols) == 1 and iterable(symbols[0]):
        symbols = symbols[0]
    if not ordered_symbols:
        # we do this to make the results returned canonical in case f
        # contains a system of nonlinear equations; all other cases should
        # be unambiguous
        symbols = sorted(symbols, key=lambda i: i.sort_key())

    # we can solve for Function and Derivative instances by replacing them
    # with Dummy symbols
    symbols_new = []
    symbol_swapped = False
    symbols_passed = list(symbols)

    for i, s in enumerate(symbols):
        if s.is_Symbol:
            s_new = s
        elif s.is_Function:
            symbol_swapped = True
            s_new = Dummy('F%d' % i)
        elif s.is_Derivative:
            symbol_swapped = True
            s_new = Dummy('D%d' % i)
        else:
            msg = 'expected Symbol, Function or Derivative but got %s'
            raise TypeError(msg % type(s))
        symbols_new.append(s_new)

    if symbol_swapped:
        swap_back_dict = dict(zip(symbols_new, symbols))
        swap_dict = zip(symbols, symbols_new)
        f = [fi.subs(swap_dict) for fi in f]
        symbols = symbols_new

    #
    # try to get a solution
    ###########################################################################
    if bare_f:
        # pass f the way it was passed to solve; if it wasn't a list then
        # a list of solutions will be returned, otherwise a dictionary is
        # going to be returned
        f = f[0]
    solution = _solve(f, *symbols, **flags)

    #
    # postprocessing
    ###########################################################################
    # Restore original Functions and Derivatives if a dictionary is returned.
    # This is not necessary for
    #   - the single equation, single unknown case
    #     since the symbol will have been removed from the solution;
    #   - the nonlinear poly_system since that only support zero-dimensional
    #     systems and those results come back as a list
    if symbol_swapped and type(solution) is dict:
            solution = dict([(swap_back_dict[k], v.subs(swap_back_dict))
                              for k, v in solution.iteritems()])
    # warn if ambiguous results are being obtained
    # XXX agree on how to make this unambiguous
    # see issue 2405 for logic in how Polys chooses ordering and
    # for discussion of what to return see http://groups.google.com/group/sympy
    #                           Apr 18, 2011 posting 'using results from solve'
    elif (not ordered_symbols and
          len(symbols) > 1 and
          solution and
          is_sequence(solution) and
          is_sequence(solution[0]) and
          any(len(set(s)) > 1 for s in solution)
         ):
        msg = ('\n\tFor nonlinear systems of equations, symbols should be' +
               '\n\tgiven as a list so as to avoid ambiguity in the results.' +
               '\n\tsolve sorted the symbols as %s')
        if symbol_swapped:
            from itertools import izip
            tmp = izip(*swap_dict) # separate for the benefit of 2to3
            print msg % list(tmp.next())
        else:
            print msg % symbols

    # Get assumptions about symbols, to filter solutions.
    # Note that if assumptions about a solution can't be verified, it is still returned.
    # XXX: Currently, there are some cases which are not handled,
    # see issue 2098 comment 13: http://code.google.com/p/sympy/issues/detail?id=2098#c13.
    warn = flags.get('warning', False)
    if type(solution) is list:
        if solution:
            unchecked = []
            filtered = []
            if type(solution[0]) is tuple:
                for sol in solution:
                    full_check = True
                    for symb, val in zip(symbols, sol):
                        test = check_assumptions(val, **symb.assumptions0)
                        if test is None:
                            full_check = False
                        if test is False: # not None nor True
                            break
                    if test is not False:
                        filtered.append(sol)
                    if not full_check:
                        unchecked.append(sol)
                solution = filtered
            else:
                if len(symbols) != 1: # find which one was solved for
                    symbols = list(f.free_symbols - set.union(*(s.free_symbols for s in solution)))
                if len(symbols) == 1:
                    for sol in solution:
                        test = check_assumptions(sol, **symbols[0].assumptions0)
                        if test is None:
                            unchecked.append(sol)
                        if test is not False: # None or True
                            filtered.append(sol)
                    solution = filtered
                else:
                    if warn:
                        print("\n\tWarning: assumptions can't be checked"
                              "\n\t(can't find for which variable equation was solved).")
            if warn and unchecked:
                print("\n\tWarning: assumptions concerning following solution(s) can't be checked:"
                      + '\n\t' + ', '.join(str(s) for s in unchecked))

    elif type(solution) is dict:
        full_check = True
        for symb, val in solution.iteritems():
            test = check_assumptions(val, **symb.assumptions0)
            if test is None:
                full_check = False
            if test is False: # not None nor True
                solution = None
                break

        if warn and not full_check:
            print("\n\tWarning: assumptions concerning solution can't be checked.")
    elif isinstance(solution, (Relational, And, Or)):
        assert len(symbols) == 1
        if warn and symbols[0].assumptions0:
            print("\n\tWarning: assumptions about variable '%s' are not handled currently." %symbols[0])
        # TODO: check also variable assumptions for inequalities
    elif solution is not None:
        raise TypeError('Unrecognized solution') # improve the checker to handle this

    #
    # done
    ###########################################################################

    return solution
Beispiel #34
0
def test_N3():
    with assuming(Q.real(x)):
        assert reduce_inequalities(abs(x) < 1) is And(Lt(-1, x), Lt(x, 1))
Beispiel #35
0
def test_hacky_inequalities():
    assert reduce_inequalities(x + y < 1, symbols=[x]) == (x < 1 - y)
    assert reduce_inequalities(x + y >= 1, symbols=[x]) == (x >= 1 - y)
Beispiel #36
0
def test_reduce_inequalities_boolean():
    assert reduce_inequalities([Eq(x**2, 0), True]) == Eq(x, 0)
    assert reduce_inequalities([Eq(x**2, 0), False]) == False
Beispiel #37
0
def _solve(f, *symbols, **flags):
    """Solves equations and systems of equations.

       Currently supported are univariate polynomial, transcendental
       equations, piecewise combinations thereof and systems of linear
       and polynomial equations.  Input is formed as a single expression
       or an equation,  or an iterable container in case of an equation
       system.  The type of output may vary and depends heavily on the
       input. For more details refer to more problem specific functions.

       By default all solutions are simplified to make the output more
       readable. If this is not the expected behavior (e.g., because of
       speed issues) set simplified=False in function arguments.

       To solve equations and systems of equations like recurrence relations
       or differential equations, use rsolve() or dsolve(), respectively.

       >>> from sympy import I, solve
       >>> from sympy.abc import x, y

       Solve a polynomial equation:

       >>> solve(x**4-1, x)
       [1, -1, -I, I]

       Solve a linear system:

       >>> solve((x+5*y-2, -3*x+6*y-15), x, y)
       {x: -3, y: 1}

    """
    def sympified_list(w):
        return map(sympify, iff(isinstance(w, (list, tuple, set)), w, [w]))

    # make f and symbols into lists of sympified quantities
    # keeping track of how f was passed since if it is a list
    # a dictionary of results will be returned.
    bare_f = not iterable(f)
    f, symbols = (sympified_list(w) for w in [f, symbols])

    for i, fi in enumerate(f):
        if isinstance(fi, Equality):
            f[i] = fi.lhs - fi.rhs
        elif isinstance(fi, Poly):
            f[i] = fi.as_expr()
        elif isinstance(fi, bool) or fi.is_Relational:
            return reduce_inequalities(f, assume=flags.get('assume'))

    if not symbols:
        #get symbols from equations or supply dummy symbols since
        #solve(3,x) returns []...though it seems that it should raise some sort of error TODO
        symbols = set([])
        for fi in f:
            symbols |= fi.free_symbols or set([Dummy('x')])
        symbols = list(symbols)
        symbols.sort(key=Basic.sort_key)

    if len(symbols) == 1:
        if isinstance(symbols[0], (list, tuple, set)):
            symbols = symbols[0]

    result = list()

    # Begin code handling for Function and Derivative instances
    # Basic idea:  store all the passed symbols in symbols_passed, check to see
    # if any of them are Function or Derivative types, if so, use a dummy
    # symbol in their place, and set symbol_swapped = True so that other parts
    # of the code can be aware of the swap.  Once all swapping is done, the
    # continue on with regular solving as usual, and swap back at the end of
    # the routine, so that whatever was passed in symbols is what is returned.
    symbols_new = []
    symbol_swapped = False

    symbols_passed = list(symbols)

    for i, s in enumerate(symbols):
        if s.is_Symbol:
            s_new = s
        elif s.is_Function:
            symbol_swapped = True
            s_new = Dummy('F%d' % i)
        elif s.is_Derivative:
            symbol_swapped = True
            s_new = Dummy('D%d' % i)
        else:
            raise TypeError('not a Symbol or a Function')
        symbols_new.append(s_new)

        if symbol_swapped:
            swap_back_dict = dict(zip(symbols_new, symbols))
    # End code for handling of Function and Derivative instances

    if bare_f:
        f = f[0]

        # Create a swap dictionary for storing the passed symbols to be solved
        # for, so that they may be swapped back.
        if symbol_swapped:
            swap_dict = zip(symbols, symbols_new)
            f = f.subs(swap_dict)
            symbols = symbols_new

        # Any embedded piecewise functions need to be brought out to the
        # top level so that the appropriate strategy gets selected.
        f = piecewise_fold(f)

        if len(symbols) != 1:
            soln = None
            free = f.free_symbols
            ex = free - set(symbols)
            if len(ex) == 1:
                ex = ex.pop()
                try:
                    # may come back as dict or list (if non-linear)
                    soln = solve_undetermined_coeffs(f, symbols, ex)
                except NotImplementedError:
                    pass
            if soln is None:
                n, d = solve_linear(f, x=symbols)
                if n.is_Symbol:
                    soln = {n: cancel(d)}
            if soln:
                if symbol_swapped and isinstance(soln, dict):
                    return dict([(swap_back_dict[k], v.subs(swap_back_dict))
                                 for k, v in soln.iteritems()])
                return soln

        symbol = symbols[0]

        # first see if it really depends on symbol and whether there
        # is a linear solution
        f_num, sol = solve_linear(f, x=symbols)
        if not symbol in f_num.free_symbols:
            return []
        elif f_num.is_Symbol:
            return [cancel(sol)]

        strategy = guess_solve_strategy(f, symbol)
        result = False  # no solution was obtained

        if strategy == GS_POLY:
            poly = f.as_poly(symbol)
            if poly is None:
                msg = "Cannot solve equation %s for %s" % (f, symbol)
            else:
                # for cubics and quartics, if the flag wasn't set, DON'T do it
                # by default since the results are quite long. Perhaps one could
                # base this decision on a certain crtical length of the roots.
                if poly.degree() > 2:
                    flags['simplified'] = flags.get('simplified', False)
                result = roots(poly, cubics=True, quartics=True).keys()

        elif strategy == GS_RATIONAL:
            P, _ = f.as_numer_denom()
            dens = denoms(f, x=symbols)
            # reject any result that makes Q affirmatively 0;
            # if in doubt, keep it
            try:
                soln = _solve(P, symbol, **flags)
            except NotImplementedError:
                msg = "Cannot solve equation %s for %s" % (P, symbol)
                result = []
            else:
                if dens:
                    result = [
                        s for s in soln
                        if all(not checksol(den, {symbol: s}) for den in dens)
                    ]
                else:
                    result = soln

        elif strategy == GS_POLY_CV_1:
            args = list(f.args)
            if isinstance(f, Pow):
                result = _solve(args[0], symbol, **flags)
            elif isinstance(f, Add):
                # we must search for a suitable change of variables
                # collect exponents
                exponents_denom = list()
                for arg in args:
                    if isinstance(arg, Pow):
                        exponents_denom.append(arg.exp.q)
                    elif isinstance(arg, Mul):
                        for mul_arg in arg.args:
                            if isinstance(mul_arg, Pow):
                                exponents_denom.append(mul_arg.exp.q)
                assert len(exponents_denom) > 0
                if len(exponents_denom) == 1:
                    m = exponents_denom[0]
                else:
                    # get the LCM of the denominators
                    m = reduce(ilcm, exponents_denom)
                # x -> y**m.
                # we assume positive for simplification purposes
                t = Dummy('t', positive=True)
                f_ = f.subs(symbol, t**m)
                if guess_solve_strategy(f_, t) != GS_POLY:
                    msg = "Could not convert to a polynomial equation: %s" % f_
                    result = []
                else:
                    soln = [s**m for s in _solve(f_, t)]
                    # we might have introduced solutions from another branch
                    # when changing variables; check and keep solutions
                    # unless they definitely aren't a solution
                    result = [
                        s for s in soln
                        if checksol(f, {symbol: s}) is not False
                    ]

            elif isinstance(f, Mul):
                result = []
                for m in f.args:
                    result.extend(_solve(m, symbol, **flags) or [])

        elif strategy == GS_POLY_CV_2:
            m = 0
            args = list(f.args)
            if isinstance(f, Add):
                for arg in args:
                    if isinstance(arg, Pow):
                        m = min(m, arg.exp)
                    elif isinstance(arg, Mul):
                        for mul_arg in arg.args:
                            if isinstance(mul_arg, Pow):
                                m = min(m, mul_arg.exp)
            elif isinstance(f, Mul):
                for mul_arg in args:
                    if isinstance(mul_arg, Pow):
                        m = min(m, mul_arg.exp)

            if m and m != 1:
                f_ = simplify(f * symbol**(-m))
                try:
                    sols = _solve(f_, symbol)
                except NotImplementedError:
                    msg = 'Could not solve %s for %s' % (f_, symbol)
                else:
                    # we might have introduced unwanted solutions
                    # when multiplying by x**-m; check and keep solutions
                    # unless they definitely aren't a solution
                    if sols:
                        result = [
                            s for s in sols
                            if checksol(f, {symbol: s}) is not False
                        ]
            else:
                msg = 'CV_2 calculated %d but it should have been other than 0 or 1' % m

        elif strategy == GS_PIECEWISE:
            result = set()
            for expr, cond in f.args:
                candidates = _solve(expr, *symbols)
                if isinstance(cond, bool) or cond.is_Number:
                    if not cond:
                        continue

                    # Only include solutions that do not match the condition
                    # of any of the other pieces.
                    for candidate in candidates:
                        matches_other_piece = False
                        for other_expr, other_cond in f.args:
                            if isinstance(other_cond, bool) \
                               or other_cond.is_Number:
                                continue
                            if bool(other_cond.subs(symbol, candidate)):
                                matches_other_piece = True
                                break
                        if not matches_other_piece:
                            result.add(candidate)
                else:
                    for candidate in candidates:
                        if bool(cond.subs(symbol, candidate)):
                            result.add(candidate)

            result = list(result)

        elif strategy == -1:
            raise ValueError('Could not parse expression %s' % f)

        # this is the fallback for not getting any other solution
        if result is False or strategy == GS_TRANSCENDENTAL:
            # reject any result that makes any dens affirmatively 0,
            # if in doubt, keep it
            soln = tsolve(f_num, symbol)
            dens = denoms(f, x=symbols)
            if not dens:
                result = soln
            else:
                result = [
                    s for s in soln
                    if all(not checksol(den, {symbol: s}) for den in dens)
                ]

        if result is False:
            raise NotImplementedError(
                msg +
                "\nNo algorithms are implemented to solve equation %s" % f)

        if flags.get('simplified', True) and strategy != GS_RATIONAL:
            result = map(simplify, result)

        return result
    else:
        if not f:
            return []
        else:
            # Create a swap dictionary for storing the passed symbols to be
            # solved for, so that they may be swapped back.
            if symbol_swapped:
                swap_dict = zip(symbols, symbols_new)
                f = [fi.subs(swap_dict) for fi in f]
                symbols = symbols_new

            polys = []

            for g in f:

                poly = g.as_poly(*symbols, extension=True)

                if poly is not None:
                    polys.append(poly)
                else:
                    raise NotImplementedError()

            if all(p.is_linear for p in polys):
                n, m = len(f), len(symbols)
                matrix = zeros((n, m + 1))

                for i, poly in enumerate(polys):
                    for monom, coeff in poly.terms():
                        try:
                            j = list(monom).index(1)
                            matrix[i, j] = coeff
                        except ValueError:
                            matrix[i, m] = -coeff

                # a dictionary of symbols: values or None
                soln = solve_linear_system(matrix, *symbols, **flags)
                # Use swap_dict to ensure we return the same type as what was
                # passed; this is not necessary in the poly-system case which
                # only supports zero-dimensional systems
                if symbol_swapped and soln:
                    soln = dict([(swap_back_dict[k], v.subs(swap_back_dict))
                                 for k, v in soln.iteritems()])
                return soln
            else:
                # a list of tuples, T, where T[i] [j] corresponds to the ith solution for symbols[j]
                return solve_poly_system(polys)
Beispiel #38
0
def test_reduce_inequalities_multivariate():
    assert reduce_inequalities([Ge(x**2, 1), Ge(y**2, 1)]) == And(
        Or(And(Le(1, x), Lt(x, oo)), And(Le(x, -1), Lt(-oo, x))),
        Or(And(Le(1, y), Lt(y, oo)), And(Le(y, -1), Lt(-oo, y))))
Beispiel #39
0
def test_reduce_inequalities_multivariate():
    assert reduce_inequalities([Ge(x**2, 1), Ge(y**2, 1)]) == And(
        Or(And(Le(1, x), Lt(x, oo)), And(Le(x, -1), Lt(-oo, x))),
        Or(And(Le(1, y), Lt(y, oo)), And(Le(y, -1), Lt(-oo, y))))
Beispiel #40
0
def test_reduce_inequalities_errors():
    raises(NotImplementedError, lambda: reduce_inequalities(Ge(sin(x) + x, 1)))
    raises(NotImplementedError, lambda: reduce_inequalities(Ge(x**2*y + y, 1)))
Beispiel #41
0
def test__solve_inequalities():
    assert reduce_inequalities(x + y < 1, symbols=[x]) == (x < 1 - y)
    assert reduce_inequalities(x + y >= 1,
                               symbols=[x]) == (x < oo) & (x >= -y + 1)
    assert reduce_inequalities(Eq(0, x - y), symbols=[x]) == Eq(x, y)
    assert reduce_inequalities(Ne(0, x - y), symbols=[x]) == Ne(x, y)
Beispiel #42
0
def test_issue_6343():
    eq = -3*x**2/2 - 45*x/4 + S(33)/2 > 0
    assert reduce_inequalities(eq) == \
        And(x < -S(15)/4 + sqrt(401)/4, -sqrt(401)/4 - S(15)/4 < x)
def test_reduce_inequalities_boolean():
    x = Symbol('x')

    assert reduce_inequalities([Eq(x**2, 0),
                                True]) == And(Eq(re(x), 0), Eq(im(x), 0))
    assert reduce_inequalities([Eq(x**2, 0), False]) is False
Beispiel #44
0
def test_issue_8545():
    eq = 1 - x - abs(1 - x)
    ans = And(Lt(1, x), Lt(x, oo))
    assert reduce_abs_inequality(eq, '<', x) == ans
    eq = 1 - x - sqrt((1 - x)**2)
    assert reduce_inequalities(eq < 0) == ans
Beispiel #45
0
def test_reduce_inequalities_boolean():
    assert reduce_inequalities(
        [Eq(x**2, 0), True]) == Eq(x, 0)
    assert reduce_inequalities([Eq(x**2, 0), False]) == False
Beispiel #46
0
def test_reduce_inequalities_multivariate():
    assert reduce_inequalities([Ge(x**2, 1), Ge(y**2, 1)]) == \
        And(And(Or(Le(re(x), -1), Ge(re(x), 1)), Eq(im(x), 0)),
            And(Or(Le(re(y), -1), Ge(re(y), 1)), Eq(im(y), 0)))
def test_hacky_inequalities():
    x = Symbol('x')
    y = Symbol('y')

    assert reduce_inequalities(x + y < 1, symbols=[x]) == (x < 1 - y)
    assert reduce_inequalities(x + y >= 1, symbols=[x]) == (x >= 1 - y)
Beispiel #48
0
def test_reduce_inequalities_boolean():
    assert reduce_inequalities([Eq(x**2, 0), True]) == Eq(x, 0)
    assert reduce_inequalities([Eq(x**2, 0), False]) == False
    assert reduce_inequalities(x**2 >= 0) is S.true  # issue 10196
Beispiel #49
0
def test_hacky_inequalities():
    assert reduce_inequalities(x + y < 1, symbols=[x]) == (x < 1 - y)
    assert reduce_inequalities(x + y >= 1, symbols=[x]) == (x >= 1 - y)
Beispiel #50
0
def test_reduce_inequalities_errors():
    raises(NotImplementedError, lambda: reduce_inequalities(Ge(sin(x) + x, 1)))
    raises(NotImplementedError,
           lambda: reduce_inequalities(Ge(x**2 * y + y, 1)))
Beispiel #51
0
 def _handle_irel(self, x, handler):
     """Return either None (if the conditions of self depend only on x) else
     a Piecewise expression whose expressions (handled by the handler that
     was passed) are paired with the governing x-independent relationals,
     e.g. Piecewise((A, a(x) & b(y)), (B, c(x) | c(y)) ->
     Piecewise(
         (handler(Piecewise((A, a(x) & True), (B, c(x) | True)), b(y) & c(y)),
         (handler(Piecewise((A, a(x) & True), (B, c(x) | False)), b(y)),
         (handler(Piecewise((A, a(x) & False), (B, c(x) | True)), c(y)),
         (handler(Piecewise((A, a(x) & False), (B, c(x) | False)), True))
     """
     # identify governing relationals
     rel = self.atoms(Relational)
     irel = list(ordered([r for r in rel if x not in r.free_symbols
         and r not in (S.true, S.false)]))
     if irel:
         args = {}
         exprinorder = []
         for truth in product((1, 0), repeat=len(irel)):
             reps = dict(zip(irel, truth))
             # only store the true conditions since the false are implied
             # when they appear lower in the Piecewise args
             if 1 not in truth:
                 cond = None  # flag this one so it doesn't get combined
             else:
                 andargs = Tuple(*[i for i in reps if reps[i]])
                 free = list(andargs.free_symbols)
                 if len(free) == 1:
                     from sympy.solvers.inequalities import (
                         reduce_inequalities, _solve_inequality)
                     try:
                         t = reduce_inequalities(andargs, free[0])
                         # ValueError when there are potentially
                         # nonvanishing imaginary parts
                     except (ValueError, NotImplementedError):
                         # at least isolate free symbol on left
                         t = And(*[_solve_inequality(
                             a, free[0], linear=True)
                             for a in andargs])
                 else:
                     t = And(*andargs)
                 if t is S.false:
                     continue  # an impossible combination
                 cond = t
             expr = handler(self.xreplace(reps))
             if isinstance(expr, self.func) and len(expr.args) == 1:
                 expr, econd = expr.args[0]
                 cond = And(econd, True if cond is None else cond)
             # the ec pairs are being collected since all possibilities
             # are being enumerated, but don't put the last one in since
             # its expr might match a previous expression and it
             # must appear last in the args
             if cond is not None:
                 args.setdefault(expr, []).append(cond)
                 # but since we only store the true conditions we must maintain
                 # the order so that the expression with the most true values
                 # comes first
                 exprinorder.append(expr)
         # convert collected conditions as args of Or
         for k in args:
             args[k] = Or(*args[k])
         # take them in the order obtained
         args = [(e, args[e]) for e in uniq(exprinorder)]
         # add in the last arg
         args.append((expr, True))
         # if any condition reduced to True, it needs to go last
         # and there should only be one of them or else the exprs
         # should agree
         trues = [i for i in range(len(args)) if args[i][1] is S.true]
         if not trues:
             # make the last one True since all cases were enumerated
             e, c = args[-1]
             args[-1] = (e, S.true)
         else:
             assert len(set([e for e, c in [args[i] for i in trues]])) == 1
             args.append(args.pop(trues.pop()))
             while trues:
                 args.pop(trues.pop())
         return Piecewise(*args)
Beispiel #52
0
def test_issue_6343():
    eq = -3 * x**2 / 2 - 45 * x / 4 + S(33) / 2 > 0
    assert reduce_inequalities(eq) == \
        And(x < -S(15)/4 + sqrt(401)/4, -sqrt(401)/4 - S(15)/4 < x)
Beispiel #53
0
def solve(f, *symbols, **flags):
    """
    Algebraically solves equations and systems of equations.

        Currently supported are:
            - univariate polynomial,
            - transcendental
            - piecewise combinations of the above
            - systems of linear and polynomial equations
            - sytems containing relational expressions.

        Input is formed as:
            f
                - a single Expr or Poly that must be zero,
                - an Equality
                - a Relational expression or boolean
                - iterable of one or more of the above

            symbols (Symbol, Function or Derivative) specified as
                - none given (all free symbols will be used)
                - single symbol
                - denested list of symbols
                  e.g. solve(f, x, y)
                - ordered iterable of symbols
                  e.g. solve(f, [x, y])

            flags
                - ``simplified``, when False, will not simplify solutions
                                 (default=True except for polynomials of
                                  order 3 or greater)

        The output varies according to the input and can be seen by example:

            >>> from sympy import solve, Poly, Eq, Function, exp
            >>> from sympy.abc import x, y, z, a, b

            o boolean or univariate Relational

                >>> solve(x < 3)
                And(im(x) == 0, re(x) < 3)

            o single expression and single symbol that is in the expression

                >>> solve(x - y, x)
                [y]
                >>> solve(x - 3, x)
                [3]
                >>> solve(Eq(x, 3), x)
                [3]
                >>> solve(Poly(x - 3), x)
                [3]
                >>> solve(x**2 - y**2, x)
                [y, -y]
                >>> solve(x**4 - 1, x)
                [1, -1, -I, I]

            o single expression with no symbol that is in the expression

                >>> solve(3, x)
                []
                >>> solve(x - 3, y)
                []

            o when no symbol is given then all free symbols will be used
              and sorted with default_sort_key and the result will be the
              same as above as if those symbols had been supplied

                >>> solve(x - 3)
                [3]
                >>> solve(x**2 - y**2)
                [y, -y]

            o when a Function or Derivative is given as a symbol, it is isolated
              algebraically and an implicit solution may be obtained

                >>> f = Function('f')
                >>> solve(f(x) - x, f(x))
                [x]
                >>> solve(f(x).diff(x) - f(x) - x, f(x).diff(x))
                [x + f(x)]

            o single expression and more than 1 symbol

                when there is a linear solution
                    >>> solve(x - y**2, x, y)
                    {x: y**2}
                    >>> solve(x**2 - y, x, y)
                    {y: x**2}

                when undetermined coefficients are identified
                    that are linear
                        >>> solve((a + b)*x - b + 2, a, b)
                        {a: -2, b: 2}

                    that are nonlinear
                        >>> solve((a + b)*x - b**2 + 2, a, b)
                        [(-2**(1/2), 2**(1/2)), (2**(1/2), -2**(1/2))]

                if there is no linear solution then the first successful
                attempt for a nonlinear solution will be returned
                    >>> solve(x**2 - y**2, x, y)
                    [y, -y]
                    >>> solve(x**2 - y**2/exp(x), x, y)
                    [x*exp(x/2), -x*exp(x/2)]

            o iterable of one or more of the above

                involving relationals or bools
                    >>> solve([x < 3, x - 2])
                    And(im(x) == 0, re(x) == 2)
                    >>> solve([x > 3, x - 2])
                    False

                when the system is linear
                    with a solution
                        >>> solve([x - 3], x)
                        {x: 3}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y)
                        {x: -3, y: 1}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y, z)
                        {x: -3, y: 1}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - z), z, x, y)
                        {x: -5*y + 2, z: 21*y - 6}

                    without a solution
                        >>> solve([x + 3, x - 3])

                when the system is not linear
                    >>> solve([x**2 + y -2, y**2 - 4], x, y)
                    [(-2, -2), (0, 2), (0, 2), (2, -2)]

                Warning: there is a possibility of obtaining ambiguous results
                if no symbols are given for a nonlinear system of equations or
                are given as a set since the symbols are not presently reported
                with the solution. A warning will be issued in this situation.
                    >>> solve([x - 2, x**2 + y])
                    <BLANKLINE>
                        For nonlinear systems of equations, symbols should be
                        given as a list so as to avoid ambiguity in the results.
                        solve sorted the symbols as [x, y]
                    [(2, -4)]

                    >>> solve([x - 2, x**2 + f(x)], set([f(x), x]))
                    <BLANKLINE>
                        For nonlinear systems of equations, symbols should be
                        given as a list so as to avoid ambiguity in the results.
                        solve sorted the symbols as [x, f(x)]
                    [(2, -4)]

       See also:
          rsolve() for solving recurrence relationships
          dsolve() for solving differential equations

    """

    # make f and symbols into lists of sympified quantities
    # keeping track of how f was passed since if it is a list
    # a dictionary of results will be returned.
    ###########################################################################
    def sympified_list(w):
        return map(sympify, iff(iterable(w), w, [w]))

    bare_f = not iterable(f)
    ordered_symbols = (symbols and symbols[0] and
                       (isinstance(symbols[0], Symbol)
                        or ordered_iter(symbols[0], include=GeneratorType)))
    f, symbols = (sympified_list(w) for w in [f, symbols])

    # preprocess equation(s)
    ###########################################################################
    for i, fi in enumerate(f):
        if isinstance(fi, Equality):
            f[i] = fi.lhs - fi.rhs
        elif isinstance(fi, Poly):
            f[i] = fi.as_expr()
        elif isinstance(fi, bool) or fi.is_Relational:
            return reduce_inequalities(f, assume=flags.get('assume'))
        # Any embedded piecewise functions need to be brought out to the
        # top level so that the appropriate strategy gets selected.
        f[i] = piecewise_fold(f[i])

    # preprocess symbol(s)
    ###########################################################################
    if not symbols:
        # get symbols from equations or supply dummy symbols so solve(3) behaves
        # like solve(3, x).
        symbols = set([])
        for fi in f:
            symbols |= fi.free_symbols or set([Dummy()])
        ordered_symbols = False
    elif len(symbols) == 1 and iterable(symbols[0]):
        symbols = symbols[0]
    if not ordered_symbols:
        # we do this to make the results returned canonical in case f
        # contains a system of nonlinear equations; all other cases should
        # be unambiguous
        symbols = sorted(symbols, key=lambda i: i.sort_key())

    # we can solve for Function and Derivative instances by replacing them
    # with Dummy symbols
    symbols_new = []
    symbol_swapped = False
    symbols_passed = list(symbols)

    for i, s in enumerate(symbols):
        if s.is_Symbol:
            s_new = s
        elif s.is_Function:
            symbol_swapped = True
            s_new = Dummy('F%d' % i)
        elif s.is_Derivative:
            symbol_swapped = True
            s_new = Dummy('D%d' % i)
        else:
            msg = 'expected Symbol, Function or Derivative but got %s'
            raise TypeError(msg % type(s))
        symbols_new.append(s_new)

    if symbol_swapped:
        swap_back_dict = dict(zip(symbols_new, symbols))
        swap_dict = zip(symbols, symbols_new)
        f = [fi.subs(swap_dict) for fi in f]
        symbols = symbols_new

    #
    # try to get a solution
    ###########################################################################
    if bare_f:
        # pass f the way it was passed to solve; if it wasn't a list then
        # a list of solutions will be returned, otherwise a dictionary is
        # going to be returned
        f = f[0]
    solution = _solve(f, *symbols, **flags)

    #
    # postprocessing
    ###########################################################################
    # Restore original Functions and Derivatives if a dictionary is returned.
    # This is not necessary for
    #   - the single equation, single unknown case
    #     since the symbol will have been removed from the solution;
    #   - the nonlinear poly_system since that only support zero-dimensional
    #     systems and those results come back as a list
    if symbol_swapped and type(solution) is dict:
        solution = dict([(swap_back_dict[k], v.subs(swap_back_dict))
                         for k, v in solution.iteritems()])
    # warn if ambiguous results are being obtained
    # XXX agree on how to make this unambiguous
    # see issue 2405 for logic in how Polys chooses ordering and
    # for discussion of what to return see http://groups.google.com/group/sympy
    #                           Apr 18, 2011 posting 'using results from solve'
    elif (not ordered_symbols and len(symbols) > 1 and solution
          and ordered_iter(solution) and ordered_iter(solution[0])
          and any(len(set(s)) > 1 for s in solution)):
        msg = ('\n\tFor nonlinear systems of equations, symbols should be' +
               '\n\tgiven as a list so as to avoid ambiguity in the results.' +
               '\n\tsolve sorted the symbols as %s')
        print msg % str(
            bool(symbol_swapped) and list(zip(*swap_dict)[0]) or symbols)
    #
    # done
    ###########################################################################
    return solution
Beispiel #54
0
def test_issue_8545():
    eq = 1 - x - abs(1 - x)
    ans = And(Lt(1, x), Lt(x, oo))
    assert reduce_abs_inequality(eq, '<', x) == ans
    eq = 1 - x - sqrt((1 - x)**2)
    assert reduce_inequalities(eq < 0) == ans
Beispiel #55
0
def test_hacky_inequalities():
    assert reduce_inequalities(x + y < 1, symbols=[x]) == (x < 1 - y)
    assert reduce_inequalities(x + y >= 1, symbols=[x]) == (x >= 1 - y)
    assert reduce_inequalities(Eq(0, x - y), symbols=[x]) == Eq(x, y)
    assert reduce_inequalities(Ne(0, x - y), symbols=[x]) == Ne(x, y)
Beispiel #56
0
 def _handle_irel(self, x, handler):
     """Return either None (if the conditions of self depend only on x) else
     a Piecewise expression whose expressions (handled by the handler that
     was passed) are paired with the governing x-independent relationals,
     e.g. Piecewise((A, a(x) & b(y)), (B, c(x) | c(y)) ->
     Piecewise(
         (handler(Piecewise((A, a(x) & True), (B, c(x) | True)), b(y) & c(y)),
         (handler(Piecewise((A, a(x) & True), (B, c(x) | False)), b(y)),
         (handler(Piecewise((A, a(x) & False), (B, c(x) | True)), c(y)),
         (handler(Piecewise((A, a(x) & False), (B, c(x) | False)), True))
     """
     # identify governing relationals
     rel = self.atoms(Relational)
     irel = list(
         ordered([
             r for r in rel
             if x not in r.free_symbols and r not in (S.true, S.false)
         ]))
     if irel:
         args = {}
         exprinorder = []
         for truth in product((1, 0), repeat=len(irel)):
             reps = dict(zip(irel, truth))
             # only store the true conditions since the false are implied
             # when they appear lower in the Piecewise args
             if 1 not in truth:
                 cond = None  # flag this one so it doesn't get combined
             else:
                 andargs = Tuple(*[i for i in reps if reps[i]])
                 free = list(andargs.free_symbols)
                 if len(free) == 1:
                     from sympy.solvers.inequalities import (
                         reduce_inequalities, _solve_inequality)
                     try:
                         t = reduce_inequalities(andargs, free[0])
                         # ValueError when there are potentially
                         # nonvanishing imaginary parts
                     except (ValueError, NotImplementedError):
                         # at least isolate free symbol on left
                         t = And(*[
                             _solve_inequality(a, free[0], linear=True)
                             for a in andargs
                         ])
                 else:
                     t = And(*andargs)
                 if t is S.false:
                     continue  # an impossible combination
                 cond = t
             expr = handler(self.xreplace(reps))
             if isinstance(expr, self.func) and len(expr.args) == 1:
                 expr, econd = expr.args[0]
                 cond = And(econd, True if cond is None else cond)
             # the ec pairs are being collected since all possibilities
             # are being enumerated, but don't put the last one in since
             # its expr might match a previous expression and it
             # must appear last in the args
             if cond is not None:
                 args.setdefault(expr, []).append(cond)
                 # but since we only store the true conditions we must maintain
                 # the order so that the expression with the most true values
                 # comes first
                 exprinorder.append(expr)
         # convert collected conditions as args of Or
         for k in args:
             args[k] = Or(*args[k])
         # take them in the order obtained
         args = [(e, args[e]) for e in uniq(exprinorder)]
         # add in the last arg
         args.append((expr, True))
         # if any condition reduced to True, it needs to go last
         # and there should only be one of them or else the exprs
         # should agree
         trues = [i for i in range(len(args)) if args[i][1] is S.true]
         if not trues:
             # make the last one True since all cases were enumerated
             e, c = args[-1]
             args[-1] = (e, S.true)
         else:
             assert len(set([e for e, c in [args[i] for i in trues]])) == 1
             args.append(args.pop(trues.pop()))
             while trues:
                 args.pop(trues.pop())
         return Piecewise(*args)
Beispiel #57
0
def test__solve_inequalities():
    assert reduce_inequalities(x + y < 1, symbols=[x]) == (x < 1 - y)
    assert reduce_inequalities(x + y >= 1, symbols=[x]) == (x < oo) & (x >= -y + 1)
    assert reduce_inequalities(Eq(0, x - y), symbols=[x]) == Eq(x, y)
    assert reduce_inequalities(Ne(0, x - y), symbols=[x]) == Ne(x, y)
Beispiel #58
0
def solve(f, *symbols, **flags):
    """Solves equations and systems of equations.

       Currently supported are univariate polynomial, transcendental
       equations, piecewise combinations thereof and systems of linear
       and polynomial equations.  Input is formed as a single expression
       or an equation,  or an iterable container in case of an equation
       system.  The type of output may vary and depends heavily on the
       input. For more details refer to more problem specific functions.

       By default all solutions are simplified to make the output more
       readable. If this is not the expected behavior (e.g., because of
       speed issues) set simplified=False in function arguments.

       To solve equations and systems of equations like recurrence relations
       or differential equations, use rsolve() or dsolve(), respectively.

       >>> from sympy import I, solve
       >>> from sympy.abc import x, y

       Solve a polynomial equation:

       >>> solve(x**4-1, x)
       [1, -1, -I, I]

       Solve a linear system:

       >>> solve((x+5*y-2, -3*x+6*y-15), x, y)
       {x: -3, y: 1}

    """

    def sympit(w):
        return map(sympify, iff(isinstance(w, (list, tuple, set)), w, [w]))

    # make f and symbols into lists of sympified quantities
    # keeping track of how f was passed since if it is a list
    # a dictionary of results will be returned.
    bare_f = not isinstance(f, (list, tuple, set))
    f, symbols = (sympit(w) for w in [f, symbols])

    if any(isinstance(fi, bool) or (fi.is_Relational and not fi.is_Equality) for fi in f):
        return reduce_inequalities(f, assume=flags.get("assume"))

    for i, fi in enumerate(f):
        if fi.is_Equality:
            f[i] = fi.lhs - fi.rhs

    if not symbols:
        # get symbols from equations or supply dummy symbols since
        # solve(3,x) returns []...though it seems that it should raise some sort of error TODO
        symbols = set([])
        for fi in f:
            symbols |= fi.atoms(Symbol) or set([Dummy("x")])
        symbols = list(symbols)

    if bare_f:
        f = f[0]
    if len(symbols) == 1:
        if isinstance(symbols[0], (list, tuple, set)):
            symbols = symbols[0]

    result = list()

    # Begin code handling for Function and Derivative instances
    # Basic idea:  store all the passed symbols in symbols_passed, check to see
    # if any of them are Function or Derivative types, if so, use a dummy
    # symbol in their place, and set symbol_swapped = True so that other parts
    # of the code can be aware of the swap.  Once all swapping is done, the
    # continue on with regular solving as usual, and swap back at the end of
    # the routine, so that whatever was passed in symbols is what is returned.
    symbols_new = []
    symbol_swapped = False

    symbols_passed = list(symbols)

    for i, s in enumerate(symbols):
        if s.is_Symbol:
            s_new = s
        elif s.is_Function:
            symbol_swapped = True
            s_new = Dummy("F%d" % i)
        elif s.is_Derivative:
            symbol_swapped = True
            s_new = Dummy("D%d" % i)
        else:
            raise TypeError("not a Symbol or a Function")
        symbols_new.append(s_new)

        if symbol_swapped:
            swap_back_dict = dict(zip(symbols_new, symbols))
    # End code for handling of Function and Derivative instances

    if not isinstance(f, (tuple, list, set)):

        # Create a swap dictionary for storing the passed symbols to be solved
        # for, so that they may be swapped back.
        if symbol_swapped:
            swap_dict = zip(symbols, symbols_new)
            f = f.subs(swap_dict)
            symbols = symbols_new

        # Any embedded piecewise functions need to be brought out to the
        # top level so that the appropriate strategy gets selected.
        f = piecewise_fold(f)

        if len(symbols) != 1:
            result = {}
            for s in symbols:
                result[s] = solve(f, s, **flags)
            if flags.get("simplified", True):
                for s, r in result.items():
                    result[s] = map(simplify, r)
            return result

        symbol = symbols[0]
        strategy = guess_solve_strategy(f, symbol)

        if strategy == GS_POLY:
            poly = f.as_poly(symbol)
            if poly is None:
                raise NotImplementedError("Cannot solve equation " + str(f) + " for " + str(symbol))
            # for cubics and quartics, if the flag wasn't set, DON'T do it
            # by default since the results are quite long. Perhaps one could
            # base this decision on a certain crtical length of the roots.
            if poly.degree > 2:
                flags["simplified"] = flags.get("simplified", False)
            result = roots(poly, cubics=True, quartics=True).keys()

        elif strategy == GS_RATIONAL:
            P, Q = f.as_numer_denom()
            # TODO: check for Q != 0
            result = solve(P, symbol, **flags)

        elif strategy == GS_POLY_CV_1:
            args = list(f.args)
            if isinstance(f, Add):
                # we must search for a suitable change of variable
                # collect exponents
                exponents_denom = list()
                for arg in args:
                    if isinstance(arg, Pow):
                        exponents_denom.append(arg.exp.q)
                    elif isinstance(arg, Mul):
                        for mul_arg in arg.args:
                            if isinstance(mul_arg, Pow):
                                exponents_denom.append(mul_arg.exp.q)
                assert len(exponents_denom) > 0
                if len(exponents_denom) == 1:
                    m = exponents_denom[0]
                else:
                    # get the LCM of the denominators
                    m = reduce(ilcm, exponents_denom)
                # x -> y**m.
                # we assume positive for simplification purposes
                t = Dummy("t", positive=True)
                f_ = f.subs(symbol, t ** m)
                if guess_solve_strategy(f_, t) != GS_POLY:
                    raise NotImplementedError("Could not convert to a polynomial equation: %s" % f_)
                cv_sols = solve(f_, t)
                for sol in cv_sols:
                    result.append(sol ** m)

            elif isinstance(f, Mul):
                for mul_arg in args:
                    result.extend(solve(mul_arg, symbol))

        elif strategy == GS_POLY_CV_2:
            m = 0
            args = list(f.args)
            if isinstance(f, Add):
                for arg in args:
                    if isinstance(arg, Pow):
                        m = min(m, arg.exp)
                    elif isinstance(arg, Mul):
                        for mul_arg in arg.args:
                            if isinstance(mul_arg, Pow):
                                m = min(m, mul_arg.exp)
            elif isinstance(f, Mul):
                for mul_arg in args:
                    if isinstance(mul_arg, Pow):
                        m = min(m, mul_arg.exp)
            f1 = simplify(f * symbol ** (-m))
            result = solve(f1, symbol)
            # TODO: we might have introduced unwanted solutions
            # when multiplied by x**-m

        elif strategy == GS_PIECEWISE:
            result = set()
            for expr, cond in f.args:
                candidates = solve(expr, *symbols)
                if isinstance(cond, bool) or cond.is_Number:
                    if not cond:
                        continue

                    # Only include solutions that do not match the condition
                    # of any of the other pieces.
                    for candidate in candidates:
                        matches_other_piece = False
                        for other_expr, other_cond in f.args:
                            if isinstance(other_cond, bool) or other_cond.is_Number:
                                continue
                            if bool(other_cond.subs(symbol, candidate)):
                                matches_other_piece = True
                                break
                        if not matches_other_piece:
                            result.add(candidate)
                else:
                    for candidate in candidates:
                        if bool(cond.subs(symbol, candidate)):
                            result.add(candidate)

            result = list(result)

        elif strategy == GS_TRANSCENDENTAL:
            # a, b = f.as_numer_denom()
            # Let's throw away the denominator for now. When we have robust
            # assumptions, it should be checked, that for the solution,
            # b!=0.
            result = tsolve(f, *symbols)
        elif strategy == -1:
            raise ValueError("Could not parse expression %s" % f)
        else:
            raise NotImplementedError("No algorithms are implemented to solve equation %s" % f)

        # This symbol swap should not be necessary for the single symbol case: if you've
        # solved for the symbol the it will not appear in the solution. Right now, however
        # ode's are getting solutions for solve (even though they shouldn't be -- see the
        # swap_back test in test_solvers).
        if symbol_swapped:
            result = [ri.subs(swap_back_dict) for ri in result]

        if flags.get("simplified", True) and strategy != GS_RATIONAL:
            return map(simplify, result)
        else:
            return result
    else:
        if not f:
            return {}
        else:
            # Create a swap dictionary for storing the passed symbols to be
            # solved for, so that they may be swapped back.
            if symbol_swapped:
                swap_dict = zip(symbols, symbols_new)
                f = [fi.subs(swap_dict) for fi in f]
                symbols = symbols_new

            polys = []

            for g in f:

                poly = g.as_poly(*symbols)

                if poly is not None:
                    polys.append(poly)
                else:
                    raise NotImplementedError()

            if all(p.is_linear for p in polys):
                n, m = len(f), len(symbols)
                matrix = zeros((n, m + 1))

                for i, poly in enumerate(polys):
                    for monom, coeff in poly.terms():
                        try:
                            j = list(monom).index(1)
                            matrix[i, j] = coeff
                        except ValueError:
                            matrix[i, m] = -coeff

                soln = solve_linear_system(matrix, *symbols, **flags)
            else:
                soln = solve_poly_system(polys)

            # Use swap_dict to ensure we return the same type as what was
            # passed
            if symbol_swapped:
                if isinstance(soln, dict):
                    res = {}
                    for k in soln.keys():
                        res.update({swap_back_dict[k]: soln[k]})
                    return res
                else:
                    return soln
            else:
                return soln
Beispiel #59
0
def test_reduce_inequalities_boolean():
    assert reduce_inequalities(
        [Eq(x**2, 0), True]) == And(Eq(re(x), 0), Eq(im(x), 0))
    assert reduce_inequalities([Eq(x**2, 0), False]) is False