Repository: sympy/sympy
Pull request: Fixed set is equal to set only
<!-- Your title above should be a short description of what
was changed. Do not include the issue number in the title. -->

#### References to other Issues or PRs
<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact
format, e.g. "Fixes #1234" (see
https://tinyurl.com/auto-closing for more information). Also, please
write a comment on that issue linking back to this pull request once it is
open. -->
Fixes #20089 

#### Brief description of what is fixed or changed
Earlier #in #subset gave wrong output due to inconsistency of #Eq with sets and expr

#### Other comments


#### Release Notes

<!-- Write the release notes for this release below. See
https://github.com/sympy/sympy/wiki/Writing-Release-Notes for more information
on how to write release notes. The bot will check your release notes
automatically to see if they are formatted correctly. -->

<!-- BEGIN RELEASE NOTES -->
- sets
     - Earlier expr and sets were treated equal which gave incorrect output for some set functions(mainly : - in, is_subset), made sets and expr not to be equal
<!-- END RELEASE NOTES -->

Problem statement:
FiniteSet not Value False
A=FiniteSet(1,2)
B=(FiniteSet(1,2),FiniteSet(1))

{1} in A
AttributeError                            Traceback (most recent call last)
<ipython-input-80-becd25ec8a42> in <module>()
----> 1 {1} in A

/usr/lib/python3/dist-packages/sympy/sets/sets.py in __contains__(self, other)
    577 
    578     def __contains__(self, other):
--> 579         symb = sympify(self.contains(other))
    580         if not (symb is S.true or symb is S.false):
    581             raise TypeError('contains did not evaluate to a bool: %r' % symb)

/usr/lib/python3/dist-packages/sympy/sets/sets.py in contains(self, other)
    305         """
    306         other = sympify(other, strict=True)
--> 307         ret = sympify(self._contains(other))
    308         if ret is None:
    309             ret = Contains(other, self, evaluate=False)

/usr/lib/python3/dist-packages/sympy/sets/sets.py in _contains(self, other)
   2001         r = false
   2002         for e in self._elements:
-> 2003             t = Eq(e, other, evaluate=True)
   2004             if isinstance(t, Eq):
   2005                 t = t.simplify()

/usr/lib/python3/dist-packages/sympy/core/relational.py in __new__(cls, lhs, rhs, **options)
    302                     return r
    303             if hasattr(rhs, '_eval_Eq'):
--> 304                 r = rhs._eval_Eq(lhs)
    305                 if r is not None:
    306                     return r

/usr/lib/python3/dist-packages/sympy/sets/sets.py in _eval_Eq(self, other)
   1899 
   1900     def _eval_Eq(self, other):
-> 1901         if not other.is_FiniteSet:
   1902             if (other.is_Union or other.is_Complement or
   1903                 other.is_Intersection or other.is_Produ

Hints from issue discussion:
![FiniteSet](https://user-images.githubusercontent.com/55705860/93277096-c1b1d180-f797-11ea-9d78-4139b6f088b7.png)

Hi! Can you please clarify the issue further? 
This is what I get with sympy 1.6.2:
```julia
In [8]: A = FiniteSet(1, 2)                                                                                                                    

In [9]: B = FiniteSet(FiniteSet(1, 2), FiniteSet(1))                                                                                           

In [10]: A                                                                                                                                     
Out[10]: {1, 2}

In [11]: B                                                                                                                                     
Out[11]: {{1}, {1, 2}}

In [12]: A in B                                                                                                                                
Out[12]: True

In [15]: 1 in A                                                                                                                                
Out[15]: True

In [13]: print(A.issubset(B)) # should be False                                                                                                
None

In [14]: 1 in B           # should be False                                                                                                                     
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-14-858aaa7d4c4d> in <module>
----> 1 1 in B

~/current/sympy/sympy/sympy/sets/sets.py in __contains__(self, other)
    673             # x in y must evaluate to T or F; to entertain a None
    674             # result with Set use y.contains(x)
--> 675             raise TypeError('did not evaluate to a bool: %r' % c)
    676         return b
    677 

TypeError: did not evaluate to a bool: None
```
These would evaluate correctly if `Eq` could recognise that a Set is never equal to an Expr:
```julia
In [11]: Eq(1, FiniteSet(1, 2))                                                                                                                
Out[11]: 1 = {1, 2}

In [12]: Eq(1, FiniteSet(1))                                                                                                                   
Out[12]: 1 = {1}
```

Commit message: Fixed sets eq function('in' , 'subset')

Patch to review:
diff --git a/sympy/sets/handlers/comparison.py b/sympy/sets/handlers/comparison.py
index e21ab30b4312..6f7a19fccfaf 100644
--- a/sympy/sets/handlers/comparison.py
+++ b/sympy/sets/handlers/comparison.py
@@ -1,8 +1,9 @@
 from sympy.core.relational import Eq, is_eq
+from sympy.core.basic import Basic
 from sympy.core.logic import fuzzy_and, fuzzy_bool
 from sympy.logic.boolalg import And
 from sympy.multipledispatch import dispatch
-from sympy.sets.sets import tfn, ProductSet, Interval, FiniteSet
+from sympy.sets.sets import tfn, ProductSet, Interval, FiniteSet, Set
 
 
 @dispatch(Interval, FiniteSet) # type:ignore
@@ -46,3 +47,13 @@ def _eval_is_eq(lhs, rhs): # noqa: F811
 
     eqs = (is_eq(x, y) for x, y in zip(lhs.sets, rhs.sets))
     return tfn[fuzzy_and(map(fuzzy_bool, eqs))]
+
+
+@dispatch(Set, Basic) # type:ignore
+def _eval_is_eq(lhs, rhs): # noqa: F811
+    return False
+
+
+@dispatch(Set, Set) # type:ignore
+def _eval_is_eq(lhs, rhs): # noqa: F811
+    return None
diff --git a/sympy/sets/tests/test_sets.py b/sympy/sets/tests/test_sets.py
index e92cb1f23f6a..2fb976156e9e 100644
--- a/sympy/sets/tests/test_sets.py
+++ b/sympy/sets/tests/test_sets.py
@@ -1581,3 +1581,11 @@ def test_DisjointUnion_len():
     assert len(DisjointUnion(FiniteSet(3, 5, 7, 9), FiniteSet(x, y, z))) == 7
     assert len(DisjointUnion(S.EmptySet, S.EmptySet, FiniteSet(x, y, z), S.EmptySet)) == 3
     raises(ValueError, lambda: len(DisjointUnion(Interval(0, 1), S.EmptySet)))
+
+def test_issue_20089():
+    B = FiniteSet(FiniteSet(1, 2), FiniteSet(1))
+    assert not 1 in B
+    assert Eq(1, FiniteSet(1, 2)) == False
+    assert FiniteSet(1) in B
+    A = FiniteSet(1, 2)
+    assert not A.issubset(B)


Code review comments:
diff_hunk: @@ -1581,3 +1581,11 @@ def test_DisjointUnion_len():
     assert len(DisjointUnion(FiniteSet(3, 5, 7, 9), FiniteSet(x, y, z))) == 7
     assert len(DisjointUnion(S.EmptySet, S.EmptySet, FiniteSet(x, y, z), S.EmptySet)) == 3
     raises(ValueError, lambda: len(DisjointUnion(Interval(0, 1), S.EmptySet)))
+
+def test_issue_20089():
+    B = FiniteSet(FiniteSet(1, 2), FiniteSet(1))
+    assert not 1 in B
+    assert Eq(1, FiniteSet(1, 2)) == False
path: sympy/sets/tests/test_sets.py
text: @user1:
This should be `is S.false` rather than `== False`.