Repository: sympy/sympy

Issue:
Defining printing for `S.Naturals0`
```
>>> init_printing(use_unicode=True)
>>> S.Naturals
ℕ
>>> S.Naturals0
ℕ
```

There should should be some difference in their printing may be putting a `N0`(0 in subscript) for `S.Naturals0`.

Discussion:

Patch:
diff --git a/sympy/functions/combinatorial/factorials.py b/sympy/functions/combinatorial/factorials.py
index 4ed7582a76..99bd6dff9e 100644
--- a/sympy/functions/combinatorial/factorials.py
+++ b/sympy/functions/combinatorial/factorials.py
@@ -498,54 +498,40 @@ def _sage_(self):
 
 class FallingFactorial(CombinatorialFunction):
     """Falling factorial (related to rising factorial) is a double valued
-    function arising in concrete mathematics, hypergeometric functions
-    and series expansions. It is defined by
+       function arising in concrete mathematics, hypergeometric functions
+       and series expansions. It is defined by
 
-                ff(x, k) = x * (x-1) * ... * (x - k+1)
+                   ff(x, k) = x * (x-1) * ... * (x - k+1)
 
-    where 'x' can be arbitrary expression and 'k' is an integer. For
-    more information check "Concrete mathematics" by Graham, pp. 66
-    or visit http://mathworld.wolfram.com/FallingFactorial.html page.
+       where 'x' can be arbitrary expression and 'k' is an integer. For
+       more information check "Concrete mathematics" by Graham, pp. 66
+       or visit http://mathworld.wolfram.com/FallingFactorial.html page.
 
-    When x is a polynomial f of a single variable y of order >= 1,
-    ff(x,k) = f(y) * f(y-1) * ... * f(x-k+1) as described in
-    Peter Paule, "Greatest Factorial Factorization and Symbolic Summation",
-    Journal of Symbolic Computation, vol. 20, pp. 235-268, 1995.
+       When x is a polynomial f of a single variable y of order >= 1,
+       ff(x,k) = f(y) * f(y-1) * ... * f(x-k+1) as described in
+       Peter Paule, "Greatest Factorial Factorization and Symbolic Summation",
+       Journal of Symbolic Computation, vol. 20, pp. 235-268, 1995.
 
-    >>> from sympy import ff, factorial, rf, gamma, polygamma, binomial, symbols
-    >>> from sympy.abc import x, k
-    >>> n, m = symbols('n m', integer=True)
-    >>> ff(x, 0)
-    1
-    >>> ff(5, 5)
-    120
-    >>> ff(x, 5) == x*(x-1)*(x-2)*(x-3)*(x-4)
-    True
-    >>> ff(x**2, 2)
-    Poly(x**4 - 2*x**3 + x**2, x, domain='ZZ')
-    >>> ff(n, n)
-    factorial(n)
-
-    Rewrite
-
-    >>> ff(x, k).rewrite(gamma)
-    (-1)**k*gamma(k - x)/gamma(-x)
-    >>> ff(x, k).rewrite(rf)
-    RisingFactorial(-k + x + 1, k)
-    >>> ff(x, m).rewrite(binomial)
-    binomial(x, m)*factorial(m)
-    >>> ff(n, m).rewrite(factorial)
-    factorial(n)/factorial(-m + n)
+       >>> from sympy import ff
+       >>> from sympy.abc import x
 
-    See Also
-    ========
+       >>> ff(x, 0)
+       1
 
-    factorial, factorial2, RisingFactorial
+       >>> ff(5, 5)
+       120
 
-    References
-    ==========
+       >>> ff(x, 5) == x*(x-1)*(x-2)*(x-3)*(x-4)
+       True
+
+       >>> ff(x**2, 2)
+       Poly(x**4 - 2*x**3 + x**2, x, domain='ZZ')
 
-    .. [1] http://mathworld.wolfram.com/FallingFactorial.html
+
+       See Also
+       ========
+
+       factorial, factorial2, RisingFactorial
     """
 
     @classmethod
