Repository: sympy/sympy

Issue:
Deprecate redundant methods in `carmichael`
The following static methods are redundant and should be deprecated:

https://github.com/sympy/sympy/blob/dc4f807f4116c449b82433fe4ae583dfab06bf5c/sympy/functions/combinatorial/numbers.py#L109-L119

Just look at where `is_square` and `isprime` is imported from and point to that as `useinstead`. For `divides` it is enough to type the corresponding Python code as `useinstead`.

**Note that there is a change in the deprecation procedure**, see #22900 , so it makes sense to wait with introducing these deprecations until that is merged and done (and to follow the new procedure).

Discussion:

Patch:
diff --git a/doc/src/explanation/active-deprecations.md b/doc/src/explanation/active-deprecations.md
index 84fda0eb75..47906be87e 100644
--- a/doc/src/explanation/active-deprecations.md
+++ b/doc/src/explanation/active-deprecations.md
@@ -105,6 +105,19 @@ Now you can do the same with
 21
 ```
 
+(deprecated-carmichael-static-methods)=
+### Redundant static methods in `carmichael`
+
+A number of static methods in `~.carmichael` are just wrappers around other
+functions. Instead of ``carmichael.is_perfect_square`` use
+`sympy.ntheory.primetest.is_square` and instead of ``carmichael.is_prime`` use
+`~.isprime`. Finally, ``carmichael.divides`` can be replaced by instead checking
+
+```py
+n % p == 0
+```
+
+
 ## Version 1.10
 
 (deprecated-traversal-functions-moved)=
diff --git a/sympy/functions/combinatorial/numbers.py b/sympy/functions/combinatorial/numbers.py
index b675a7d207..84c21c8640 100644
--- a/sympy/functions/combinatorial/numbers.py
+++ b/sympy/functions/combinatorial/numbers.py
@@ -24,6 +24,7 @@
     factorial, subfactorial)
 from sympy.ntheory.primetest import isprime, is_square
 from sympy.utilities.enumerative import MultisetPartitionTraverser
+from sympy.utilities.exceptions import sympy_deprecation_warning
 from sympy.utilities.iterables import multiset, multiset_derangements, iterable
 from sympy.utilities.memoization import recurrence_memo
 from sympy.utilities.misc import as_int
@@ -54,32 +55,34 @@ def _divides(p, n):
     return n % p == 0
 
 class carmichael(Function):
-    """
+    r"""
     Carmichael Numbers:
 
     Certain cryptographic algorithms make use of big prime numbers.
     However, checking whether a big number is prime is not so easy.
-    Randomized prime number checking tests exist that offer a high degree of confidence of
-    accurate determination at low cost, such as the Fermat test.
+    Randomized prime number checking tests exist that offer a high degree of
+    confidence of accurate determination at low cost, such as the Fermat test.
 
-    Let 'a' be a random number between 2 and n - 1, where n is the number whose primality we are testing.
-    Then, n is probably prime if it satisfies the modular arithmetic congruence relation :
+    Let 'a' be a random number between $2$ and $n - 1$, where $n$ is the
+    number whose primality we are testing. Then, $n$ is probably prime if it
+    satisfies the modular arithmetic congruence relation:
+
+    .. math :: a^{n-1} = 1 \pmod{n}
 
-    a^(n-1) = 1(mod n).
     (where mod refers to the modulo operation)
 
     If a number passes the Fermat test several times, then it is prime with a
     high probability.
 
-    Unfortunately, certain composite numbers (non-primes) still pass the Fermat test
-    with every number smaller than themselves.
+    Unfortunately, certain composite numbers (non-primes) still pass the Fermat
+    test with every number smaller than themselves.
     These numbers are called Carmichael numbers.
 
-    A Carmichael number will pass a Fermat primality test to every base b relatively prime to the number,
-    even though it is not actually prime. This makes tests based on Fermat's Little Theorem less effective than
-    strong probable prime tests such as the Baillie-PSW primality test and the Miller-Rabin primality test.
-    mr functions given in sympy/sympy/ntheory/primetest.py will produce wrong results for each and every
-    carmichael number.
+    A Carmichael number will pass a Fermat primality test to every base $b$
+    relatively prime to the number, even though it is not actually prime.
+    This makes tests based on Fermat's Little Theorem less effective than
+    strong probable prime tests such as the Baillie-PSW primality test and
+    the Miller-Rabin primality test.
 
     Examples
     ========
@@ -87,10 +90,6 @@ class carmichael(Function):
     >>> from sympy import carmichael
     >>> carmichael.find_first_n_carmichaels(5)
     [561, 1105, 1729, 2465, 2821]
-    >>> carmichael.is_prime(2465)
-    False
-    >>> carmichael.is_prime(1729)
-    False
     >>> carmichael.find_carmichael_numbers_in_range(0, 562)
     [561]
     >>> carmichael.find_carmichael_numbers_in_range(0,1000)
@@ -108,14 +107,37 @@ class carmichael(Function):
 
     @staticmethod
     def is_perfect_square(n):
+        sympy_deprecation_warning(
+        """
+is_perfect_square is just a wrapper around sympy.ntheory.primetest.is_square
+so use that directly instead.
+        """,
+        deprecated_since_version="1.11",
+        active_deprecations_target='deprecated-carmichael-static-methods',
+        )
         return is_square(n)
 
     @staticmethod
     def divides(p, n):
+        sympy_deprecation_warning(
+        """
+        divides can be replaced by directly testing n % p == 0.
+        """,
+        deprecated_since_version="1.11",
+        active_deprecations_target='deprecated-carmichael-static-methods',
+        )
         return n % p == 0
 
     @staticmethod
     def is_prime(n):
+        sympy_deprecation_warning(
+        """
+is_prime is just a wrapper around sympy.ntheory.primetest.isprime so use that
+directly instead.
+        """,
+        deprecated_since_version="1.11",
+        active_deprecations_target='deprecated-carmichael-static-methods',
+        )
         return isprime(n)
 
     @staticmethod


Test patch:
diff --git a/sympy/functions/combinatorial/tests/test_comb_numbers.py b/sympy/functions/combinatorial/tests/test_comb_numbers.py
index 64a30a48c1..4c726b081b 100644
--- a/sympy/functions/combinatorial/tests/test_comb_numbers.py
+++ b/sympy/functions/combinatorial/tests/test_comb_numbers.py
@@ -21,7 +21,8 @@
 from sympy.core.expr import unchanged
 from sympy.core.numbers import GoldenRatio, Integer
 
-from sympy.testing.pytest import XFAIL, raises, nocache_fail
+from sympy.testing.pytest import (XFAIL, raises, nocache_fail,
+                                  warns_deprecated_sympy)
 from sympy.abc import x
 
 
@@ -31,14 +32,11 @@ def test_carmichael():
     assert carmichael.find_carmichael_numbers_in_range(561, 1105) == carmichael.find_carmichael_numbers_in_range(561,
                                                                                                                  562)
     assert carmichael.find_first_n_carmichaels(5) == [561, 1105, 1729, 2465, 2821]
-    assert carmichael.is_prime(2821) == False
-    assert carmichael.is_prime(2465) == False
-    assert carmichael.is_prime(1729) == False
-    assert carmichael.is_prime(1105) == False
-    assert carmichael.is_prime(561) == False
     raises(ValueError, lambda: carmichael.is_carmichael(-2))
     raises(ValueError, lambda: carmichael.find_carmichael_numbers_in_range(-2, 2))
     raises(ValueError, lambda: carmichael.find_carmichael_numbers_in_range(22, 2))
+    with warns_deprecated_sympy():
+        assert carmichael.is_prime(2821) == False
 
 
 def test_bernoulli():