Repository: sympy/sympy

Issue:
solveset regression: rational inequality with abs()
Solving the inequality `abs((x-1)/(x-5)) <= 1/3` was fixed in #9565. However, with the current Git master the solution `[-1.0, 2.0]` is not found any more:
```python
>>> x = symbols('x', real=True)
>>> from sympy.solvers.solveset import solveset
>>> solveset(abs((x-1)/(x-5)) <= 1/3, domain=S.Reals)
⎧            │x - 1│                    ⎫
⎨x | x ∊ ℝ ∧ ─────── ≤ 0.333333333333333⎬
⎩            │x - 5│                    ⎭
```

FWIW, the similar inequality without `abs()` works:
```python
>>> solveset((x-1)/(x-5) <= 1/3, domain=S.Reals)
[-1.0, 5)
```

This is on `SymPy 1.0.1.dev (Python 2.7.12-64-bit)`.


Discussion:

Patch:
diff --git a/sympy/calculus/util.py b/sympy/calculus/util.py
index cf2cb44fce..773cecbbf4 100644
--- a/sympy/calculus/util.py
+++ b/sympy/calculus/util.py
@@ -1,4 +1,4 @@
-from sympy import Order, S, log, limit, lcm_list, pi
+from sympy import Order, S, log, limit, lcm_list, pi, Abs
 from sympy.core.basic import Basic
 from sympy.core import Add, Mul, Pow
 from sympy.logic.boolalg import And
@@ -57,17 +57,21 @@ def continuous_domain(f, symbol, domain):
 
     try:
         sings = S.EmptySet
-        for atom in f.atoms(Pow):
-            predicate, denom = _has_rational_power(atom, symbol)
-            if predicate and denom == 2:
-                sings = solveset(1/f, symbol, domain)
-                break
+        if f.has(Abs):
+            sings = solveset(1/f, symbol, domain)
         else:
-            sings = Intersection(solveset(1/f, symbol), domain)
+            for atom in f.atoms(Pow):
+                predicate, denom = _has_rational_power(atom, symbol)
+                if predicate and denom == 2:
+                    sings = solveset(1/f, symbol, domain)
+                    break
+            else:
+                sings = Intersection(solveset(1/f, symbol), domain)
+
 
     except:
         raise NotImplementedError("Methods for determining the continuous domains"
-                                  " of this function has not been developed.")
+                                  " of this function have not been developed.")
 
     return domain - sings
 
diff --git a/sympy/solvers/inequalities.py b/sympy/solvers/inequalities.py
index 09e86db36e..3457bc65e3 100644
--- a/sympy/solvers/inequalities.py
+++ b/sympy/solvers/inequalities.py
@@ -379,7 +379,7 @@ def reduce_abs_inequalities(exprs, gen):
         for expr, rel in exprs ])
 
 