@@ -553,12 +539,12 @@ def eval(cls, x, k):
         x = sympify(x)
         k = sympify(k)
 
-        if x is S.NaN or k is S.NaN:
+        if x is S.NaN:
             return S.NaN
-        elif k.is_integer and x == k:
-            return factorial(x)
         elif k.is_Integer:
-            if k is S.Zero:
+            if k is S.NaN:
+                return S.NaN
+            elif k is S.Zero:
                 return S.One
             else:
                 if k.is_positive:
@@ -573,16 +559,12 @@ def eval(cls, x, k):
                         try:
                             F, opt = poly_from_expr(x)
                         except PolificationFailed:
-                            return reduce(lambda r, i: r*(x - i),
-                                          range(0, int(k)), 1)
+                            return reduce(lambda r, i: r*(x - i), range(0, int(k)), 1)
                         if len(opt.gens) > 1 or F.degree() <= 1:
-                            return reduce(lambda r, i: r*(x - i),
-                                          range(0, int(k)), 1)
+                            return reduce(lambda r, i: r*(x - i), range(0, int(k)), 1)
                         else:
                             v = opt.gens[0]
-                            return reduce(lambda r, i:
-                                          r*(F.subs(v, v - i).expand()),
-                                          range(0, int(k)), 1)
+                            return reduce(lambda r, i: r*(F.subs(v, v - i).expand()), range(0, int(k)), 1)
                 else:
                     if x is S.Infinity:
                         return S.Infinity
@@ -592,31 +574,16 @@ def eval(cls, x, k):
                         try:
                             F, opt = poly_from_expr(x)
                         except PolificationFailed:
-                            return 1/reduce(lambda r, i: r*(x + i),
-                                            range(1, abs(int(k)) + 1), 1)
+                            return 1/reduce(lambda r, i: r*(x + i), range(1, abs(int(k)) + 1), 1)
                         if len(opt.gens) > 1 or F.degree() <= 1:
-                            return 1/reduce(lambda r, i: r*(x + i),
-                                            range(1, abs(int(k)) + 1), 1)
+                            return 1/reduce(lambda r, i: r*(x + i), range(1, abs(int(k)) + 1), 1)
                         else:
                             v = opt.gens[0]
-                            return 1/reduce(lambda r, i:
-                                            r*(F.subs(v, v + i).expand()),
-                                            range(1, abs(int(k)) + 1), 1)
+                            return 1/reduce(lambda r, i: r*(F.subs(v, v + i).expand()), range(1, abs(int(k)) + 1), 1)
 
     def _eval_rewrite_as_gamma(self, x, k):
         from sympy import gamma
