Repository: sympy/sympy

Issue:
Change interface for ConditionSet
In a recent [PR](https://github.com/sympy/sympy/pull/9696) we added a ConditionSet class to represent sets of form `{x | condition(x) is True for x in S}`. The current interface to create a condition set is `ConditionSet(imageset(var, condition), input_set)`. Since the first argument is always an `imageset` the interface can be simplified to `ConditionSet(var, condition, input_set)`.

Discussion:

Patch:
diff --git a/sympy/printing/latex.py b/sympy/printing/latex.py
index d177f2aedd..4391242388 100644
--- a/sympy/printing/latex.py
+++ b/sympy/printing/latex.py
@@ -9,6 +9,7 @@
 from sympy.core.sympify import SympifyError
 from sympy.core.alphabets import greeks
 from sympy.core.operations import AssocOp
+from sympy.core.containers import Tuple
 from sympy.logic.boolalg import true
 
 ## sympy.printing imports
@@ -1571,12 +1572,12 @@ def _print_ImageSet(self, s):
             self._print(s.base_set))
 
     def _print_ConditionSet(self, s):
-        vars_print = ', '.join([self._print(var) for var in s.condition.variables])
+        vars_print = ', '.join([self._print(var) for var in Tuple(s.sym)])
         return r"\left\{%s\; |\; %s \in %s \wedge %s \right\}" % (
             vars_print,
             vars_print,
             self._print(s.base_set),
-            self._print(s.condition.expr))
+            self._print(s.condition.as_expr()))
 
     def _print_ComplexPlane(self, s):
         vars_print = ', '.join([self._print(var) for var in s.args[0].variables])
diff --git a/sympy/printing/pretty/pretty.py b/sympy/printing/pretty/pretty.py
index b46013af50..0685dabfa5 100644
--- a/sympy/printing/pretty/pretty.py
+++ b/sympy/printing/pretty/pretty.py
@@ -1,6 +1,7 @@
 from __future__ import print_function, division
 
 from sympy.core import S
+from sympy.core.containers import Tuple
 from sympy.core.function import _coeff_isneg
 from sympy.core.mul import Mul
 from sympy.core.numbers import Rational
@@ -1523,8 +1524,8 @@ def _print_ConditionSet(self, ts):
         else:
             inn = 'in'
             _and = 'and'
-        variables = self._print_seq(ts.condition.variables)
-        cond = self._print(ts.condition.expr)
+        variables = self._print_seq(Tuple(ts.sym))
+        cond = self._print(ts.condition.as_expr())
         bar = self._print("|")
         base = self._print(ts.base_set)
 
diff --git a/sympy/sets/conditionset.py b/sympy/sets/conditionset.py
index 2e0c3daaf5..1fa874f219 100644
--- a/sympy/sets/conditionset.py
+++ b/sympy/sets/conditionset.py
@@ -2,6 +2,7 @@
 
 from sympy import S
 from sympy.core.basic import Basic
+from sympy.core.function import Lambda
 from sympy.logic.boolalg import And
 from sympy.sets.sets import (Set, Interval, Intersection, EmptySet, Union,
                              FiniteSet)
@@ -18,30 +19,31 @@ class ConditionSet(Set):
 
     >>> from sympy import Symbol, S, ConditionSet, Lambda, pi, Eq, sin, Interval
     >>> x = Symbol('x')
-    >>> sin_sols = ConditionSet(Lambda(x, Eq(sin(x), 0)), Interval(0, 2*pi))
+    >>> sin_sols = ConditionSet(x, Eq(sin(x), 0), Interval(0, 2*pi))
     >>> 2*pi in sin_sols
     True
     >>> pi/2 in sin_sols
     False
     >>> 3*pi in sin_sols
     False
