Repository: sympy/sympy
Pull request: Wrong result with solveset. Fix issue 13550
Fix #13550.
The expression `solveset(x**2 - 2*x - 15, symbol = x, domain = Interval(-oo, 0))`
returns `EmptySet()` instead of `FiniteSet(-3)`. The bug is due to the
function `_invert(f_x, y, x, domain=S.Complexes)` in `solveset.py`. It returns `x1, s.intersection(domain)`
but in such example `x1` is `x**2 - 2*x`, so that `s` does not represent
the inversion. Hence the intersection with the domain is meaningless.

In the case `x1` is not equal to the symbol, i.e. the function is not inverted, it is better to return `x1, s`

A test is added.

<!-- Please give this pull request a descriptive title. Pull requests with descriptive titles are more likely to receive reviews. Describe what you changed! A title that only references an issue number is not descriptive. -->

<!-- If this pull request fixes an issue please indicate which issue by typing "Fixes #NNNN" below. -->


Problem statement:
Wrong result with solveset
```
>>> from sympy import *
>>> x = Symbol('x')
>>> solveset(x**2 - 2*x - 15, symbol = x, domain = Interval(-oo, 0))
EmptySet()
```
This is incorrect. The correct output for the above code should be `FiniteSet(-3)`. When the `domain = S.Reals`, `FiniteSet(-3, 5)` is returned.

Hints from issue discussion:

Commit message: Wrong result with solveset. Issue 13350

Fix 13350.
The expression solveset(x**2 - 2*x - 15, symbol = x, domain = Interval(-oo, 0))
returns EmptySet() instead of FiniteSet(-3). The bug is due to the
function _invert(f_x, y, x, domain=S.Complexes). It returns
x1, s.intersection(domain)
but in such example x1 is x**2 - 2*x, so that 's' does not represent
the solution. Hence the intersection with the domain is meaningless.

In the case x1 is not equal to the symbol, it is better to return x1, s

A test is added.

Patch to review:
diff --git a/sympy/solvers/solveset.py b/sympy/solvers/solveset.py
index 885918210d50..7d02714cd666 100644
--- a/sympy/solvers/solveset.py
+++ b/sympy/solvers/solveset.py
@@ -108,6 +108,9 @@ def _invert(f_x, y, x, domain=S.Complexes):
     if not isinstance(s, FiniteSet) or x1 == f_x:
         return x1, s
 
+    if not x1 == x:
+        return x1, s
+
     return x1, s.intersection(domain)
 
 
diff --git a/sympy/solvers/tests/test_solveset.py b/sympy/solvers/tests/test_solveset.py
index b84df55e3c00..a4527e63ad99 100644
--- a/sympy/solvers/tests/test_solveset.py
+++ b/sympy/solvers/tests/test_solveset.py
@@ -1633,3 +1633,6 @@ def test__is_finite_with_finite_vars():
     assert all(f(1/x) is None for x in (
         Dummy(), Dummy(real=True), Dummy(complex=True)))
     assert f(1/Dummy(real=False)) is True  # b/c it's finite but not 0
+
+def test_issue_13550():
+    assert solveset(x**2 - 2*x - 15, symbol = x, domain = Interval(-oo, 0)) == FiniteSet(-3)


Code review comments:
diff_hunk: @@ -108,6 +108,9 @@ def _invert(f_x, y, x, domain=S.Complexes):
     if not isinstance(s, FiniteSet) or x1 == f_x:
path: sympy/solvers/solveset.py
text: @user1:
I guess the condition `or x1 != x` could be appended here instead of adding a new block below.

@author:
Thanks. You are right. Modification done.