-        return (-1)**k*gamma(k - x) / gamma(-x)
-
-    def _eval_rewrite_as_RisingFactorial(self, x, k):
-        return rf(x - k + 1, k)
-
-    def _eval_rewrite_as_binomial(self, x, k):
-        if k.is_integer:
-            return factorial(k) * binomial(x, k)
-
-    def _eval_rewrite_as_factorial(self, x, k):
-        if x.is_integer and k.is_integer:
-            return factorial(x) / factorial(x - k)
+        return (-1)**k * gamma(-x + k) / gamma(-x)
 
     def _eval_is_integer(self):
         return fuzzy_and((self.args[0].is_integer, self.args[1].is_integer,
@@ -624,8 +591,7 @@ def _eval_is_integer(self):
 
     def _sage_(self):
         import sage.all as sage
-        return sage.falling_factorial(self.args[0]._sage_(),
-                                      self.args[1]._sage_())
+        return sage.falling_factorial(self.args[0]._sage_(), self.args[1]._sage_())
 
 
 rf = RisingFactorial
@@ -817,10 +783,6 @@ def _eval_rewrite_as_gamma(self, n, k):
         from sympy import gamma
         return gamma(n + 1)/(gamma(k + 1)*gamma(n - k + 1))
 
-    def _eval_rewrite_as_FallingFactorial(self, n, k):
-        if k.is_integer:
-            return ff(n, k) / factorial(k)
-
     def _eval_is_integer(self):
         n, k = self.args
         if n.is_integer and k.is_integer:
diff --git a/sympy/printing/latex.py b/sympy/printing/latex.py
index 31dce95a55..8b92a8be78 100644
--- a/sympy/printing/latex.py
+++ b/sympy/printing/latex.py
@@ -1552,6 +1552,9 @@ def _print_EmptySet(self, e):
     def _print_Naturals(self, n):
         return r"\mathbb{N}"
 
+    def _print_Naturals0(self, n):
+        return r"\mathbb{N_0}"
+
     def _print_Integers(self, i):
         return r"\mathbb{Z}"
 
@@ -1575,13 +1578,6 @@ def _print_ConditionSet(self, s):
             self._print(s.base_set),
             self._print(s.condition.expr))
 
-    def _print_ComplexPlane(self, s):
-        vars_print = ', '.join([self._print(var) for var in s.args[0].variables])
-        return r"\left\{%s\; |\; %s \in %s \right\}" % (
-            self._print(s.args[0].expr),
-            vars_print,
-            self._print(s.sets))
-
     def _print_Contains(self, e):
         return r"%s \in %s" % tuple(self._print(a) for a in e.args)
 
diff --git a/sympy/printing/pretty/pretty.py b/sympy/printing/pretty/pretty.py
index e1f457c622..7300ba464d 100644
--- a/sympy/printing/pretty/pretty.py
+++ b/sympy/printing/pretty/pretty.py
@@ -93,6 +93,7 @@ def _print_Atom(self, e):
     _print_NegativeInfinity = _print_Atom
     _print_EmptySet = _print_Atom
     _print_Naturals = _print_Atom
+    _print_Naturals0 = _print_Atom
     _print_Integers = _print_Atom
     _print_Reals = _print_Atom
     _print_Complexes = _print_Atom
@@ -1530,18 +1531,6 @@ def _print_ConditionSet(self, ts):
         return self._print_seq((variables, bar, variables, inn,
                                 base, _and, cond), "{", "}", ' ')
 
-    def _print_ComplexPlane(self, ts):
-        if self._use_unicode:
-            inn = u("\N{SMALL ELEMENT OF}")
-        else:
-            inn = 'in'
-        variables = self._print_seq(ts.args[0].variables)
-        expr = self._print(ts.args[0].expr)
-        bar = self._print("|")
-        prodsets = self._print(ts.sets)
-
-        return self._print_seq((expr, bar, variables, inn, prodsets), "{", "}", ' ')
-
     def _print_Contains(self, e):
         var, set = e.args
         if self._use_unicode:
diff --git a/sympy/printing/pretty/pretty_symbology.py b/sympy/printing/pretty/pretty_symbology.py
index 3701dd5fad..36ff6bbac9 100644
--- a/sympy/printing/pretty/pretty_symbology.py
+++ b/sympy/printing/pretty/pretty_symbology.py
@@ -468,6 +468,9 @@ def xsym(sym):
     'ImaginaryUnit':           U('DOUBLE-STRUCK ITALIC SMALL I'),
     'EmptySet':                U('EMPTY SET'),
     'Naturals':                U('DOUBLE-STRUCK CAPITAL N'),
+    'Naturals0':               (U('DOUBLE-STRUCK CAPITAL N') and
+                                (U('DOUBLE-STRUCK CAPITAL N') +
+                                 U('SUBSCRIPT ZERO'))),
     'Integers':                U('DOUBLE-STRUCK CAPITAL Z'),
     'Reals':                   U('DOUBLE-STRUCK CAPITAL R'),
     'Complexes':               U('DOUBLE-STRUCK CAPITAL C'),


Test patch:
diff --git a/sympy/functions/combinatorial/tests/test_comb_factorials.py b/sympy/functions/combinatorial/tests/test_comb_factorials.py
index 5baf0bf434..31ec8b7a81 100644
--- a/sympy/functions/combinatorial/tests/test_comb_factorials.py
+++ b/sympy/functions/combinatorial/tests/test_comb_factorials.py
@@ -50,11 +50,8 @@ def test_rf_eval_apply():
 
 def test_ff_eval_apply():
     x, y = symbols('x,y')
-    n, k = symbols('n k', integer=True)
-    m = Symbol('m', integer=True, nonnegative=True)
 
     assert ff(nan, y) == nan
-    assert ff(x, nan) == nan
 
     assert ff(x, y) == ff(x, y)
 
@@ -82,6 +79,9 @@ def test_ff_eval_apply():
     assert ff(2*x**2 - 5*x, 2) == 4*x**4 - 28*x**3 + 59*x**2 - 35*x
     assert ff(x**2 + 3*x, -2) == 1/(x**4 + 12*x**3 + 49*x**2 + 78*x + 40)
 
+    n = Symbol('n', integer=True)
+    k = Symbol('k', integer=True)
+    m = Symbol('m', integer=True, nonnegative=True)
     assert ff(x, m).is_integer is None
     assert ff(n, k).is_integer is None
     assert ff(n, m).is_integer is True
@@ -89,14 +89,6 @@ def test_ff_eval_apply():
     assert ff(n, m + pi).is_integer is False
     assert ff(pi, m).is_integer is False
 
-    assert isinstance(ff(x, x), ff)
-    assert ff(n, n) == factorial(n)
-
-    assert ff(x, k).rewrite(rf) == rf(x - k + 1, k)
-    assert ff(x, k).rewrite(gamma) == (-1)**k*gamma(k - x) / gamma(-x)
-    assert ff(n, k).rewrite(factorial) == factorial(n) / factorial(n - k)
-    assert ff(x, k).rewrite(binomial) == factorial(k) * binomial(x, k)
-
 
 def test_factorial():
     x = Symbol('x')
@@ -314,7 +306,6 @@ def test_binomial_rewrite():
         factorial) == factorial(n)/(factorial(k)*factorial(n - k))
     assert binomial(
         n, k).rewrite(gamma) == gamma(n + 1)/(gamma(k + 1)*gamma(n - k + 1))