-    >>> 5 in ConditionSet(Lambda(x, x**2 > 4), S.Reals)
+    >>> 5 in ConditionSet(x, x**2 > 4, S.Reals)
     True
     """
-    def __new__(cls, condition, base_set):
-        if condition.args[1] is S.false:
+    def __new__(cls, sym, condition, base_set):
+        if condition == S.false:
             return S.EmptySet
-        if condition.args[1] is S.true:
+        if condition == S.true:
             return base_set
-        return Basic.__new__(cls, condition, base_set)
+        return Basic.__new__(cls, sym, condition, base_set)
 
-    condition = property(lambda self: self.args[0])
-    base_set = property(lambda self: self.args[1])
+    sym = property(lambda self: self.args[0])
+    condition = property(lambda self: self.args[1])
+    base_set = property(lambda self: self.args[2])
 
     def _intersect(self, other):
         if not isinstance(other, ConditionSet):
-            return ConditionSet(self.condition,
+            return ConditionSet(self.sym, self.condition,
                                 Intersection(self.base_set, other))
 
     def contains(self, other):
-        return And(self.condition(other), self.base_set.contains(other))
+        return And(Lambda(self.sym, self.condition)(other), self.base_set.contains(other))
diff --git a/sympy/solvers/solveset.py b/sympy/solvers/solveset.py
index 73116e8e49..62a082b058 100644
--- a/sympy/solvers/solveset.py
+++ b/sympy/solvers/solveset.py
@@ -502,7 +502,7 @@ def solveset_real(f, symbol):
                 else:
                     result += solveset_real(equation, symbol)
         else:
-            result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Reals)
+            result = ConditionSet(symbol, Eq(f, 0), S.Reals)
 
     if isinstance(result, FiniteSet):
         result = [s for s in result
@@ -535,7 +535,7 @@ def _solve_real_trig(f, symbol):
     g, h = g.expand(), h.expand()
     g, h = g.subs(exp(I*symbol), y), h.subs(exp(I*symbol), y)
     if g.has(symbol) or h.has(symbol):
-        return ConditionSet(Lambda(symbol, Eq(f, 0)), S.Reals)
+        return ConditionSet(symbol, Eq(f, 0), S.Reals)
 
     solns = solveset_complex(g, y) - solveset_complex(h, y)
 
@@ -545,7 +545,7 @@ def _solve_real_trig(f, symbol):
     elif solns is S.EmptySet:
         return S.EmptySet
     else:
-        return ConditionSet(Lambda(symbol, Eq(f, 0)), S.Reals)
+        return ConditionSet(symbol, Eq(f, 0), S.Reals)
 
 
 def _solve_as_poly(f, symbol, solveset_solver, invert_func):
@@ -567,11 +567,11 @@ def _solve_as_poly(f, symbol, solveset_solver, invert_func):
             if poly.degree() <= len(solns):
                 result = FiniteSet(*solns)
             else:
-                result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes)
+                result = ConditionSet(symbol, Eq(f, 0), S.Complexes)
     else:
         poly = Poly(f)
         if poly is None:
-            result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes)
+            result = ConditionSet(symbol, Eq(f, 0), S.Complexes)
         gens = [g for g in poly.gens if g.has(symbol)]
 
         if len(gens) == 1:
@@ -583,7 +583,7 @@ def _solve_as_poly(f, symbol, solveset_solver, invert_func):
                                           quintics=True).keys())
 
             if len(poly_solns) < deg:
-                result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes)
+                result = ConditionSet(symbol, Eq(f, 0), S.Complexes)
 
             if gen != symbol:
                 y = Dummy('y')
@@ -591,9 +591,9 @@ def _solve_as_poly(f, symbol, solveset_solver, invert_func):
                 if lhs is symbol:
                     result = Union(*[rhs_s.subs(y, s) for s in poly_solns])
                 else:
-                    result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes)
+                    result = ConditionSet(symbol, Eq(f, 0), S.Complexes)
         else:
-            result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes)
+            result = ConditionSet(symbol, Eq(f, 0), S.Complexes)
 
     if result is not None:
         if isinstance(result, FiniteSet):
@@ -607,7 +607,7 @@ def _solve_as_poly(f, symbol, solveset_solver, invert_func):
                 result = imageset(Lambda(s, expand_complex(s)), result)
         return result
     else:
-        return ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes)
+        return ConditionSet(symbol, Eq(f, 0), S.Complexes)
 
 
 def _solve_as_poly_real(f, symbol):
@@ -706,7 +706,7 @@ def _solve_abs(f, symbol):
                                            symbol).intersect(q_neg_cond)
         return Union(sols_q_pos, sols_q_neg)
     else:
-        return ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes)
+        return ConditionSet(symbol, Eq(f, 0), S.Complexes)
 
 
 def solveset_complex(f, symbol):
@@ -806,7 +806,7 @@ def solveset_complex(f, symbol):
                 else:
                     result += solveset_complex(equation, symbol)
         else:
-            result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes)
+            result = ConditionSet(symbol, Eq(f, 0), S.Complexes)
 
     if isinstance(result, FiniteSet):
         result = [s for s in result
@@ -931,7 +931,7 @@ def solveset(f, symbol=None, domain=S.Complexes):
             result = solve_univariate_inequality(
             f, symbol, relational=False).intersection(domain)
         except NotImplementedError:
-            result = ConditionSet(Lambda(symbol, f), domain)
+            result = ConditionSet(symbol, f, domain)
         return result
 
     if isinstance(f, (Expr, Number)):


Test patch:
diff --git a/sympy/core/tests/test_args.py b/sympy/core/tests/test_args.py
index a21a53ea15..a4a78520cc 100644
--- a/sympy/core/tests/test_args.py
+++ b/sympy/core/tests/test_args.py
@@ -569,7 +569,7 @@ def test_sympy__sets__conditionset__ConditionSet():
     from sympy.sets.conditionset import ConditionSet
     from sympy import S, Symbol
     x = Symbol('x')
-    assert _test_args(ConditionSet(Lambda(x, Eq(x**2, 1)), S.Reals))
+    assert _test_args(ConditionSet(x, Eq(x**2, 1), S.Reals))
 
 
 def test_sympy__sets__contains__Contains():
diff --git a/sympy/printing/pretty/tests/test_pretty.py b/sympy/printing/pretty/tests/test_pretty.py
index 9cba38a101..ec8a01a8bf 100644
--- a/sympy/printing/pretty/tests/test_pretty.py
+++ b/sympy/printing/pretty/tests/test_pretty.py
@@ -3104,8 +3104,8 @@ def test_pretty_ConditionSet():
     from sympy import ConditionSet
     ascii_str = '{x | x in (-oo, oo) and sin(x) = 0}'
     ucode_str = u('{x | x ∊ ℝ ∧ sin(x) = 0}')
-    assert pretty(ConditionSet(Lambda(x, Eq(sin(x), 0)), S.Reals)) == ascii_str
-    assert upretty(ConditionSet(Lambda(x, Eq(sin(x), 0)), S.Reals)) == ucode_str
+    assert pretty(ConditionSet(x, Eq(sin(x), 0), S.Reals)) == ascii_str
+    assert upretty(ConditionSet(x, Eq(sin(x), 0), S.Reals)) == ucode_str
 
 
 def test_pretty_ComplexPlane():
diff --git a/sympy/printing/tests/test_latex.py b/sympy/printing/tests/test_latex.py
index a24fc533d2..7c3a966cc9 100644
--- a/sympy/printing/tests/test_latex.py
+++ b/sympy/printing/tests/test_latex.py
@@ -612,7 +612,7 @@ def test_latex_ImageSet():
 
 def test_latex_ConditionSet():
     x = Symbol('x')
-    assert latex(ConditionSet(Lambda(x, Eq(x**2, 1)), S.Reals)) == \
+    assert latex(ConditionSet(x, Eq(x**2, 1), S.Reals)) == \
         r"\left\{x\; |\; x \in \mathbb{R} \wedge x^{2} = 1 \right\}"
 
 
diff --git a/sympy/sets/tests/test_conditionset.py b/sympy/sets/tests/test_conditionset.py
index 368621310f..c7d02044b4 100644
--- a/sympy/sets/tests/test_conditionset.py
+++ b/sympy/sets/tests/test_conditionset.py
@@ -5,22 +5,22 @@
 
 
 def test_CondSet():
-    sin_sols_principal = ConditionSet(Lambda(x, Eq(sin(x), 0)),
+    sin_sols_principal = ConditionSet(x, Eq(sin(x), 0),
                                       Interval(0, 2*pi, False, True))
     assert pi in sin_sols_principal
     assert pi/2 not in sin_sols_principal
     assert 3*pi not in sin_sols_principal
-    assert 5 in ConditionSet(Lambda(x, x**2 > 4), S.Reals)
-    assert 1 not in ConditionSet(Lambda(x, x**2 > 4), S.Reals)
+    assert 5 in ConditionSet(x, x**2 > 4, S.Reals)
+    assert 1 not in ConditionSet(x, x**2 > 4, S.Reals)
 
 
 def test_CondSet_intersect():
-    input_conditionset = ConditionSet(Lambda(x, x**2 > 4), Interval(1, 4, False, False))
+    input_conditionset = ConditionSet(x, x**2 > 4, Interval(1, 4, False, False))
     other_domain = Interval(0, 3, False, False)
-    output_conditionset = ConditionSet(Lambda(x, x**2 > 4), Interval(1, 3, False, False))
+    output_conditionset = ConditionSet(x, x**2 > 4, Interval(1, 3, False, False))
     assert Intersection(input_conditionset, other_domain) == output_conditionset
 
 
 def test_issue_9849():
-    assert ConditionSet(Lambda(x, Eq(x, x)), S.Naturals) == S.Naturals
-    assert ConditionSet(Lambda(x, Eq(Abs(sin(x)), -1)), S.Naturals) == S.EmptySet
+    assert ConditionSet(x, Eq(x, x), S.Naturals) == S.Naturals
+    assert ConditionSet(x, Eq(Abs(sin(x)), -1), S.Naturals) == S.EmptySet
diff --git a/sympy/solvers/tests/test_solveset.py b/sympy/solvers/tests/test_solveset.py
index fae00b37ed..ea004acea7 100644
--- a/sympy/solvers/tests/test_solveset.py
+++ b/sympy/solvers/tests/test_solveset.py
@@ -439,7 +439,7 @@ def test_solve_sqrt_3():
     eq = -sqrt((m - q)**2 + (-m/(2*q) + S(1)/2)**2) + sqrt((-m**2/2 - sqrt(
         4*m**4 - 4*m**2 + 8*m + 1)/4 - S(1)/4)**2 + (m**2/2 - m - sqrt(
             4*m**4 - 4*m**2 + 8*m + 1)/4 - S(1)/4)**2)
-    unsolved_object = ConditionSet(Lambda(q, Eq((-2*sqrt(4*q**2*(m - q)**2 + (-m + q)**2) + sqrt((-2*m**2 - sqrt(4*m**4 - 4*m**2 + 8*m + 1) - 1)**2 + (2*m**2 - 4*m - sqrt(4*m**4 - 4*m**2 + 8*m + 1) - 1)**2)*Abs(q))/Abs(q), 0)), S.Reals)
+    unsolved_object = ConditionSet(q, Eq((-2*sqrt(4*q**2*(m - q)**2 + (-m + q)**2) + sqrt((-2*m**2 - sqrt(4*m**4 - 4*m**2 + 8*m + 1) - 1)**2 + (2*m**2 - 4*m - sqrt(4*m**4 - 4*m**2 + 8*m + 1) - 1)**2)*Abs(q))/Abs(q), 0), S.Reals)
     assert solveset_real(eq, q) == unsolved_object
 
 
@@ -723,7 +723,7 @@ def test_solve_invalid_sol():
 
 
 def test_solve_complex_unsolvable():
-    unsolved_object = ConditionSet(Lambda(x, Eq(2*cos(x) - 1, 0)), S.Complexes)
+    unsolved_object = ConditionSet(x, Eq(2*cos(x) - 1, 0), S.Complexes)
     solution = solveset_complex(cos(x) - S.Half, x)
     assert solution == unsolved_object
 
@@ -851,25 +851,25 @@ def test_solveset():
 
 def test_conditonset():
     assert solveset(Eq(sin(x)**2 + cos(x)**2, 1), x, domain=S.Reals) == \
-        ConditionSet(Lambda(x, True), S.Reals)
+        ConditionSet(x, True, S.Reals)
 
     assert solveset(Eq(x**2 + x*sin(x), 1), x, domain=S.Reals) == \
-        ConditionSet(Lambda(x, Eq(x*(x + sin(x)) - 1, 0)), S.Reals)
+        ConditionSet(x, Eq(x*(x + sin(x)) - 1, 0), S.Reals)
 
     assert solveset(Eq(sin(Abs(x)), x), x, domain=S.Reals) == \
-        ConditionSet(Lambda(x, Eq(-x + sin(Abs(x)), 0)), Interval(-oo, oo))
+        ConditionSet(x, Eq(-x + sin(Abs(x)), 0), Interval(-oo, oo))
 
     assert solveset(Eq(-I*(exp(I*x) - exp(-I*x))/2, 1), x) == \
         imageset(Lambda(n, 2*n*pi + pi/2), S.Integers)
 
     assert solveset(x + sin(x) > 1, x, domain=S.Reals) == \
-        ConditionSet(Lambda(x, x + sin(x) > 1), S.Reals)
+        ConditionSet(x, x + sin(x) > 1, S.Reals)
 
 
 @XFAIL
 def test_conditionset_equality():
     ''' Checking equality of different representations of ConditionSet'''
-    assert solveset(Eq(tan(x), y), x) == ConditionSet(Lambda(x, Eq(tan(x), y)), S.Complexes)
+    assert solveset(Eq(tan(x), y), x) == ConditionSet(x, Eq(tan(x), y), S.Complexes)
 
 
 def test_solveset_domain():
@@ -885,7 +885,7 @@ def test_improve_coverage():
     x = Symbol('x')
     y = exp(x+1/x**2)
     solution = solveset(y**2+y, x, S.Reals)
-    unsolved_object = ConditionSet(Lambda(x, Eq((exp((x**3 + 1)/x**2) + 1)*exp((x**3 + 1)/x**2), 0)), S.Reals)
+    unsolved_object = ConditionSet(x, Eq((exp((x**3 + 1)/x**2) + 1)*exp((x**3 + 1)/x**2), 0), S.Reals)
     assert solution == unsolved_object
 
     assert _has_rational_power(sin(x)*exp(x) + 1, x) == (False, S.One)