Coverage for sympy/solvers/inequalities.py : 96%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
"""Tools for solving inequalities and systems of inequalities. """
"""Solve a polynomial inequality with rational coefficients.
Examples ========
>>> from sympy import Poly >>> from sympy.abc import x >>> from sympy.solvers.inequalities import solve_poly_inequality
>>> solve_poly_inequality(Poly(x, x, domain='ZZ'), '==') [{0}]
>>> solve_poly_inequality(Poly(x**2 - 1, x, domain='ZZ'), '!=') [Interval.open(-oo, -1), Interval.open(-1, 1), Interval.open(1, oo)]
>>> solve_poly_inequality(Poly(x**2 - 1, x, domain='ZZ'), '==') [{-1}, {1}]
See Also ======== solve_poly_inequalities """ raise ValueError( 'For efficiency reasons, `poly` should be a Poly instance') else: raise NotImplementedError( "could not determine truth value of %s" % t)
else: else:
else: raise ValueError("'%s' is not a valid relation" % rel)
0, Interval(left, right, not equal, right_open))
else: 0, Interval(left, right, True, right_open))
0, Interval(S.NegativeInfinity, right, True, right_open))
"""Solve polynomial inequalities with rational coefficients.
Examples ========
>>> from sympy.solvers.inequalities import solve_poly_inequalities >>> from sympy.polys import Poly >>> from sympy.abc import x >>> solve_poly_inequalities((( ... Poly(x**2 - 3), ">"), ( ... Poly(-x**2 + 1), ">"))) Union(Interval.open(-oo, -sqrt(3)), Interval.open(-1, 1), Interval.open(sqrt(3), oo)) """ from sympy import Union return Union(*[solve_poly_inequality(*p) for p in polys])
"""Solve a system of rational inequalities with rational coefficients.
Examples ========
>>> from sympy.abc import x >>> from sympy import Poly >>> from sympy.solvers.inequalities import solve_rational_inequalities
>>> solve_rational_inequalities([[ ... ((Poly(-x + 1), Poly(1, x)), '>='), ... ((Poly(-x + 1), Poly(1, x)), '<=')]]) {1}
>>> solve_rational_inequalities([[ ... ((Poly(x), Poly(1, x)), '!='), ... ((Poly(-x + 1), Poly(1, x)), '>=')]]) Union(Interval.open(-oo, 0), Interval.Lopen(0, 1))
See Also ======== solve_poly_inequality """
"""Reduce a system of rational inequalities with rational coefficients.
Examples ========
>>> from sympy import Poly, Symbol >>> from sympy.solvers.inequalities import reduce_rational_inequalities
>>> x = Symbol('x', real=True)
>>> reduce_rational_inequalities([[x**2 <= 0]], x) Eq(x, 0)
>>> reduce_rational_inequalities([[x + 2 > 0]], x) (-2 < x) & (x < oo) >>> reduce_rational_inequalities([[(x + 2, ">")]], x) (-2 < x) & (x < oo) >>> reduce_rational_inequalities([[x + 2]], x) Eq(x, -2) """
else: else:
numer, denom, rel = S.Zero, S.One, '==' else:
(numer, denom), gen) only polynomials and rational functions are supported in this context. '''))
else:
for i in eqs for ((n, d), _) in i if d.has(gen)]])
"""Reduce an inequality with nested absolute values.
Examples ========
>>> from sympy import Abs, Symbol >>> from sympy.solvers.inequalities import reduce_abs_inequality >>> x = Symbol('x', real=True)
>>> reduce_abs_inequality(Abs(x - 5) - 3, '<', x) (2 < x) & (x < 8)
>>> reduce_abs_inequality(Abs(x + 2)*3 - 13, '<', x) (-19/3 < x) & (x < 7/3)
See Also ========
reduce_abs_inequalities """ raise TypeError(filldedent(''' can't solve inequalities with absolute values containing non-real variables. '''))
else:
else:
else:
"""Reduce a system of inequalities with nested absolute values.
Examples ========
>>> from sympy import Abs, Symbol >>> from sympy.abc import x >>> from sympy.solvers.inequalities import reduce_abs_inequalities >>> x = Symbol('x', real=True)
>>> reduce_abs_inequalities([(Abs(3*x - 5) - 7, '<'), ... (Abs(x + 25) - 13, '>')], x) (-2/3 < x) & (x < 4) & (((-oo < x) & (x < -38)) | ((-12 < x) & (x < oo)))
>>> reduce_abs_inequalities([(Abs(x - 4) + Abs(3*x - 5) - 7, '<')], x) (1/2 < x) & (x < 4)
See Also ========
reduce_abs_inequality """ for expr, rel in exprs ])
"""Solves a real univariate inequality.
Parameters ==========
expr : Relational The target inequality gen : Symbol The variable for which the inequality is solved relational : bool A Relational type output is expected or not domain : Set The domain over which the equation is solved continuous: bool True if expr is known to be continuous over the given domain (and so continuous_domain() doesn't need to be called on it)
Raises ======
NotImplementedError The solution of the inequality cannot be determined due to limitation in `solvify`.
Notes =====
Currently, we cannot solve all the inequalities due to limitations in `solvify`. Also, the solution returned for trigonometric inequalities are restricted in its periodic interval.
See Also ========
solvify: solver returning solveset solutions with solve's output API
Examples ========
>>> from sympy.solvers.inequalities import solve_univariate_inequality >>> from sympy import Symbol, sin, Interval, S >>> x = Symbol('x')
>>> solve_univariate_inequality(x**2 >= 4, x) ((2 <= x) & (x < oo)) | ((x <= -2) & (-oo < x))
>>> solve_univariate_inequality(x**2 >= 4, x, relational=False) Union(Interval(-oo, -2), Interval(2, oo))
>>> domain = Interval(0, S.Infinity) >>> solve_univariate_inequality(x**2 >= 4, x, False, domain) Interval(2, oo)
>>> solve_univariate_inequality(sin(x) > 0, x, relational=False) Interval.open(0, pi)
""" function_range)
# This keeps the function independent of the assumptions about `gen`. # `solveset` makes sure this function is called only when the domain is # real. rv = S.EmptySet return rv if not relational else rv.as_relational(_gen) When gen is real, the relational has a complex part which leads to an invalid comparison like I < 0. '''))
else:
# this might raise ValueError on its own # or it might give None... # in which case we raise ValueError # replace gen with generic x since it's # univariate anyway raise NotImplementedError(filldedent(''' The inequality, %s, cannot be solved using solve_univariate_inequality. ''' % expr.subs(gen, Symbol('x'))))
# this is used to see if gen=x satisfies the # relational by substituting it into the # expanded form and testing against 0, e.g. # if expr = x*(x + 1) < 2 then e = x*(x + 1) - 2 # and expanded_e = x**2 + x - 2; the test is # whether a given value of x satisfies # x**2 + x - 2 < 0 # # expanded_e, expr and gen used from enclosing scope if v.is_real is False: return S.false else: v = v.n(2) if v.is_comparable: return expr.func(v, 0) # not comparable or couldn't be evaluated raise NotImplementedError( 'relationship did not evaluate: %s' % r)
FiniteSet(domain.inf, domain.sup)) # remove points that are not between inf and sup of domain discontinuities))).intersection( Interval(domain.inf, domain.sup, domain.inf not in domain, domain.sup not in domain)) else: # there were some roots that weren't known # to be real raise NotImplementedError raise NotImplementedError raise NotImplementedError('sorting of these roots is not supported')
# If expr contains imaginary coefficients, only take real # values of x for which the imaginary part is 0 else: im_sol += Interval.Ropen(start, z) else:
%s contains imaginary parts which cannot be made 0 for any value of %s satisfying the inequality, leading to relations like I < 0. ''' % (expr.subs(gen, _gen), _gen)))
else: else: # it's a solution
else: (Union(*sol_sets)), make_real, _domain).subs(gen, _gen)
"""Return a point between start and end""" else: end.is_infinite and end.is_positive is None): start.is_infinite and start.is_positive): # if possible, use a multiple of self which has # better behavior when checking assumptions than # an expression obtained by adding or subtracting 1 else: else:
"""Return the inequality with s isolated on the left, if possible. If the relationship is non-linear, a solution involving And or Or may be returned. False or True are returned if the relationship is never True or always True, respectively.
If `linear` is True (default is False) an `s`-dependent expression will be isoloated on the left, if possible but it will not be solved for `s` unless the expression is linear in `s`. Furthermore, only "safe" operations which don't change the sense of the relationship are applied: no division by an unsigned value is attempted unless the relationship involves Eq or Ne and no division by a value not known to be nonzero is ever attempted.
Examples ========
>>> from sympy import Eq, Symbol >>> from sympy.solvers.inequalities import _solve_inequality as f >>> from sympy.abc import x, y
For linear expressions, the symbol can be isolated:
>>> f(x - 2 < 0, x) x < 2 >>> f(-x - 6 < x, x) x > -3
Sometimes nonlinear relationships will be False
>>> f(x**2 + 4 < 0, x) False
Or they may involve more than one region of values:
>>> f(x**2 - 4 < 0, x) (-2 < x) & (x < 2)
To restrict the solution to a relational, set linear=True and only the x-dependent portion will be isolated on the left:
>>> f(x**2 - 4 < 0, x, linear=True) x**2 < 4
Division of only nonzero quantities is allowed, so x cannot be isolated by dividing by y:
>>> y.is_nonzero is None # it is unknown whether it is 0 or not True >>> f(x*y < 1, x) x*y < 1
And while an equality (or unequality) still holds after dividing by a non-zero quantity
>>> nz = Symbol('nz', nonzero=True) >>> f(Eq(x*nz, 1), x) Eq(x, 1/nz)
the sign must be known for other inequalities involving > or <:
>>> f(x*nz <= 1, x) nz*x <= 1 >>> p = Symbol('p', positive=True) >>> f(x*p <= 1, x) x <= 1/p
When there are denominators in the original expression that are removed by expansion, conditions for them will be returned as part of the result:
>>> f(x < x*(2/x - 1), x) (x < 1) & Ne(x, 0) """
# return True or False if ie evaluates when substituting s with # i else None (if unevaluated) or NaN (when there is an error # in evaluating) return v
rv = ie.func(p.as_expr(), 0) # handle in except clause raise NotImplementedError # remove restrictions wrt +/-oo that may have been # applied when using sets to simplify the relationship classify(rv, s, -oo) is S.false): rv = And(-oo < s, rv) else:
# Do a safe inversion of e, moving non-s terms # to the rhs and dividing by a nonzero factor if # the relational is Eq/Ne; for other relationals # the sign must also be positive or negative a.is_negative == a.is_positive == None and # if sign is not known then ie.rel_op not in ('!=', '==')): # reject if not Eq/Ne else:
# return conditions under which the value is # valid, too. # rv is permitting this value but it shouldn't classify(ie, s, i) is not S.true):
# helper for reduce_inequalities
# check for gens using atoms which is more strict than free_symbols to # guard against EX domain which won't be handled by # reduce_rational_inequalities
else: else: raise NotImplementedError(filldedent(''' inequality has more than one symbol of interest. '''))
else: u.has(gen) and ( u.is_Function or u.is_Pow and not u.exp.is_Integer)) else:
"""Reduce a system of inequalities with rational coefficients.
Examples ========
>>> from sympy import sympify as S, Symbol >>> from sympy.abc import x, y >>> from sympy.solvers.inequalities import reduce_inequalities
>>> reduce_inequalities(0 <= x + 3, []) (-3 <= x) & (x < oo)
>>> reduce_inequalities(0 <= x + y*2 - 1, [x]) (x < oo) & (x >= -2*y + 1) """
inequalities cannot contain symbols that are not real. '''))
# make vanilla symbol real for i in gens if i.is_real is None])
# prefilter raise NotImplementedError( "could not determine truth value of %s" % i)
# solve system
# restore original symbols and return |