-    assert binomial(n, k).rewrite(ff) == ff(n, k) / factorial(k)
 
 
 @XFAIL
diff --git a/sympy/printing/pretty/tests/test_pretty.py b/sympy/printing/pretty/tests/test_pretty.py
index d2ad29306a..3ac278343d 100644
--- a/sympy/printing/pretty/tests/test_pretty.py
+++ b/sympy/printing/pretty/tests/test_pretty.py
@@ -3108,15 +3108,6 @@ def test_pretty_ConditionSet():
     assert upretty(ConditionSet(Lambda(x, Eq(sin(x), 0)), S.Reals)) == ucode_str
 
 
-def test_pretty_ComplexPlane():
-    from sympy import ComplexPlane
-    ucode_str = u('{x + ⅈ⋅y | x, y ∊ [3, 5] × [4, 6]}')
-    assert upretty(ComplexPlane(Interval(3, 5)*Interval(4, 6))) == ucode_str
-
-    ucode_str = u('{r⋅(ⅈ⋅sin(θ) + cos(θ)) | r, θ ∊ [0, 1] × [0, 2⋅π)}')
-    assert upretty(ComplexPlane(Interval(0, 1)*Interval(0, 2*pi), polar=True)) == ucode_str
-
-
 def test_ProductSet_paranthesis():
     from sympy import Interval, Union, FiniteSet
     ucode_str = u('([4, 7] × {1, 2}) ∪ ([2, 3] × [4, 7])')
