Repository: sympy/sympy

Issue:
sets.Complement fails on certain Unions
`sympy.sets.Complement` fails on certain unions.  That is, it seems to get stuck in a loop.

To recreate

    from sympy import S
    from sympy.sets import *
    
    a = Interval(0,1) + Interval(2,3)
    # this works
    Complement( S.Reals, a )
    # this gets stuck in a loop
    Complement( S.UniversalSet, a)

The expected behaviour is for it to output `UniversalSet() \ ([0,1] U [2,3])`



Discussion:

Patch:
diff --git a/sympy/sets/sets.py b/sympy/sets/sets.py
index ac7a486dba..f033f647fb 100644
--- a/sympy/sets/sets.py
+++ b/sympy/sets/sets.py
@@ -206,7 +206,7 @@ def _complement(self, other):
             return Union(o - self for o in other.args)
 
         elif isinstance(other, Complement):
-            return Complement(other.args[0], Union(other.args[1], self))
+            return Complement(other.args[0], Union(other.args[1], self), evaluate=False)
 
         elif isinstance(other, EmptySet):
             return S.EmptySet


Test patch:
diff --git a/sympy/sets/tests/test_sets.py b/sympy/sets/tests/test_sets.py
index 1afe34c7bb..ec7538cdd0 100644
--- a/sympy/sets/tests/test_sets.py
+++ b/sympy/sets/tests/test_sets.py
@@ -161,7 +161,6 @@ def test_Complement():
     assert S.Reals - Union(S.Naturals, FiniteSet(pi)) == \
             Intersection(S.Reals - S.Naturals, S.Reals - FiniteSet(pi))
 
-
 def test_complement():
     assert Interval(0, 1).complement(S.Reals) == \
         Union(Interval(-oo, 0, True, True), Interval(1, oo, True, True))
@@ -941,3 +940,11 @@ def test_issue_10113():
 def test_issue_10248():
     assert list(Intersection(S.Reals, FiniteSet(x))) == [
         And(x < oo, x > -oo)]
+
+
+def test_issue_9447():
+    a = Interval(0, 1) + Interval(2, 3)
+    assert Complement(S.UniversalSet, a) == Complement(
+            S.UniversalSet, Union(Interval(0, 1), Interval(2, 3)), evaluate=False)
+    assert Complement(S.Naturals, a) == Complement(
+            S.Naturals, Union(Interval(0, 1), Interval(2, 3)), evaluate=False)