Skip to content

Commit

Permalink
Merge pull request #1856 from smichr/ratineq
Browse files Browse the repository at this point in the history
Added support for rational inequalities (#3528, #3448)
  • Loading branch information
smichr committed Mar 2, 2013
2 parents baa06aa + 17f330a commit 664eab4
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 104 deletions.
86 changes: 52 additions & 34 deletions sympy/solvers/inequalities.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from sympy.assumptions import ask, AppliedPredicate, Q
from sympy.functions import re, im, Abs
from sympy.logic import And
from sympy.polys import Poly
from sympy.polys import Poly, PolynomialError, parallel_poly_from_expr


def solve_poly_inequality(poly, rel):
Expand Down Expand Up @@ -90,22 +90,24 @@ def solve_poly_inequality(poly, rel):
return intervals


def solve_poly_inequalities(polys):
"""Solve a system of polynomial inequalities with rational coefficients.
def solve_rational_inequalities(eqs):
"""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_poly_inequalities
>>> from sympy.solvers.inequalities import solve_rational_inequalities
>>> solve_poly_inequalities([[(Poly(-x + 1, x, domain='ZZ'), '>='),
... (Poly(-x + 1, x, domain='ZZ'), '<=')]])
>>> solve_rational_inequalities([[
... ((Poly(-x + 1), Poly(1, x)), '>='),
... ((Poly(-x + 1), Poly(1, x)), '<=')]])
{1}
>>> solve_poly_inequalities([[(Poly(x, x, domain='ZZ'), '!='),
... (Poly(-x + 1, x, domain='ZZ'), '>=')]])
>>> solve_rational_inequalities([[
... ((Poly(x), Poly(1, x)), '!='),
... ((Poly(-x + 1), Poly(1, x)), '>=')]])
(-oo, 0) U (0, 1]
See Also
Expand All @@ -114,26 +116,38 @@ def solve_poly_inequalities(polys):
"""
result = S.EmptySet

for _polys in polys:
for _eqs in eqs:
global_intervals = None

for poly, rel in _polys:
local_intervals = solve_poly_inequality(poly, rel)
for (numer, denom), rel in _eqs:
numer_intervals = solve_poly_inequality(numer*denom, rel)
denom_intervals = solve_poly_inequality(denom, '==')

if global_intervals is None:
global_intervals = local_intervals
global_intervals = numer_intervals
else:
intervals = []

for local_interval in local_intervals:
for numer_interval in numer_intervals:
for global_interval in global_intervals:
interval = local_interval.intersect(global_interval)
interval = numer_interval.intersect(global_interval)

if interval is not S.EmptySet:
intervals.append(interval)

global_intervals = intervals

intervals = []

for global_interval in global_intervals:
for denom_interval in denom_intervals:
global_interval -= denom_interval

if global_interval is not S.EmptySet:
intervals.append(global_interval)

global_intervals = intervals

if not global_intervals:
break

Expand All @@ -143,28 +157,28 @@ def solve_poly_inequalities(polys):
return result


def reduce_poly_inequalities(exprs, gen, assume=True, relational=True):
"""Reduce a system of polynomial inequalities with rational coefficients.
def reduce_rational_inequalities(exprs, gen, assume=True, relational=True):
"""Reduce a system of rational inequalities with rational coefficients.
Examples
========
>>> from sympy import Poly, Symbol
>>> from sympy.solvers.inequalities import reduce_poly_inequalities
>>> from sympy.solvers.inequalities import reduce_rational_inequalities
>>> x = Symbol('x', real=True)
>>> reduce_poly_inequalities([[x**2 <= 0]], x)
>>> reduce_rational_inequalities([[x**2 <= 0]], x)
x == 0
>>> reduce_poly_inequalities([[x + 2 > 0]], x)
>>> reduce_rational_inequalities([[x + 2 > 0]], x)
-2 < x
"""
exact = True
polys = []
eqs = []

for _exprs in exprs:
_polys = []
_eqs = []

for expr in _exprs:
if isinstance(expr, tuple):
Expand All @@ -175,22 +189,24 @@ def reduce_poly_inequalities(exprs, gen, assume=True, relational=True):
else:
expr, rel = expr, '=='

poly = Poly(expr, gen)
try:
(numer, denom), opt = parallel_poly_from_expr(expr.together().as_numer_denom(), gen)
except PolynomialError:
raise PolynomialError("only polynomials and rational functions are supported in this context")

if not poly.get_domain().is_Exact:
poly, exact = poly.to_exact(), False
if not opt.domain.is_Exact:
numer, denom, exact = numer.to_exact(), denom.to_exact(), False

domain = poly.get_domain()
domain = opt.domain.get_exact()

if not (domain.is_ZZ or domain.is_QQ):
raise NotImplementedError(
"inequality solving is not supported over %s" % domain)
raise NotImplementedError("inequality solving is not supported over %s" % opt.domain)

_polys.append((poly, rel))
_eqs.append(((numer, denom), rel))

polys.append(_polys)
eqs.append(_eqs)

solution = solve_poly_inequalities(polys)
solution = solve_rational_inequalities(eqs)

if not exact:
solution = solution.evalf()
Expand Down Expand Up @@ -285,7 +301,7 @@ def _bottom_up_scan(expr):

inequalities.append([expr] + conds)

return reduce_poly_inequalities(inequalities, gen, assume)
return reduce_rational_inequalities(inequalities, gen, assume)


def reduce_abs_inequalities(exprs, gen, assume=True):
Expand Down Expand Up @@ -316,11 +332,13 @@ def reduce_abs_inequalities(exprs, gen, assume=True):
def _solve_inequality(ie, s):
""" A hacky replacement for solve, since the latter only works for
univariate inequalities. """
from sympy import Poly
if not ie.rel_op in ('>', '>=', '<', '<='):
raise NotImplementedError
expr = ie.lhs - ie.rhs
p = Poly(expr, s)
try:
p = Poly(expr, s)
except PolynomialError:
raise NotImplementedError
if p.degree() != 1:
raise NotImplementedError('%s' % ie)
a, b = p.all_coeffs()
Expand Down Expand Up @@ -413,7 +431,7 @@ def reduce_inequalities(inequalities, assume=True, symbols=[]):
abs_reduced = []

for gen, exprs in poly_part.iteritems():
poly_reduced.append(reduce_poly_inequalities([exprs], gen, assume))
poly_reduced.append(reduce_rational_inequalities([exprs], gen, assume))

for gen, exprs in abs_part.iteritems():
abs_reduced.append(reduce_abs_inequalities(exprs, gen, assume))
Expand Down
Loading

0 comments on commit 664eab4

Please sign in to comment.