|
""" |
|
Integer factorization |
|
""" |
|
|
|
from collections import defaultdict |
|
import math |
|
|
|
from sympy.core.containers import Dict |
|
from sympy.core.mul import Mul |
|
from sympy.core.numbers import Rational, Integer |
|
from sympy.core.intfunc import num_digits |
|
from sympy.core.power import Pow |
|
from sympy.core.random import _randint |
|
from sympy.core.singleton import S |
|
from sympy.external.gmpy import (SYMPY_INTS, gcd, sqrt as isqrt, |
|
sqrtrem, iroot, bit_scan1, remove) |
|
from .primetest import isprime, MERSENNE_PRIME_EXPONENTS, is_mersenne_prime |
|
from .generate import sieve, primerange, nextprime |
|
from .digits import digits |
|
from sympy.utilities.decorator import deprecated |
|
from sympy.utilities.iterables import flatten |
|
from sympy.utilities.misc import as_int, filldedent |
|
from .ecm import _ecm_one_factor |
|
|
|
|
|
def smoothness(n): |
|
""" |
|
Return the B-smooth and B-power smooth values of n. |
|
|
|
The smoothness of n is the largest prime factor of n; the power- |
|
smoothness is the largest divisor raised to its multiplicity. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.ntheory.factor_ import smoothness |
|
>>> smoothness(2**7*3**2) |
|
(3, 128) |
|
>>> smoothness(2**4*13) |
|
(13, 16) |
|
>>> smoothness(2) |
|
(2, 2) |
|
|
|
See Also |
|
======== |
|
|
|
factorint, smoothness_p |
|
""" |
|
|
|
if n == 1: |
|
return (1, 1) |
|
facs = factorint(n) |
|
return max(facs), max(m**facs[m] for m in facs) |
|
|
|
|
|
def smoothness_p(n, m=-1, power=0, visual=None): |
|
""" |
|
Return a list of [m, (p, (M, sm(p + m), psm(p + m)))...] |
|
where: |
|
|
|
1. p**M is the base-p divisor of n |
|
2. sm(p + m) is the smoothness of p + m (m = -1 by default) |
|
3. psm(p + m) is the power smoothness of p + m |
|
|
|
The list is sorted according to smoothness (default) or by power smoothness |
|
if power=1. |
|
|
|
The smoothness of the numbers to the left (m = -1) or right (m = 1) of a |
|
factor govern the results that are obtained from the p +/- 1 type factoring |
|
methods. |
|
|
|
>>> from sympy.ntheory.factor_ import smoothness_p, factorint |
|
>>> smoothness_p(10431, m=1) |
|
(1, [(3, (2, 2, 4)), (19, (1, 5, 5)), (61, (1, 31, 31))]) |
|
>>> smoothness_p(10431) |
|
(-1, [(3, (2, 2, 2)), (19, (1, 3, 9)), (61, (1, 5, 5))]) |
|
>>> smoothness_p(10431, power=1) |
|
(-1, [(3, (2, 2, 2)), (61, (1, 5, 5)), (19, (1, 3, 9))]) |
|
|
|
If visual=True then an annotated string will be returned: |
|
|
|
>>> print(smoothness_p(21477639576571, visual=1)) |
|
p**i=4410317**1 has p-1 B=1787, B-pow=1787 |
|
p**i=4869863**1 has p-1 B=2434931, B-pow=2434931 |
|
|
|
This string can also be generated directly from a factorization dictionary |
|
and vice versa: |
|
|
|
>>> factorint(17*9) |
|
{3: 2, 17: 1} |
|
>>> smoothness_p(_) |
|
'p**i=3**2 has p-1 B=2, B-pow=2\\np**i=17**1 has p-1 B=2, B-pow=16' |
|
>>> smoothness_p(_) |
|
{3: 2, 17: 1} |
|
|
|
The table of the output logic is: |
|
|
|
====== ====== ======= ======= |
|
| Visual |
|
------ ---------------------- |
|
Input True False other |
|
====== ====== ======= ======= |
|
dict str tuple str |
|
str str tuple dict |
|
tuple str tuple str |
|
n str tuple tuple |
|
mul str tuple tuple |
|
====== ====== ======= ======= |
|
|
|
See Also |
|
======== |
|
|
|
factorint, smoothness |
|
""" |
|
|
|
|
|
if visual in (1, 0): |
|
visual = bool(visual) |
|
elif visual not in (True, False): |
|
visual = None |
|
|
|
if isinstance(n, str): |
|
if visual: |
|
return n |
|
d = {} |
|
for li in n.splitlines(): |
|
k, v = [int(i) for i in |
|
li.split('has')[0].split('=')[1].split('**')] |
|
d[k] = v |
|
if visual is not True and visual is not False: |
|
return d |
|
return smoothness_p(d, visual=False) |
|
elif not isinstance(n, tuple): |
|
facs = factorint(n, visual=False) |
|
|
|
if power: |
|
k = -1 |
|
else: |
|
k = 1 |
|
if isinstance(n, tuple): |
|
rv = n |
|
else: |
|
rv = (m, sorted([(f, |
|
tuple([M] + list(smoothness(f + m)))) |
|
for f, M in list(facs.items())], |
|
key=lambda x: (x[1][k], x[0]))) |
|
|
|
if visual is False or (visual is not True) and (type(n) in [int, Mul]): |
|
return rv |
|
lines = [] |
|
for dat in rv[1]: |
|
dat = flatten(dat) |
|
dat.insert(2, m) |
|
lines.append('p**i=%i**%i has p%+i B=%i, B-pow=%i' % tuple(dat)) |
|
return '\n'.join(lines) |
|
|
|
|
|
def multiplicity(p, n): |
|
""" |
|
Find the greatest integer m such that p**m divides n. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import multiplicity, Rational |
|
>>> [multiplicity(5, n) for n in [8, 5, 25, 125, 250]] |
|
[0, 1, 2, 3, 3] |
|
>>> multiplicity(3, Rational(1, 9)) |
|
-2 |
|
|
|
Note: when checking for the multiplicity of a number in a |
|
large factorial it is most efficient to send it as an unevaluated |
|
factorial or to call ``multiplicity_in_factorial`` directly: |
|
|
|
>>> from sympy.ntheory import multiplicity_in_factorial |
|
>>> from sympy import factorial |
|
>>> p = factorial(25) |
|
>>> n = 2**100 |
|
>>> nfac = factorial(n, evaluate=False) |
|
>>> multiplicity(p, nfac) |
|
52818775009509558395695966887 |
|
>>> _ == multiplicity_in_factorial(p, n) |
|
True |
|
|
|
See Also |
|
======== |
|
|
|
trailing |
|
|
|
""" |
|
try: |
|
p, n = as_int(p), as_int(n) |
|
except ValueError: |
|
from sympy.functions.combinatorial.factorials import factorial |
|
if all(isinstance(i, (SYMPY_INTS, Rational)) for i in (p, n)): |
|
p = Rational(p) |
|
n = Rational(n) |
|
if p.q == 1: |
|
if n.p == 1: |
|
return -multiplicity(p.p, n.q) |
|
return multiplicity(p.p, n.p) - multiplicity(p.p, n.q) |
|
elif p.p == 1: |
|
return multiplicity(p.q, n.q) |
|
else: |
|
like = min( |
|
multiplicity(p.p, n.p), |
|
multiplicity(p.q, n.q)) |
|
cross = min( |
|
multiplicity(p.q, n.p), |
|
multiplicity(p.p, n.q)) |
|
return like - cross |
|
elif (isinstance(p, (SYMPY_INTS, Integer)) and |
|
isinstance(n, factorial) and |
|
isinstance(n.args[0], Integer) and |
|
n.args[0] >= 0): |
|
return multiplicity_in_factorial(p, n.args[0]) |
|
raise ValueError('expecting ints or fractions, got %s and %s' % (p, n)) |
|
|
|
if n == 0: |
|
raise ValueError('no such integer exists: multiplicity of %s is not-defined' %(n)) |
|
return remove(n, p)[1] |
|
|
|
|
|
def multiplicity_in_factorial(p, n): |
|
"""return the largest integer ``m`` such that ``p**m`` divides ``n!`` |
|
without calculating the factorial of ``n``. |
|
|
|
Parameters |
|
========== |
|
|
|
p : Integer |
|
positive integer |
|
n : Integer |
|
non-negative integer |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.ntheory import multiplicity_in_factorial |
|
>>> from sympy import factorial |
|
|
|
>>> multiplicity_in_factorial(2, 3) |
|
1 |
|
|
|
An instructive use of this is to tell how many trailing zeros |
|
a given factorial has. For example, there are 6 in 25!: |
|
|
|
>>> factorial(25) |
|
15511210043330985984000000 |
|
>>> multiplicity_in_factorial(10, 25) |
|
6 |
|
|
|
For large factorials, it is much faster/feasible to use |
|
this function rather than computing the actual factorial: |
|
|
|
>>> multiplicity_in_factorial(factorial(25), 2**100) |
|
52818775009509558395695966887 |
|
|
|
See Also |
|
======== |
|
|
|
multiplicity |
|
|
|
""" |
|
|
|
p, n = as_int(p), as_int(n) |
|
|
|
if p <= 0: |
|
raise ValueError('expecting positive integer got %s' % p ) |
|
|
|
if n < 0: |
|
raise ValueError('expecting non-negative integer got %s' % n ) |
|
|
|
|
|
|
|
|
|
f = defaultdict(int) |
|
for k, v in factorint(p).items(): |
|
f[v] = max(k, f[v]) |
|
|
|
|
|
|
|
|
|
return min((n + k - sum(digits(n, k)))//(k - 1)//v for v, k in f.items()) |
|
|
|
|
|
def _perfect_power(n, next_p=2): |
|
""" Return integers ``(b, e)`` such that ``n == b**e`` if ``n`` is a unique |
|
perfect power with ``e > 1``, else ``False`` (e.g. 1 is not a perfect power). |
|
|
|
Explanation |
|
=========== |
|
|
|
This is a low-level helper for ``perfect_power``, for internal use. |
|
|
|
Parameters |
|
========== |
|
|
|
n : int |
|
assume that n is a nonnegative integer |
|
next_p : int |
|
Assume that n has no factor less than next_p. |
|
i.e., all(n % p for p in range(2, next_p)) is True |
|
|
|
Examples |
|
======== |
|
>>> from sympy.ntheory.factor_ import _perfect_power |
|
>>> _perfect_power(16) |
|
(2, 4) |
|
>>> _perfect_power(17) |
|
False |
|
|
|
""" |
|
if n <= 3: |
|
return False |
|
|
|
factors = {} |
|
g = 0 |
|
multi = 1 |
|
|
|
def done(n, factors, g, multi): |
|
g = gcd(g, multi) |
|
if g == 1: |
|
return False |
|
factors[n] = multi |
|
return math.prod(p**(e//g) for p, e in factors.items()), g |
|
|
|
|
|
if n <= 1_000_000: |
|
n = _factorint_small(factors, n, 1_000, 1_000, next_p)[0] |
|
if n > 1: |
|
return False |
|
g = gcd(*factors.values()) |
|
if g == 1: |
|
return False |
|
return math.prod(p**(e//g) for p, e in factors.items()), g |
|
|
|
|
|
if next_p < 3: |
|
g = bit_scan1(n) |
|
if g: |
|
if g == 1: |
|
return False |
|
n >>= g |
|
factors[2] = g |
|
if n == 1: |
|
return 2, g |
|
else: |
|
|
|
|
|
m, _exact = iroot(n, g) |
|
if _exact: |
|
return 2*m, g |
|
elif isprime(g): |
|
return False |
|
next_p = 3 |
|
|
|
|
|
while n & 7 == 1: |
|
m, _exact = iroot(n, 2) |
|
if _exact: |
|
n = m |
|
multi <<= 1 |
|
else: |
|
break |
|
if n < next_p**3: |
|
return done(n, factors, g, multi) |
|
|
|
|
|
|
|
|
|
|
|
tf_max = n.bit_length()//27 + 24 |
|
if next_p < tf_max: |
|
for p in primerange(next_p, tf_max): |
|
m, t = remove(n, p) |
|
if t: |
|
n = m |
|
t *= multi |
|
_g = gcd(g, t) |
|
if _g == 1: |
|
return False |
|
factors[p] = t |
|
if n == 1: |
|
return math.prod(p**(e//_g) |
|
for p, e in factors.items()), _g |
|
elif g == 0 or _g < g: |
|
g = _g |
|
m, _exact = iroot(n**multi, g) |
|
if _exact: |
|
return m * math.prod(p**(e//g) |
|
for p, e in factors.items()), g |
|
elif isprime(g): |
|
return False |
|
next_p = tf_max |
|
if n < next_p**3: |
|
return done(n, factors, g, multi) |
|
|
|
|
|
if g: |
|
|
|
|
|
prime_iter = sorted(factorint(g >> bit_scan1(g)).keys()) |
|
else: |
|
|
|
|
|
prime_iter = primerange(3, int(math.log(n, next_p)) + 2) |
|
logn = math.log2(n) |
|
threshold = logn / 40 |
|
for p in prime_iter: |
|
if threshold < p: |
|
|
|
while True: |
|
b = pow(2, logn / p) |
|
rb = int(b + 0.5) |
|
if abs(rb - b) < 0.01 and rb**p == n: |
|
n = rb |
|
multi *= p |
|
logn = math.log2(n) |
|
else: |
|
break |
|
else: |
|
while True: |
|
m, _exact = iroot(n, p) |
|
if _exact: |
|
n = m |
|
multi *= p |
|
logn = math.log2(n) |
|
else: |
|
break |
|
if n < next_p**(p + 2): |
|
break |
|
return done(n, factors, g, multi) |
|
|
|
|
|
def perfect_power(n, candidates=None, big=True, factor=True): |
|
""" |
|
Return ``(b, e)`` such that ``n`` == ``b**e`` if ``n`` is a unique |
|
perfect power with ``e > 1``, else ``False`` (e.g. 1 is not a |
|
perfect power). A ValueError is raised if ``n`` is not Rational. |
|
|
|
By default, the base is recursively decomposed and the exponents |
|
collected so the largest possible ``e`` is sought. If ``big=False`` |
|
then the smallest possible ``e`` (thus prime) will be chosen. |
|
|
|
If ``factor=True`` then simultaneous factorization of ``n`` is |
|
attempted since finding a factor indicates the only possible root |
|
for ``n``. This is True by default since only a few small factors will |
|
be tested in the course of searching for the perfect power. |
|
|
|
The use of ``candidates`` is primarily for internal use; if provided, |
|
False will be returned if ``n`` cannot be written as a power with one |
|
of the candidates as an exponent and factoring (beyond testing for |
|
a factor of 2) will not be attempted. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import perfect_power, Rational |
|
>>> perfect_power(16) |
|
(2, 4) |
|
>>> perfect_power(16, big=False) |
|
(4, 2) |
|
|
|
Negative numbers can only have odd perfect powers: |
|
|
|
>>> perfect_power(-4) |
|
False |
|
>>> perfect_power(-8) |
|
(-2, 3) |
|
|
|
Rationals are also recognized: |
|
|
|
>>> perfect_power(Rational(1, 2)**3) |
|
(1/2, 3) |
|
>>> perfect_power(Rational(-3, 2)**3) |
|
(-3/2, 3) |
|
|
|
Notes |
|
===== |
|
|
|
To know whether an integer is a perfect power of 2 use |
|
|
|
>>> is2pow = lambda n: bool(n and not n & (n - 1)) |
|
>>> [(i, is2pow(i)) for i in range(5)] |
|
[(0, False), (1, True), (2, True), (3, False), (4, True)] |
|
|
|
It is not necessary to provide ``candidates``. When provided |
|
it will be assumed that they are ints. The first one that is |
|
larger than the computed maximum possible exponent will signal |
|
failure for the routine. |
|
|
|
>>> perfect_power(3**8, [9]) |
|
False |
|
>>> perfect_power(3**8, [2, 4, 8]) |
|
(3, 8) |
|
>>> perfect_power(3**8, [4, 8], big=False) |
|
(9, 4) |
|
|
|
See Also |
|
======== |
|
sympy.core.intfunc.integer_nthroot |
|
sympy.ntheory.primetest.is_square |
|
""" |
|
if isinstance(n, Rational) and not n.is_Integer: |
|
p, q = n.as_numer_denom() |
|
if p is S.One: |
|
pp = perfect_power(q) |
|
if pp: |
|
pp = (n.func(1, pp[0]), pp[1]) |
|
else: |
|
pp = perfect_power(p) |
|
if pp: |
|
num, e = pp |
|
pq = perfect_power(q, [e]) |
|
if pq: |
|
den, _ = pq |
|
pp = n.func(num, den), e |
|
return pp |
|
|
|
n = as_int(n) |
|
if n < 0: |
|
pp = perfect_power(-n) |
|
if pp: |
|
b, e = pp |
|
if e % 2: |
|
return -b, e |
|
return False |
|
|
|
if candidates is None and big: |
|
return _perfect_power(n) |
|
|
|
if n <= 3: |
|
|
|
|
|
return False |
|
logn = math.log2(n) |
|
max_possible = int(logn) + 2 |
|
not_square = n % 10 in [2, 3, 7, 8] |
|
min_possible = 2 + not_square |
|
if not candidates: |
|
candidates = primerange(min_possible, max_possible) |
|
else: |
|
candidates = sorted([i for i in candidates |
|
if min_possible <= i < max_possible]) |
|
if n%2 == 0: |
|
e = bit_scan1(n) |
|
candidates = [i for i in candidates if e%i == 0] |
|
if big: |
|
candidates = reversed(candidates) |
|
for e in candidates: |
|
r, ok = iroot(n, e) |
|
if ok: |
|
return int(r), e |
|
return False |
|
|
|
def _factors(): |
|
rv = 2 + n % 2 |
|
while True: |
|
yield rv |
|
rv = nextprime(rv) |
|
|
|
for fac, e in zip(_factors(), candidates): |
|
|
|
if factor and n % fac == 0: |
|
|
|
e = remove(n, fac)[1] |
|
|
|
if e == 1: |
|
return False |
|
|
|
|
|
r, exact = iroot(n, e) |
|
if not exact: |
|
|
|
|
|
|
|
|
|
|
|
m = n//fac**e |
|
rE = perfect_power(m, candidates=divisors(e, generator=True)) |
|
if not rE: |
|
return False |
|
else: |
|
r, E = rE |
|
r, e = fac**(e//E)*r, E |
|
if not big: |
|
e0 = primefactors(e) |
|
if e0[0] != e: |
|
r, e = r**(e//e0[0]), e0[0] |
|
return int(r), e |
|
|
|
|
|
if logn/e < 40: |
|
b = 2.0**(logn/e) |
|
if abs(int(b + 0.5) - b) > 0.01: |
|
continue |
|
|
|
|
|
r, exact = iroot(n, e) |
|
if exact: |
|
if big: |
|
m = perfect_power(r, big=big, factor=factor) |
|
if m: |
|
r, e = m[0], e*m[1] |
|
return int(r), e |
|
|
|
return False |
|
|
|
|
|
def pollard_rho(n, s=2, a=1, retries=5, seed=1234, max_steps=None, F=None): |
|
r""" |
|
Use Pollard's rho method to try to extract a nontrivial factor |
|
of ``n``. The returned factor may be a composite number. If no |
|
factor is found, ``None`` is returned. |
|
|
|
The algorithm generates pseudo-random values of x with a generator |
|
function, replacing x with F(x). If F is not supplied then the |
|
function x**2 + ``a`` is used. The first value supplied to F(x) is ``s``. |
|
Upon failure (if ``retries`` is > 0) a new ``a`` and ``s`` will be |
|
supplied; the ``a`` will be ignored if F was supplied. |
|
|
|
The sequence of numbers generated by such functions generally have a |
|
a lead-up to some number and then loop around back to that number and |
|
begin to repeat the sequence, e.g. 1, 2, 3, 4, 5, 3, 4, 5 -- this leader |
|
and loop look a bit like the Greek letter rho, and thus the name, 'rho'. |
|
|
|
For a given function, very different leader-loop values can be obtained |
|
so it is a good idea to allow for retries: |
|
|
|
>>> from sympy.ntheory.generate import cycle_length |
|
>>> n = 16843009 |
|
>>> F = lambda x:(2048*pow(x, 2, n) + 32767) % n |
|
>>> for s in range(5): |
|
... print('loop length = %4i; leader length = %3i' % next(cycle_length(F, s))) |
|
... |
|
loop length = 2489; leader length = 43 |
|
loop length = 78; leader length = 121 |
|
loop length = 1482; leader length = 100 |
|
loop length = 1482; leader length = 286 |
|
loop length = 1482; leader length = 101 |
|
|
|
Here is an explicit example where there is a three element leadup to |
|
a sequence of 3 numbers (11, 14, 4) that then repeat: |
|
|
|
>>> x=2 |
|
>>> for i in range(9): |
|
... print(x) |
|
... x=(x**2+12)%17 |
|
... |
|
2 |
|
16 |
|
13 |
|
11 |
|
14 |
|
4 |
|
11 |
|
14 |
|
4 |
|
>>> next(cycle_length(lambda x: (x**2+12)%17, 2)) |
|
(3, 3) |
|
>>> list(cycle_length(lambda x: (x**2+12)%17, 2, values=True)) |
|
[2, 16, 13, 11, 14, 4] |
|
|
|
Instead of checking the differences of all generated values for a gcd |
|
with n, only the kth and 2*kth numbers are checked, e.g. 1st and 2nd, |
|
2nd and 4th, 3rd and 6th until it has been detected that the loop has been |
|
traversed. Loops may be many thousands of steps long before rho finds a |
|
factor or reports failure. If ``max_steps`` is specified, the iteration |
|
is cancelled with a failure after the specified number of steps. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import pollard_rho |
|
>>> n=16843009 |
|
>>> F=lambda x:(2048*pow(x,2,n) + 32767) % n |
|
>>> pollard_rho(n, F=F) |
|
257 |
|
|
|
Use the default setting with a bad value of ``a`` and no retries: |
|
|
|
>>> pollard_rho(n, a=n-2, retries=0) |
|
|
|
If retries is > 0 then perhaps the problem will correct itself when |
|
new values are generated for a: |
|
|
|
>>> pollard_rho(n, a=n-2, retries=1) |
|
257 |
|
|
|
References |
|
========== |
|
|
|
.. [1] Richard Crandall & Carl Pomerance (2005), "Prime Numbers: |
|
A Computational Perspective", Springer, 2nd edition, 229-231 |
|
|
|
""" |
|
n = int(n) |
|
if n < 5: |
|
raise ValueError('pollard_rho should receive n > 4') |
|
randint = _randint(seed + retries) |
|
V = s |
|
for i in range(retries + 1): |
|
U = V |
|
if not F: |
|
F = lambda x: (pow(x, 2, n) + a) % n |
|
j = 0 |
|
while 1: |
|
if max_steps and (j > max_steps): |
|
break |
|
j += 1 |
|
U = F(U) |
|
V = F(F(V)) |
|
g = gcd(U - V, n) |
|
if g == 1: |
|
continue |
|
if g == n: |
|
break |
|
return int(g) |
|
V = randint(0, n - 1) |
|
a = randint(1, n - 3) |
|
F = None |
|
return None |
|
|
|
|
|
def pollard_pm1(n, B=10, a=2, retries=0, seed=1234): |
|
""" |
|
Use Pollard's p-1 method to try to extract a nontrivial factor |
|
of ``n``. Either a divisor (perhaps composite) or ``None`` is returned. |
|
|
|
The value of ``a`` is the base that is used in the test gcd(a**M - 1, n). |
|
The default is 2. If ``retries`` > 0 then if no factor is found after the |
|
first attempt, a new ``a`` will be generated randomly (using the ``seed``) |
|
and the process repeated. |
|
|
|
Note: the value of M is lcm(1..B) = reduce(ilcm, range(2, B + 1)). |
|
|
|
A search is made for factors next to even numbers having a power smoothness |
|
less than ``B``. Choosing a larger B increases the likelihood of finding a |
|
larger factor but takes longer. Whether a factor of n is found or not |
|
depends on ``a`` and the power smoothness of the even number just less than |
|
the factor p (hence the name p - 1). |
|
|
|
Although some discussion of what constitutes a good ``a`` some |
|
descriptions are hard to interpret. At the modular.math site referenced |
|
below it is stated that if gcd(a**M - 1, n) = N then a**M % q**r is 1 |
|
for every prime power divisor of N. But consider the following: |
|
|
|
>>> from sympy.ntheory.factor_ import smoothness_p, pollard_pm1 |
|
>>> n=257*1009 |
|
>>> smoothness_p(n) |
|
(-1, [(257, (1, 2, 256)), (1009, (1, 7, 16))]) |
|
|
|
So we should (and can) find a root with B=16: |
|
|
|
>>> pollard_pm1(n, B=16, a=3) |
|
1009 |
|
|
|
If we attempt to increase B to 256 we find that it does not work: |
|
|
|
>>> pollard_pm1(n, B=256) |
|
>>> |
|
|
|
But if the value of ``a`` is changed we find that only multiples of |
|
257 work, e.g.: |
|
|
|
>>> pollard_pm1(n, B=256, a=257) |
|
1009 |
|
|
|
Checking different ``a`` values shows that all the ones that did not |
|
work had a gcd value not equal to ``n`` but equal to one of the |
|
factors: |
|
|
|
>>> from sympy import ilcm, igcd, factorint, Pow |
|
>>> M = 1 |
|
>>> for i in range(2, 256): |
|
... M = ilcm(M, i) |
|
... |
|
>>> set([igcd(pow(a, M, n) - 1, n) for a in range(2, 256) if |
|
... igcd(pow(a, M, n) - 1, n) != n]) |
|
{1009} |
|
|
|
But does aM % d for every divisor of n give 1? |
|
|
|
>>> aM = pow(255, M, n) |
|
>>> [(d, aM%Pow(*d.args)) for d in factorint(n, visual=True).args] |
|
[(257**1, 1), (1009**1, 1)] |
|
|
|
No, only one of them. So perhaps the principle is that a root will |
|
be found for a given value of B provided that: |
|
|
|
1) the power smoothness of the p - 1 value next to the root |
|
does not exceed B |
|
2) a**M % p != 1 for any of the divisors of n. |
|
|
|
By trying more than one ``a`` it is possible that one of them |
|
will yield a factor. |
|
|
|
Examples |
|
======== |
|
|
|
With the default smoothness bound, this number cannot be cracked: |
|
|
|
>>> from sympy.ntheory import pollard_pm1 |
|
>>> pollard_pm1(21477639576571) |
|
|
|
Increasing the smoothness bound helps: |
|
|
|
>>> pollard_pm1(21477639576571, B=2000) |
|
4410317 |
|
|
|
Looking at the smoothness of the factors of this number we find: |
|
|
|
>>> from sympy.ntheory.factor_ import smoothness_p, factorint |
|
>>> print(smoothness_p(21477639576571, visual=1)) |
|
p**i=4410317**1 has p-1 B=1787, B-pow=1787 |
|
p**i=4869863**1 has p-1 B=2434931, B-pow=2434931 |
|
|
|
The B and B-pow are the same for the p - 1 factorizations of the divisors |
|
because those factorizations had a very large prime factor: |
|
|
|
>>> factorint(4410317 - 1) |
|
{2: 2, 617: 1, 1787: 1} |
|
>>> factorint(4869863-1) |
|
{2: 1, 2434931: 1} |
|
|
|
Note that until B reaches the B-pow value of 1787, the number is not cracked; |
|
|
|
>>> pollard_pm1(21477639576571, B=1786) |
|
>>> pollard_pm1(21477639576571, B=1787) |
|
4410317 |
|
|
|
The B value has to do with the factors of the number next to the divisor, |
|
not the divisors themselves. A worst case scenario is that the number next |
|
to the factor p has a large prime divisisor or is a perfect power. If these |
|
conditions apply then the power-smoothness will be about p/2 or p. The more |
|
realistic is that there will be a large prime factor next to p requiring |
|
a B value on the order of p/2. Although primes may have been searched for |
|
up to this level, the p/2 is a factor of p - 1, something that we do not |
|
know. The modular.math reference below states that 15% of numbers in the |
|
range of 10**15 to 15**15 + 10**4 are 10**6 power smooth so a B of 10**6 |
|
will fail 85% of the time in that range. From 10**8 to 10**8 + 10**3 the |
|
percentages are nearly reversed...but in that range the simple trial |
|
division is quite fast. |
|
|
|
References |
|
========== |
|
|
|
.. [1] Richard Crandall & Carl Pomerance (2005), "Prime Numbers: |
|
A Computational Perspective", Springer, 2nd edition, 236-238 |
|
.. [2] https://web.archive.org/web/20150716201437/http://modular.math.washington.edu/edu/2007/spring/ent/ent-html/node81.html |
|
.. [3] https://www.cs.toronto.edu/~yuvalf/Factorization.pdf |
|
""" |
|
|
|
n = int(n) |
|
if n < 4 or B < 3: |
|
raise ValueError('pollard_pm1 should receive n > 3 and B > 2') |
|
randint = _randint(seed + B) |
|
|
|
|
|
|
|
|
|
for i in range(retries + 1): |
|
aM = a |
|
for p in sieve.primerange(2, B + 1): |
|
e = int(math.log(B, p)) |
|
aM = pow(aM, pow(p, e), n) |
|
g = gcd(aM - 1, n) |
|
if 1 < g < n: |
|
return int(g) |
|
|
|
|
|
|
|
|
|
|
|
|
|
a = randint(2, n - 2) |
|
|
|
|
|
def _trial(factors, n, candidates, verbose=False): |
|
""" |
|
Helper function for integer factorization. Trial factors ``n` |
|
against all integers given in the sequence ``candidates`` |
|
and updates the dict ``factors`` in-place. Returns the reduced |
|
value of ``n`` and a flag indicating whether any factors were found. |
|
""" |
|
if verbose: |
|
factors0 = list(factors.keys()) |
|
nfactors = len(factors) |
|
for d in candidates: |
|
if n % d == 0: |
|
n, m = remove(n // d, d) |
|
factors[d] = m + 1 |
|
if verbose: |
|
for k in sorted(set(factors).difference(set(factors0))): |
|
print(factor_msg % (k, factors[k])) |
|
return int(n), len(factors) != nfactors |
|
|
|
|
|
def _check_termination(factors, n, limit, use_trial, use_rho, use_pm1, |
|
verbose, next_p): |
|
""" |
|
Helper function for integer factorization. Checks if ``n`` |
|
is a prime or a perfect power, and in those cases updates the factorization. |
|
""" |
|
if verbose: |
|
print('Check for termination') |
|
if n == 1: |
|
if verbose: |
|
print(complete_msg) |
|
return True |
|
if n < next_p**2 or isprime(n): |
|
factors[int(n)] = 1 |
|
if verbose: |
|
print(complete_msg) |
|
return True |
|
|
|
|
|
|
|
p = _perfect_power(n, next_p) |
|
if not p: |
|
return False |
|
base, exp = p |
|
if base < next_p**2 or isprime(base): |
|
factors[base] = exp |
|
else: |
|
facs = factorint(base, limit, use_trial, use_rho, use_pm1, |
|
verbose=False) |
|
for b, e in facs.items(): |
|
if verbose: |
|
print(factor_msg % (b, e)) |
|
|
|
factors[b] = int(exp*e) |
|
if verbose: |
|
print(complete_msg) |
|
return True |
|
|
|
|
|
trial_int_msg = "Trial division with ints [%i ... %i] and fail_max=%i" |
|
trial_msg = "Trial division with primes [%i ... %i]" |
|
rho_msg = "Pollard's rho with retries %i, max_steps %i and seed %i" |
|
pm1_msg = "Pollard's p-1 with smoothness bound %i and seed %i" |
|
ecm_msg = "Elliptic Curve with B1 bound %i, B2 bound %i, num_curves %i" |
|
factor_msg = '\t%i ** %i' |
|
fermat_msg = 'Close factors satisying Fermat condition found.' |
|
complete_msg = 'Factorization is complete.' |
|
|
|
|
|
def _factorint_small(factors, n, limit, fail_max, next_p=2): |
|
""" |
|
Return the value of n and either a 0 (indicating that factorization up |
|
to the limit was complete) or else the next near-prime that would have |
|
been tested. |
|
|
|
Factoring stops if there are fail_max unsuccessful tests in a row. |
|
|
|
If factors of n were found they will be in the factors dictionary as |
|
{factor: multiplicity} and the returned value of n will have had those |
|
factors removed. The factors dictionary is modified in-place. |
|
|
|
""" |
|
|
|
def done(n, d): |
|
"""return n, d if the sqrt(n) was not reached yet, else |
|
n, 0 indicating that factoring is done. |
|
""" |
|
if d*d <= n: |
|
return n, d |
|
return n, 0 |
|
|
|
limit2 = limit**2 |
|
threshold2 = min(n, limit2) |
|
|
|
if next_p < 3: |
|
if not n & 1: |
|
m = bit_scan1(n) |
|
factors[2] = m |
|
n >>= m |
|
threshold2 = min(n, limit2) |
|
next_p = 3 |
|
if threshold2 < 9: |
|
return done(n, next_p) |
|
|
|
if next_p < 5: |
|
if not n % 3: |
|
n //= 3 |
|
m = 1 |
|
while not n % 3: |
|
n //= 3 |
|
m += 1 |
|
if m == 20: |
|
n, mm = remove(n, 3) |
|
m += mm |
|
break |
|
factors[3] = m |
|
threshold2 = min(n, limit2) |
|
next_p = 5 |
|
if threshold2 < 25: |
|
return done(n, next_p) |
|
|
|
|
|
|
|
|
|
|
|
p6 = next_p % 6 |
|
next_p += (-1 if p6 < 2 else 5) - p6 |
|
|
|
fails = 0 |
|
while fails < fail_max: |
|
|
|
if n % next_p: |
|
fails += 1 |
|
else: |
|
n //= next_p |
|
m = 1 |
|
while not n % next_p: |
|
n //= next_p |
|
m += 1 |
|
if m == 20: |
|
n, mm = remove(n, next_p) |
|
m += mm |
|
break |
|
factors[next_p] = m |
|
fails = 0 |
|
threshold2 = min(n, limit2) |
|
next_p += 2 |
|
if threshold2 < next_p**2: |
|
return done(n, next_p) |
|
|
|
|
|
if n % next_p: |
|
fails += 1 |
|
else: |
|
n //= next_p |
|
m = 1 |
|
while not n % next_p: |
|
n //= next_p |
|
m += 1 |
|
if m == 20: |
|
n, mm = remove(n, next_p) |
|
m += mm |
|
break |
|
factors[next_p] = m |
|
fails = 0 |
|
threshold2 = min(n, limit2) |
|
next_p += 4 |
|
if threshold2 < next_p**2: |
|
return done(n, next_p) |
|
return done(n, next_p) |
|
|
|
|
|
def factorint(n, limit=None, use_trial=True, use_rho=True, use_pm1=True, |
|
use_ecm=True, verbose=False, visual=None, multiple=False): |
|
r""" |
|
Given a positive integer ``n``, ``factorint(n)`` returns a dict containing |
|
the prime factors of ``n`` as keys and their respective multiplicities |
|
as values. For example: |
|
|
|
>>> from sympy.ntheory import factorint |
|
>>> factorint(2000) # 2000 = (2**4) * (5**3) |
|
{2: 4, 5: 3} |
|
>>> factorint(65537) # This number is prime |
|
{65537: 1} |
|
|
|
For input less than 2, factorint behaves as follows: |
|
|
|
- ``factorint(1)`` returns the empty factorization, ``{}`` |
|
- ``factorint(0)`` returns ``{0:1}`` |
|
- ``factorint(-n)`` adds ``-1:1`` to the factors and then factors ``n`` |
|
|
|
Partial Factorization: |
|
|
|
If ``limit`` (> 3) is specified, the search is stopped after performing |
|
trial division up to (and including) the limit (or taking a |
|
corresponding number of rho/p-1 steps). This is useful if one has |
|
a large number and only is interested in finding small factors (if |
|
any). Note that setting a limit does not prevent larger factors |
|
from being found early; it simply means that the largest factor may |
|
be composite. Since checking for perfect power is relatively cheap, it is |
|
done regardless of the limit setting. |
|
|
|
This number, for example, has two small factors and a huge |
|
semi-prime factor that cannot be reduced easily: |
|
|
|
>>> from sympy.ntheory import isprime |
|
>>> a = 1407633717262338957430697921446883 |
|
>>> f = factorint(a, limit=10000) |
|
>>> f == {991: 1, int(202916782076162456022877024859): 1, 7: 1} |
|
True |
|
>>> isprime(max(f)) |
|
False |
|
|
|
This number has a small factor and a residual perfect power whose |
|
base is greater than the limit: |
|
|
|
>>> factorint(3*101**7, limit=5) |
|
{3: 1, 101: 7} |
|
|
|
List of Factors: |
|
|
|
If ``multiple`` is set to ``True`` then a list containing the |
|
prime factors including multiplicities is returned. |
|
|
|
>>> factorint(24, multiple=True) |
|
[2, 2, 2, 3] |
|
|
|
Visual Factorization: |
|
|
|
If ``visual`` is set to ``True``, then it will return a visual |
|
factorization of the integer. For example: |
|
|
|
>>> from sympy import pprint |
|
>>> pprint(factorint(4200, visual=True)) |
|
3 1 2 1 |
|
2 *3 *5 *7 |
|
|
|
Note that this is achieved by using the evaluate=False flag in Mul |
|
and Pow. If you do other manipulations with an expression where |
|
evaluate=False, it may evaluate. Therefore, you should use the |
|
visual option only for visualization, and use the normal dictionary |
|
returned by visual=False if you want to perform operations on the |
|
factors. |
|
|
|
You can easily switch between the two forms by sending them back to |
|
factorint: |
|
|
|
>>> from sympy import Mul |
|
>>> regular = factorint(1764); regular |
|
{2: 2, 3: 2, 7: 2} |
|
>>> pprint(factorint(regular)) |
|
2 2 2 |
|
2 *3 *7 |
|
|
|
>>> visual = factorint(1764, visual=True); pprint(visual) |
|
2 2 2 |
|
2 *3 *7 |
|
>>> print(factorint(visual)) |
|
{2: 2, 3: 2, 7: 2} |
|
|
|
If you want to send a number to be factored in a partially factored form |
|
you can do so with a dictionary or unevaluated expression: |
|
|
|
>>> factorint(factorint({4: 2, 12: 3})) # twice to toggle to dict form |
|
{2: 10, 3: 3} |
|
>>> factorint(Mul(4, 12, evaluate=False)) |
|
{2: 4, 3: 1} |
|
|
|
The table of the output logic is: |
|
|
|
====== ====== ======= ======= |
|
Visual |
|
------ ---------------------- |
|
Input True False other |
|
====== ====== ======= ======= |
|
dict mul dict mul |
|
n mul dict dict |
|
mul mul dict dict |
|
====== ====== ======= ======= |
|
|
|
Notes |
|
===== |
|
|
|
Algorithm: |
|
|
|
The function switches between multiple algorithms. Trial division |
|
quickly finds small factors (of the order 1-5 digits), and finds |
|
all large factors if given enough time. The Pollard rho and p-1 |
|
algorithms are used to find large factors ahead of time; they |
|
will often find factors of the order of 10 digits within a few |
|
seconds: |
|
|
|
>>> factors = factorint(12345678910111213141516) |
|
>>> for base, exp in sorted(factors.items()): |
|
... print('%s %s' % (base, exp)) |
|
... |
|
2 2 |
|
2507191691 1 |
|
1231026625769 1 |
|
|
|
Any of these methods can optionally be disabled with the following |
|
boolean parameters: |
|
|
|
- ``use_trial``: Toggle use of trial division |
|
- ``use_rho``: Toggle use of Pollard's rho method |
|
- ``use_pm1``: Toggle use of Pollard's p-1 method |
|
|
|
``factorint`` also periodically checks if the remaining part is |
|
a prime number or a perfect power, and in those cases stops. |
|
|
|
For unevaluated factorial, it uses Legendre's formula(theorem). |
|
|
|
|
|
If ``verbose`` is set to ``True``, detailed progress is printed. |
|
|
|
See Also |
|
======== |
|
|
|
smoothness, smoothness_p, divisors |
|
|
|
""" |
|
if isinstance(n, Dict): |
|
n = dict(n) |
|
if multiple: |
|
fac = factorint(n, limit=limit, use_trial=use_trial, |
|
use_rho=use_rho, use_pm1=use_pm1, |
|
verbose=verbose, visual=False, multiple=False) |
|
factorlist = sum(([p] * fac[p] if fac[p] > 0 else [S.One/p]*(-fac[p]) |
|
for p in sorted(fac)), []) |
|
return factorlist |
|
|
|
factordict = {} |
|
if visual and not isinstance(n, (Mul, dict)): |
|
factordict = factorint(n, limit=limit, use_trial=use_trial, |
|
use_rho=use_rho, use_pm1=use_pm1, |
|
verbose=verbose, visual=False) |
|
elif isinstance(n, Mul): |
|
factordict = {int(k): int(v) for k, v in |
|
n.as_powers_dict().items()} |
|
elif isinstance(n, dict): |
|
factordict = n |
|
if factordict and isinstance(n, (Mul, dict)): |
|
|
|
for key in list(factordict.keys()): |
|
if isprime(key): |
|
continue |
|
e = factordict.pop(key) |
|
d = factorint(key, limit=limit, use_trial=use_trial, use_rho=use_rho, |
|
use_pm1=use_pm1, verbose=verbose, visual=False) |
|
for k, v in d.items(): |
|
if k in factordict: |
|
factordict[k] += v*e |
|
else: |
|
factordict[k] = v*e |
|
if visual or (type(n) is dict and |
|
visual is not True and |
|
visual is not False): |
|
if factordict == {}: |
|
return S.One |
|
if -1 in factordict: |
|
factordict.pop(-1) |
|
args = [S.NegativeOne] |
|
else: |
|
args = [] |
|
args.extend([Pow(*i, evaluate=False) |
|
for i in sorted(factordict.items())]) |
|
return Mul(*args, evaluate=False) |
|
elif isinstance(n, (dict, Mul)): |
|
return factordict |
|
|
|
assert use_trial or use_rho or use_pm1 or use_ecm |
|
|
|
from sympy.functions.combinatorial.factorials import factorial |
|
if isinstance(n, factorial): |
|
x = as_int(n.args[0]) |
|
if x >= 20: |
|
factors = {} |
|
m = 2 |
|
for p in sieve.primerange(2, x + 1): |
|
if m > 1: |
|
m, q = 0, x // p |
|
while q != 0: |
|
m += q |
|
q //= p |
|
factors[p] = m |
|
if factors and verbose: |
|
for k in sorted(factors): |
|
print(factor_msg % (k, factors[k])) |
|
if verbose: |
|
print(complete_msg) |
|
return factors |
|
else: |
|
|
|
|
|
n = n.func(x) |
|
|
|
n = as_int(n) |
|
if limit: |
|
limit = int(limit) |
|
use_ecm = False |
|
|
|
|
|
if n < 0: |
|
factors = factorint( |
|
-n, limit=limit, use_trial=use_trial, use_rho=use_rho, |
|
use_pm1=use_pm1, verbose=verbose, visual=False) |
|
factors[-1] = 1 |
|
return factors |
|
|
|
if limit and limit < 2: |
|
if n == 1: |
|
return {} |
|
return {n: 1} |
|
elif n < 10: |
|
|
|
|
|
return [{0: 1}, {}, {2: 1}, {3: 1}, {2: 2}, {5: 1}, |
|
{2: 1, 3: 1}, {7: 1}, {2: 3}, {3: 2}][n] |
|
|
|
factors = {} |
|
|
|
|
|
if verbose: |
|
sn = str(n) |
|
if len(sn) > 50: |
|
print('Factoring %s' % sn[:5] + \ |
|
'..(%i other digits)..' % (len(sn) - 10) + sn[-5:]) |
|
else: |
|
print('Factoring', n) |
|
|
|
|
|
|
|
|
|
small = 2**15 |
|
fail_max = 600 |
|
small = min(small, limit or small) |
|
if verbose: |
|
print(trial_int_msg % (2, small, fail_max)) |
|
n, next_p = _factorint_small(factors, n, small, fail_max) |
|
if factors and verbose: |
|
for k in sorted(factors): |
|
print(factor_msg % (k, factors[k])) |
|
if next_p == 0: |
|
if n > 1: |
|
factors[int(n)] = 1 |
|
if verbose: |
|
print(complete_msg) |
|
return factors |
|
|
|
|
|
|
|
if limit and next_p > limit: |
|
if verbose: |
|
print('Exceeded limit:', limit) |
|
if _check_termination(factors, n, limit, use_trial, |
|
use_rho, use_pm1, verbose, next_p): |
|
return factors |
|
if n > 1: |
|
factors[int(n)] = 1 |
|
return factors |
|
if _check_termination(factors, n, limit, use_trial, |
|
use_rho, use_pm1, verbose, next_p): |
|
return factors |
|
|
|
|
|
|
|
|
|
|
|
|
|
sqrt_n = isqrt(n) |
|
a = sqrt_n + 1 |
|
|
|
if (n % 4 == 1) ^ (a & 1): |
|
a += 1 |
|
a2 = a**2 |
|
b2 = a2 - n |
|
for _ in range(3): |
|
b, fermat = sqrtrem(b2) |
|
if not fermat: |
|
if verbose: |
|
print(fermat_msg) |
|
for r in [a - b, a + b]: |
|
facs = factorint(r, limit=limit, use_trial=use_trial, |
|
use_rho=use_rho, use_pm1=use_pm1, |
|
verbose=verbose) |
|
for k, v in facs.items(): |
|
factors[k] = factors.get(k, 0) + v |
|
if verbose: |
|
print(complete_msg) |
|
return factors |
|
b2 += (a + 1) << 2 |
|
a += 2 |
|
|
|
|
|
|
|
low, high = next_p, 2*next_p |
|
|
|
|
|
_limit = (limit or sqrt_n) + 1 |
|
iteration = 0 |
|
while 1: |
|
high_ = min(high, _limit) |
|
|
|
|
|
if use_trial: |
|
if verbose: |
|
print(trial_msg % (low, high_)) |
|
ps = sieve.primerange(low, high_) |
|
n, found_trial = _trial(factors, n, ps, verbose) |
|
next_p = high_ |
|
if found_trial and _check_termination(factors, n, limit, use_trial, |
|
use_rho, use_pm1, verbose, next_p): |
|
return factors |
|
else: |
|
found_trial = False |
|
|
|
if high > _limit: |
|
if verbose: |
|
print('Exceeded limit:', _limit) |
|
if n > 1: |
|
factors[int(n)] = 1 |
|
if verbose: |
|
print(complete_msg) |
|
return factors |
|
|
|
|
|
if not found_trial: |
|
|
|
if use_pm1: |
|
if verbose: |
|
print(pm1_msg % (low, high_)) |
|
c = pollard_pm1(n, B=low, seed=high_) |
|
if c: |
|
if c < next_p**2 or isprime(c): |
|
ps = [c] |
|
else: |
|
ps = factorint(c, limit=limit, |
|
use_trial=use_trial, |
|
use_rho=use_rho, |
|
use_pm1=use_pm1, |
|
use_ecm=use_ecm, |
|
verbose=verbose) |
|
n, _ = _trial(factors, n, ps, verbose=False) |
|
if _check_termination(factors, n, limit, use_trial, |
|
use_rho, use_pm1, verbose, next_p): |
|
return factors |
|
|
|
|
|
if use_rho: |
|
if verbose: |
|
print(rho_msg % (1, low, high_)) |
|
c = pollard_rho(n, retries=1, max_steps=low, seed=high_) |
|
if c: |
|
if c < next_p**2 or isprime(c): |
|
ps = [c] |
|
else: |
|
ps = factorint(c, limit=limit, |
|
use_trial=use_trial, |
|
use_rho=use_rho, |
|
use_pm1=use_pm1, |
|
use_ecm=use_ecm, |
|
verbose=verbose) |
|
n, _ = _trial(factors, n, ps, verbose=False) |
|
if _check_termination(factors, n, limit, use_trial, |
|
use_rho, use_pm1, verbose, next_p): |
|
return factors |
|
|
|
|
|
|
|
iteration += 1 |
|
if use_ecm and iteration >= 3 and num_digits(n) >= 24: |
|
break |
|
low, high = high, high*2 |
|
|
|
B1 = 10000 |
|
B2 = 100*B1 |
|
num_curves = 50 |
|
while(1): |
|
if verbose: |
|
print(ecm_msg % (B1, B2, num_curves)) |
|
factor = _ecm_one_factor(n, B1, B2, num_curves, seed=B1) |
|
if factor: |
|
if factor < next_p**2 or isprime(factor): |
|
ps = [factor] |
|
else: |
|
ps = factorint(factor, limit=limit, |
|
use_trial=use_trial, |
|
use_rho=use_rho, |
|
use_pm1=use_pm1, |
|
use_ecm=use_ecm, |
|
verbose=verbose) |
|
n, _ = _trial(factors, n, ps, verbose=False) |
|
if _check_termination(factors, n, limit, use_trial, |
|
use_rho, use_pm1, verbose, next_p): |
|
return factors |
|
B1 *= 5 |
|
B2 = 100*B1 |
|
num_curves *= 4 |
|
|
|
|
|
def factorrat(rat, limit=None, use_trial=True, use_rho=True, use_pm1=True, |
|
verbose=False, visual=None, multiple=False): |
|
r""" |
|
Given a Rational ``r``, ``factorrat(r)`` returns a dict containing |
|
the prime factors of ``r`` as keys and their respective multiplicities |
|
as values. For example: |
|
|
|
>>> from sympy import factorrat, S |
|
>>> factorrat(S(8)/9) # 8/9 = (2**3) * (3**-2) |
|
{2: 3, 3: -2} |
|
>>> factorrat(S(-1)/987) # -1/789 = -1 * (3**-1) * (7**-1) * (47**-1) |
|
{-1: 1, 3: -1, 7: -1, 47: -1} |
|
|
|
Please see the docstring for ``factorint`` for detailed explanations |
|
and examples of the following keywords: |
|
|
|
- ``limit``: Integer limit up to which trial division is done |
|
- ``use_trial``: Toggle use of trial division |
|
- ``use_rho``: Toggle use of Pollard's rho method |
|
- ``use_pm1``: Toggle use of Pollard's p-1 method |
|
- ``verbose``: Toggle detailed printing of progress |
|
- ``multiple``: Toggle returning a list of factors or dict |
|
- ``visual``: Toggle product form of output |
|
""" |
|
if multiple: |
|
fac = factorrat(rat, limit=limit, use_trial=use_trial, |
|
use_rho=use_rho, use_pm1=use_pm1, |
|
verbose=verbose, visual=False, multiple=False) |
|
factorlist = sum(([p] * fac[p] if fac[p] > 0 else [S.One/p]*(-fac[p]) |
|
for p, _ in sorted(fac.items(), |
|
key=lambda elem: elem[0] |
|
if elem[1] > 0 |
|
else 1/elem[0])), []) |
|
return factorlist |
|
|
|
f = factorint(rat.p, limit=limit, use_trial=use_trial, |
|
use_rho=use_rho, use_pm1=use_pm1, |
|
verbose=verbose).copy() |
|
f = defaultdict(int, f) |
|
for p, e in factorint(rat.q, limit=limit, |
|
use_trial=use_trial, |
|
use_rho=use_rho, |
|
use_pm1=use_pm1, |
|
verbose=verbose).items(): |
|
f[p] += -e |
|
|
|
if len(f) > 1 and 1 in f: |
|
del f[1] |
|
if not visual: |
|
return dict(f) |
|
else: |
|
if -1 in f: |
|
f.pop(-1) |
|
args = [S.NegativeOne] |
|
else: |
|
args = [] |
|
args.extend([Pow(*i, evaluate=False) |
|
for i in sorted(f.items())]) |
|
return Mul(*args, evaluate=False) |
|
|
|
|
|
def primefactors(n, limit=None, verbose=False, **kwargs): |
|
"""Return a sorted list of n's prime factors, ignoring multiplicity |
|
and any composite factor that remains if the limit was set too low |
|
for complete factorization. Unlike factorint(), primefactors() does |
|
not return -1 or 0. |
|
|
|
Parameters |
|
========== |
|
|
|
n : integer |
|
limit, verbose, **kwargs : |
|
Additional keyword arguments to be passed to ``factorint``. |
|
Since ``kwargs`` is new in version 1.13, |
|
``limit`` and ``verbose`` are retained for compatibility purposes. |
|
|
|
Returns |
|
======= |
|
|
|
list(int) : List of prime numbers dividing ``n`` |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.ntheory import primefactors, factorint, isprime |
|
>>> primefactors(6) |
|
[2, 3] |
|
>>> primefactors(-5) |
|
[5] |
|
|
|
>>> sorted(factorint(123456).items()) |
|
[(2, 6), (3, 1), (643, 1)] |
|
>>> primefactors(123456) |
|
[2, 3, 643] |
|
|
|
>>> sorted(factorint(10000000001, limit=200).items()) |
|
[(101, 1), (99009901, 1)] |
|
>>> isprime(99009901) |
|
False |
|
>>> primefactors(10000000001, limit=300) |
|
[101] |
|
|
|
See Also |
|
======== |
|
|
|
factorint, divisors |
|
|
|
""" |
|
n = int(n) |
|
kwargs.update({"visual": None, "multiple": False, |
|
"limit": limit, "verbose": verbose}) |
|
factors = sorted(factorint(n=n, **kwargs).keys()) |
|
|
|
|
|
s = [f for f in factors[:-1:] if f not in [-1, 0, 1]] |
|
if factors and isprime(factors[-1]): |
|
s += [factors[-1]] |
|
return s |
|
|
|
|
|
def _divisors(n, proper=False): |
|
"""Helper function for divisors which generates the divisors. |
|
|
|
Parameters |
|
========== |
|
|
|
n : int |
|
a nonnegative integer |
|
proper: bool |
|
If `True`, returns the generator that outputs only the proper divisor (i.e., excluding n). |
|
|
|
""" |
|
if n <= 1: |
|
if not proper and n: |
|
yield 1 |
|
return |
|
|
|
factordict = factorint(n) |
|
ps = sorted(factordict.keys()) |
|
|
|
def rec_gen(n=0): |
|
if n == len(ps): |
|
yield 1 |
|
else: |
|
pows = [1] |
|
for _ in range(factordict[ps[n]]): |
|
pows.append(pows[-1] * ps[n]) |
|
yield from (p * q for q in rec_gen(n + 1) for p in pows) |
|
|
|
if proper: |
|
yield from (p for p in rec_gen() if p != n) |
|
else: |
|
yield from rec_gen() |
|
|
|
|
|
def divisors(n, generator=False, proper=False): |
|
r""" |
|
Return all divisors of n sorted from 1..n by default. |
|
If generator is ``True`` an unordered generator is returned. |
|
|
|
The number of divisors of n can be quite large if there are many |
|
prime factors (counting repeated factors). If only the number of |
|
factors is desired use divisor_count(n). |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import divisors, divisor_count |
|
>>> divisors(24) |
|
[1, 2, 3, 4, 6, 8, 12, 24] |
|
>>> divisor_count(24) |
|
8 |
|
|
|
>>> list(divisors(120, generator=True)) |
|
[1, 2, 4, 8, 3, 6, 12, 24, 5, 10, 20, 40, 15, 30, 60, 120] |
|
|
|
Notes |
|
===== |
|
|
|
This is a slightly modified version of Tim Peters referenced at: |
|
https://stackoverflow.com/questions/1010381/python-factorization |
|
|
|
See Also |
|
======== |
|
|
|
primefactors, factorint, divisor_count |
|
""" |
|
rv = _divisors(as_int(abs(n)), proper) |
|
return rv if generator else sorted(rv) |
|
|
|
|
|
def divisor_count(n, modulus=1, proper=False): |
|
""" |
|
Return the number of divisors of ``n``. If ``modulus`` is not 1 then only |
|
those that are divisible by ``modulus`` are counted. If ``proper`` is True |
|
then the divisor of ``n`` will not be counted. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import divisor_count |
|
>>> divisor_count(6) |
|
4 |
|
>>> divisor_count(6, 2) |
|
2 |
|
>>> divisor_count(6, proper=True) |
|
3 |
|
|
|
See Also |
|
======== |
|
|
|
factorint, divisors, totient, proper_divisor_count |
|
|
|
""" |
|
|
|
if not modulus: |
|
return 0 |
|
elif modulus != 1: |
|
n, r = divmod(n, modulus) |
|
if r: |
|
return 0 |
|
if n == 0: |
|
return 0 |
|
n = Mul(*[v + 1 for k, v in factorint(n).items() if k > 1]) |
|
if n and proper: |
|
n -= 1 |
|
return n |
|
|
|
|
|
def proper_divisors(n, generator=False): |
|
""" |
|
Return all divisors of n except n, sorted by default. |
|
If generator is ``True`` an unordered generator is returned. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import proper_divisors, proper_divisor_count |
|
>>> proper_divisors(24) |
|
[1, 2, 3, 4, 6, 8, 12] |
|
>>> proper_divisor_count(24) |
|
7 |
|
>>> list(proper_divisors(120, generator=True)) |
|
[1, 2, 4, 8, 3, 6, 12, 24, 5, 10, 20, 40, 15, 30, 60] |
|
|
|
See Also |
|
======== |
|
|
|
factorint, divisors, proper_divisor_count |
|
|
|
""" |
|
return divisors(n, generator=generator, proper=True) |
|
|
|
|
|
def proper_divisor_count(n, modulus=1): |
|
""" |
|
Return the number of proper divisors of ``n``. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import proper_divisor_count |
|
>>> proper_divisor_count(6) |
|
3 |
|
>>> proper_divisor_count(6, modulus=2) |
|
1 |
|
|
|
See Also |
|
======== |
|
|
|
divisors, proper_divisors, divisor_count |
|
|
|
""" |
|
return divisor_count(n, modulus=modulus, proper=True) |
|
|
|
|
|
def _udivisors(n): |
|
"""Helper function for udivisors which generates the unitary divisors. |
|
|
|
Parameters |
|
========== |
|
|
|
n : int |
|
a nonnegative integer |
|
|
|
""" |
|
if n <= 1: |
|
if n == 1: |
|
yield 1 |
|
return |
|
|
|
factorpows = [p**e for p, e in factorint(n).items()] |
|
|
|
|
|
for i in range(2**len(factorpows)): |
|
d = 1 |
|
for k in range(i.bit_length()): |
|
if i & 1: |
|
d *= factorpows[k] |
|
i >>= 1 |
|
yield d |
|
|
|
|
|
def udivisors(n, generator=False): |
|
r""" |
|
Return all unitary divisors of n sorted from 1..n by default. |
|
If generator is ``True`` an unordered generator is returned. |
|
|
|
The number of unitary divisors of n can be quite large if there are many |
|
prime factors. If only the number of unitary divisors is desired use |
|
udivisor_count(n). |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.ntheory.factor_ import udivisors, udivisor_count |
|
>>> udivisors(15) |
|
[1, 3, 5, 15] |
|
>>> udivisor_count(15) |
|
4 |
|
|
|
>>> sorted(udivisors(120, generator=True)) |
|
[1, 3, 5, 8, 15, 24, 40, 120] |
|
|
|
See Also |
|
======== |
|
|
|
primefactors, factorint, divisors, divisor_count, udivisor_count |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://en.wikipedia.org/wiki/Unitary_divisor |
|
.. [2] https://mathworld.wolfram.com/UnitaryDivisor.html |
|
|
|
""" |
|
rv = _udivisors(as_int(abs(n))) |
|
return rv if generator else sorted(rv) |
|
|
|
|
|
def udivisor_count(n): |
|
""" |
|
Return the number of unitary divisors of ``n``. |
|
|
|
Parameters |
|
========== |
|
|
|
n : integer |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.ntheory.factor_ import udivisor_count |
|
>>> udivisor_count(120) |
|
8 |
|
|
|
See Also |
|
======== |
|
|
|
factorint, divisors, udivisors, divisor_count, totient |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://mathworld.wolfram.com/UnitaryDivisorFunction.html |
|
|
|
""" |
|
|
|
if n == 0: |
|
return 0 |
|
return 2**len([p for p in factorint(n) if p > 1]) |
|
|
|
|
|
def _antidivisors(n): |
|
"""Helper function for antidivisors which generates the antidivisors. |
|
|
|
Parameters |
|
========== |
|
|
|
n : int |
|
a nonnegative integer |
|
|
|
""" |
|
if n <= 2: |
|
return |
|
for d in _divisors(n): |
|
y = 2*d |
|
if n > y and n % y: |
|
yield y |
|
for d in _divisors(2*n-1): |
|
if n > d >= 2 and n % d: |
|
yield d |
|
for d in _divisors(2*n+1): |
|
if n > d >= 2 and n % d: |
|
yield d |
|
|
|
|
|
def antidivisors(n, generator=False): |
|
r""" |
|
Return all antidivisors of n sorted from 1..n by default. |
|
|
|
Antidivisors [1]_ of n are numbers that do not divide n by the largest |
|
possible margin. If generator is True an unordered generator is returned. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.ntheory.factor_ import antidivisors |
|
>>> antidivisors(24) |
|
[7, 16] |
|
|
|
>>> sorted(antidivisors(128, generator=True)) |
|
[3, 5, 15, 17, 51, 85] |
|
|
|
See Also |
|
======== |
|
|
|
primefactors, factorint, divisors, divisor_count, antidivisor_count |
|
|
|
References |
|
========== |
|
|
|
.. [1] definition is described in https://oeis.org/A066272/a066272a.html |
|
|
|
""" |
|
rv = _antidivisors(as_int(abs(n))) |
|
return rv if generator else sorted(rv) |
|
|
|
|
|
def antidivisor_count(n): |
|
""" |
|
Return the number of antidivisors [1]_ of ``n``. |
|
|
|
Parameters |
|
========== |
|
|
|
n : integer |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.ntheory.factor_ import antidivisor_count |
|
>>> antidivisor_count(13) |
|
4 |
|
>>> antidivisor_count(27) |
|
5 |
|
|
|
See Also |
|
======== |
|
|
|
factorint, divisors, antidivisors, divisor_count, totient |
|
|
|
References |
|
========== |
|
|
|
.. [1] formula from https://oeis.org/A066272 |
|
|
|
""" |
|
|
|
n = as_int(abs(n)) |
|
if n <= 2: |
|
return 0 |
|
return divisor_count(2*n - 1) + divisor_count(2*n + 1) + \ |
|
divisor_count(n) - divisor_count(n, 2) - 5 |
|
|
|
@deprecated("""\ |
|
The `sympy.ntheory.factor_.totient` has been moved to `sympy.functions.combinatorial.numbers.totient`.""", |
|
deprecated_since_version="1.13", |
|
active_deprecations_target='deprecated-ntheory-symbolic-functions') |
|
def totient(n): |
|
r""" |
|
Calculate the Euler totient function phi(n) |
|
|
|
.. deprecated:: 1.13 |
|
|
|
The ``totient`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.totient` |
|
instead. See its documentation for more information. See |
|
:ref:`deprecated-ntheory-symbolic-functions` for details. |
|
|
|
``totient(n)`` or `\phi(n)` is the number of positive integers `\leq` n |
|
that are relatively prime to n. |
|
|
|
Parameters |
|
========== |
|
|
|
n : integer |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.functions.combinatorial.numbers import totient |
|
>>> totient(1) |
|
1 |
|
>>> totient(25) |
|
20 |
|
>>> totient(45) == totient(5)*totient(9) |
|
True |
|
|
|
See Also |
|
======== |
|
|
|
divisor_count |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://en.wikipedia.org/wiki/Euler%27s_totient_function |
|
.. [2] https://mathworld.wolfram.com/TotientFunction.html |
|
|
|
""" |
|
from sympy.functions.combinatorial.numbers import totient as _totient |
|
return _totient(n) |
|
|
|
|
|
@deprecated("""\ |
|
The `sympy.ntheory.factor_.reduced_totient` has been moved to `sympy.functions.combinatorial.numbers.reduced_totient`.""", |
|
deprecated_since_version="1.13", |
|
active_deprecations_target='deprecated-ntheory-symbolic-functions') |
|
def reduced_totient(n): |
|
r""" |
|
Calculate the Carmichael reduced totient function lambda(n) |
|
|
|
.. deprecated:: 1.13 |
|
|
|
The ``reduced_totient`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.reduced_totient` |
|
instead. See its documentation for more information. See |
|
:ref:`deprecated-ntheory-symbolic-functions` for details. |
|
|
|
``reduced_totient(n)`` or `\lambda(n)` is the smallest m > 0 such that |
|
`k^m \equiv 1 \mod n` for all k relatively prime to n. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.functions.combinatorial.numbers import reduced_totient |
|
>>> reduced_totient(1) |
|
1 |
|
>>> reduced_totient(8) |
|
2 |
|
>>> reduced_totient(30) |
|
4 |
|
|
|
See Also |
|
======== |
|
|
|
totient |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://en.wikipedia.org/wiki/Carmichael_function |
|
.. [2] https://mathworld.wolfram.com/CarmichaelFunction.html |
|
|
|
""" |
|
from sympy.functions.combinatorial.numbers import reduced_totient as _reduced_totient |
|
return _reduced_totient(n) |
|
|
|
|
|
@deprecated("""\ |
|
The `sympy.ntheory.factor_.divisor_sigma` has been moved to `sympy.functions.combinatorial.numbers.divisor_sigma`.""", |
|
deprecated_since_version="1.13", |
|
active_deprecations_target='deprecated-ntheory-symbolic-functions') |
|
def divisor_sigma(n, k=1): |
|
r""" |
|
Calculate the divisor function `\sigma_k(n)` for positive integer n |
|
|
|
.. deprecated:: 1.13 |
|
|
|
The ``divisor_sigma`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.divisor_sigma` |
|
instead. See its documentation for more information. See |
|
:ref:`deprecated-ntheory-symbolic-functions` for details. |
|
|
|
``divisor_sigma(n, k)`` is equal to ``sum([x**k for x in divisors(n)])`` |
|
|
|
If n's prime factorization is: |
|
|
|
.. math :: |
|
n = \prod_{i=1}^\omega p_i^{m_i}, |
|
|
|
then |
|
|
|
.. math :: |
|
\sigma_k(n) = \prod_{i=1}^\omega (1+p_i^k+p_i^{2k}+\cdots |
|
+ p_i^{m_ik}). |
|
|
|
Parameters |
|
========== |
|
|
|
n : integer |
|
|
|
k : integer, optional |
|
power of divisors in the sum |
|
|
|
for k = 0, 1: |
|
``divisor_sigma(n, 0)`` is equal to ``divisor_count(n)`` |
|
``divisor_sigma(n, 1)`` is equal to ``sum(divisors(n))`` |
|
|
|
Default for k is 1. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.functions.combinatorial.numbers import divisor_sigma |
|
>>> divisor_sigma(18, 0) |
|
6 |
|
>>> divisor_sigma(39, 1) |
|
56 |
|
>>> divisor_sigma(12, 2) |
|
210 |
|
>>> divisor_sigma(37) |
|
38 |
|
|
|
See Also |
|
======== |
|
|
|
divisor_count, totient, divisors, factorint |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://en.wikipedia.org/wiki/Divisor_function |
|
|
|
""" |
|
from sympy.functions.combinatorial.numbers import divisor_sigma as func_divisor_sigma |
|
return func_divisor_sigma(n, k) |
|
|
|
|
|
def _divisor_sigma(n:int, k:int=1) -> int: |
|
r""" Calculate the divisor function `\sigma_k(n)` for positive integer n |
|
|
|
Parameters |
|
========== |
|
|
|
n : int |
|
positive integer |
|
k : int |
|
nonnegative integer |
|
|
|
See Also |
|
======== |
|
|
|
sympy.functions.combinatorial.numbers.divisor_sigma |
|
|
|
""" |
|
if k == 0: |
|
return math.prod(e + 1 for e in factorint(n).values()) |
|
return math.prod((p**(k*(e + 1)) - 1)//(p**k - 1) for p, e in factorint(n).items()) |
|
|
|
|
|
def core(n, t=2): |
|
r""" |
|
Calculate core(n, t) = `core_t(n)` of a positive integer n |
|
|
|
``core_2(n)`` is equal to the squarefree part of n |
|
|
|
If n's prime factorization is: |
|
|
|
.. math :: |
|
n = \prod_{i=1}^\omega p_i^{m_i}, |
|
|
|
then |
|
|
|
.. math :: |
|
core_t(n) = \prod_{i=1}^\omega p_i^{m_i \mod t}. |
|
|
|
Parameters |
|
========== |
|
|
|
n : integer |
|
|
|
t : integer |
|
core(n, t) calculates the t-th power free part of n |
|
|
|
``core(n, 2)`` is the squarefree part of ``n`` |
|
``core(n, 3)`` is the cubefree part of ``n`` |
|
|
|
Default for t is 2. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.ntheory.factor_ import core |
|
>>> core(24, 2) |
|
6 |
|
>>> core(9424, 3) |
|
1178 |
|
>>> core(379238) |
|
379238 |
|
>>> core(15**11, 10) |
|
15 |
|
|
|
See Also |
|
======== |
|
|
|
factorint, sympy.solvers.diophantine.diophantine.square_factor |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://en.wikipedia.org/wiki/Square-free_integer#Squarefree_core |
|
|
|
""" |
|
|
|
n = as_int(n) |
|
t = as_int(t) |
|
if n <= 0: |
|
raise ValueError("n must be a positive integer") |
|
elif t <= 1: |
|
raise ValueError("t must be >= 2") |
|
else: |
|
y = 1 |
|
for p, e in factorint(n).items(): |
|
y *= p**(e % t) |
|
return y |
|
|
|
|
|
@deprecated("""\ |
|
The `sympy.ntheory.factor_.udivisor_sigma` has been moved to `sympy.functions.combinatorial.numbers.udivisor_sigma`.""", |
|
deprecated_since_version="1.13", |
|
active_deprecations_target='deprecated-ntheory-symbolic-functions') |
|
def udivisor_sigma(n, k=1): |
|
r""" |
|
Calculate the unitary divisor function `\sigma_k^*(n)` for positive integer n |
|
|
|
.. deprecated:: 1.13 |
|
|
|
The ``udivisor_sigma`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.udivisor_sigma` |
|
instead. See its documentation for more information. See |
|
:ref:`deprecated-ntheory-symbolic-functions` for details. |
|
|
|
``udivisor_sigma(n, k)`` is equal to ``sum([x**k for x in udivisors(n)])`` |
|
|
|
If n's prime factorization is: |
|
|
|
.. math :: |
|
n = \prod_{i=1}^\omega p_i^{m_i}, |
|
|
|
then |
|
|
|
.. math :: |
|
\sigma_k^*(n) = \prod_{i=1}^\omega (1+ p_i^{m_ik}). |
|
|
|
Parameters |
|
========== |
|
|
|
k : power of divisors in the sum |
|
|
|
for k = 0, 1: |
|
``udivisor_sigma(n, 0)`` is equal to ``udivisor_count(n)`` |
|
``udivisor_sigma(n, 1)`` is equal to ``sum(udivisors(n))`` |
|
|
|
Default for k is 1. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.functions.combinatorial.numbers import udivisor_sigma |
|
>>> udivisor_sigma(18, 0) |
|
4 |
|
>>> udivisor_sigma(74, 1) |
|
114 |
|
>>> udivisor_sigma(36, 3) |
|
47450 |
|
>>> udivisor_sigma(111) |
|
152 |
|
|
|
See Also |
|
======== |
|
|
|
divisor_count, totient, divisors, udivisors, udivisor_count, divisor_sigma, |
|
factorint |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://mathworld.wolfram.com/UnitaryDivisorFunction.html |
|
|
|
""" |
|
from sympy.functions.combinatorial.numbers import udivisor_sigma as _udivisor_sigma |
|
return _udivisor_sigma(n, k) |
|
|
|
|
|
@deprecated("""\ |
|
The `sympy.ntheory.factor_.primenu` has been moved to `sympy.functions.combinatorial.numbers.primenu`.""", |
|
deprecated_since_version="1.13", |
|
active_deprecations_target='deprecated-ntheory-symbolic-functions') |
|
def primenu(n): |
|
r""" |
|
Calculate the number of distinct prime factors for a positive integer n. |
|
|
|
.. deprecated:: 1.13 |
|
|
|
The ``primenu`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.primenu` |
|
instead. See its documentation for more information. See |
|
:ref:`deprecated-ntheory-symbolic-functions` for details. |
|
|
|
If n's prime factorization is: |
|
|
|
.. math :: |
|
n = \prod_{i=1}^k p_i^{m_i}, |
|
|
|
then ``primenu(n)`` or `\nu(n)` is: |
|
|
|
.. math :: |
|
\nu(n) = k. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.functions.combinatorial.numbers import primenu |
|
>>> primenu(1) |
|
0 |
|
>>> primenu(30) |
|
3 |
|
|
|
See Also |
|
======== |
|
|
|
factorint |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://mathworld.wolfram.com/PrimeFactor.html |
|
|
|
""" |
|
from sympy.functions.combinatorial.numbers import primenu as _primenu |
|
return _primenu(n) |
|
|
|
|
|
@deprecated("""\ |
|
The `sympy.ntheory.factor_.primeomega` has been moved to `sympy.functions.combinatorial.numbers.primeomega`.""", |
|
deprecated_since_version="1.13", |
|
active_deprecations_target='deprecated-ntheory-symbolic-functions') |
|
def primeomega(n): |
|
r""" |
|
Calculate the number of prime factors counting multiplicities for a |
|
positive integer n. |
|
|
|
.. deprecated:: 1.13 |
|
|
|
The ``primeomega`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.primeomega` |
|
instead. See its documentation for more information. See |
|
:ref:`deprecated-ntheory-symbolic-functions` for details. |
|
|
|
If n's prime factorization is: |
|
|
|
.. math :: |
|
n = \prod_{i=1}^k p_i^{m_i}, |
|
|
|
then ``primeomega(n)`` or `\Omega(n)` is: |
|
|
|
.. math :: |
|
\Omega(n) = \sum_{i=1}^k m_i. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.functions.combinatorial.numbers import primeomega |
|
>>> primeomega(1) |
|
0 |
|
>>> primeomega(20) |
|
3 |
|
|
|
See Also |
|
======== |
|
|
|
factorint |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://mathworld.wolfram.com/PrimeFactor.html |
|
|
|
""" |
|
from sympy.functions.combinatorial.numbers import primeomega as _primeomega |
|
return _primeomega(n) |
|
|
|
|
|
def mersenne_prime_exponent(nth): |
|
"""Returns the exponent ``i`` for the nth Mersenne prime (which |
|
has the form `2^i - 1`). |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.ntheory.factor_ import mersenne_prime_exponent |
|
>>> mersenne_prime_exponent(1) |
|
2 |
|
>>> mersenne_prime_exponent(20) |
|
4423 |
|
""" |
|
n = as_int(nth) |
|
if n < 1: |
|
raise ValueError("nth must be a positive integer; mersenne_prime_exponent(1) == 2") |
|
if n > 51: |
|
raise ValueError("There are only 51 perfect numbers; nth must be less than or equal to 51") |
|
return MERSENNE_PRIME_EXPONENTS[n - 1] |
|
|
|
|
|
def is_perfect(n): |
|
"""Returns True if ``n`` is a perfect number, else False. |
|
|
|
A perfect number is equal to the sum of its positive, proper divisors. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.functions.combinatorial.numbers import divisor_sigma |
|
>>> from sympy.ntheory.factor_ import is_perfect, divisors |
|
>>> is_perfect(20) |
|
False |
|
>>> is_perfect(6) |
|
True |
|
>>> 6 == divisor_sigma(6) - 6 == sum(divisors(6)[:-1]) |
|
True |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://mathworld.wolfram.com/PerfectNumber.html |
|
.. [2] https://en.wikipedia.org/wiki/Perfect_number |
|
|
|
""" |
|
n = as_int(n) |
|
if n < 1: |
|
return False |
|
if n % 2 == 0: |
|
m = (n.bit_length() + 1) >> 1 |
|
if (1 << (m - 1)) * ((1 << m) - 1) != n: |
|
|
|
return False |
|
return m in MERSENNE_PRIME_EXPONENTS or is_mersenne_prime(2**m - 1) |
|
|
|
|
|
if n < 10**2000: |
|
return False |
|
if n % 105 == 0: |
|
return False |
|
if all(n % m != r for m, r in [(12, 1), (468, 117), (324, 81)]): |
|
return False |
|
|
|
|
|
|
|
|
|
|
|
|
|
result = abundance(n) == 0 |
|
if result: |
|
raise ValueError(filldedent('''In 1888, Sylvester stated: " |
|
...a prolonged meditation on the subject has satisfied |
|
me that the existence of any one such [odd perfect number] |
|
-- its escape, so to say, from the complex web of conditions |
|
which hem it in on all sides -- would be little short of a |
|
miracle." I guess SymPy just found that miracle and it |
|
factors like this: %s''' % factorint(n))) |
|
return result |
|
|
|
|
|
def abundance(n): |
|
"""Returns the difference between the sum of the positive |
|
proper divisors of a number and the number. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.ntheory import abundance, is_perfect, is_abundant |
|
>>> abundance(6) |
|
0 |
|
>>> is_perfect(6) |
|
True |
|
>>> abundance(10) |
|
-2 |
|
>>> is_abundant(10) |
|
False |
|
""" |
|
return _divisor_sigma(n) - 2 * n |
|
|
|
|
|
def is_abundant(n): |
|
"""Returns True if ``n`` is an abundant number, else False. |
|
|
|
A abundant number is smaller than the sum of its positive proper divisors. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.ntheory.factor_ import is_abundant |
|
>>> is_abundant(20) |
|
True |
|
>>> is_abundant(15) |
|
False |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://mathworld.wolfram.com/AbundantNumber.html |
|
|
|
""" |
|
n = as_int(n) |
|
if is_perfect(n): |
|
return False |
|
return n % 6 == 0 or bool(abundance(n) > 0) |
|
|
|
|
|
def is_deficient(n): |
|
"""Returns True if ``n`` is a deficient number, else False. |
|
|
|
A deficient number is greater than the sum of its positive proper divisors. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.ntheory.factor_ import is_deficient |
|
>>> is_deficient(20) |
|
False |
|
>>> is_deficient(15) |
|
True |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://mathworld.wolfram.com/DeficientNumber.html |
|
|
|
""" |
|
n = as_int(n) |
|
if is_perfect(n): |
|
return False |
|
return bool(abundance(n) < 0) |
|
|
|
|
|
def is_amicable(m, n): |
|
"""Returns True if the numbers `m` and `n` are "amicable", else False. |
|
|
|
Amicable numbers are two different numbers so related that the sum |
|
of the proper divisors of each is equal to that of the other. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.functions.combinatorial.numbers import divisor_sigma |
|
>>> from sympy.ntheory.factor_ import is_amicable |
|
>>> is_amicable(220, 284) |
|
True |
|
>>> divisor_sigma(220) == divisor_sigma(284) |
|
True |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://en.wikipedia.org/wiki/Amicable_numbers |
|
|
|
""" |
|
return m != n and m + n == _divisor_sigma(m) == _divisor_sigma(n) |
|
|
|
|
|
def is_carmichael(n): |
|
""" Returns True if the numbers `n` is Carmichael number, else False. |
|
|
|
Parameters |
|
========== |
|
|
|
n : Integer |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://en.wikipedia.org/wiki/Carmichael_number |
|
.. [2] https://oeis.org/A002997 |
|
|
|
""" |
|
if n < 561: |
|
return False |
|
return n % 2 and not isprime(n) and \ |
|
all(e == 1 and (n - 1) % (p - 1) == 0 for p, e in factorint(n).items()) |
|
|
|
|
|
def find_carmichael_numbers_in_range(x, y): |
|
""" Returns a list of the number of Carmichael in the range |
|
|
|
See Also |
|
======== |
|
|
|
is_carmichael |
|
|
|
""" |
|
if 0 <= x <= y: |
|
if x % 2 == 0: |
|
return [i for i in range(x + 1, y, 2) if is_carmichael(i)] |
|
else: |
|
return [i for i in range(x, y, 2) if is_carmichael(i)] |
|
else: |
|
raise ValueError('The provided range is not valid. x and y must be non-negative integers and x <= y') |
|
|
|
|
|
def find_first_n_carmichaels(n): |
|
""" Returns the first n Carmichael numbers. |
|
|
|
Parameters |
|
========== |
|
|
|
n : Integer |
|
|
|
See Also |
|
======== |
|
|
|
is_carmichael |
|
|
|
""" |
|
i = 561 |
|
carmichaels = [] |
|
|
|
while len(carmichaels) < n: |
|
if is_carmichael(i): |
|
carmichaels.append(i) |
|
i += 2 |
|
|
|
return carmichaels |
|
|
|
|
|
def dra(n, b): |
|
""" |
|
Returns the additive digital root of a natural number ``n`` in base ``b`` |
|
which is a single digit value obtained by an iterative process of summing |
|
digits, on each iteration using the result from the previous iteration to |
|
compute a digit sum. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.ntheory.factor_ import dra |
|
>>> dra(3110, 12) |
|
8 |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://en.wikipedia.org/wiki/Digital_root |
|
|
|
""" |
|
|
|
num = abs(as_int(n)) |
|
b = as_int(b) |
|
if b <= 1: |
|
raise ValueError("Base should be an integer greater than 1") |
|
|
|
if num == 0: |
|
return 0 |
|
|
|
return (1 + (num - 1) % (b - 1)) |
|
|
|
|
|
def drm(n, b): |
|
""" |
|
Returns the multiplicative digital root of a natural number ``n`` in a given |
|
base ``b`` which is a single digit value obtained by an iterative process of |
|
multiplying digits, on each iteration using the result from the previous |
|
iteration to compute the digit multiplication. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.ntheory.factor_ import drm |
|
>>> drm(9876, 10) |
|
0 |
|
|
|
>>> drm(49, 10) |
|
8 |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://mathworld.wolfram.com/MultiplicativeDigitalRoot.html |
|
|
|
""" |
|
|
|
n = abs(as_int(n)) |
|
b = as_int(b) |
|
if b <= 1: |
|
raise ValueError("Base should be an integer greater than 1") |
|
while n > b: |
|
mul = 1 |
|
while n > 1: |
|
n, r = divmod(n, b) |
|
if r == 0: |
|
return 0 |
|
mul *= r |
|
n = mul |
|
return n |
|
|