@@ -5052,6 +5043,8 @@ def test_issue_7180():
 def test_pretty_Complement():
     assert pretty(S.Reals - S.Naturals) == '(-oo, oo) \ Naturals()'
     assert upretty(S.Reals - S.Naturals) == u('ℝ \ ℕ')
+    assert pretty(S.Reals - S.Naturals0) == '(-oo, oo) \ Naturals0()'
+    assert upretty(S.Reals - S.Naturals0) == u('ℝ \ ℕ₀')
 
 
 def test_pretty_SymmetricDifference():
diff --git a/sympy/printing/tests/test_latex.py b/sympy/printing/tests/test_latex.py
index a397db0c96..9bb886d199 100644
--- a/sympy/printing/tests/test_latex.py
+++ b/sympy/printing/tests/test_latex.py
@@ -15,7 +15,7 @@
     uppergamma, zeta, subfactorial, totient, elliptic_k, elliptic_f,
     elliptic_e, elliptic_pi, cos, tan, Wild, true, false, Equivalent, Not,
     Contains, divisor_sigma, SymmetricDifference, SeqPer, SeqFormula,
-    SeqAdd, SeqMul, fourier_series, pi, ConditionSet, ComplexPlane, fps)
+    SeqAdd, SeqMul, fourier_series, pi, ConditionSet, fps)
 
 
 from sympy.ntheory.factor_ import udivisor_sigma
@@ -594,6 +594,13 @@ def test_latex_productset():
 
 def test_latex_Naturals():
     assert latex(S.Naturals) == r"\mathbb{N}"
+
+
+def test_latex_Naturals0():
+    assert latex(S.Naturals0) == r"\mathbb{N_0}"
+
+
+def test_latex_Integers():
     assert latex(S.Integers) == r"\mathbb{Z}"
 
 
@@ -609,13 +616,6 @@ def test_latex_ConditionSet():
         r"\left\{x\; |\; x \in \mathbb{R} \wedge x^{2} = 1 \right\}"
 
 
-def test_latex_ComplexPlane():
-    assert latex(ComplexPlane(Interval(3, 5)*Interval(4, 6))) == \
-        r"\left\{x + i y\; |\; x, y \in \left[3, 5\right] \times \left[4, 6\right] \right\}"
-    assert latex(ComplexPlane(Interval(0, 1)*Interval(0, 2*pi), polar=True)) == \
-        r"\left\{r \left(i \sin{\left (\theta \right )} + \cos{\left (\theta \right )}\right)\; |\; r, \theta \in \left[0, 1\right] \times \left[0, 2 \pi\right) \right\}"
-
-
 def test_latex_Contains():
     x = Symbol('x')
     assert latex(Contains(x, S.Naturals)) == r"x \in \mathbb{N}"
diff --git a/sympy/solvers/tests/test_solveset.py b/sympy/solvers/tests/test_solveset.py
index 44f3548acc..64062b4d33 100644
--- a/sympy/solvers/tests/test_solveset.py
+++ b/sympy/solvers/tests/test_solveset.py
@@ -603,7 +603,6 @@ def test_atan2():
 
 def test_piecewise():
     eq = Piecewise((x - 2, Gt(x, 2)), (2 - x, True)) - 3
-    f = Piecewise(((x - 2)**2, x >= 0), (0, True))
     assert set(solveset_real(eq, x)) == set(FiniteSet(-1, 5))
     absxm3 = Piecewise(
         (x - 3, S(0) <= x - 3),
@@ -611,7 +610,6 @@ def test_piecewise():
     )
     y = Symbol('y', positive=True)
     assert solveset_real(absxm3 - y, x) == FiniteSet(-y + 3, y + 3)
-    assert solveset(f, x, domain=S.Reals) == Union(FiniteSet(2), Interval(-oo, 0, True, True))
 
 
 def test_solveset_complex_polynomial():