-def solve_univariate_inequality(expr, gen, relational=True, domain=S.Reals):
+def solve_univariate_inequality(expr, gen, relational=True, domain=S.Reals, continuous=False):
     """Solves a real univariate inequality.
 
     Parameters
@@ -393,6 +393,9 @@ def solve_univariate_inequality(expr, gen, relational=True, domain=S.Reals):
         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
     ======
@@ -481,8 +484,8 @@ def solve_univariate_inequality(expr, gen, relational=True, domain=S.Reals):
             singularities = []
             for d in denoms(e):
                 singularities.extend(solvify(d, gen, domain))
-
-            domain = continuous_domain(e, gen, domain)
+            if not continuous:
+                domain = continuous_domain(e, gen, domain)
             solns = solvify(e, gen, domain)
 
             if solns is None:
diff --git a/sympy/solvers/solvers.py b/sympy/solvers/solvers.py
index 937955386f..c84f71a9bb 100644
--- a/sympy/solvers/solvers.py
+++ b/sympy/solvers/solvers.py
@@ -2014,7 +2014,7 @@ def solve_linear(lhs, rhs=0, symbols=[], exclude=[]):
             if dnewn_dxi is S.NaN:
                 break
             if xi not in dnewn_dxi.free_symbols:
-                vi = -(newn.subs(xi, 0))/dnewn_dxi
+                vi = -1/dnewn_dxi*(newn.subs(xi, 0))
                 if dens is None:
                     dens = _simple_dens(eq, symbols)
                 if not any(checksol(di, {xi: vi}, minimal=True) is True
diff --git a/sympy/solvers/solveset.py b/sympy/solvers/solveset.py
index f41a769084..fcc5333102 100644
--- a/sympy/solvers/solveset.py
+++ b/sympy/solvers/solveset.py
@@ -31,7 +31,7 @@
 from sympy.solvers.polysys import solve_poly_system
 from sympy.solvers.inequalities import solve_univariate_inequality
 from sympy.utilities import filldedent
-from sympy.calculus.util import periodicity
+from sympy.calculus.util import periodicity, continuous_domain
 from sympy.core.compatibility import ordered, default_sort_key
 
 
@@ -367,7 +367,13 @@ def _solve_as_rational(f, symbol, domain):
     f = together(f, deep=True)
     g, h = fraction(f)
     if not h.has(symbol):
-        return _solve_as_poly(g, symbol, domain)
+        try:
+            return _solve_as_poly(g, symbol, domain)
+        except NotImplementedError:
+            # The polynomial formed from g could end up having
+            # coefficients in a ring over which finding roots
+            # isn't implemented yet, e.g. ZZ[a] for some symbol a
+            return ConditionSet(f, symbol, domain)
     else:
         valid_solns = _solveset(g, symbol, domain)
         invalid_solns = _solveset(h, symbol, domain)
@@ -516,7 +522,7 @@ def _solve_radical(f, symbol, solveset_solver):
         result = Union(*[imageset(Lambda(y, g_y), f_y_sols)
                          for g_y in g_y_s])
 
-    if isinstance(result, Complement):
+    if isinstance(result, Complement) or isinstance(result,ConditionSet):
         solution_set = result
     else:
         f_set = []  # solutions for FiniteSet
@@ -541,10 +547,11 @@ def _solve_abs(f, symbol, domain):
     pattern_match = f.match(p*Abs(q) + r) or {}
     if not pattern_match.get(p, S.Zero).is_zero:
         f_p, f_q, f_r = pattern_match[p], pattern_match[q], pattern_match[r]
+
+        domain = continuous_domain(f_q, symbol, domain)
         q_pos_cond = solve_univariate_inequality(f_q >= 0, symbol,
-                                                 relational=False)
-        q_neg_cond = solve_univariate_inequality(f_q < 0, symbol,
-                                                 relational=False)
+                                                 relational=False, domain=domain, continuous=True)
+        q_neg_cond = q_pos_cond.complement(domain)
 
         sols_q_pos = solveset_real(f_p*f_q + f_r,
                                            symbol).intersect(q_pos_cond)
@@ -643,7 +650,6 @@ def _solveset(f, symbol, domain, _check=False):
     if f.is_Add:
         a, h = f.as_independent(symbol)
         m, h = h.as_independent(symbol, as_Add=False)
-
         if m not in set([S.ComplexInfinity, S.Zero, S.Infinity,
                               S.NegativeInfinity]):
             f = a/m + h  # XXX condition `m != 0` should be added to soln
@@ -722,6 +728,14 @@ def _solveset(f, symbol, domain, _check=False):
         elif rhs_s is not S.EmptySet:
             result = ConditionSet(symbol, Eq(f, 0), domain)
 
+    if isinstance(result, ConditionSet):
+        num, den = f.as_numer_denom()
+        if den.has(symbol):
+            _result = _solveset(num, symbol, domain)
+            if not isinstance(_result, ConditionSet):
+                singularities = _solveset(den, symbol, domain)
+                result = _result - singularities
+
     if _check:
         if isinstance(result, ConditionSet):
             # it wasn't solved or has enumerated all conditions


Test patch:
diff --git a/sympy/solvers/tests/test_solvers.py b/sympy/solvers/tests/test_solvers.py
index 4390a11fba..b1ffb2f806 100644
--- a/sympy/solvers/tests/test_solvers.py
+++ b/sympy/solvers/tests/test_solvers.py
@@ -1823,7 +1823,6 @@ def test_issue_12114():
                   d: -f/2 + sqrt(-3*f**2 + 6)/2,
                   e: -f/2 - sqrt(3)*sqrt(-f**2 + 2)/2, g: 2}]
 
-
 def test_inf():
     assert solve(1 - oo*x) == []
     assert solve(oo*x, x) == []
diff --git a/sympy/solvers/tests/test_solveset.py b/sympy/solvers/tests/test_solveset.py
index 0ceeac15dd..aef1efc5d8 100644
--- a/sympy/solvers/tests/test_solveset.py
+++ b/sympy/solvers/tests/test_solveset.py
@@ -579,12 +579,10 @@ def test_solve_abs():
     raises(ValueError, lambda: solveset(abs(x) - 1, x))
 
 
-@XFAIL
 def test_issue_9565():
     assert solveset_real(Abs((x - 1)/(x - 5)) <= S(1)/3, x) == Interval(-1, 2)
 
 
-@XFAIL
 def test_issue_10069():
     eq = abs(1/(x - 1)) - 1 > 0
     u = Union(Interval.open(0, 1), Interval.open(1, 2))