Source code for py3nt.functions.unary.totient
"""Totient functions"""
import numpy as np
from py3nt.core.factorize import FactorizationFactory
[docs]
def jordan(
n: int,
k: int,
factorizer: None | FactorizationFactory = None,
factorization: None | dict[int, int] = None,
) -> int:
r"""Calculate Jordan's Totient function of :math:`n`:
The number of positive integer tuples :math:`(a_{1},\ldots,a_{k})`
not exceeding :math:`n`.
A generation of Euler's Totient function.
.. math::
J_{k}(n) = n^{k}\prod_{p\mid n}\left(1-\dfrac{1}{p^{k}}\right)\\
\varphi(n) = J_{1}(n)
Parameters
----------
n : ``int``
A positive integer.
k : ``int``
A positive integer.
factorizer : ``Optional[FactorizationFactory]``
If a factorizer object is provided, then it is used to factorize :math:`n` first.
The prime factorization is used to calculate the value.
factorization: ``Optional[dict]``
A dictionary of prime factorization.
Keys must be primes.
Values must be the corresponding multiplicities.
Returns
-------
``int``
:math:`J_{k}(n)`.
Raises
------
``ValueError``
If both ``factorizer`` and ``factorization`` are none.
"""
if n < 1 or k < 1:
raise ValueError("`n` or `k` must be a positive integer.")
if not factorization:
if not factorizer:
raise ValueError("`factorizer` cannot be None")
factorization = factorizer.factorize(n=n)
phi = pow(n, k)
for prime in factorization:
p_k = pow(prime, k)
phi //= p_k
phi *= p_k - 1
return phi
[docs]
def carmichael(
n: int,
factorizer: None | FactorizationFactory = None,
factorization: None | dict[int, int] = None,
) -> int:
r"""Carmichael function :math:`\lambda(n)`.
Also known as the universal exponent :math:`\pmod{n}`.
Calculated using the prime factorization of :math:`n=p_{1}^{e_{1}}\cdots p_{k}^{e_{k}}`
.. math::
\lambda(2^{k+2}) = 2^{k}\\
\lambda(p^{k}) = p^{k-1}(p-1)\\
\lambda(ab) = \mbox{lcm}(\lambda(a), \lambda(b))
if :math:`p` is an odd prime and :math:`\gcd(a,b)=1`.
Use this on the prime factorization.
Parameters
----------
n : ``int``
A positive integer.
factorizer : Optional[FactorizationFactory]
If a factorizer object is provided, then it is used to factorize :math:`n` first.
The prime factorization is used to calculate the value.
factorization: ``Optional[dict]``
A dictionary of prime factorization.
Keys must be primes.
Values must be the corresponding multiplicities.
Returns
-------
``int``
:math:`\lambda(n)`.
Raises
------
ValueError
If :math:`n` is not positive or both `factorization` and `factorizer` are `None`.
"""
if n < 1:
raise ValueError("`n` must be a positive integer.")
if not factorization:
if not factorizer:
raise ValueError("`factorizer` cannot be None")
factorization = factorizer.factorize(n=n)
universal_exponent = 1
if (n & 1) == 0:
multiplicity = 0
while (n & 1) == 0:
n >>= 1
multiplicity += 1
if multiplicity > 1:
universal_exponent *= 1 << (multiplicity - 2)
if n == 1:
return universal_exponent
for prime, multiplicity in factorization.items():
universal_exponent = np.lcm(universal_exponent, pow(prime, multiplicity - 1))
universal_exponent = np.lcm(universal_exponent, prime - 1)
return universal_exponent