Add files using upload-large-folder tool
Browse files- lib/python3.12/site-packages/sympy/liealgebras/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/__pycache__/cartan_matrix.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/__pycache__/cartan_type.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/__pycache__/dynkin_diagram.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/__pycache__/root_system.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/__pycache__/type_a.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/__pycache__/type_b.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/__pycache__/type_c.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/__pycache__/type_d.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/__pycache__/type_e.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/__pycache__/type_f.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/__pycache__/type_g.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/__pycache__/weyl_group.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_cartan_matrix.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_cartan_type.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_dynkin_diagram.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_root_system.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_type_A.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_type_B.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_type_C.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_type_D.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_type_E.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_type_F.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_type_G.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/sympy/ntheory/__init__.py +67 -0
- lib/python3.12/site-packages/sympy/ntheory/bbp_pi.py +190 -0
- lib/python3.12/site-packages/sympy/ntheory/continued_fraction.py +369 -0
- lib/python3.12/site-packages/sympy/ntheory/digits.py +150 -0
- lib/python3.12/site-packages/sympy/ntheory/ecm.py +345 -0
- lib/python3.12/site-packages/sympy/ntheory/egyptian_fraction.py +223 -0
- lib/python3.12/site-packages/sympy/ntheory/elliptic_curve.py +397 -0
- lib/python3.12/site-packages/sympy/ntheory/factor_.py +2668 -0
- lib/python3.12/site-packages/sympy/ntheory/generate.py +1147 -0
- lib/python3.12/site-packages/sympy/ntheory/modular.py +291 -0
- lib/python3.12/site-packages/sympy/ntheory/multinomial.py +188 -0
- lib/python3.12/site-packages/sympy/ntheory/partitions_.py +278 -0
- lib/python3.12/site-packages/sympy/ntheory/primetest.py +793 -0
- lib/python3.12/site-packages/sympy/ntheory/qs.py +511 -0
- lib/python3.12/site-packages/sympy/ntheory/residue_ntheory.py +1954 -0
- lib/python3.12/site-packages/sympy/ntheory/tests/__init__.py +0 -0
- lib/python3.12/site-packages/sympy/ntheory/tests/test_bbp_pi.py +134 -0
- lib/python3.12/site-packages/sympy/ntheory/tests/test_continued_fraction.py +77 -0
- lib/python3.12/site-packages/sympy/ntheory/tests/test_digits.py +55 -0
- lib/python3.12/site-packages/sympy/ntheory/tests/test_egyptian_fraction.py +49 -0
- lib/python3.12/site-packages/sympy/ntheory/tests/test_generate.py +285 -0
- lib/python3.12/site-packages/sympy/ntheory/tests/test_hypothesis.py +24 -0
- lib/python3.12/site-packages/sympy/ntheory/tests/test_partitions.py +27 -0
- lib/python3.12/site-packages/sympy/ntheory/tests/test_primetest.py +230 -0
- lib/python3.12/site-packages/sympy/ntheory/tests/test_qs.py +124 -0
lib/python3.12/site-packages/sympy/liealgebras/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (290 Bytes). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/__pycache__/cartan_matrix.cpython-312.pyc
ADDED
|
Binary file (857 Bytes). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/__pycache__/cartan_type.cpython-312.pyc
ADDED
|
Binary file (2.96 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/__pycache__/dynkin_diagram.cpython-312.pyc
ADDED
|
Binary file (869 Bytes). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/__pycache__/root_system.cpython-312.pyc
ADDED
|
Binary file (8.72 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/__pycache__/type_a.cpython-312.pyc
ADDED
|
Binary file (6.64 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/__pycache__/type_b.cpython-312.pyc
ADDED
|
Binary file (6.77 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/__pycache__/type_c.cpython-312.pyc
ADDED
|
Binary file (6.64 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/__pycache__/type_d.cpython-312.pyc
ADDED
|
Binary file (7.09 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/__pycache__/type_e.cpython-312.pyc
ADDED
|
Binary file (10.8 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/__pycache__/type_f.cpython-312.pyc
ADDED
|
Binary file (6.3 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/__pycache__/type_g.cpython-312.pyc
ADDED
|
Binary file (4.02 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/__pycache__/weyl_group.cpython-312.pyc
ADDED
|
Binary file (18.5 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (202 Bytes). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_cartan_matrix.cpython-312.pyc
ADDED
|
Binary file (756 Bytes). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_cartan_type.cpython-312.pyc
ADDED
|
Binary file (905 Bytes). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_dynkin_diagram.cpython-312.pyc
ADDED
|
Binary file (613 Bytes). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_root_system.cpython-312.pyc
ADDED
|
Binary file (1.85 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_type_A.cpython-312.pyc
ADDED
|
Binary file (1.55 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_type_B.cpython-312.pyc
ADDED
|
Binary file (1.51 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_type_C.cpython-312.pyc
ADDED
|
Binary file (2.15 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_type_D.cpython-312.pyc
ADDED
|
Binary file (1.65 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_type_E.cpython-312.pyc
ADDED
|
Binary file (2.06 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_type_F.cpython-312.pyc
ADDED
|
Binary file (4.07 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/liealgebras/tests/__pycache__/test_type_G.cpython-312.pyc
ADDED
|
Binary file (1.32 kB). View file
|
|
|
lib/python3.12/site-packages/sympy/ntheory/__init__.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Number theory module (primes, etc)
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from .generate import nextprime, prevprime, prime, primepi, primerange, \
|
| 6 |
+
randprime, Sieve, sieve, primorial, cycle_length, composite, compositepi
|
| 7 |
+
from .primetest import isprime, is_gaussian_prime, is_mersenne_prime
|
| 8 |
+
from .factor_ import divisors, proper_divisors, factorint, multiplicity, \
|
| 9 |
+
multiplicity_in_factorial, perfect_power, pollard_pm1, pollard_rho, \
|
| 10 |
+
primefactors, totient, \
|
| 11 |
+
divisor_count, proper_divisor_count, divisor_sigma, factorrat, \
|
| 12 |
+
reduced_totient, primenu, primeomega, mersenne_prime_exponent, \
|
| 13 |
+
is_perfect, is_abundant, is_deficient, is_amicable, is_carmichael, \
|
| 14 |
+
abundance, dra, drm
|
| 15 |
+
|
| 16 |
+
from .partitions_ import npartitions
|
| 17 |
+
from .residue_ntheory import is_primitive_root, is_quad_residue, \
|
| 18 |
+
legendre_symbol, jacobi_symbol, n_order, sqrt_mod, quadratic_residues, \
|
| 19 |
+
primitive_root, nthroot_mod, is_nthpow_residue, sqrt_mod_iter, mobius, \
|
| 20 |
+
discrete_log, quadratic_congruence, polynomial_congruence
|
| 21 |
+
from .multinomial import binomial_coefficients, binomial_coefficients_list, \
|
| 22 |
+
multinomial_coefficients
|
| 23 |
+
from .continued_fraction import continued_fraction_periodic, \
|
| 24 |
+
continued_fraction_iterator, continued_fraction_reduce, \
|
| 25 |
+
continued_fraction_convergents, continued_fraction
|
| 26 |
+
from .digits import count_digits, digits, is_palindromic
|
| 27 |
+
from .egyptian_fraction import egyptian_fraction
|
| 28 |
+
from .ecm import ecm
|
| 29 |
+
from .qs import qs
|
| 30 |
+
__all__ = [
|
| 31 |
+
'nextprime', 'prevprime', 'prime', 'primepi', 'primerange', 'randprime',
|
| 32 |
+
'Sieve', 'sieve', 'primorial', 'cycle_length', 'composite', 'compositepi',
|
| 33 |
+
|
| 34 |
+
'isprime', 'is_gaussian_prime', 'is_mersenne_prime',
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
'divisors', 'proper_divisors', 'factorint', 'multiplicity', 'perfect_power',
|
| 38 |
+
'pollard_pm1', 'pollard_rho', 'primefactors', 'totient',
|
| 39 |
+
'divisor_count', 'proper_divisor_count', 'divisor_sigma', 'factorrat',
|
| 40 |
+
'reduced_totient', 'primenu', 'primeomega', 'mersenne_prime_exponent',
|
| 41 |
+
'is_perfect', 'is_abundant', 'is_deficient', 'is_amicable',
|
| 42 |
+
'is_carmichael', 'abundance', 'dra', 'drm', 'multiplicity_in_factorial',
|
| 43 |
+
|
| 44 |
+
'npartitions',
|
| 45 |
+
|
| 46 |
+
'is_primitive_root', 'is_quad_residue', 'legendre_symbol',
|
| 47 |
+
'jacobi_symbol', 'n_order', 'sqrt_mod', 'quadratic_residues',
|
| 48 |
+
'primitive_root', 'nthroot_mod', 'is_nthpow_residue', 'sqrt_mod_iter',
|
| 49 |
+
'mobius', 'discrete_log', 'quadratic_congruence', 'polynomial_congruence',
|
| 50 |
+
|
| 51 |
+
'binomial_coefficients', 'binomial_coefficients_list',
|
| 52 |
+
'multinomial_coefficients',
|
| 53 |
+
|
| 54 |
+
'continued_fraction_periodic', 'continued_fraction_iterator',
|
| 55 |
+
'continued_fraction_reduce', 'continued_fraction_convergents',
|
| 56 |
+
'continued_fraction',
|
| 57 |
+
|
| 58 |
+
'digits',
|
| 59 |
+
'count_digits',
|
| 60 |
+
'is_palindromic',
|
| 61 |
+
|
| 62 |
+
'egyptian_fraction',
|
| 63 |
+
|
| 64 |
+
'ecm',
|
| 65 |
+
|
| 66 |
+
'qs',
|
| 67 |
+
]
|
lib/python3.12/site-packages/sympy/ntheory/bbp_pi.py
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'''
|
| 2 |
+
This implementation is a heavily modified fixed point implementation of
|
| 3 |
+
BBP_formula for calculating the nth position of pi. The original hosted
|
| 4 |
+
at: https://web.archive.org/web/20151116045029/http://en.literateprograms.org/Pi_with_the_BBP_formula_(Python)
|
| 5 |
+
|
| 6 |
+
# Permission is hereby granted, free of charge, to any person obtaining
|
| 7 |
+
# a copy of this software and associated documentation files (the
|
| 8 |
+
# "Software"), to deal in the Software without restriction, including
|
| 9 |
+
# without limitation the rights to use, copy, modify, merge, publish,
|
| 10 |
+
# distribute, sub-license, and/or sell copies of the Software, and to
|
| 11 |
+
# permit persons to whom the Software is furnished to do so, subject to
|
| 12 |
+
# the following conditions:
|
| 13 |
+
#
|
| 14 |
+
# The above copyright notice and this permission notice shall be
|
| 15 |
+
# included in all copies or substantial portions of the Software.
|
| 16 |
+
#
|
| 17 |
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
| 18 |
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
| 19 |
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
| 20 |
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
| 21 |
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
| 22 |
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
| 23 |
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
| 24 |
+
|
| 25 |
+
Modifications:
|
| 26 |
+
|
| 27 |
+
1.Once the nth digit and desired number of digits is selected, the
|
| 28 |
+
number of digits of working precision is calculated to ensure that
|
| 29 |
+
the hexadecimal digits returned are accurate. This is calculated as
|
| 30 |
+
|
| 31 |
+
int(math.log(start + prec)/math.log(16) + prec + 3)
|
| 32 |
+
--------------------------------------- --------
|
| 33 |
+
/ /
|
| 34 |
+
number of hex digits additional digits
|
| 35 |
+
|
| 36 |
+
This was checked by the following code which completed without
|
| 37 |
+
errors (and dig are the digits included in the test_bbp.py file):
|
| 38 |
+
|
| 39 |
+
for i in range(0,1000):
|
| 40 |
+
for j in range(1,1000):
|
| 41 |
+
a, b = pi_hex_digits(i, j), dig[i:i+j]
|
| 42 |
+
if a != b:
|
| 43 |
+
print('%s\n%s'%(a,b))
|
| 44 |
+
|
| 45 |
+
Deceasing the additional digits by 1 generated errors, so '3' is
|
| 46 |
+
the smallest additional precision needed to calculate the above
|
| 47 |
+
loop without errors. The following trailing 10 digits were also
|
| 48 |
+
checked to be accurate (and the times were slightly faster with
|
| 49 |
+
some of the constant modifications that were made):
|
| 50 |
+
|
| 51 |
+
>> from time import time
|
| 52 |
+
>> t=time();pi_hex_digits(10**2-10 + 1, 10), time()-t
|
| 53 |
+
('e90c6cc0ac', 0.0)
|
| 54 |
+
>> t=time();pi_hex_digits(10**4-10 + 1, 10), time()-t
|
| 55 |
+
('26aab49ec6', 0.17100000381469727)
|
| 56 |
+
>> t=time();pi_hex_digits(10**5-10 + 1, 10), time()-t
|
| 57 |
+
('a22673c1a5', 4.7109999656677246)
|
| 58 |
+
>> t=time();pi_hex_digits(10**6-10 + 1, 10), time()-t
|
| 59 |
+
('9ffd342362', 59.985999822616577)
|
| 60 |
+
>> t=time();pi_hex_digits(10**7-10 + 1, 10), time()-t
|
| 61 |
+
('c1a42e06a1', 689.51800012588501)
|
| 62 |
+
|
| 63 |
+
2. The while loop to evaluate whether the series has converged quits
|
| 64 |
+
when the addition amount `dt` has dropped to zero.
|
| 65 |
+
|
| 66 |
+
3. the formatting string to convert the decimal to hexadecimal is
|
| 67 |
+
calculated for the given precision.
|
| 68 |
+
|
| 69 |
+
4. pi_hex_digits(n) changed to have coefficient to the formula in an
|
| 70 |
+
array (perhaps just a matter of preference).
|
| 71 |
+
|
| 72 |
+
'''
|
| 73 |
+
|
| 74 |
+
from sympy.utilities.misc import as_int
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def _series(j, n, prec=14):
|
| 78 |
+
|
| 79 |
+
# Left sum from the bbp algorithm
|
| 80 |
+
s = 0
|
| 81 |
+
D = _dn(n, prec)
|
| 82 |
+
D4 = 4 * D
|
| 83 |
+
d = j
|
| 84 |
+
for k in range(n + 1):
|
| 85 |
+
s += (pow(16, n - k, d) << D4) // d
|
| 86 |
+
d += 8
|
| 87 |
+
|
| 88 |
+
# Right sum iterates to infinity for full precision, but we
|
| 89 |
+
# stop at the point where one iteration is beyond the precision
|
| 90 |
+
# specified.
|
| 91 |
+
|
| 92 |
+
t = 0
|
| 93 |
+
k = n + 1
|
| 94 |
+
e = D4 - 4 # 4*(D + n - k)
|
| 95 |
+
d = 8 * k + j
|
| 96 |
+
while True:
|
| 97 |
+
dt = (1 << e) // d
|
| 98 |
+
if not dt:
|
| 99 |
+
break
|
| 100 |
+
t += dt
|
| 101 |
+
# k += 1
|
| 102 |
+
e -= 4
|
| 103 |
+
d += 8
|
| 104 |
+
total = s + t
|
| 105 |
+
|
| 106 |
+
return total
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def pi_hex_digits(n, prec=14):
|
| 110 |
+
"""Returns a string containing ``prec`` (default 14) digits
|
| 111 |
+
starting at the nth digit of pi in hex. Counting of digits
|
| 112 |
+
starts at 0 and the decimal is not counted, so for n = 0 the
|
| 113 |
+
returned value starts with 3; n = 1 corresponds to the first
|
| 114 |
+
digit past the decimal point (which in hex is 2).
|
| 115 |
+
|
| 116 |
+
Parameters
|
| 117 |
+
==========
|
| 118 |
+
|
| 119 |
+
n : non-negative integer
|
| 120 |
+
prec : non-negative integer. default = 14
|
| 121 |
+
|
| 122 |
+
Returns
|
| 123 |
+
=======
|
| 124 |
+
|
| 125 |
+
str : Returns a string containing ``prec`` digits
|
| 126 |
+
starting at the nth digit of pi in hex.
|
| 127 |
+
If ``prec`` = 0, returns empty string.
|
| 128 |
+
|
| 129 |
+
Raises
|
| 130 |
+
======
|
| 131 |
+
|
| 132 |
+
ValueError
|
| 133 |
+
If ``n`` < 0 or ``prec`` < 0.
|
| 134 |
+
Or ``n`` or ``prec`` is not an integer.
|
| 135 |
+
|
| 136 |
+
Examples
|
| 137 |
+
========
|
| 138 |
+
|
| 139 |
+
>>> from sympy.ntheory.bbp_pi import pi_hex_digits
|
| 140 |
+
>>> pi_hex_digits(0)
|
| 141 |
+
'3243f6a8885a30'
|
| 142 |
+
>>> pi_hex_digits(0, 3)
|
| 143 |
+
'324'
|
| 144 |
+
|
| 145 |
+
These are consistent with the following results
|
| 146 |
+
|
| 147 |
+
>>> import math
|
| 148 |
+
>>> hex(int(math.pi * 2**((14-1)*4)))
|
| 149 |
+
'0x3243f6a8885a30'
|
| 150 |
+
>>> hex(int(math.pi * 2**((3-1)*4)))
|
| 151 |
+
'0x324'
|
| 152 |
+
|
| 153 |
+
References
|
| 154 |
+
==========
|
| 155 |
+
|
| 156 |
+
.. [1] http://www.numberworld.org/digits/Pi/
|
| 157 |
+
"""
|
| 158 |
+
n, prec = as_int(n), as_int(prec)
|
| 159 |
+
if n < 0:
|
| 160 |
+
raise ValueError('n cannot be negative')
|
| 161 |
+
if prec < 0:
|
| 162 |
+
raise ValueError('prec cannot be negative')
|
| 163 |
+
if prec == 0:
|
| 164 |
+
return ''
|
| 165 |
+
|
| 166 |
+
# main of implementation arrays holding formulae coefficients
|
| 167 |
+
n -= 1
|
| 168 |
+
a = [4, 2, 1, 1]
|
| 169 |
+
j = [1, 4, 5, 6]
|
| 170 |
+
|
| 171 |
+
#formulae
|
| 172 |
+
D = _dn(n, prec)
|
| 173 |
+
x = + (a[0]*_series(j[0], n, prec)
|
| 174 |
+
- a[1]*_series(j[1], n, prec)
|
| 175 |
+
- a[2]*_series(j[2], n, prec)
|
| 176 |
+
- a[3]*_series(j[3], n, prec)) & (16**D - 1)
|
| 177 |
+
|
| 178 |
+
s = ("%0" + "%ix" % prec) % (x // 16**(D - prec))
|
| 179 |
+
return s
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
def _dn(n, prec):
|
| 183 |
+
# controller for n dependence on precision
|
| 184 |
+
# n = starting digit index
|
| 185 |
+
# prec = the number of total digits to compute
|
| 186 |
+
n += 1 # because we subtract 1 for _series
|
| 187 |
+
|
| 188 |
+
# assert int(math.log(n + prec)/math.log(16)) ==\
|
| 189 |
+
# ((n + prec).bit_length() - 1) // 4
|
| 190 |
+
return ((n + prec).bit_length() - 1) // 4 + prec + 3
|
lib/python3.12/site-packages/sympy/ntheory/continued_fraction.py
ADDED
|
@@ -0,0 +1,369 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
import itertools
|
| 3 |
+
from sympy.core.exprtools import factor_terms
|
| 4 |
+
from sympy.core.numbers import Integer, Rational
|
| 5 |
+
from sympy.core.singleton import S
|
| 6 |
+
from sympy.core.symbol import Dummy
|
| 7 |
+
from sympy.core.sympify import _sympify
|
| 8 |
+
from sympy.utilities.misc import as_int
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def continued_fraction(a) -> list:
|
| 12 |
+
"""Return the continued fraction representation of a Rational or
|
| 13 |
+
quadratic irrational.
|
| 14 |
+
|
| 15 |
+
Examples
|
| 16 |
+
========
|
| 17 |
+
|
| 18 |
+
>>> from sympy.ntheory.continued_fraction import continued_fraction
|
| 19 |
+
>>> from sympy import sqrt
|
| 20 |
+
>>> continued_fraction((1 + 2*sqrt(3))/5)
|
| 21 |
+
[0, 1, [8, 3, 34, 3]]
|
| 22 |
+
|
| 23 |
+
See Also
|
| 24 |
+
========
|
| 25 |
+
continued_fraction_periodic, continued_fraction_reduce, continued_fraction_convergents
|
| 26 |
+
"""
|
| 27 |
+
e = _sympify(a)
|
| 28 |
+
if all(i.is_Rational for i in e.atoms()):
|
| 29 |
+
if e.is_Integer:
|
| 30 |
+
return continued_fraction_periodic(e, 1, 0)
|
| 31 |
+
elif e.is_Rational:
|
| 32 |
+
return continued_fraction_periodic(e.p, e.q, 0)
|
| 33 |
+
elif e.is_Pow and e.exp is S.Half and e.base.is_Integer:
|
| 34 |
+
return continued_fraction_periodic(0, 1, e.base)
|
| 35 |
+
elif e.is_Mul and len(e.args) == 2 and (
|
| 36 |
+
e.args[0].is_Rational and
|
| 37 |
+
e.args[1].is_Pow and
|
| 38 |
+
e.args[1].base.is_Integer and
|
| 39 |
+
e.args[1].exp is S.Half):
|
| 40 |
+
a, b = e.args
|
| 41 |
+
return continued_fraction_periodic(0, a.q, b.base, a.p)
|
| 42 |
+
else:
|
| 43 |
+
# this should not have to work very hard- no
|
| 44 |
+
# simplification, cancel, etc... which should be
|
| 45 |
+
# done by the user. e.g. This is a fancy 1 but
|
| 46 |
+
# the user should simplify it first:
|
| 47 |
+
# sqrt(2)*(1 + sqrt(2))/(sqrt(2) + 2)
|
| 48 |
+
p, d = e.expand().as_numer_denom()
|
| 49 |
+
if d.is_Integer:
|
| 50 |
+
if p.is_Rational:
|
| 51 |
+
return continued_fraction_periodic(p, d)
|
| 52 |
+
# look for a + b*c
|
| 53 |
+
# with c = sqrt(s)
|
| 54 |
+
if p.is_Add and len(p.args) == 2:
|
| 55 |
+
a, bc = p.args
|
| 56 |
+
else:
|
| 57 |
+
a = S.Zero
|
| 58 |
+
bc = p
|
| 59 |
+
if a.is_Integer:
|
| 60 |
+
b = S.NaN
|
| 61 |
+
if bc.is_Mul and len(bc.args) == 2:
|
| 62 |
+
b, c = bc.args
|
| 63 |
+
elif bc.is_Pow:
|
| 64 |
+
b = Integer(1)
|
| 65 |
+
c = bc
|
| 66 |
+
if b.is_Integer and (
|
| 67 |
+
c.is_Pow and c.exp is S.Half and
|
| 68 |
+
c.base.is_Integer):
|
| 69 |
+
# (a + b*sqrt(c))/d
|
| 70 |
+
c = c.base
|
| 71 |
+
return continued_fraction_periodic(a, d, c, b)
|
| 72 |
+
raise ValueError(
|
| 73 |
+
'expecting a rational or quadratic irrational, not %s' % e)
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def continued_fraction_periodic(p, q, d=0, s=1) -> list:
|
| 77 |
+
r"""
|
| 78 |
+
Find the periodic continued fraction expansion of a quadratic irrational.
|
| 79 |
+
|
| 80 |
+
Compute the continued fraction expansion of a rational or a
|
| 81 |
+
quadratic irrational number, i.e. `\frac{p + s\sqrt{d}}{q}`, where
|
| 82 |
+
`p`, `q \ne 0` and `d \ge 0` are integers.
|
| 83 |
+
|
| 84 |
+
Returns the continued fraction representation (canonical form) as
|
| 85 |
+
a list of integers, optionally ending (for quadratic irrationals)
|
| 86 |
+
with list of integers representing the repeating digits.
|
| 87 |
+
|
| 88 |
+
Parameters
|
| 89 |
+
==========
|
| 90 |
+
|
| 91 |
+
p : int
|
| 92 |
+
the rational part of the number's numerator
|
| 93 |
+
q : int
|
| 94 |
+
the denominator of the number
|
| 95 |
+
d : int, optional
|
| 96 |
+
the irrational part (discriminator) of the number's numerator
|
| 97 |
+
s : int, optional
|
| 98 |
+
the coefficient of the irrational part
|
| 99 |
+
|
| 100 |
+
Examples
|
| 101 |
+
========
|
| 102 |
+
|
| 103 |
+
>>> from sympy.ntheory.continued_fraction import continued_fraction_periodic
|
| 104 |
+
>>> continued_fraction_periodic(3, 2, 7)
|
| 105 |
+
[2, [1, 4, 1, 1]]
|
| 106 |
+
|
| 107 |
+
Golden ratio has the simplest continued fraction expansion:
|
| 108 |
+
|
| 109 |
+
>>> continued_fraction_periodic(1, 2, 5)
|
| 110 |
+
[[1]]
|
| 111 |
+
|
| 112 |
+
If the discriminator is zero or a perfect square then the number will be a
|
| 113 |
+
rational number:
|
| 114 |
+
|
| 115 |
+
>>> continued_fraction_periodic(4, 3, 0)
|
| 116 |
+
[1, 3]
|
| 117 |
+
>>> continued_fraction_periodic(4, 3, 49)
|
| 118 |
+
[3, 1, 2]
|
| 119 |
+
|
| 120 |
+
See Also
|
| 121 |
+
========
|
| 122 |
+
|
| 123 |
+
continued_fraction_iterator, continued_fraction_reduce
|
| 124 |
+
|
| 125 |
+
References
|
| 126 |
+
==========
|
| 127 |
+
|
| 128 |
+
.. [1] https://en.wikipedia.org/wiki/Periodic_continued_fraction
|
| 129 |
+
.. [2] K. Rosen. Elementary Number theory and its applications.
|
| 130 |
+
Addison-Wesley, 3 Sub edition, pages 379-381, January 1992.
|
| 131 |
+
|
| 132 |
+
"""
|
| 133 |
+
from sympy.functions import sqrt, floor
|
| 134 |
+
|
| 135 |
+
p, q, d, s = list(map(as_int, [p, q, d, s]))
|
| 136 |
+
|
| 137 |
+
if d < 0:
|
| 138 |
+
raise ValueError("expected non-negative for `d` but got %s" % d)
|
| 139 |
+
|
| 140 |
+
if q == 0:
|
| 141 |
+
raise ValueError("The denominator cannot be 0.")
|
| 142 |
+
|
| 143 |
+
if not s:
|
| 144 |
+
d = 0
|
| 145 |
+
|
| 146 |
+
# check for rational case
|
| 147 |
+
sd = sqrt(d)
|
| 148 |
+
if sd.is_Integer:
|
| 149 |
+
return list(continued_fraction_iterator(Rational(p + s*sd, q)))
|
| 150 |
+
|
| 151 |
+
# irrational case with sd != Integer
|
| 152 |
+
if q < 0:
|
| 153 |
+
p, q, s = -p, -q, -s
|
| 154 |
+
|
| 155 |
+
n = (p + s*sd)/q
|
| 156 |
+
if n < 0:
|
| 157 |
+
w = floor(-n)
|
| 158 |
+
f = -n - w
|
| 159 |
+
one_f = continued_fraction(1 - f) # 1-f < 1 so cf is [0 ... [...]]
|
| 160 |
+
one_f[0] -= w + 1
|
| 161 |
+
return one_f
|
| 162 |
+
|
| 163 |
+
d *= s**2
|
| 164 |
+
sd *= s
|
| 165 |
+
|
| 166 |
+
if (d - p**2)%q:
|
| 167 |
+
d *= q**2
|
| 168 |
+
sd *= q
|
| 169 |
+
p *= q
|
| 170 |
+
q *= q
|
| 171 |
+
|
| 172 |
+
terms: list[int] = []
|
| 173 |
+
pq = {}
|
| 174 |
+
|
| 175 |
+
while (p, q) not in pq:
|
| 176 |
+
pq[(p, q)] = len(terms)
|
| 177 |
+
terms.append((p + sd)//q)
|
| 178 |
+
p = terms[-1]*q - p
|
| 179 |
+
q = (d - p**2)//q
|
| 180 |
+
|
| 181 |
+
i = pq[(p, q)]
|
| 182 |
+
return terms[:i] + [terms[i:]] # type: ignore
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
def continued_fraction_reduce(cf):
|
| 186 |
+
"""
|
| 187 |
+
Reduce a continued fraction to a rational or quadratic irrational.
|
| 188 |
+
|
| 189 |
+
Compute the rational or quadratic irrational number from its
|
| 190 |
+
terminating or periodic continued fraction expansion. The
|
| 191 |
+
continued fraction expansion (cf) should be supplied as a
|
| 192 |
+
terminating iterator supplying the terms of the expansion. For
|
| 193 |
+
terminating continued fractions, this is equivalent to
|
| 194 |
+
``list(continued_fraction_convergents(cf))[-1]``, only a little more
|
| 195 |
+
efficient. If the expansion has a repeating part, a list of the
|
| 196 |
+
repeating terms should be returned as the last element from the
|
| 197 |
+
iterator. This is the format returned by
|
| 198 |
+
continued_fraction_periodic.
|
| 199 |
+
|
| 200 |
+
For quadratic irrationals, returns the largest solution found,
|
| 201 |
+
which is generally the one sought, if the fraction is in canonical
|
| 202 |
+
form (all terms positive except possibly the first).
|
| 203 |
+
|
| 204 |
+
Examples
|
| 205 |
+
========
|
| 206 |
+
|
| 207 |
+
>>> from sympy.ntheory.continued_fraction import continued_fraction_reduce
|
| 208 |
+
>>> continued_fraction_reduce([1, 2, 3, 4, 5])
|
| 209 |
+
225/157
|
| 210 |
+
>>> continued_fraction_reduce([-2, 1, 9, 7, 1, 2])
|
| 211 |
+
-256/233
|
| 212 |
+
>>> continued_fraction_reduce([2, 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8]).n(10)
|
| 213 |
+
2.718281835
|
| 214 |
+
>>> continued_fraction_reduce([1, 4, 2, [3, 1]])
|
| 215 |
+
(sqrt(21) + 287)/238
|
| 216 |
+
>>> continued_fraction_reduce([[1]])
|
| 217 |
+
(1 + sqrt(5))/2
|
| 218 |
+
>>> from sympy.ntheory.continued_fraction import continued_fraction_periodic
|
| 219 |
+
>>> continued_fraction_reduce(continued_fraction_periodic(8, 5, 13))
|
| 220 |
+
(sqrt(13) + 8)/5
|
| 221 |
+
|
| 222 |
+
See Also
|
| 223 |
+
========
|
| 224 |
+
|
| 225 |
+
continued_fraction_periodic
|
| 226 |
+
|
| 227 |
+
"""
|
| 228 |
+
from sympy.solvers import solve
|
| 229 |
+
|
| 230 |
+
period = []
|
| 231 |
+
x = Dummy('x')
|
| 232 |
+
|
| 233 |
+
def untillist(cf):
|
| 234 |
+
for nxt in cf:
|
| 235 |
+
if isinstance(nxt, list):
|
| 236 |
+
period.extend(nxt)
|
| 237 |
+
yield x
|
| 238 |
+
break
|
| 239 |
+
yield nxt
|
| 240 |
+
|
| 241 |
+
a = S.Zero
|
| 242 |
+
for a in continued_fraction_convergents(untillist(cf)):
|
| 243 |
+
pass
|
| 244 |
+
|
| 245 |
+
if period:
|
| 246 |
+
y = Dummy('y')
|
| 247 |
+
solns = solve(continued_fraction_reduce(period + [y]) - y, y)
|
| 248 |
+
solns.sort()
|
| 249 |
+
pure = solns[-1]
|
| 250 |
+
rv = a.subs(x, pure).radsimp()
|
| 251 |
+
else:
|
| 252 |
+
rv = a
|
| 253 |
+
if rv.is_Add:
|
| 254 |
+
rv = factor_terms(rv)
|
| 255 |
+
if rv.is_Mul and rv.args[0] == -1:
|
| 256 |
+
rv = rv.func(*rv.args)
|
| 257 |
+
return rv
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
def continued_fraction_iterator(x):
|
| 261 |
+
"""
|
| 262 |
+
Return continued fraction expansion of x as iterator.
|
| 263 |
+
|
| 264 |
+
Examples
|
| 265 |
+
========
|
| 266 |
+
|
| 267 |
+
>>> from sympy import Rational, pi
|
| 268 |
+
>>> from sympy.ntheory.continued_fraction import continued_fraction_iterator
|
| 269 |
+
|
| 270 |
+
>>> list(continued_fraction_iterator(Rational(3, 8)))
|
| 271 |
+
[0, 2, 1, 2]
|
| 272 |
+
>>> list(continued_fraction_iterator(Rational(-3, 8)))
|
| 273 |
+
[-1, 1, 1, 1, 2]
|
| 274 |
+
|
| 275 |
+
>>> for i, v in enumerate(continued_fraction_iterator(pi)):
|
| 276 |
+
... if i > 7:
|
| 277 |
+
... break
|
| 278 |
+
... print(v)
|
| 279 |
+
3
|
| 280 |
+
7
|
| 281 |
+
15
|
| 282 |
+
1
|
| 283 |
+
292
|
| 284 |
+
1
|
| 285 |
+
1
|
| 286 |
+
1
|
| 287 |
+
|
| 288 |
+
References
|
| 289 |
+
==========
|
| 290 |
+
|
| 291 |
+
.. [1] https://en.wikipedia.org/wiki/Continued_fraction
|
| 292 |
+
|
| 293 |
+
"""
|
| 294 |
+
from sympy.functions import floor
|
| 295 |
+
while True:
|
| 296 |
+
i = floor(x)
|
| 297 |
+
yield i
|
| 298 |
+
x -= i
|
| 299 |
+
if not x:
|
| 300 |
+
break
|
| 301 |
+
x = 1/x
|
| 302 |
+
|
| 303 |
+
|
| 304 |
+
def continued_fraction_convergents(cf):
|
| 305 |
+
"""
|
| 306 |
+
Return an iterator over the convergents of a continued fraction (cf).
|
| 307 |
+
|
| 308 |
+
The parameter should be in either of the following to forms:
|
| 309 |
+
- A list of partial quotients, possibly with the last element being a list
|
| 310 |
+
of repeating partial quotients, such as might be returned by
|
| 311 |
+
continued_fraction and continued_fraction_periodic.
|
| 312 |
+
- An iterable returning successive partial quotients of the continued
|
| 313 |
+
fraction, such as might be returned by continued_fraction_iterator.
|
| 314 |
+
|
| 315 |
+
In computing the convergents, the continued fraction need not be strictly
|
| 316 |
+
in canonical form (all integers, all but the first positive).
|
| 317 |
+
Rational and negative elements may be present in the expansion.
|
| 318 |
+
|
| 319 |
+
Examples
|
| 320 |
+
========
|
| 321 |
+
|
| 322 |
+
>>> from sympy.core import pi
|
| 323 |
+
>>> from sympy import S
|
| 324 |
+
>>> from sympy.ntheory.continued_fraction import \
|
| 325 |
+
continued_fraction_convergents, continued_fraction_iterator
|
| 326 |
+
|
| 327 |
+
>>> list(continued_fraction_convergents([0, 2, 1, 2]))
|
| 328 |
+
[0, 1/2, 1/3, 3/8]
|
| 329 |
+
|
| 330 |
+
>>> list(continued_fraction_convergents([1, S('1/2'), -7, S('1/4')]))
|
| 331 |
+
[1, 3, 19/5, 7]
|
| 332 |
+
|
| 333 |
+
>>> it = continued_fraction_convergents(continued_fraction_iterator(pi))
|
| 334 |
+
>>> for n in range(7):
|
| 335 |
+
... print(next(it))
|
| 336 |
+
3
|
| 337 |
+
22/7
|
| 338 |
+
333/106
|
| 339 |
+
355/113
|
| 340 |
+
103993/33102
|
| 341 |
+
104348/33215
|
| 342 |
+
208341/66317
|
| 343 |
+
|
| 344 |
+
>>> it = continued_fraction_convergents([1, [1, 2]]) # sqrt(3)
|
| 345 |
+
>>> for n in range(7):
|
| 346 |
+
... print(next(it))
|
| 347 |
+
1
|
| 348 |
+
2
|
| 349 |
+
5/3
|
| 350 |
+
7/4
|
| 351 |
+
19/11
|
| 352 |
+
26/15
|
| 353 |
+
71/41
|
| 354 |
+
|
| 355 |
+
See Also
|
| 356 |
+
========
|
| 357 |
+
|
| 358 |
+
continued_fraction_iterator, continued_fraction, continued_fraction_periodic
|
| 359 |
+
|
| 360 |
+
"""
|
| 361 |
+
if isinstance(cf, list) and isinstance(cf[-1], list):
|
| 362 |
+
cf = itertools.chain(cf[:-1], itertools.cycle(cf[-1]))
|
| 363 |
+
p_2, q_2 = S.Zero, S.One
|
| 364 |
+
p_1, q_1 = S.One, S.Zero
|
| 365 |
+
for a in cf:
|
| 366 |
+
p, q = a*p_1 + p_2, a*q_1 + q_2
|
| 367 |
+
p_2, q_2 = p_1, q_1
|
| 368 |
+
p_1, q_1 = p, q
|
| 369 |
+
yield p/q
|
lib/python3.12/site-packages/sympy/ntheory/digits.py
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from collections import defaultdict
|
| 2 |
+
|
| 3 |
+
from sympy.utilities.iterables import multiset, is_palindromic as _palindromic
|
| 4 |
+
from sympy.utilities.misc import as_int
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def digits(n, b=10, digits=None):
|
| 8 |
+
"""
|
| 9 |
+
Return a list of the digits of ``n`` in base ``b``. The first
|
| 10 |
+
element in the list is ``b`` (or ``-b`` if ``n`` is negative).
|
| 11 |
+
|
| 12 |
+
Examples
|
| 13 |
+
========
|
| 14 |
+
|
| 15 |
+
>>> from sympy.ntheory.digits import digits
|
| 16 |
+
>>> digits(35)
|
| 17 |
+
[10, 3, 5]
|
| 18 |
+
|
| 19 |
+
If the number is negative, the negative sign will be placed on the
|
| 20 |
+
base (which is the first element in the returned list):
|
| 21 |
+
|
| 22 |
+
>>> digits(-35)
|
| 23 |
+
[-10, 3, 5]
|
| 24 |
+
|
| 25 |
+
Bases other than 10 (and greater than 1) can be selected with ``b``:
|
| 26 |
+
|
| 27 |
+
>>> digits(27, b=2)
|
| 28 |
+
[2, 1, 1, 0, 1, 1]
|
| 29 |
+
|
| 30 |
+
Use the ``digits`` keyword if a certain number of digits is desired:
|
| 31 |
+
|
| 32 |
+
>>> digits(35, digits=4)
|
| 33 |
+
[10, 0, 0, 3, 5]
|
| 34 |
+
|
| 35 |
+
Parameters
|
| 36 |
+
==========
|
| 37 |
+
|
| 38 |
+
n: integer
|
| 39 |
+
The number whose digits are returned.
|
| 40 |
+
|
| 41 |
+
b: integer
|
| 42 |
+
The base in which digits are computed.
|
| 43 |
+
|
| 44 |
+
digits: integer (or None for all digits)
|
| 45 |
+
The number of digits to be returned (padded with zeros, if
|
| 46 |
+
necessary).
|
| 47 |
+
|
| 48 |
+
See Also
|
| 49 |
+
========
|
| 50 |
+
sympy.core.intfunc.num_digits, count_digits
|
| 51 |
+
"""
|
| 52 |
+
|
| 53 |
+
b = as_int(b)
|
| 54 |
+
n = as_int(n)
|
| 55 |
+
if b < 2:
|
| 56 |
+
raise ValueError("b must be greater than 1")
|
| 57 |
+
else:
|
| 58 |
+
x, y = abs(n), []
|
| 59 |
+
while x >= b:
|
| 60 |
+
x, r = divmod(x, b)
|
| 61 |
+
y.append(r)
|
| 62 |
+
y.append(x)
|
| 63 |
+
y.append(-b if n < 0 else b)
|
| 64 |
+
y.reverse()
|
| 65 |
+
ndig = len(y) - 1
|
| 66 |
+
if digits is not None:
|
| 67 |
+
if ndig > digits:
|
| 68 |
+
raise ValueError(
|
| 69 |
+
"For %s, at least %s digits are needed." % (n, ndig))
|
| 70 |
+
elif ndig < digits:
|
| 71 |
+
y[1:1] = [0]*(digits - ndig)
|
| 72 |
+
return y
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def count_digits(n, b=10):
|
| 76 |
+
"""
|
| 77 |
+
Return a dictionary whose keys are the digits of ``n`` in the
|
| 78 |
+
given base, ``b``, with keys indicating the digits appearing in the
|
| 79 |
+
number and values indicating how many times that digit appeared.
|
| 80 |
+
|
| 81 |
+
Examples
|
| 82 |
+
========
|
| 83 |
+
|
| 84 |
+
>>> from sympy.ntheory import count_digits
|
| 85 |
+
|
| 86 |
+
>>> count_digits(1111339)
|
| 87 |
+
{1: 4, 3: 2, 9: 1}
|
| 88 |
+
|
| 89 |
+
The digits returned are always represented in base-10
|
| 90 |
+
but the number itself can be entered in any format that is
|
| 91 |
+
understood by Python; the base of the number can also be
|
| 92 |
+
given if it is different than 10:
|
| 93 |
+
|
| 94 |
+
>>> n = 0xFA; n
|
| 95 |
+
250
|
| 96 |
+
>>> count_digits(_)
|
| 97 |
+
{0: 1, 2: 1, 5: 1}
|
| 98 |
+
>>> count_digits(n, 16)
|
| 99 |
+
{10: 1, 15: 1}
|
| 100 |
+
|
| 101 |
+
The default dictionary will return a 0 for any digit that did
|
| 102 |
+
not appear in the number. For example, which digits appear 7
|
| 103 |
+
times in ``77!``:
|
| 104 |
+
|
| 105 |
+
>>> from sympy import factorial
|
| 106 |
+
>>> c77 = count_digits(factorial(77))
|
| 107 |
+
>>> [i for i in range(10) if c77[i] == 7]
|
| 108 |
+
[1, 3, 7, 9]
|
| 109 |
+
|
| 110 |
+
See Also
|
| 111 |
+
========
|
| 112 |
+
sympy.core.intfunc.num_digits, digits
|
| 113 |
+
"""
|
| 114 |
+
rv = defaultdict(int, multiset(digits(n, b)).items())
|
| 115 |
+
rv.pop(b) if b in rv else rv.pop(-b) # b or -b is there
|
| 116 |
+
return rv
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
def is_palindromic(n, b=10):
|
| 120 |
+
"""return True if ``n`` is the same when read from left to right
|
| 121 |
+
or right to left in the given base, ``b``.
|
| 122 |
+
|
| 123 |
+
Examples
|
| 124 |
+
========
|
| 125 |
+
|
| 126 |
+
>>> from sympy.ntheory import is_palindromic
|
| 127 |
+
|
| 128 |
+
>>> all(is_palindromic(i) for i in (-11, 1, 22, 121))
|
| 129 |
+
True
|
| 130 |
+
|
| 131 |
+
The second argument allows you to test numbers in other
|
| 132 |
+
bases. For example, 88 is palindromic in base-10 but not
|
| 133 |
+
in base-8:
|
| 134 |
+
|
| 135 |
+
>>> is_palindromic(88, 8)
|
| 136 |
+
False
|
| 137 |
+
|
| 138 |
+
On the other hand, a number can be palindromic in base-8 but
|
| 139 |
+
not in base-10:
|
| 140 |
+
|
| 141 |
+
>>> 0o121, is_palindromic(0o121)
|
| 142 |
+
(81, False)
|
| 143 |
+
|
| 144 |
+
Or it might be palindromic in both bases:
|
| 145 |
+
|
| 146 |
+
>>> oct(121), is_palindromic(121, 8) and is_palindromic(121)
|
| 147 |
+
('0o171', True)
|
| 148 |
+
|
| 149 |
+
"""
|
| 150 |
+
return _palindromic(digits(n, b), 1)
|
lib/python3.12/site-packages/sympy/ntheory/ecm.py
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from math import log
|
| 2 |
+
|
| 3 |
+
from sympy.core.random import _randint
|
| 4 |
+
from sympy.external.gmpy import gcd, invert, sqrt
|
| 5 |
+
from sympy.utilities.misc import as_int
|
| 6 |
+
from .generate import sieve, primerange
|
| 7 |
+
from .primetest import isprime
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
#----------------------------------------------------------------------------#
|
| 11 |
+
# #
|
| 12 |
+
# Lenstra's Elliptic Curve Factorization #
|
| 13 |
+
# #
|
| 14 |
+
#----------------------------------------------------------------------------#
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class Point:
|
| 18 |
+
"""Montgomery form of Points in an elliptic curve.
|
| 19 |
+
In this form, the addition and doubling of points
|
| 20 |
+
does not need any y-coordinate information thus
|
| 21 |
+
decreasing the number of operations.
|
| 22 |
+
Using Montgomery form we try to perform point addition
|
| 23 |
+
and doubling in least amount of multiplications.
|
| 24 |
+
|
| 25 |
+
The elliptic curve used here is of the form
|
| 26 |
+
(E : b*y**2*z = x**3 + a*x**2*z + x*z**2).
|
| 27 |
+
The a_24 parameter is equal to (a + 2)/4.
|
| 28 |
+
|
| 29 |
+
References
|
| 30 |
+
==========
|
| 31 |
+
|
| 32 |
+
.. [1] Kris Gaj, Soonhak Kwon, Patrick Baier, Paul Kohlbrenner, Hoang Le, Mohammed Khaleeluddin, Ramakrishna Bachimanchi,
|
| 33 |
+
Implementing the Elliptic Curve Method of Factoring in Reconfigurable Hardware,
|
| 34 |
+
Cryptographic Hardware and Embedded Systems - CHES 2006 (2006), pp. 119-133,
|
| 35 |
+
https://doi.org/10.1007/11894063_10
|
| 36 |
+
https://www.hyperelliptic.org/tanja/SHARCS/talks06/Gaj.pdf
|
| 37 |
+
|
| 38 |
+
"""
|
| 39 |
+
|
| 40 |
+
def __init__(self, x_cord, z_cord, a_24, mod):
|
| 41 |
+
"""
|
| 42 |
+
Initial parameters for the Point class.
|
| 43 |
+
|
| 44 |
+
Parameters
|
| 45 |
+
==========
|
| 46 |
+
|
| 47 |
+
x_cord : X coordinate of the Point
|
| 48 |
+
z_cord : Z coordinate of the Point
|
| 49 |
+
a_24 : Parameter of the elliptic curve in Montgomery form
|
| 50 |
+
mod : modulus
|
| 51 |
+
"""
|
| 52 |
+
self.x_cord = x_cord
|
| 53 |
+
self.z_cord = z_cord
|
| 54 |
+
self.a_24 = a_24
|
| 55 |
+
self.mod = mod
|
| 56 |
+
|
| 57 |
+
def __eq__(self, other):
|
| 58 |
+
"""Two points are equal if X/Z of both points are equal
|
| 59 |
+
"""
|
| 60 |
+
if self.a_24 != other.a_24 or self.mod != other.mod:
|
| 61 |
+
return False
|
| 62 |
+
return self.x_cord * other.z_cord % self.mod ==\
|
| 63 |
+
other.x_cord * self.z_cord % self.mod
|
| 64 |
+
|
| 65 |
+
def add(self, Q, diff):
|
| 66 |
+
"""
|
| 67 |
+
Add two points self and Q where diff = self - Q. Moreover the assumption
|
| 68 |
+
is self.x_cord*Q.x_cord*(self.x_cord - Q.x_cord) != 0. This algorithm
|
| 69 |
+
requires 6 multiplications. Here the difference between the points
|
| 70 |
+
is already known and using this algorithm speeds up the addition
|
| 71 |
+
by reducing the number of multiplication required. Also in the
|
| 72 |
+
mont_ladder algorithm is constructed in a way so that the difference
|
| 73 |
+
between intermediate points is always equal to the initial point.
|
| 74 |
+
So, we always know what the difference between the point is.
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
Parameters
|
| 78 |
+
==========
|
| 79 |
+
|
| 80 |
+
Q : point on the curve in Montgomery form
|
| 81 |
+
diff : self - Q
|
| 82 |
+
|
| 83 |
+
Examples
|
| 84 |
+
========
|
| 85 |
+
|
| 86 |
+
>>> from sympy.ntheory.ecm import Point
|
| 87 |
+
>>> p1 = Point(11, 16, 7, 29)
|
| 88 |
+
>>> p2 = Point(13, 10, 7, 29)
|
| 89 |
+
>>> p3 = p2.add(p1, p1)
|
| 90 |
+
>>> p3.x_cord
|
| 91 |
+
23
|
| 92 |
+
>>> p3.z_cord
|
| 93 |
+
17
|
| 94 |
+
"""
|
| 95 |
+
u = (self.x_cord - self.z_cord)*(Q.x_cord + Q.z_cord)
|
| 96 |
+
v = (self.x_cord + self.z_cord)*(Q.x_cord - Q.z_cord)
|
| 97 |
+
add, subt = u + v, u - v
|
| 98 |
+
x_cord = diff.z_cord * add * add % self.mod
|
| 99 |
+
z_cord = diff.x_cord * subt * subt % self.mod
|
| 100 |
+
return Point(x_cord, z_cord, self.a_24, self.mod)
|
| 101 |
+
|
| 102 |
+
def double(self):
|
| 103 |
+
"""
|
| 104 |
+
Doubles a point in an elliptic curve in Montgomery form.
|
| 105 |
+
This algorithm requires 5 multiplications.
|
| 106 |
+
|
| 107 |
+
Examples
|
| 108 |
+
========
|
| 109 |
+
|
| 110 |
+
>>> from sympy.ntheory.ecm import Point
|
| 111 |
+
>>> p1 = Point(11, 16, 7, 29)
|
| 112 |
+
>>> p2 = p1.double()
|
| 113 |
+
>>> p2.x_cord
|
| 114 |
+
13
|
| 115 |
+
>>> p2.z_cord
|
| 116 |
+
10
|
| 117 |
+
"""
|
| 118 |
+
u = pow(self.x_cord + self.z_cord, 2, self.mod)
|
| 119 |
+
v = pow(self.x_cord - self.z_cord, 2, self.mod)
|
| 120 |
+
diff = u - v
|
| 121 |
+
x_cord = u*v % self.mod
|
| 122 |
+
z_cord = diff*(v + self.a_24*diff) % self.mod
|
| 123 |
+
return Point(x_cord, z_cord, self.a_24, self.mod)
|
| 124 |
+
|
| 125 |
+
def mont_ladder(self, k):
|
| 126 |
+
"""
|
| 127 |
+
Scalar multiplication of a point in Montgomery form
|
| 128 |
+
using Montgomery Ladder Algorithm.
|
| 129 |
+
A total of 11 multiplications are required in each step of this
|
| 130 |
+
algorithm.
|
| 131 |
+
|
| 132 |
+
Parameters
|
| 133 |
+
==========
|
| 134 |
+
|
| 135 |
+
k : The positive integer multiplier
|
| 136 |
+
|
| 137 |
+
Examples
|
| 138 |
+
========
|
| 139 |
+
|
| 140 |
+
>>> from sympy.ntheory.ecm import Point
|
| 141 |
+
>>> p1 = Point(11, 16, 7, 29)
|
| 142 |
+
>>> p3 = p1.mont_ladder(3)
|
| 143 |
+
>>> p3.x_cord
|
| 144 |
+
23
|
| 145 |
+
>>> p3.z_cord
|
| 146 |
+
17
|
| 147 |
+
"""
|
| 148 |
+
Q = self
|
| 149 |
+
R = self.double()
|
| 150 |
+
for i in bin(k)[3:]:
|
| 151 |
+
if i == '1':
|
| 152 |
+
Q = R.add(Q, self)
|
| 153 |
+
R = R.double()
|
| 154 |
+
else:
|
| 155 |
+
R = Q.add(R, self)
|
| 156 |
+
Q = Q.double()
|
| 157 |
+
return Q
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
def _ecm_one_factor(n, B1=10000, B2=100000, max_curve=200, seed=None):
|
| 161 |
+
"""Returns one factor of n using
|
| 162 |
+
Lenstra's 2 Stage Elliptic curve Factorization
|
| 163 |
+
with Suyama's Parameterization. Here Montgomery
|
| 164 |
+
arithmetic is used for fast computation of addition
|
| 165 |
+
and doubling of points in elliptic curve.
|
| 166 |
+
|
| 167 |
+
Explanation
|
| 168 |
+
===========
|
| 169 |
+
|
| 170 |
+
This ECM method considers elliptic curves in Montgomery
|
| 171 |
+
form (E : b*y**2*z = x**3 + a*x**2*z + x*z**2) and involves
|
| 172 |
+
elliptic curve operations (mod N), where the elements in
|
| 173 |
+
Z are reduced (mod N). Since N is not a prime, E over FF(N)
|
| 174 |
+
is not really an elliptic curve but we can still do point additions
|
| 175 |
+
and doubling as if FF(N) was a field.
|
| 176 |
+
|
| 177 |
+
Stage 1 : The basic algorithm involves taking a random point (P) on an
|
| 178 |
+
elliptic curve in FF(N). The compute k*P using Montgomery ladder algorithm.
|
| 179 |
+
Let q be an unknown factor of N. Then the order of the curve E, |E(FF(q))|,
|
| 180 |
+
might be a smooth number that divides k. Then we have k = l * |E(FF(q))|
|
| 181 |
+
for some l. For any point belonging to the curve E, |E(FF(q))|*P = O,
|
| 182 |
+
hence k*P = l*|E(FF(q))|*P. Thus kP.z_cord = 0 (mod q), and the unknownn
|
| 183 |
+
factor of N (q) can be recovered by taking gcd(kP.z_cord, N).
|
| 184 |
+
|
| 185 |
+
Stage 2 : This is a continuation of Stage 1 if k*P != O. The idea utilize
|
| 186 |
+
the fact that even if kP != 0, the value of k might miss just one large
|
| 187 |
+
prime divisor of |E(FF(q))|. In this case we only need to compute the
|
| 188 |
+
scalar multiplication by p to get p*k*P = O. Here a second bound B2
|
| 189 |
+
restrict the size of possible values of p.
|
| 190 |
+
|
| 191 |
+
Parameters
|
| 192 |
+
==========
|
| 193 |
+
|
| 194 |
+
n : Number to be Factored
|
| 195 |
+
B1 : Stage 1 Bound. Must be an even number.
|
| 196 |
+
B2 : Stage 2 Bound. Must be an even number.
|
| 197 |
+
max_curve : Maximum number of curves generated
|
| 198 |
+
|
| 199 |
+
Returns
|
| 200 |
+
=======
|
| 201 |
+
|
| 202 |
+
integer | None : ``n`` (if it is prime) else a non-trivial divisor of ``n``. ``None`` if not found
|
| 203 |
+
|
| 204 |
+
References
|
| 205 |
+
==========
|
| 206 |
+
|
| 207 |
+
.. [1] Carl Pomerance, Richard Crandall, Prime Numbers: A Computational Perspective,
|
| 208 |
+
2nd Edition (2005), page 344, ISBN:978-0387252827
|
| 209 |
+
"""
|
| 210 |
+
randint = _randint(seed)
|
| 211 |
+
if isprime(n):
|
| 212 |
+
return n
|
| 213 |
+
|
| 214 |
+
# When calculating T, if (B1 - 2*D) is negative, it cannot be calculated.
|
| 215 |
+
D = min(sqrt(B2), B1 // 2 - 1)
|
| 216 |
+
sieve.extend(D)
|
| 217 |
+
beta = [0] * D
|
| 218 |
+
S = [0] * D
|
| 219 |
+
k = 1
|
| 220 |
+
for p in primerange(2, B1 + 1):
|
| 221 |
+
k *= pow(p, int(log(B1, p)))
|
| 222 |
+
|
| 223 |
+
# Pre-calculate the prime numbers to be used in stage 2.
|
| 224 |
+
# Using the fact that the x-coordinates of point P and its
|
| 225 |
+
# inverse -P coincide, the number of primes to be checked
|
| 226 |
+
# in stage 2 can be reduced.
|
| 227 |
+
deltas_list = []
|
| 228 |
+
for r in range(B1 + 2*D, B2 + 2*D, 4*D):
|
| 229 |
+
deltas = set()
|
| 230 |
+
deltas.update((abs(q - r) - 1) // 2 for q in primerange(r - 2*D, r + 2*D))
|
| 231 |
+
# d in deltas iff r+(2d+1) and/or r-(2d+1) is prime
|
| 232 |
+
deltas_list.append(list(deltas))
|
| 233 |
+
|
| 234 |
+
for _ in range(max_curve):
|
| 235 |
+
#Suyama's Parametrization
|
| 236 |
+
sigma = randint(6, n - 1)
|
| 237 |
+
u = (sigma**2 - 5) % n
|
| 238 |
+
v = (4*sigma) % n
|
| 239 |
+
u_3 = pow(u, 3, n)
|
| 240 |
+
|
| 241 |
+
try:
|
| 242 |
+
# We use the elliptic curve y**2 = x**3 + a*x**2 + x
|
| 243 |
+
# where a = pow(v - u, 3, n)*(3*u + v)*invert(4*u_3*v, n) - 2
|
| 244 |
+
# However, we do not declare a because it is more convenient
|
| 245 |
+
# to use a24 = (a + 2)*invert(4, n) in the calculation.
|
| 246 |
+
a24 = pow(v - u, 3, n)*(3*u + v)*invert(16*u_3*v, n) % n
|
| 247 |
+
except ZeroDivisionError:
|
| 248 |
+
#If the invert(16*u_3*v, n) doesn't exist (i.e., g != 1)
|
| 249 |
+
g = gcd(2*u_3*v, n)
|
| 250 |
+
#If g = n, try another curve
|
| 251 |
+
if g == n:
|
| 252 |
+
continue
|
| 253 |
+
return g
|
| 254 |
+
|
| 255 |
+
Q = Point(u_3, pow(v, 3, n), a24, n)
|
| 256 |
+
Q = Q.mont_ladder(k)
|
| 257 |
+
g = gcd(Q.z_cord, n)
|
| 258 |
+
|
| 259 |
+
#Stage 1 factor
|
| 260 |
+
if g != 1 and g != n:
|
| 261 |
+
return g
|
| 262 |
+
#Stage 1 failure. Q.z = 0, Try another curve
|
| 263 |
+
elif g == n:
|
| 264 |
+
continue
|
| 265 |
+
|
| 266 |
+
#Stage 2 - Improved Standard Continuation
|
| 267 |
+
S[0] = Q
|
| 268 |
+
Q2 = Q.double()
|
| 269 |
+
S[1] = Q2.add(Q, Q)
|
| 270 |
+
beta[0] = (S[0].x_cord*S[0].z_cord) % n
|
| 271 |
+
beta[1] = (S[1].x_cord*S[1].z_cord) % n
|
| 272 |
+
for d in range(2, D):
|
| 273 |
+
S[d] = S[d - 1].add(Q2, S[d - 2])
|
| 274 |
+
beta[d] = (S[d].x_cord*S[d].z_cord) % n
|
| 275 |
+
# i.e., S[i] = Q.mont_ladder(2*i + 1)
|
| 276 |
+
|
| 277 |
+
g = 1
|
| 278 |
+
W = Q.mont_ladder(4*D)
|
| 279 |
+
T = Q.mont_ladder(B1 - 2*D)
|
| 280 |
+
R = Q.mont_ladder(B1 + 2*D)
|
| 281 |
+
for deltas in deltas_list:
|
| 282 |
+
# R = Q.mont_ladder(r) where r in range(B1 + 2*D, B2 + 2*D, 4*D)
|
| 283 |
+
alpha = (R.x_cord*R.z_cord) % n
|
| 284 |
+
for delta in deltas:
|
| 285 |
+
# We want to calculate
|
| 286 |
+
# f = R.x_cord * S[delta].z_cord - S[delta].x_cord * R.z_cord
|
| 287 |
+
f = (R.x_cord - S[delta].x_cord)*\
|
| 288 |
+
(R.z_cord + S[delta].z_cord) - alpha + beta[delta]
|
| 289 |
+
g = (g*f) % n
|
| 290 |
+
T, R = R, R.add(W, T)
|
| 291 |
+
g = gcd(n, g)
|
| 292 |
+
|
| 293 |
+
#Stage 2 Factor found
|
| 294 |
+
if g != 1 and g != n:
|
| 295 |
+
return g
|
| 296 |
+
|
| 297 |
+
|
| 298 |
+
def ecm(n, B1=10000, B2=100000, max_curve=200, seed=1234):
|
| 299 |
+
"""Performs factorization using Lenstra's Elliptic curve method.
|
| 300 |
+
|
| 301 |
+
This function repeatedly calls ``_ecm_one_factor`` to compute the factors
|
| 302 |
+
of n. First all the small factors are taken out using trial division.
|
| 303 |
+
Then ``_ecm_one_factor`` is used to compute one factor at a time.
|
| 304 |
+
|
| 305 |
+
Parameters
|
| 306 |
+
==========
|
| 307 |
+
|
| 308 |
+
n : Number to be Factored
|
| 309 |
+
B1 : Stage 1 Bound. Must be an even number.
|
| 310 |
+
B2 : Stage 2 Bound. Must be an even number.
|
| 311 |
+
max_curve : Maximum number of curves generated
|
| 312 |
+
seed : Initialize pseudorandom generator
|
| 313 |
+
|
| 314 |
+
Examples
|
| 315 |
+
========
|
| 316 |
+
|
| 317 |
+
>>> from sympy.ntheory import ecm
|
| 318 |
+
>>> ecm(25645121643901801)
|
| 319 |
+
{5394769, 4753701529}
|
| 320 |
+
>>> ecm(9804659461513846513)
|
| 321 |
+
{4641991, 2112166839943}
|
| 322 |
+
"""
|
| 323 |
+
n = as_int(n)
|
| 324 |
+
if B1 % 2 != 0 or B2 % 2 != 0:
|
| 325 |
+
raise ValueError("both bounds must be even")
|
| 326 |
+
_factors = set()
|
| 327 |
+
for prime in sieve.primerange(1, 100000):
|
| 328 |
+
if n % prime == 0:
|
| 329 |
+
_factors.add(prime)
|
| 330 |
+
while(n % prime == 0):
|
| 331 |
+
n //= prime
|
| 332 |
+
while(n > 1):
|
| 333 |
+
factor = _ecm_one_factor(n, B1, B2, max_curve, seed)
|
| 334 |
+
if factor is None:
|
| 335 |
+
raise ValueError("Increase the bounds")
|
| 336 |
+
_factors.add(factor)
|
| 337 |
+
n //= factor
|
| 338 |
+
|
| 339 |
+
factors = set()
|
| 340 |
+
for factor in _factors:
|
| 341 |
+
if isprime(factor):
|
| 342 |
+
factors.add(factor)
|
| 343 |
+
continue
|
| 344 |
+
factors |= ecm(factor)
|
| 345 |
+
return factors
|
lib/python3.12/site-packages/sympy/ntheory/egyptian_fraction.py
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.core.containers import Tuple
|
| 2 |
+
from sympy.core.numbers import (Integer, Rational)
|
| 3 |
+
from sympy.core.singleton import S
|
| 4 |
+
import sympy.polys
|
| 5 |
+
|
| 6 |
+
from math import gcd
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def egyptian_fraction(r, algorithm="Greedy"):
|
| 10 |
+
"""
|
| 11 |
+
Return the list of denominators of an Egyptian fraction
|
| 12 |
+
expansion [1]_ of the said rational `r`.
|
| 13 |
+
|
| 14 |
+
Parameters
|
| 15 |
+
==========
|
| 16 |
+
|
| 17 |
+
r : Rational or (p, q)
|
| 18 |
+
a positive rational number, ``p/q``.
|
| 19 |
+
algorithm : { "Greedy", "Graham Jewett", "Takenouchi", "Golomb" }, optional
|
| 20 |
+
Denotes the algorithm to be used (the default is "Greedy").
|
| 21 |
+
|
| 22 |
+
Examples
|
| 23 |
+
========
|
| 24 |
+
|
| 25 |
+
>>> from sympy import Rational
|
| 26 |
+
>>> from sympy.ntheory.egyptian_fraction import egyptian_fraction
|
| 27 |
+
>>> egyptian_fraction(Rational(3, 7))
|
| 28 |
+
[3, 11, 231]
|
| 29 |
+
>>> egyptian_fraction((3, 7), "Graham Jewett")
|
| 30 |
+
[7, 8, 9, 56, 57, 72, 3192]
|
| 31 |
+
>>> egyptian_fraction((3, 7), "Takenouchi")
|
| 32 |
+
[4, 7, 28]
|
| 33 |
+
>>> egyptian_fraction((3, 7), "Golomb")
|
| 34 |
+
[3, 15, 35]
|
| 35 |
+
>>> egyptian_fraction((11, 5), "Golomb")
|
| 36 |
+
[1, 2, 3, 4, 9, 234, 1118, 2580]
|
| 37 |
+
|
| 38 |
+
See Also
|
| 39 |
+
========
|
| 40 |
+
|
| 41 |
+
sympy.core.numbers.Rational
|
| 42 |
+
|
| 43 |
+
Notes
|
| 44 |
+
=====
|
| 45 |
+
|
| 46 |
+
Currently the following algorithms are supported:
|
| 47 |
+
|
| 48 |
+
1) Greedy Algorithm
|
| 49 |
+
|
| 50 |
+
Also called the Fibonacci-Sylvester algorithm [2]_.
|
| 51 |
+
At each step, extract the largest unit fraction less
|
| 52 |
+
than the target and replace the target with the remainder.
|
| 53 |
+
|
| 54 |
+
It has some distinct properties:
|
| 55 |
+
|
| 56 |
+
a) Given `p/q` in lowest terms, generates an expansion of maximum
|
| 57 |
+
length `p`. Even as the numerators get large, the number of
|
| 58 |
+
terms is seldom more than a handful.
|
| 59 |
+
|
| 60 |
+
b) Uses minimal memory.
|
| 61 |
+
|
| 62 |
+
c) The terms can blow up (standard examples of this are 5/121 and
|
| 63 |
+
31/311). The denominator is at most squared at each step
|
| 64 |
+
(doubly-exponential growth) and typically exhibits
|
| 65 |
+
singly-exponential growth.
|
| 66 |
+
|
| 67 |
+
2) Graham Jewett Algorithm
|
| 68 |
+
|
| 69 |
+
The algorithm suggested by the result of Graham and Jewett.
|
| 70 |
+
Note that this has a tendency to blow up: the length of the
|
| 71 |
+
resulting expansion is always ``2**(x/gcd(x, y)) - 1``. See [3]_.
|
| 72 |
+
|
| 73 |
+
3) Takenouchi Algorithm
|
| 74 |
+
|
| 75 |
+
The algorithm suggested by Takenouchi (1921).
|
| 76 |
+
Differs from the Graham-Jewett algorithm only in the handling
|
| 77 |
+
of duplicates. See [3]_.
|
| 78 |
+
|
| 79 |
+
4) Golomb's Algorithm
|
| 80 |
+
|
| 81 |
+
A method given by Golumb (1962), using modular arithmetic and
|
| 82 |
+
inverses. It yields the same results as a method using continued
|
| 83 |
+
fractions proposed by Bleicher (1972). See [4]_.
|
| 84 |
+
|
| 85 |
+
If the given rational is greater than or equal to 1, a greedy algorithm
|
| 86 |
+
of summing the harmonic sequence 1/1 + 1/2 + 1/3 + ... is used, taking
|
| 87 |
+
all the unit fractions of this sequence until adding one more would be
|
| 88 |
+
greater than the given number. This list of denominators is prefixed
|
| 89 |
+
to the result from the requested algorithm used on the remainder. For
|
| 90 |
+
example, if r is 8/3, using the Greedy algorithm, we get [1, 2, 3, 4,
|
| 91 |
+
5, 6, 7, 14, 420], where the beginning of the sequence, [1, 2, 3, 4, 5,
|
| 92 |
+
6, 7] is part of the harmonic sequence summing to 363/140, leaving a
|
| 93 |
+
remainder of 31/420, which yields [14, 420] by the Greedy algorithm.
|
| 94 |
+
The result of egyptian_fraction(Rational(8, 3), "Golomb") is [1, 2, 3,
|
| 95 |
+
4, 5, 6, 7, 14, 574, 2788, 6460, 11590, 33062, 113820], and so on.
|
| 96 |
+
|
| 97 |
+
References
|
| 98 |
+
==========
|
| 99 |
+
|
| 100 |
+
.. [1] https://en.wikipedia.org/wiki/Egyptian_fraction
|
| 101 |
+
.. [2] https://en.wikipedia.org/wiki/Greedy_algorithm_for_Egyptian_fractions
|
| 102 |
+
.. [3] https://www.ics.uci.edu/~eppstein/numth/egypt/conflict.html
|
| 103 |
+
.. [4] https://web.archive.org/web/20180413004012/https://ami.ektf.hu/uploads/papers/finalpdf/AMI_42_from129to134.pdf
|
| 104 |
+
|
| 105 |
+
"""
|
| 106 |
+
|
| 107 |
+
if not isinstance(r, Rational):
|
| 108 |
+
if isinstance(r, (Tuple, tuple)) and len(r) == 2:
|
| 109 |
+
r = Rational(*r)
|
| 110 |
+
else:
|
| 111 |
+
raise ValueError("Value must be a Rational or tuple of ints")
|
| 112 |
+
if r <= 0:
|
| 113 |
+
raise ValueError("Value must be positive")
|
| 114 |
+
|
| 115 |
+
# common cases that all methods agree on
|
| 116 |
+
x, y = r.as_numer_denom()
|
| 117 |
+
if y == 1 and x == 2:
|
| 118 |
+
return [Integer(i) for i in [1, 2, 3, 6]]
|
| 119 |
+
if x == y + 1:
|
| 120 |
+
return [S.One, y]
|
| 121 |
+
|
| 122 |
+
prefix, rem = egypt_harmonic(r)
|
| 123 |
+
if rem == 0:
|
| 124 |
+
return prefix
|
| 125 |
+
# work in Python ints
|
| 126 |
+
x, y = rem.p, rem.q
|
| 127 |
+
# assert x < y and gcd(x, y) = 1
|
| 128 |
+
|
| 129 |
+
if algorithm == "Greedy":
|
| 130 |
+
postfix = egypt_greedy(x, y)
|
| 131 |
+
elif algorithm == "Graham Jewett":
|
| 132 |
+
postfix = egypt_graham_jewett(x, y)
|
| 133 |
+
elif algorithm == "Takenouchi":
|
| 134 |
+
postfix = egypt_takenouchi(x, y)
|
| 135 |
+
elif algorithm == "Golomb":
|
| 136 |
+
postfix = egypt_golomb(x, y)
|
| 137 |
+
else:
|
| 138 |
+
raise ValueError("Entered invalid algorithm")
|
| 139 |
+
return prefix + [Integer(i) for i in postfix]
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
def egypt_greedy(x, y):
|
| 143 |
+
# assumes gcd(x, y) == 1
|
| 144 |
+
if x == 1:
|
| 145 |
+
return [y]
|
| 146 |
+
else:
|
| 147 |
+
a = (-y) % x
|
| 148 |
+
b = y*(y//x + 1)
|
| 149 |
+
c = gcd(a, b)
|
| 150 |
+
if c > 1:
|
| 151 |
+
num, denom = a//c, b//c
|
| 152 |
+
else:
|
| 153 |
+
num, denom = a, b
|
| 154 |
+
return [y//x + 1] + egypt_greedy(num, denom)
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
def egypt_graham_jewett(x, y):
|
| 158 |
+
# assumes gcd(x, y) == 1
|
| 159 |
+
l = [y] * x
|
| 160 |
+
|
| 161 |
+
# l is now a list of integers whose reciprocals sum to x/y.
|
| 162 |
+
# we shall now proceed to manipulate the elements of l without
|
| 163 |
+
# changing the reciprocated sum until all elements are unique.
|
| 164 |
+
|
| 165 |
+
while len(l) != len(set(l)):
|
| 166 |
+
l.sort() # so the list has duplicates. find a smallest pair
|
| 167 |
+
for i in range(len(l) - 1):
|
| 168 |
+
if l[i] == l[i + 1]:
|
| 169 |
+
break
|
| 170 |
+
# we have now identified a pair of identical
|
| 171 |
+
# elements: l[i] and l[i + 1].
|
| 172 |
+
# now comes the application of the result of graham and jewett:
|
| 173 |
+
l[i + 1] = l[i] + 1
|
| 174 |
+
# and we just iterate that until the list has no duplicates.
|
| 175 |
+
l.append(l[i]*(l[i] + 1))
|
| 176 |
+
return sorted(l)
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
def egypt_takenouchi(x, y):
|
| 180 |
+
# assumes gcd(x, y) == 1
|
| 181 |
+
# special cases for 3/y
|
| 182 |
+
if x == 3:
|
| 183 |
+
if y % 2 == 0:
|
| 184 |
+
return [y//2, y]
|
| 185 |
+
i = (y - 1)//2
|
| 186 |
+
j = i + 1
|
| 187 |
+
k = j + i
|
| 188 |
+
return [j, k, j*k]
|
| 189 |
+
l = [y] * x
|
| 190 |
+
while len(l) != len(set(l)):
|
| 191 |
+
l.sort()
|
| 192 |
+
for i in range(len(l) - 1):
|
| 193 |
+
if l[i] == l[i + 1]:
|
| 194 |
+
break
|
| 195 |
+
k = l[i]
|
| 196 |
+
if k % 2 == 0:
|
| 197 |
+
l[i] = l[i] // 2
|
| 198 |
+
del l[i + 1]
|
| 199 |
+
else:
|
| 200 |
+
l[i], l[i + 1] = (k + 1)//2, k*(k + 1)//2
|
| 201 |
+
return sorted(l)
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
def egypt_golomb(x, y):
|
| 205 |
+
# assumes x < y and gcd(x, y) == 1
|
| 206 |
+
if x == 1:
|
| 207 |
+
return [y]
|
| 208 |
+
xp = sympy.polys.ZZ.invert(int(x), int(y))
|
| 209 |
+
rv = [xp*y]
|
| 210 |
+
rv.extend(egypt_golomb((x*xp - 1)//y, xp))
|
| 211 |
+
return sorted(rv)
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def egypt_harmonic(r):
|
| 215 |
+
# assumes r is Rational
|
| 216 |
+
rv = []
|
| 217 |
+
d = S.One
|
| 218 |
+
acc = S.Zero
|
| 219 |
+
while acc + 1/d <= r:
|
| 220 |
+
acc += 1/d
|
| 221 |
+
rv.append(d)
|
| 222 |
+
d += 1
|
| 223 |
+
return (rv, r - acc)
|
lib/python3.12/site-packages/sympy/ntheory/elliptic_curve.py
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.core.numbers import oo
|
| 2 |
+
from sympy.core.symbol import symbols
|
| 3 |
+
from sympy.polys.domains import FiniteField, QQ, RationalField, FF
|
| 4 |
+
from sympy.polys.polytools import Poly
|
| 5 |
+
from sympy.solvers.solvers import solve
|
| 6 |
+
from sympy.utilities.iterables import is_sequence
|
| 7 |
+
from sympy.utilities.misc import as_int
|
| 8 |
+
from .factor_ import divisors
|
| 9 |
+
from .residue_ntheory import polynomial_congruence
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
class EllipticCurve:
|
| 13 |
+
"""
|
| 14 |
+
Create the following Elliptic Curve over domain.
|
| 15 |
+
|
| 16 |
+
`y^{2} + a_{1} x y + a_{3} y = x^{3} + a_{2} x^{2} + a_{4} x + a_{6}`
|
| 17 |
+
|
| 18 |
+
The default domain is ``QQ``. If no coefficient ``a1``, ``a2``, ``a3``,
|
| 19 |
+
is given then it creates a curve with the following form:
|
| 20 |
+
|
| 21 |
+
`y^{2} = x^{3} + a_{4} x + a_{6}`
|
| 22 |
+
|
| 23 |
+
Examples
|
| 24 |
+
========
|
| 25 |
+
|
| 26 |
+
References
|
| 27 |
+
==========
|
| 28 |
+
|
| 29 |
+
.. [1] J. Silverman "A Friendly Introduction to Number Theory" Third Edition
|
| 30 |
+
.. [2] https://mathworld.wolfram.com/EllipticDiscriminant.html
|
| 31 |
+
.. [3] G. Hardy, E. Wright "An Introduction to the Theory of Numbers" Sixth Edition
|
| 32 |
+
|
| 33 |
+
"""
|
| 34 |
+
|
| 35 |
+
def __init__(self, a4, a6, a1=0, a2=0, a3=0, modulus=0):
|
| 36 |
+
if modulus == 0:
|
| 37 |
+
domain = QQ
|
| 38 |
+
else:
|
| 39 |
+
domain = FF(modulus)
|
| 40 |
+
a1, a2, a3, a4, a6 = map(domain.convert, (a1, a2, a3, a4, a6))
|
| 41 |
+
self._domain = domain
|
| 42 |
+
self.modulus = modulus
|
| 43 |
+
# Calculate discriminant
|
| 44 |
+
b2 = a1**2 + 4 * a2
|
| 45 |
+
b4 = 2 * a4 + a1 * a3
|
| 46 |
+
b6 = a3**2 + 4 * a6
|
| 47 |
+
b8 = a1**2 * a6 + 4 * a2 * a6 - a1 * a3 * a4 + a2 * a3**2 - a4**2
|
| 48 |
+
self._b2, self._b4, self._b6, self._b8 = b2, b4, b6, b8
|
| 49 |
+
self._discrim = -b2**2 * b8 - 8 * b4**3 - 27 * b6**2 + 9 * b2 * b4 * b6
|
| 50 |
+
self._a1 = a1
|
| 51 |
+
self._a2 = a2
|
| 52 |
+
self._a3 = a3
|
| 53 |
+
self._a4 = a4
|
| 54 |
+
self._a6 = a6
|
| 55 |
+
x, y, z = symbols('x y z')
|
| 56 |
+
self.x, self.y, self.z = x, y, z
|
| 57 |
+
self._poly = Poly(y**2*z + a1*x*y*z + a3*y*z**2 - x**3 - a2*x**2*z - a4*x*z**2 - a6*z**3, domain=domain)
|
| 58 |
+
if isinstance(self._domain, FiniteField):
|
| 59 |
+
self._rank = 0
|
| 60 |
+
elif isinstance(self._domain, RationalField):
|
| 61 |
+
self._rank = None
|
| 62 |
+
|
| 63 |
+
def __call__(self, x, y, z=1):
|
| 64 |
+
return EllipticCurvePoint(x, y, z, self)
|
| 65 |
+
|
| 66 |
+
def __contains__(self, point):
|
| 67 |
+
if is_sequence(point):
|
| 68 |
+
if len(point) == 2:
|
| 69 |
+
z1 = 1
|
| 70 |
+
else:
|
| 71 |
+
z1 = point[2]
|
| 72 |
+
x1, y1 = point[:2]
|
| 73 |
+
elif isinstance(point, EllipticCurvePoint):
|
| 74 |
+
x1, y1, z1 = point.x, point.y, point.z
|
| 75 |
+
else:
|
| 76 |
+
raise ValueError('Invalid point.')
|
| 77 |
+
if self.characteristic == 0 and z1 == 0:
|
| 78 |
+
return True
|
| 79 |
+
return self._poly.subs({self.x: x1, self.y: y1, self.z: z1}) == 0
|
| 80 |
+
|
| 81 |
+
def __repr__(self):
|
| 82 |
+
return self._poly.__repr__()
|
| 83 |
+
|
| 84 |
+
def minimal(self):
|
| 85 |
+
"""
|
| 86 |
+
Return minimal Weierstrass equation.
|
| 87 |
+
|
| 88 |
+
Examples
|
| 89 |
+
========
|
| 90 |
+
|
| 91 |
+
>>> from sympy.ntheory.elliptic_curve import EllipticCurve
|
| 92 |
+
|
| 93 |
+
>>> e1 = EllipticCurve(-10, -20, 0, -1, 1)
|
| 94 |
+
>>> e1.minimal()
|
| 95 |
+
Poly(-x**3 + 13392*x*z**2 + y**2*z + 1080432*z**3, x, y, z, domain='QQ')
|
| 96 |
+
|
| 97 |
+
"""
|
| 98 |
+
char = self.characteristic
|
| 99 |
+
if char == 2:
|
| 100 |
+
return self
|
| 101 |
+
if char == 3:
|
| 102 |
+
return EllipticCurve(self._b4/2, self._b6/4, a2=self._b2/4, modulus=self.modulus)
|
| 103 |
+
c4 = self._b2**2 - 24*self._b4
|
| 104 |
+
c6 = -self._b2**3 + 36*self._b2*self._b4 - 216*self._b6
|
| 105 |
+
return EllipticCurve(-27*c4, -54*c6, modulus=self.modulus)
|
| 106 |
+
|
| 107 |
+
def points(self):
|
| 108 |
+
"""
|
| 109 |
+
Return points of curve over Finite Field.
|
| 110 |
+
|
| 111 |
+
Examples
|
| 112 |
+
========
|
| 113 |
+
|
| 114 |
+
>>> from sympy.ntheory.elliptic_curve import EllipticCurve
|
| 115 |
+
>>> e2 = EllipticCurve(1, 1, 1, 1, 1, modulus=5)
|
| 116 |
+
>>> e2.points()
|
| 117 |
+
{(0, 2), (1, 4), (2, 0), (2, 2), (3, 0), (3, 1), (4, 0)}
|
| 118 |
+
|
| 119 |
+
"""
|
| 120 |
+
|
| 121 |
+
char = self.characteristic
|
| 122 |
+
all_pt = set()
|
| 123 |
+
if char >= 1:
|
| 124 |
+
for i in range(char):
|
| 125 |
+
congruence_eq = self._poly.subs({self.x: i, self.z: 1}).expr
|
| 126 |
+
sol = polynomial_congruence(congruence_eq, char)
|
| 127 |
+
all_pt.update((i, num) for num in sol)
|
| 128 |
+
return all_pt
|
| 129 |
+
else:
|
| 130 |
+
raise ValueError("Infinitely many points")
|
| 131 |
+
|
| 132 |
+
def points_x(self, x):
|
| 133 |
+
"""Returns points on the curve for the given x-coordinate."""
|
| 134 |
+
pt = []
|
| 135 |
+
if self._domain == QQ:
|
| 136 |
+
for y in solve(self._poly.subs(self.x, x)):
|
| 137 |
+
pt.append((x, y))
|
| 138 |
+
else:
|
| 139 |
+
congruence_eq = self._poly.subs({self.x: x, self.z: 1}).expr
|
| 140 |
+
for y in polynomial_congruence(congruence_eq, self.characteristic):
|
| 141 |
+
pt.append((x, y))
|
| 142 |
+
return pt
|
| 143 |
+
|
| 144 |
+
def torsion_points(self):
|
| 145 |
+
"""
|
| 146 |
+
Return torsion points of curve over Rational number.
|
| 147 |
+
|
| 148 |
+
Return point objects those are finite order.
|
| 149 |
+
According to Nagell-Lutz theorem, torsion point p(x, y)
|
| 150 |
+
x and y are integers, either y = 0 or y**2 is divisor
|
| 151 |
+
of discriminent. According to Mazur's theorem, there are
|
| 152 |
+
at most 15 points in torsion collection.
|
| 153 |
+
|
| 154 |
+
Examples
|
| 155 |
+
========
|
| 156 |
+
|
| 157 |
+
>>> from sympy.ntheory.elliptic_curve import EllipticCurve
|
| 158 |
+
>>> e2 = EllipticCurve(-43, 166)
|
| 159 |
+
>>> sorted(e2.torsion_points())
|
| 160 |
+
[(-5, -16), (-5, 16), O, (3, -8), (3, 8), (11, -32), (11, 32)]
|
| 161 |
+
|
| 162 |
+
"""
|
| 163 |
+
if self.characteristic > 0:
|
| 164 |
+
raise ValueError("No torsion point for Finite Field.")
|
| 165 |
+
l = [EllipticCurvePoint.point_at_infinity(self)]
|
| 166 |
+
for xx in solve(self._poly.subs({self.y: 0, self.z: 1})):
|
| 167 |
+
if xx.is_rational:
|
| 168 |
+
l.append(self(xx, 0))
|
| 169 |
+
for i in divisors(self.discriminant, generator=True):
|
| 170 |
+
j = int(i**.5)
|
| 171 |
+
if j**2 == i:
|
| 172 |
+
for xx in solve(self._poly.subs({self.y: j, self.z: 1})):
|
| 173 |
+
if not xx.is_rational:
|
| 174 |
+
continue
|
| 175 |
+
p = self(xx, j)
|
| 176 |
+
if p.order() != oo:
|
| 177 |
+
l.extend([p, -p])
|
| 178 |
+
return l
|
| 179 |
+
|
| 180 |
+
@property
|
| 181 |
+
def characteristic(self):
|
| 182 |
+
"""
|
| 183 |
+
Return domain characteristic.
|
| 184 |
+
|
| 185 |
+
Examples
|
| 186 |
+
========
|
| 187 |
+
|
| 188 |
+
>>> from sympy.ntheory.elliptic_curve import EllipticCurve
|
| 189 |
+
>>> e2 = EllipticCurve(-43, 166)
|
| 190 |
+
>>> e2.characteristic
|
| 191 |
+
0
|
| 192 |
+
|
| 193 |
+
"""
|
| 194 |
+
return self._domain.characteristic()
|
| 195 |
+
|
| 196 |
+
@property
|
| 197 |
+
def discriminant(self):
|
| 198 |
+
"""
|
| 199 |
+
Return curve discriminant.
|
| 200 |
+
|
| 201 |
+
Examples
|
| 202 |
+
========
|
| 203 |
+
|
| 204 |
+
>>> from sympy.ntheory.elliptic_curve import EllipticCurve
|
| 205 |
+
>>> e2 = EllipticCurve(0, 17)
|
| 206 |
+
>>> e2.discriminant
|
| 207 |
+
-124848
|
| 208 |
+
|
| 209 |
+
"""
|
| 210 |
+
return int(self._discrim)
|
| 211 |
+
|
| 212 |
+
@property
|
| 213 |
+
def is_singular(self):
|
| 214 |
+
"""
|
| 215 |
+
Return True if curve discriminant is equal to zero.
|
| 216 |
+
"""
|
| 217 |
+
return self.discriminant == 0
|
| 218 |
+
|
| 219 |
+
@property
|
| 220 |
+
def j_invariant(self):
|
| 221 |
+
"""
|
| 222 |
+
Return curve j-invariant.
|
| 223 |
+
|
| 224 |
+
Examples
|
| 225 |
+
========
|
| 226 |
+
|
| 227 |
+
>>> from sympy.ntheory.elliptic_curve import EllipticCurve
|
| 228 |
+
>>> e1 = EllipticCurve(-2, 0, 0, 1, 1)
|
| 229 |
+
>>> e1.j_invariant
|
| 230 |
+
1404928/389
|
| 231 |
+
|
| 232 |
+
"""
|
| 233 |
+
c4 = self._b2**2 - 24*self._b4
|
| 234 |
+
return self._domain.to_sympy(c4**3 / self._discrim)
|
| 235 |
+
|
| 236 |
+
@property
|
| 237 |
+
def order(self):
|
| 238 |
+
"""
|
| 239 |
+
Number of points in Finite field.
|
| 240 |
+
|
| 241 |
+
Examples
|
| 242 |
+
========
|
| 243 |
+
|
| 244 |
+
>>> from sympy.ntheory.elliptic_curve import EllipticCurve
|
| 245 |
+
>>> e2 = EllipticCurve(1, 0, modulus=19)
|
| 246 |
+
>>> e2.order
|
| 247 |
+
19
|
| 248 |
+
|
| 249 |
+
"""
|
| 250 |
+
if self.characteristic == 0:
|
| 251 |
+
raise NotImplementedError("Still not implemented")
|
| 252 |
+
return len(self.points())
|
| 253 |
+
|
| 254 |
+
@property
|
| 255 |
+
def rank(self):
|
| 256 |
+
"""
|
| 257 |
+
Number of independent points of infinite order.
|
| 258 |
+
|
| 259 |
+
For Finite field, it must be 0.
|
| 260 |
+
"""
|
| 261 |
+
if self._rank is not None:
|
| 262 |
+
return self._rank
|
| 263 |
+
raise NotImplementedError("Still not implemented")
|
| 264 |
+
|
| 265 |
+
|
| 266 |
+
class EllipticCurvePoint:
|
| 267 |
+
"""
|
| 268 |
+
Point of Elliptic Curve
|
| 269 |
+
|
| 270 |
+
Examples
|
| 271 |
+
========
|
| 272 |
+
|
| 273 |
+
>>> from sympy.ntheory.elliptic_curve import EllipticCurve
|
| 274 |
+
>>> e1 = EllipticCurve(-17, 16)
|
| 275 |
+
>>> p1 = e1(0, -4, 1)
|
| 276 |
+
>>> p2 = e1(1, 0)
|
| 277 |
+
>>> p1 + p2
|
| 278 |
+
(15, -56)
|
| 279 |
+
>>> e3 = EllipticCurve(-1, 9)
|
| 280 |
+
>>> e3(1, -3) * 3
|
| 281 |
+
(664/169, 17811/2197)
|
| 282 |
+
>>> (e3(1, -3) * 3).order()
|
| 283 |
+
oo
|
| 284 |
+
>>> e2 = EllipticCurve(-2, 0, 0, 1, 1)
|
| 285 |
+
>>> p = e2(-1,1)
|
| 286 |
+
>>> q = e2(0, -1)
|
| 287 |
+
>>> p+q
|
| 288 |
+
(4, 8)
|
| 289 |
+
>>> p-q
|
| 290 |
+
(1, 0)
|
| 291 |
+
>>> 3*p-5*q
|
| 292 |
+
(328/361, -2800/6859)
|
| 293 |
+
"""
|
| 294 |
+
|
| 295 |
+
@staticmethod
|
| 296 |
+
def point_at_infinity(curve):
|
| 297 |
+
return EllipticCurvePoint(0, 1, 0, curve)
|
| 298 |
+
|
| 299 |
+
def __init__(self, x, y, z, curve):
|
| 300 |
+
dom = curve._domain.convert
|
| 301 |
+
self.x = dom(x)
|
| 302 |
+
self.y = dom(y)
|
| 303 |
+
self.z = dom(z)
|
| 304 |
+
self._curve = curve
|
| 305 |
+
self._domain = self._curve._domain
|
| 306 |
+
if not self._curve.__contains__(self):
|
| 307 |
+
raise ValueError("The curve does not contain this point")
|
| 308 |
+
|
| 309 |
+
def __add__(self, p):
|
| 310 |
+
if self.z == 0:
|
| 311 |
+
return p
|
| 312 |
+
if p.z == 0:
|
| 313 |
+
return self
|
| 314 |
+
x1, y1 = self.x/self.z, self.y/self.z
|
| 315 |
+
x2, y2 = p.x/p.z, p.y/p.z
|
| 316 |
+
a1 = self._curve._a1
|
| 317 |
+
a2 = self._curve._a2
|
| 318 |
+
a3 = self._curve._a3
|
| 319 |
+
a4 = self._curve._a4
|
| 320 |
+
a6 = self._curve._a6
|
| 321 |
+
if x1 != x2:
|
| 322 |
+
slope = (y1 - y2) / (x1 - x2)
|
| 323 |
+
yint = (y1 * x2 - y2 * x1) / (x2 - x1)
|
| 324 |
+
else:
|
| 325 |
+
if (y1 + y2) == 0:
|
| 326 |
+
return self.point_at_infinity(self._curve)
|
| 327 |
+
slope = (3 * x1**2 + 2*a2*x1 + a4 - a1*y1) / (a1 * x1 + a3 + 2 * y1)
|
| 328 |
+
yint = (-x1**3 + a4*x1 + 2*a6 - a3*y1) / (a1*x1 + a3 + 2*y1)
|
| 329 |
+
x3 = slope**2 + a1*slope - a2 - x1 - x2
|
| 330 |
+
y3 = -(slope + a1) * x3 - yint - a3
|
| 331 |
+
return self._curve(x3, y3, 1)
|
| 332 |
+
|
| 333 |
+
def __lt__(self, other):
|
| 334 |
+
return (self.x, self.y, self.z) < (other.x, other.y, other.z)
|
| 335 |
+
|
| 336 |
+
def __mul__(self, n):
|
| 337 |
+
n = as_int(n)
|
| 338 |
+
r = self.point_at_infinity(self._curve)
|
| 339 |
+
if n == 0:
|
| 340 |
+
return r
|
| 341 |
+
if n < 0:
|
| 342 |
+
return -self * -n
|
| 343 |
+
p = self
|
| 344 |
+
while n:
|
| 345 |
+
if n & 1:
|
| 346 |
+
r = r + p
|
| 347 |
+
n >>= 1
|
| 348 |
+
p = p + p
|
| 349 |
+
return r
|
| 350 |
+
|
| 351 |
+
def __rmul__(self, n):
|
| 352 |
+
return self * n
|
| 353 |
+
|
| 354 |
+
def __neg__(self):
|
| 355 |
+
return EllipticCurvePoint(self.x, -self.y - self._curve._a1*self.x - self._curve._a3, self.z, self._curve)
|
| 356 |
+
|
| 357 |
+
def __repr__(self):
|
| 358 |
+
if self.z == 0:
|
| 359 |
+
return 'O'
|
| 360 |
+
dom = self._curve._domain
|
| 361 |
+
try:
|
| 362 |
+
return '({}, {})'.format(dom.to_sympy(self.x), dom.to_sympy(self.y))
|
| 363 |
+
except TypeError:
|
| 364 |
+
pass
|
| 365 |
+
return '({}, {})'.format(self.x, self.y)
|
| 366 |
+
|
| 367 |
+
def __sub__(self, other):
|
| 368 |
+
return self.__add__(-other)
|
| 369 |
+
|
| 370 |
+
def order(self):
|
| 371 |
+
"""
|
| 372 |
+
Return point order n where nP = 0.
|
| 373 |
+
|
| 374 |
+
"""
|
| 375 |
+
if self.z == 0:
|
| 376 |
+
return 1
|
| 377 |
+
if self.y == 0: # P = -P
|
| 378 |
+
return 2
|
| 379 |
+
p = self * 2
|
| 380 |
+
if p.y == -self.y: # 2P = -P
|
| 381 |
+
return 3
|
| 382 |
+
i = 2
|
| 383 |
+
if self._domain != QQ:
|
| 384 |
+
while int(p.x) == p.x and int(p.y) == p.y:
|
| 385 |
+
p = self + p
|
| 386 |
+
i += 1
|
| 387 |
+
if p.z == 0:
|
| 388 |
+
return i
|
| 389 |
+
return oo
|
| 390 |
+
while p.x.numerator == p.x and p.y.numerator == p.y:
|
| 391 |
+
p = self + p
|
| 392 |
+
i += 1
|
| 393 |
+
if i > 12:
|
| 394 |
+
return oo
|
| 395 |
+
if p.z == 0:
|
| 396 |
+
return i
|
| 397 |
+
return oo
|
lib/python3.12/site-packages/sympy/ntheory/factor_.py
ADDED
|
@@ -0,0 +1,2668 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Integer factorization
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from collections import defaultdict
|
| 6 |
+
import math
|
| 7 |
+
|
| 8 |
+
from sympy.core.containers import Dict
|
| 9 |
+
from sympy.core.mul import Mul
|
| 10 |
+
from sympy.core.numbers import Rational, Integer
|
| 11 |
+
from sympy.core.intfunc import num_digits
|
| 12 |
+
from sympy.core.power import Pow
|
| 13 |
+
from sympy.core.random import _randint
|
| 14 |
+
from sympy.core.singleton import S
|
| 15 |
+
from sympy.external.gmpy import (SYMPY_INTS, gcd, sqrt as isqrt,
|
| 16 |
+
sqrtrem, iroot, bit_scan1, remove)
|
| 17 |
+
from .primetest import isprime, MERSENNE_PRIME_EXPONENTS, is_mersenne_prime
|
| 18 |
+
from .generate import sieve, primerange, nextprime
|
| 19 |
+
from .digits import digits
|
| 20 |
+
from sympy.utilities.decorator import deprecated
|
| 21 |
+
from sympy.utilities.iterables import flatten
|
| 22 |
+
from sympy.utilities.misc import as_int, filldedent
|
| 23 |
+
from .ecm import _ecm_one_factor
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def smoothness(n):
|
| 27 |
+
"""
|
| 28 |
+
Return the B-smooth and B-power smooth values of n.
|
| 29 |
+
|
| 30 |
+
The smoothness of n is the largest prime factor of n; the power-
|
| 31 |
+
smoothness is the largest divisor raised to its multiplicity.
|
| 32 |
+
|
| 33 |
+
Examples
|
| 34 |
+
========
|
| 35 |
+
|
| 36 |
+
>>> from sympy.ntheory.factor_ import smoothness
|
| 37 |
+
>>> smoothness(2**7*3**2)
|
| 38 |
+
(3, 128)
|
| 39 |
+
>>> smoothness(2**4*13)
|
| 40 |
+
(13, 16)
|
| 41 |
+
>>> smoothness(2)
|
| 42 |
+
(2, 2)
|
| 43 |
+
|
| 44 |
+
See Also
|
| 45 |
+
========
|
| 46 |
+
|
| 47 |
+
factorint, smoothness_p
|
| 48 |
+
"""
|
| 49 |
+
|
| 50 |
+
if n == 1:
|
| 51 |
+
return (1, 1) # not prime, but otherwise this causes headaches
|
| 52 |
+
facs = factorint(n)
|
| 53 |
+
return max(facs), max(m**facs[m] for m in facs)
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def smoothness_p(n, m=-1, power=0, visual=None):
|
| 57 |
+
"""
|
| 58 |
+
Return a list of [m, (p, (M, sm(p + m), psm(p + m)))...]
|
| 59 |
+
where:
|
| 60 |
+
|
| 61 |
+
1. p**M is the base-p divisor of n
|
| 62 |
+
2. sm(p + m) is the smoothness of p + m (m = -1 by default)
|
| 63 |
+
3. psm(p + m) is the power smoothness of p + m
|
| 64 |
+
|
| 65 |
+
The list is sorted according to smoothness (default) or by power smoothness
|
| 66 |
+
if power=1.
|
| 67 |
+
|
| 68 |
+
The smoothness of the numbers to the left (m = -1) or right (m = 1) of a
|
| 69 |
+
factor govern the results that are obtained from the p +/- 1 type factoring
|
| 70 |
+
methods.
|
| 71 |
+
|
| 72 |
+
>>> from sympy.ntheory.factor_ import smoothness_p, factorint
|
| 73 |
+
>>> smoothness_p(10431, m=1)
|
| 74 |
+
(1, [(3, (2, 2, 4)), (19, (1, 5, 5)), (61, (1, 31, 31))])
|
| 75 |
+
>>> smoothness_p(10431)
|
| 76 |
+
(-1, [(3, (2, 2, 2)), (19, (1, 3, 9)), (61, (1, 5, 5))])
|
| 77 |
+
>>> smoothness_p(10431, power=1)
|
| 78 |
+
(-1, [(3, (2, 2, 2)), (61, (1, 5, 5)), (19, (1, 3, 9))])
|
| 79 |
+
|
| 80 |
+
If visual=True then an annotated string will be returned:
|
| 81 |
+
|
| 82 |
+
>>> print(smoothness_p(21477639576571, visual=1))
|
| 83 |
+
p**i=4410317**1 has p-1 B=1787, B-pow=1787
|
| 84 |
+
p**i=4869863**1 has p-1 B=2434931, B-pow=2434931
|
| 85 |
+
|
| 86 |
+
This string can also be generated directly from a factorization dictionary
|
| 87 |
+
and vice versa:
|
| 88 |
+
|
| 89 |
+
>>> factorint(17*9)
|
| 90 |
+
{3: 2, 17: 1}
|
| 91 |
+
>>> smoothness_p(_)
|
| 92 |
+
'p**i=3**2 has p-1 B=2, B-pow=2\\np**i=17**1 has p-1 B=2, B-pow=16'
|
| 93 |
+
>>> smoothness_p(_)
|
| 94 |
+
{3: 2, 17: 1}
|
| 95 |
+
|
| 96 |
+
The table of the output logic is:
|
| 97 |
+
|
| 98 |
+
====== ====== ======= =======
|
| 99 |
+
| Visual
|
| 100 |
+
------ ----------------------
|
| 101 |
+
Input True False other
|
| 102 |
+
====== ====== ======= =======
|
| 103 |
+
dict str tuple str
|
| 104 |
+
str str tuple dict
|
| 105 |
+
tuple str tuple str
|
| 106 |
+
n str tuple tuple
|
| 107 |
+
mul str tuple tuple
|
| 108 |
+
====== ====== ======= =======
|
| 109 |
+
|
| 110 |
+
See Also
|
| 111 |
+
========
|
| 112 |
+
|
| 113 |
+
factorint, smoothness
|
| 114 |
+
"""
|
| 115 |
+
|
| 116 |
+
# visual must be True, False or other (stored as None)
|
| 117 |
+
if visual in (1, 0):
|
| 118 |
+
visual = bool(visual)
|
| 119 |
+
elif visual not in (True, False):
|
| 120 |
+
visual = None
|
| 121 |
+
|
| 122 |
+
if isinstance(n, str):
|
| 123 |
+
if visual:
|
| 124 |
+
return n
|
| 125 |
+
d = {}
|
| 126 |
+
for li in n.splitlines():
|
| 127 |
+
k, v = [int(i) for i in
|
| 128 |
+
li.split('has')[0].split('=')[1].split('**')]
|
| 129 |
+
d[k] = v
|
| 130 |
+
if visual is not True and visual is not False:
|
| 131 |
+
return d
|
| 132 |
+
return smoothness_p(d, visual=False)
|
| 133 |
+
elif not isinstance(n, tuple):
|
| 134 |
+
facs = factorint(n, visual=False)
|
| 135 |
+
|
| 136 |
+
if power:
|
| 137 |
+
k = -1
|
| 138 |
+
else:
|
| 139 |
+
k = 1
|
| 140 |
+
if isinstance(n, tuple):
|
| 141 |
+
rv = n
|
| 142 |
+
else:
|
| 143 |
+
rv = (m, sorted([(f,
|
| 144 |
+
tuple([M] + list(smoothness(f + m))))
|
| 145 |
+
for f, M in list(facs.items())],
|
| 146 |
+
key=lambda x: (x[1][k], x[0])))
|
| 147 |
+
|
| 148 |
+
if visual is False or (visual is not True) and (type(n) in [int, Mul]):
|
| 149 |
+
return rv
|
| 150 |
+
lines = []
|
| 151 |
+
for dat in rv[1]:
|
| 152 |
+
dat = flatten(dat)
|
| 153 |
+
dat.insert(2, m)
|
| 154 |
+
lines.append('p**i=%i**%i has p%+i B=%i, B-pow=%i' % tuple(dat))
|
| 155 |
+
return '\n'.join(lines)
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
def multiplicity(p, n):
|
| 159 |
+
"""
|
| 160 |
+
Find the greatest integer m such that p**m divides n.
|
| 161 |
+
|
| 162 |
+
Examples
|
| 163 |
+
========
|
| 164 |
+
|
| 165 |
+
>>> from sympy import multiplicity, Rational
|
| 166 |
+
>>> [multiplicity(5, n) for n in [8, 5, 25, 125, 250]]
|
| 167 |
+
[0, 1, 2, 3, 3]
|
| 168 |
+
>>> multiplicity(3, Rational(1, 9))
|
| 169 |
+
-2
|
| 170 |
+
|
| 171 |
+
Note: when checking for the multiplicity of a number in a
|
| 172 |
+
large factorial it is most efficient to send it as an unevaluated
|
| 173 |
+
factorial or to call ``multiplicity_in_factorial`` directly:
|
| 174 |
+
|
| 175 |
+
>>> from sympy.ntheory import multiplicity_in_factorial
|
| 176 |
+
>>> from sympy import factorial
|
| 177 |
+
>>> p = factorial(25)
|
| 178 |
+
>>> n = 2**100
|
| 179 |
+
>>> nfac = factorial(n, evaluate=False)
|
| 180 |
+
>>> multiplicity(p, nfac)
|
| 181 |
+
52818775009509558395695966887
|
| 182 |
+
>>> _ == multiplicity_in_factorial(p, n)
|
| 183 |
+
True
|
| 184 |
+
|
| 185 |
+
See Also
|
| 186 |
+
========
|
| 187 |
+
|
| 188 |
+
trailing
|
| 189 |
+
|
| 190 |
+
"""
|
| 191 |
+
try:
|
| 192 |
+
p, n = as_int(p), as_int(n)
|
| 193 |
+
except ValueError:
|
| 194 |
+
from sympy.functions.combinatorial.factorials import factorial
|
| 195 |
+
if all(isinstance(i, (SYMPY_INTS, Rational)) for i in (p, n)):
|
| 196 |
+
p = Rational(p)
|
| 197 |
+
n = Rational(n)
|
| 198 |
+
if p.q == 1:
|
| 199 |
+
if n.p == 1:
|
| 200 |
+
return -multiplicity(p.p, n.q)
|
| 201 |
+
return multiplicity(p.p, n.p) - multiplicity(p.p, n.q)
|
| 202 |
+
elif p.p == 1:
|
| 203 |
+
return multiplicity(p.q, n.q)
|
| 204 |
+
else:
|
| 205 |
+
like = min(
|
| 206 |
+
multiplicity(p.p, n.p),
|
| 207 |
+
multiplicity(p.q, n.q))
|
| 208 |
+
cross = min(
|
| 209 |
+
multiplicity(p.q, n.p),
|
| 210 |
+
multiplicity(p.p, n.q))
|
| 211 |
+
return like - cross
|
| 212 |
+
elif (isinstance(p, (SYMPY_INTS, Integer)) and
|
| 213 |
+
isinstance(n, factorial) and
|
| 214 |
+
isinstance(n.args[0], Integer) and
|
| 215 |
+
n.args[0] >= 0):
|
| 216 |
+
return multiplicity_in_factorial(p, n.args[0])
|
| 217 |
+
raise ValueError('expecting ints or fractions, got %s and %s' % (p, n))
|
| 218 |
+
|
| 219 |
+
if n == 0:
|
| 220 |
+
raise ValueError('no such integer exists: multiplicity of %s is not-defined' %(n))
|
| 221 |
+
return remove(n, p)[1]
|
| 222 |
+
|
| 223 |
+
|
| 224 |
+
def multiplicity_in_factorial(p, n):
|
| 225 |
+
"""return the largest integer ``m`` such that ``p**m`` divides ``n!``
|
| 226 |
+
without calculating the factorial of ``n``.
|
| 227 |
+
|
| 228 |
+
Parameters
|
| 229 |
+
==========
|
| 230 |
+
|
| 231 |
+
p : Integer
|
| 232 |
+
positive integer
|
| 233 |
+
n : Integer
|
| 234 |
+
non-negative integer
|
| 235 |
+
|
| 236 |
+
Examples
|
| 237 |
+
========
|
| 238 |
+
|
| 239 |
+
>>> from sympy.ntheory import multiplicity_in_factorial
|
| 240 |
+
>>> from sympy import factorial
|
| 241 |
+
|
| 242 |
+
>>> multiplicity_in_factorial(2, 3)
|
| 243 |
+
1
|
| 244 |
+
|
| 245 |
+
An instructive use of this is to tell how many trailing zeros
|
| 246 |
+
a given factorial has. For example, there are 6 in 25!:
|
| 247 |
+
|
| 248 |
+
>>> factorial(25)
|
| 249 |
+
15511210043330985984000000
|
| 250 |
+
>>> multiplicity_in_factorial(10, 25)
|
| 251 |
+
6
|
| 252 |
+
|
| 253 |
+
For large factorials, it is much faster/feasible to use
|
| 254 |
+
this function rather than computing the actual factorial:
|
| 255 |
+
|
| 256 |
+
>>> multiplicity_in_factorial(factorial(25), 2**100)
|
| 257 |
+
52818775009509558395695966887
|
| 258 |
+
|
| 259 |
+
See Also
|
| 260 |
+
========
|
| 261 |
+
|
| 262 |
+
multiplicity
|
| 263 |
+
|
| 264 |
+
"""
|
| 265 |
+
|
| 266 |
+
p, n = as_int(p), as_int(n)
|
| 267 |
+
|
| 268 |
+
if p <= 0:
|
| 269 |
+
raise ValueError('expecting positive integer got %s' % p )
|
| 270 |
+
|
| 271 |
+
if n < 0:
|
| 272 |
+
raise ValueError('expecting non-negative integer got %s' % n )
|
| 273 |
+
|
| 274 |
+
# keep only the largest of a given multiplicity since those
|
| 275 |
+
# of a given multiplicity will be goverened by the behavior
|
| 276 |
+
# of the largest factor
|
| 277 |
+
f = defaultdict(int)
|
| 278 |
+
for k, v in factorint(p).items():
|
| 279 |
+
f[v] = max(k, f[v])
|
| 280 |
+
# multiplicity of p in n! depends on multiplicity
|
| 281 |
+
# of prime `k` in p, so we floor divide by `v`
|
| 282 |
+
# and keep it if smaller than the multiplicity of p
|
| 283 |
+
# seen so far
|
| 284 |
+
return min((n + k - sum(digits(n, k)))//(k - 1)//v for v, k in f.items())
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
def _perfect_power(n, next_p=2):
|
| 288 |
+
""" Return integers ``(b, e)`` such that ``n == b**e`` if ``n`` is a unique
|
| 289 |
+
perfect power with ``e > 1``, else ``False`` (e.g. 1 is not a perfect power).
|
| 290 |
+
|
| 291 |
+
Explanation
|
| 292 |
+
===========
|
| 293 |
+
|
| 294 |
+
This is a low-level helper for ``perfect_power``, for internal use.
|
| 295 |
+
|
| 296 |
+
Parameters
|
| 297 |
+
==========
|
| 298 |
+
|
| 299 |
+
n : int
|
| 300 |
+
assume that n is a nonnegative integer
|
| 301 |
+
next_p : int
|
| 302 |
+
Assume that n has no factor less than next_p.
|
| 303 |
+
i.e., all(n % p for p in range(2, next_p)) is True
|
| 304 |
+
|
| 305 |
+
Examples
|
| 306 |
+
========
|
| 307 |
+
>>> from sympy.ntheory.factor_ import _perfect_power
|
| 308 |
+
>>> _perfect_power(16)
|
| 309 |
+
(2, 4)
|
| 310 |
+
>>> _perfect_power(17)
|
| 311 |
+
False
|
| 312 |
+
|
| 313 |
+
"""
|
| 314 |
+
if n <= 3:
|
| 315 |
+
return False
|
| 316 |
+
|
| 317 |
+
factors = {}
|
| 318 |
+
g = 0
|
| 319 |
+
multi = 1
|
| 320 |
+
|
| 321 |
+
def done(n, factors, g, multi):
|
| 322 |
+
g = gcd(g, multi)
|
| 323 |
+
if g == 1:
|
| 324 |
+
return False
|
| 325 |
+
factors[n] = multi
|
| 326 |
+
return math.prod(p**(e//g) for p, e in factors.items()), g
|
| 327 |
+
|
| 328 |
+
# If n is small, only trial factoring is faster
|
| 329 |
+
if n <= 1_000_000:
|
| 330 |
+
n = _factorint_small(factors, n, 1_000, 1_000, next_p)[0]
|
| 331 |
+
if n > 1:
|
| 332 |
+
return False
|
| 333 |
+
g = gcd(*factors.values())
|
| 334 |
+
if g == 1:
|
| 335 |
+
return False
|
| 336 |
+
return math.prod(p**(e//g) for p, e in factors.items()), g
|
| 337 |
+
|
| 338 |
+
# divide by 2
|
| 339 |
+
if next_p < 3:
|
| 340 |
+
g = bit_scan1(n)
|
| 341 |
+
if g:
|
| 342 |
+
if g == 1:
|
| 343 |
+
return False
|
| 344 |
+
n >>= g
|
| 345 |
+
factors[2] = g
|
| 346 |
+
if n == 1:
|
| 347 |
+
return 2, g
|
| 348 |
+
else:
|
| 349 |
+
# If `m**g`, then we have found perfect power.
|
| 350 |
+
# Otherwise, there is no possibility of perfect power, especially if `g` is prime.
|
| 351 |
+
m, _exact = iroot(n, g)
|
| 352 |
+
if _exact:
|
| 353 |
+
return 2*m, g
|
| 354 |
+
elif isprime(g):
|
| 355 |
+
return False
|
| 356 |
+
next_p = 3
|
| 357 |
+
|
| 358 |
+
# square number?
|
| 359 |
+
while n & 7 == 1: # n % 8 == 1:
|
| 360 |
+
m, _exact = iroot(n, 2)
|
| 361 |
+
if _exact:
|
| 362 |
+
n = m
|
| 363 |
+
multi <<= 1
|
| 364 |
+
else:
|
| 365 |
+
break
|
| 366 |
+
if n < next_p**3:
|
| 367 |
+
return done(n, factors, g, multi)
|
| 368 |
+
|
| 369 |
+
# trial factoring
|
| 370 |
+
# Since the maximum value an exponent can take is `log_{next_p}(n)`,
|
| 371 |
+
# the number of exponents to be checked can be reduced by performing a trial factoring.
|
| 372 |
+
# The value of `tf_max` needs more consideration.
|
| 373 |
+
tf_max = n.bit_length()//27 + 24
|
| 374 |
+
if next_p < tf_max:
|
| 375 |
+
for p in primerange(next_p, tf_max):
|
| 376 |
+
m, t = remove(n, p)
|
| 377 |
+
if t:
|
| 378 |
+
n = m
|
| 379 |
+
t *= multi
|
| 380 |
+
_g = gcd(g, t)
|
| 381 |
+
if _g == 1:
|
| 382 |
+
return False
|
| 383 |
+
factors[p] = t
|
| 384 |
+
if n == 1:
|
| 385 |
+
return math.prod(p**(e//_g)
|
| 386 |
+
for p, e in factors.items()), _g
|
| 387 |
+
elif g == 0 or _g < g: # If g is updated
|
| 388 |
+
g = _g
|
| 389 |
+
m, _exact = iroot(n**multi, g)
|
| 390 |
+
if _exact:
|
| 391 |
+
return m * math.prod(p**(e//g)
|
| 392 |
+
for p, e in factors.items()), g
|
| 393 |
+
elif isprime(g):
|
| 394 |
+
return False
|
| 395 |
+
next_p = tf_max
|
| 396 |
+
if n < next_p**3:
|
| 397 |
+
return done(n, factors, g, multi)
|
| 398 |
+
|
| 399 |
+
# check iroot
|
| 400 |
+
if g:
|
| 401 |
+
# If g is non-zero, the exponent is a divisor of g.
|
| 402 |
+
# 2 can be omitted since it has already been checked.
|
| 403 |
+
prime_iter = sorted(factorint(g >> bit_scan1(g)).keys())
|
| 404 |
+
else:
|
| 405 |
+
# The maximum possible value of the exponent is `log_{next_p}(n)`.
|
| 406 |
+
# To compensate for the presence of computational error, 2 is added.
|
| 407 |
+
prime_iter = primerange(3, int(math.log(n, next_p)) + 2)
|
| 408 |
+
logn = math.log2(n)
|
| 409 |
+
threshold = logn / 40 # Threshold for direct calculation
|
| 410 |
+
for p in prime_iter:
|
| 411 |
+
if threshold < p:
|
| 412 |
+
# If p is large, find the power root p directly without `iroot`.
|
| 413 |
+
while True:
|
| 414 |
+
b = pow(2, logn / p)
|
| 415 |
+
rb = int(b + 0.5)
|
| 416 |
+
if abs(rb - b) < 0.01 and rb**p == n:
|
| 417 |
+
n = rb
|
| 418 |
+
multi *= p
|
| 419 |
+
logn = math.log2(n)
|
| 420 |
+
else:
|
| 421 |
+
break
|
| 422 |
+
else:
|
| 423 |
+
while True:
|
| 424 |
+
m, _exact = iroot(n, p)
|
| 425 |
+
if _exact:
|
| 426 |
+
n = m
|
| 427 |
+
multi *= p
|
| 428 |
+
logn = math.log2(n)
|
| 429 |
+
else:
|
| 430 |
+
break
|
| 431 |
+
if n < next_p**(p + 2):
|
| 432 |
+
break
|
| 433 |
+
return done(n, factors, g, multi)
|
| 434 |
+
|
| 435 |
+
|
| 436 |
+
def perfect_power(n, candidates=None, big=True, factor=True):
|
| 437 |
+
"""
|
| 438 |
+
Return ``(b, e)`` such that ``n`` == ``b**e`` if ``n`` is a unique
|
| 439 |
+
perfect power with ``e > 1``, else ``False`` (e.g. 1 is not a
|
| 440 |
+
perfect power). A ValueError is raised if ``n`` is not Rational.
|
| 441 |
+
|
| 442 |
+
By default, the base is recursively decomposed and the exponents
|
| 443 |
+
collected so the largest possible ``e`` is sought. If ``big=False``
|
| 444 |
+
then the smallest possible ``e`` (thus prime) will be chosen.
|
| 445 |
+
|
| 446 |
+
If ``factor=True`` then simultaneous factorization of ``n`` is
|
| 447 |
+
attempted since finding a factor indicates the only possible root
|
| 448 |
+
for ``n``. This is True by default since only a few small factors will
|
| 449 |
+
be tested in the course of searching for the perfect power.
|
| 450 |
+
|
| 451 |
+
The use of ``candidates`` is primarily for internal use; if provided,
|
| 452 |
+
False will be returned if ``n`` cannot be written as a power with one
|
| 453 |
+
of the candidates as an exponent and factoring (beyond testing for
|
| 454 |
+
a factor of 2) will not be attempted.
|
| 455 |
+
|
| 456 |
+
Examples
|
| 457 |
+
========
|
| 458 |
+
|
| 459 |
+
>>> from sympy import perfect_power, Rational
|
| 460 |
+
>>> perfect_power(16)
|
| 461 |
+
(2, 4)
|
| 462 |
+
>>> perfect_power(16, big=False)
|
| 463 |
+
(4, 2)
|
| 464 |
+
|
| 465 |
+
Negative numbers can only have odd perfect powers:
|
| 466 |
+
|
| 467 |
+
>>> perfect_power(-4)
|
| 468 |
+
False
|
| 469 |
+
>>> perfect_power(-8)
|
| 470 |
+
(-2, 3)
|
| 471 |
+
|
| 472 |
+
Rationals are also recognized:
|
| 473 |
+
|
| 474 |
+
>>> perfect_power(Rational(1, 2)**3)
|
| 475 |
+
(1/2, 3)
|
| 476 |
+
>>> perfect_power(Rational(-3, 2)**3)
|
| 477 |
+
(-3/2, 3)
|
| 478 |
+
|
| 479 |
+
Notes
|
| 480 |
+
=====
|
| 481 |
+
|
| 482 |
+
To know whether an integer is a perfect power of 2 use
|
| 483 |
+
|
| 484 |
+
>>> is2pow = lambda n: bool(n and not n & (n - 1))
|
| 485 |
+
>>> [(i, is2pow(i)) for i in range(5)]
|
| 486 |
+
[(0, False), (1, True), (2, True), (3, False), (4, True)]
|
| 487 |
+
|
| 488 |
+
It is not necessary to provide ``candidates``. When provided
|
| 489 |
+
it will be assumed that they are ints. The first one that is
|
| 490 |
+
larger than the computed maximum possible exponent will signal
|
| 491 |
+
failure for the routine.
|
| 492 |
+
|
| 493 |
+
>>> perfect_power(3**8, [9])
|
| 494 |
+
False
|
| 495 |
+
>>> perfect_power(3**8, [2, 4, 8])
|
| 496 |
+
(3, 8)
|
| 497 |
+
>>> perfect_power(3**8, [4, 8], big=False)
|
| 498 |
+
(9, 4)
|
| 499 |
+
|
| 500 |
+
See Also
|
| 501 |
+
========
|
| 502 |
+
sympy.core.intfunc.integer_nthroot
|
| 503 |
+
sympy.ntheory.primetest.is_square
|
| 504 |
+
"""
|
| 505 |
+
if isinstance(n, Rational) and not n.is_Integer:
|
| 506 |
+
p, q = n.as_numer_denom()
|
| 507 |
+
if p is S.One:
|
| 508 |
+
pp = perfect_power(q)
|
| 509 |
+
if pp:
|
| 510 |
+
pp = (n.func(1, pp[0]), pp[1])
|
| 511 |
+
else:
|
| 512 |
+
pp = perfect_power(p)
|
| 513 |
+
if pp:
|
| 514 |
+
num, e = pp
|
| 515 |
+
pq = perfect_power(q, [e])
|
| 516 |
+
if pq:
|
| 517 |
+
den, _ = pq
|
| 518 |
+
pp = n.func(num, den), e
|
| 519 |
+
return pp
|
| 520 |
+
|
| 521 |
+
n = as_int(n)
|
| 522 |
+
if n < 0:
|
| 523 |
+
pp = perfect_power(-n)
|
| 524 |
+
if pp:
|
| 525 |
+
b, e = pp
|
| 526 |
+
if e % 2:
|
| 527 |
+
return -b, e
|
| 528 |
+
return False
|
| 529 |
+
|
| 530 |
+
if candidates is None and big:
|
| 531 |
+
return _perfect_power(n)
|
| 532 |
+
|
| 533 |
+
if n <= 3:
|
| 534 |
+
# no unique exponent for 0, 1
|
| 535 |
+
# 2 and 3 have exponents of 1
|
| 536 |
+
return False
|
| 537 |
+
logn = math.log2(n)
|
| 538 |
+
max_possible = int(logn) + 2 # only check values less than this
|
| 539 |
+
not_square = n % 10 in [2, 3, 7, 8] # squares cannot end in 2, 3, 7, 8
|
| 540 |
+
min_possible = 2 + not_square
|
| 541 |
+
if not candidates:
|
| 542 |
+
candidates = primerange(min_possible, max_possible)
|
| 543 |
+
else:
|
| 544 |
+
candidates = sorted([i for i in candidates
|
| 545 |
+
if min_possible <= i < max_possible])
|
| 546 |
+
if n%2 == 0:
|
| 547 |
+
e = bit_scan1(n)
|
| 548 |
+
candidates = [i for i in candidates if e%i == 0]
|
| 549 |
+
if big:
|
| 550 |
+
candidates = reversed(candidates)
|
| 551 |
+
for e in candidates:
|
| 552 |
+
r, ok = iroot(n, e)
|
| 553 |
+
if ok:
|
| 554 |
+
return int(r), e
|
| 555 |
+
return False
|
| 556 |
+
|
| 557 |
+
def _factors():
|
| 558 |
+
rv = 2 + n % 2
|
| 559 |
+
while True:
|
| 560 |
+
yield rv
|
| 561 |
+
rv = nextprime(rv)
|
| 562 |
+
|
| 563 |
+
for fac, e in zip(_factors(), candidates):
|
| 564 |
+
# see if there is a factor present
|
| 565 |
+
if factor and n % fac == 0:
|
| 566 |
+
# find what the potential power is
|
| 567 |
+
e = remove(n, fac)[1]
|
| 568 |
+
# if it's a trivial power we are done
|
| 569 |
+
if e == 1:
|
| 570 |
+
return False
|
| 571 |
+
|
| 572 |
+
# maybe the e-th root of n is exact
|
| 573 |
+
r, exact = iroot(n, e)
|
| 574 |
+
if not exact:
|
| 575 |
+
# Having a factor, we know that e is the maximal
|
| 576 |
+
# possible value for a root of n.
|
| 577 |
+
# If n = fac**e*m can be written as a perfect
|
| 578 |
+
# power then see if m can be written as r**E where
|
| 579 |
+
# gcd(e, E) != 1 so n = (fac**(e//E)*r)**E
|
| 580 |
+
m = n//fac**e
|
| 581 |
+
rE = perfect_power(m, candidates=divisors(e, generator=True))
|
| 582 |
+
if not rE:
|
| 583 |
+
return False
|
| 584 |
+
else:
|
| 585 |
+
r, E = rE
|
| 586 |
+
r, e = fac**(e//E)*r, E
|
| 587 |
+
if not big:
|
| 588 |
+
e0 = primefactors(e)
|
| 589 |
+
if e0[0] != e:
|
| 590 |
+
r, e = r**(e//e0[0]), e0[0]
|
| 591 |
+
return int(r), e
|
| 592 |
+
|
| 593 |
+
# Weed out downright impossible candidates
|
| 594 |
+
if logn/e < 40:
|
| 595 |
+
b = 2.0**(logn/e)
|
| 596 |
+
if abs(int(b + 0.5) - b) > 0.01:
|
| 597 |
+
continue
|
| 598 |
+
|
| 599 |
+
# now see if the plausible e makes a perfect power
|
| 600 |
+
r, exact = iroot(n, e)
|
| 601 |
+
if exact:
|
| 602 |
+
if big:
|
| 603 |
+
m = perfect_power(r, big=big, factor=factor)
|
| 604 |
+
if m:
|
| 605 |
+
r, e = m[0], e*m[1]
|
| 606 |
+
return int(r), e
|
| 607 |
+
|
| 608 |
+
return False
|
| 609 |
+
|
| 610 |
+
|
| 611 |
+
def pollard_rho(n, s=2, a=1, retries=5, seed=1234, max_steps=None, F=None):
|
| 612 |
+
r"""
|
| 613 |
+
Use Pollard's rho method to try to extract a nontrivial factor
|
| 614 |
+
of ``n``. The returned factor may be a composite number. If no
|
| 615 |
+
factor is found, ``None`` is returned.
|
| 616 |
+
|
| 617 |
+
The algorithm generates pseudo-random values of x with a generator
|
| 618 |
+
function, replacing x with F(x). If F is not supplied then the
|
| 619 |
+
function x**2 + ``a`` is used. The first value supplied to F(x) is ``s``.
|
| 620 |
+
Upon failure (if ``retries`` is > 0) a new ``a`` and ``s`` will be
|
| 621 |
+
supplied; the ``a`` will be ignored if F was supplied.
|
| 622 |
+
|
| 623 |
+
The sequence of numbers generated by such functions generally have a
|
| 624 |
+
a lead-up to some number and then loop around back to that number and
|
| 625 |
+
begin to repeat the sequence, e.g. 1, 2, 3, 4, 5, 3, 4, 5 -- this leader
|
| 626 |
+
and loop look a bit like the Greek letter rho, and thus the name, 'rho'.
|
| 627 |
+
|
| 628 |
+
For a given function, very different leader-loop values can be obtained
|
| 629 |
+
so it is a good idea to allow for retries:
|
| 630 |
+
|
| 631 |
+
>>> from sympy.ntheory.generate import cycle_length
|
| 632 |
+
>>> n = 16843009
|
| 633 |
+
>>> F = lambda x:(2048*pow(x, 2, n) + 32767) % n
|
| 634 |
+
>>> for s in range(5):
|
| 635 |
+
... print('loop length = %4i; leader length = %3i' % next(cycle_length(F, s)))
|
| 636 |
+
...
|
| 637 |
+
loop length = 2489; leader length = 43
|
| 638 |
+
loop length = 78; leader length = 121
|
| 639 |
+
loop length = 1482; leader length = 100
|
| 640 |
+
loop length = 1482; leader length = 286
|
| 641 |
+
loop length = 1482; leader length = 101
|
| 642 |
+
|
| 643 |
+
Here is an explicit example where there is a three element leadup to
|
| 644 |
+
a sequence of 3 numbers (11, 14, 4) that then repeat:
|
| 645 |
+
|
| 646 |
+
>>> x=2
|
| 647 |
+
>>> for i in range(9):
|
| 648 |
+
... print(x)
|
| 649 |
+
... x=(x**2+12)%17
|
| 650 |
+
...
|
| 651 |
+
2
|
| 652 |
+
16
|
| 653 |
+
13
|
| 654 |
+
11
|
| 655 |
+
14
|
| 656 |
+
4
|
| 657 |
+
11
|
| 658 |
+
14
|
| 659 |
+
4
|
| 660 |
+
>>> next(cycle_length(lambda x: (x**2+12)%17, 2))
|
| 661 |
+
(3, 3)
|
| 662 |
+
>>> list(cycle_length(lambda x: (x**2+12)%17, 2, values=True))
|
| 663 |
+
[2, 16, 13, 11, 14, 4]
|
| 664 |
+
|
| 665 |
+
Instead of checking the differences of all generated values for a gcd
|
| 666 |
+
with n, only the kth and 2*kth numbers are checked, e.g. 1st and 2nd,
|
| 667 |
+
2nd and 4th, 3rd and 6th until it has been detected that the loop has been
|
| 668 |
+
traversed. Loops may be many thousands of steps long before rho finds a
|
| 669 |
+
factor or reports failure. If ``max_steps`` is specified, the iteration
|
| 670 |
+
is cancelled with a failure after the specified number of steps.
|
| 671 |
+
|
| 672 |
+
Examples
|
| 673 |
+
========
|
| 674 |
+
|
| 675 |
+
>>> from sympy import pollard_rho
|
| 676 |
+
>>> n=16843009
|
| 677 |
+
>>> F=lambda x:(2048*pow(x,2,n) + 32767) % n
|
| 678 |
+
>>> pollard_rho(n, F=F)
|
| 679 |
+
257
|
| 680 |
+
|
| 681 |
+
Use the default setting with a bad value of ``a`` and no retries:
|
| 682 |
+
|
| 683 |
+
>>> pollard_rho(n, a=n-2, retries=0)
|
| 684 |
+
|
| 685 |
+
If retries is > 0 then perhaps the problem will correct itself when
|
| 686 |
+
new values are generated for a:
|
| 687 |
+
|
| 688 |
+
>>> pollard_rho(n, a=n-2, retries=1)
|
| 689 |
+
257
|
| 690 |
+
|
| 691 |
+
References
|
| 692 |
+
==========
|
| 693 |
+
|
| 694 |
+
.. [1] Richard Crandall & Carl Pomerance (2005), "Prime Numbers:
|
| 695 |
+
A Computational Perspective", Springer, 2nd edition, 229-231
|
| 696 |
+
|
| 697 |
+
"""
|
| 698 |
+
n = int(n)
|
| 699 |
+
if n < 5:
|
| 700 |
+
raise ValueError('pollard_rho should receive n > 4')
|
| 701 |
+
randint = _randint(seed + retries)
|
| 702 |
+
V = s
|
| 703 |
+
for i in range(retries + 1):
|
| 704 |
+
U = V
|
| 705 |
+
if not F:
|
| 706 |
+
F = lambda x: (pow(x, 2, n) + a) % n
|
| 707 |
+
j = 0
|
| 708 |
+
while 1:
|
| 709 |
+
if max_steps and (j > max_steps):
|
| 710 |
+
break
|
| 711 |
+
j += 1
|
| 712 |
+
U = F(U)
|
| 713 |
+
V = F(F(V)) # V is 2x further along than U
|
| 714 |
+
g = gcd(U - V, n)
|
| 715 |
+
if g == 1:
|
| 716 |
+
continue
|
| 717 |
+
if g == n:
|
| 718 |
+
break
|
| 719 |
+
return int(g)
|
| 720 |
+
V = randint(0, n - 1)
|
| 721 |
+
a = randint(1, n - 3) # for x**2 + a, a%n should not be 0 or -2
|
| 722 |
+
F = None
|
| 723 |
+
return None
|
| 724 |
+
|
| 725 |
+
|
| 726 |
+
def pollard_pm1(n, B=10, a=2, retries=0, seed=1234):
|
| 727 |
+
"""
|
| 728 |
+
Use Pollard's p-1 method to try to extract a nontrivial factor
|
| 729 |
+
of ``n``. Either a divisor (perhaps composite) or ``None`` is returned.
|
| 730 |
+
|
| 731 |
+
The value of ``a`` is the base that is used in the test gcd(a**M - 1, n).
|
| 732 |
+
The default is 2. If ``retries`` > 0 then if no factor is found after the
|
| 733 |
+
first attempt, a new ``a`` will be generated randomly (using the ``seed``)
|
| 734 |
+
and the process repeated.
|
| 735 |
+
|
| 736 |
+
Note: the value of M is lcm(1..B) = reduce(ilcm, range(2, B + 1)).
|
| 737 |
+
|
| 738 |
+
A search is made for factors next to even numbers having a power smoothness
|
| 739 |
+
less than ``B``. Choosing a larger B increases the likelihood of finding a
|
| 740 |
+
larger factor but takes longer. Whether a factor of n is found or not
|
| 741 |
+
depends on ``a`` and the power smoothness of the even number just less than
|
| 742 |
+
the factor p (hence the name p - 1).
|
| 743 |
+
|
| 744 |
+
Although some discussion of what constitutes a good ``a`` some
|
| 745 |
+
descriptions are hard to interpret. At the modular.math site referenced
|
| 746 |
+
below it is stated that if gcd(a**M - 1, n) = N then a**M % q**r is 1
|
| 747 |
+
for every prime power divisor of N. But consider the following:
|
| 748 |
+
|
| 749 |
+
>>> from sympy.ntheory.factor_ import smoothness_p, pollard_pm1
|
| 750 |
+
>>> n=257*1009
|
| 751 |
+
>>> smoothness_p(n)
|
| 752 |
+
(-1, [(257, (1, 2, 256)), (1009, (1, 7, 16))])
|
| 753 |
+
|
| 754 |
+
So we should (and can) find a root with B=16:
|
| 755 |
+
|
| 756 |
+
>>> pollard_pm1(n, B=16, a=3)
|
| 757 |
+
1009
|
| 758 |
+
|
| 759 |
+
If we attempt to increase B to 256 we find that it does not work:
|
| 760 |
+
|
| 761 |
+
>>> pollard_pm1(n, B=256)
|
| 762 |
+
>>>
|
| 763 |
+
|
| 764 |
+
But if the value of ``a`` is changed we find that only multiples of
|
| 765 |
+
257 work, e.g.:
|
| 766 |
+
|
| 767 |
+
>>> pollard_pm1(n, B=256, a=257)
|
| 768 |
+
1009
|
| 769 |
+
|
| 770 |
+
Checking different ``a`` values shows that all the ones that did not
|
| 771 |
+
work had a gcd value not equal to ``n`` but equal to one of the
|
| 772 |
+
factors:
|
| 773 |
+
|
| 774 |
+
>>> from sympy import ilcm, igcd, factorint, Pow
|
| 775 |
+
>>> M = 1
|
| 776 |
+
>>> for i in range(2, 256):
|
| 777 |
+
... M = ilcm(M, i)
|
| 778 |
+
...
|
| 779 |
+
>>> set([igcd(pow(a, M, n) - 1, n) for a in range(2, 256) if
|
| 780 |
+
... igcd(pow(a, M, n) - 1, n) != n])
|
| 781 |
+
{1009}
|
| 782 |
+
|
| 783 |
+
But does aM % d for every divisor of n give 1?
|
| 784 |
+
|
| 785 |
+
>>> aM = pow(255, M, n)
|
| 786 |
+
>>> [(d, aM%Pow(*d.args)) for d in factorint(n, visual=True).args]
|
| 787 |
+
[(257**1, 1), (1009**1, 1)]
|
| 788 |
+
|
| 789 |
+
No, only one of them. So perhaps the principle is that a root will
|
| 790 |
+
be found for a given value of B provided that:
|
| 791 |
+
|
| 792 |
+
1) the power smoothness of the p - 1 value next to the root
|
| 793 |
+
does not exceed B
|
| 794 |
+
2) a**M % p != 1 for any of the divisors of n.
|
| 795 |
+
|
| 796 |
+
By trying more than one ``a`` it is possible that one of them
|
| 797 |
+
will yield a factor.
|
| 798 |
+
|
| 799 |
+
Examples
|
| 800 |
+
========
|
| 801 |
+
|
| 802 |
+
With the default smoothness bound, this number cannot be cracked:
|
| 803 |
+
|
| 804 |
+
>>> from sympy.ntheory import pollard_pm1
|
| 805 |
+
>>> pollard_pm1(21477639576571)
|
| 806 |
+
|
| 807 |
+
Increasing the smoothness bound helps:
|
| 808 |
+
|
| 809 |
+
>>> pollard_pm1(21477639576571, B=2000)
|
| 810 |
+
4410317
|
| 811 |
+
|
| 812 |
+
Looking at the smoothness of the factors of this number we find:
|
| 813 |
+
|
| 814 |
+
>>> from sympy.ntheory.factor_ import smoothness_p, factorint
|
| 815 |
+
>>> print(smoothness_p(21477639576571, visual=1))
|
| 816 |
+
p**i=4410317**1 has p-1 B=1787, B-pow=1787
|
| 817 |
+
p**i=4869863**1 has p-1 B=2434931, B-pow=2434931
|
| 818 |
+
|
| 819 |
+
The B and B-pow are the same for the p - 1 factorizations of the divisors
|
| 820 |
+
because those factorizations had a very large prime factor:
|
| 821 |
+
|
| 822 |
+
>>> factorint(4410317 - 1)
|
| 823 |
+
{2: 2, 617: 1, 1787: 1}
|
| 824 |
+
>>> factorint(4869863-1)
|
| 825 |
+
{2: 1, 2434931: 1}
|
| 826 |
+
|
| 827 |
+
Note that until B reaches the B-pow value of 1787, the number is not cracked;
|
| 828 |
+
|
| 829 |
+
>>> pollard_pm1(21477639576571, B=1786)
|
| 830 |
+
>>> pollard_pm1(21477639576571, B=1787)
|
| 831 |
+
4410317
|
| 832 |
+
|
| 833 |
+
The B value has to do with the factors of the number next to the divisor,
|
| 834 |
+
not the divisors themselves. A worst case scenario is that the number next
|
| 835 |
+
to the factor p has a large prime divisisor or is a perfect power. If these
|
| 836 |
+
conditions apply then the power-smoothness will be about p/2 or p. The more
|
| 837 |
+
realistic is that there will be a large prime factor next to p requiring
|
| 838 |
+
a B value on the order of p/2. Although primes may have been searched for
|
| 839 |
+
up to this level, the p/2 is a factor of p - 1, something that we do not
|
| 840 |
+
know. The modular.math reference below states that 15% of numbers in the
|
| 841 |
+
range of 10**15 to 15**15 + 10**4 are 10**6 power smooth so a B of 10**6
|
| 842 |
+
will fail 85% of the time in that range. From 10**8 to 10**8 + 10**3 the
|
| 843 |
+
percentages are nearly reversed...but in that range the simple trial
|
| 844 |
+
division is quite fast.
|
| 845 |
+
|
| 846 |
+
References
|
| 847 |
+
==========
|
| 848 |
+
|
| 849 |
+
.. [1] Richard Crandall & Carl Pomerance (2005), "Prime Numbers:
|
| 850 |
+
A Computational Perspective", Springer, 2nd edition, 236-238
|
| 851 |
+
.. [2] https://web.archive.org/web/20150716201437/http://modular.math.washington.edu/edu/2007/spring/ent/ent-html/node81.html
|
| 852 |
+
.. [3] https://www.cs.toronto.edu/~yuvalf/Factorization.pdf
|
| 853 |
+
"""
|
| 854 |
+
|
| 855 |
+
n = int(n)
|
| 856 |
+
if n < 4 or B < 3:
|
| 857 |
+
raise ValueError('pollard_pm1 should receive n > 3 and B > 2')
|
| 858 |
+
randint = _randint(seed + B)
|
| 859 |
+
|
| 860 |
+
# computing a**lcm(1,2,3,..B) % n for B > 2
|
| 861 |
+
# it looks weird, but it's right: primes run [2, B]
|
| 862 |
+
# and the answer's not right until the loop is done.
|
| 863 |
+
for i in range(retries + 1):
|
| 864 |
+
aM = a
|
| 865 |
+
for p in sieve.primerange(2, B + 1):
|
| 866 |
+
e = int(math.log(B, p))
|
| 867 |
+
aM = pow(aM, pow(p, e), n)
|
| 868 |
+
g = gcd(aM - 1, n)
|
| 869 |
+
if 1 < g < n:
|
| 870 |
+
return int(g)
|
| 871 |
+
|
| 872 |
+
# get a new a:
|
| 873 |
+
# since the exponent, lcm(1..B), is even, if we allow 'a' to be 'n-1'
|
| 874 |
+
# then (n - 1)**even % n will be 1 which will give a g of 0 and 1 will
|
| 875 |
+
# give a zero, too, so we set the range as [2, n-2]. Some references
|
| 876 |
+
# say 'a' should be coprime to n, but either will detect factors.
|
| 877 |
+
a = randint(2, n - 2)
|
| 878 |
+
|
| 879 |
+
|
| 880 |
+
def _trial(factors, n, candidates, verbose=False):
|
| 881 |
+
"""
|
| 882 |
+
Helper function for integer factorization. Trial factors ``n`
|
| 883 |
+
against all integers given in the sequence ``candidates``
|
| 884 |
+
and updates the dict ``factors`` in-place. Returns the reduced
|
| 885 |
+
value of ``n`` and a flag indicating whether any factors were found.
|
| 886 |
+
"""
|
| 887 |
+
if verbose:
|
| 888 |
+
factors0 = list(factors.keys())
|
| 889 |
+
nfactors = len(factors)
|
| 890 |
+
for d in candidates:
|
| 891 |
+
if n % d == 0:
|
| 892 |
+
n, m = remove(n // d, d)
|
| 893 |
+
factors[d] = m + 1
|
| 894 |
+
if verbose:
|
| 895 |
+
for k in sorted(set(factors).difference(set(factors0))):
|
| 896 |
+
print(factor_msg % (k, factors[k]))
|
| 897 |
+
return int(n), len(factors) != nfactors
|
| 898 |
+
|
| 899 |
+
|
| 900 |
+
def _check_termination(factors, n, limit, use_trial, use_rho, use_pm1,
|
| 901 |
+
verbose, next_p):
|
| 902 |
+
"""
|
| 903 |
+
Helper function for integer factorization. Checks if ``n``
|
| 904 |
+
is a prime or a perfect power, and in those cases updates the factorization.
|
| 905 |
+
"""
|
| 906 |
+
if verbose:
|
| 907 |
+
print('Check for termination')
|
| 908 |
+
if n == 1:
|
| 909 |
+
if verbose:
|
| 910 |
+
print(complete_msg)
|
| 911 |
+
return True
|
| 912 |
+
if n < next_p**2 or isprime(n):
|
| 913 |
+
factors[int(n)] = 1
|
| 914 |
+
if verbose:
|
| 915 |
+
print(complete_msg)
|
| 916 |
+
return True
|
| 917 |
+
|
| 918 |
+
# since we've already been factoring there is no need to do
|
| 919 |
+
# simultaneous factoring with the power check
|
| 920 |
+
p = _perfect_power(n, next_p)
|
| 921 |
+
if not p:
|
| 922 |
+
return False
|
| 923 |
+
base, exp = p
|
| 924 |
+
if base < next_p**2 or isprime(base):
|
| 925 |
+
factors[base] = exp
|
| 926 |
+
else:
|
| 927 |
+
facs = factorint(base, limit, use_trial, use_rho, use_pm1,
|
| 928 |
+
verbose=False)
|
| 929 |
+
for b, e in facs.items():
|
| 930 |
+
if verbose:
|
| 931 |
+
print(factor_msg % (b, e))
|
| 932 |
+
# int() can be removed when https://github.com/flintlib/python-flint/issues/92 is resolved
|
| 933 |
+
factors[b] = int(exp*e)
|
| 934 |
+
if verbose:
|
| 935 |
+
print(complete_msg)
|
| 936 |
+
return True
|
| 937 |
+
|
| 938 |
+
|
| 939 |
+
trial_int_msg = "Trial division with ints [%i ... %i] and fail_max=%i"
|
| 940 |
+
trial_msg = "Trial division with primes [%i ... %i]"
|
| 941 |
+
rho_msg = "Pollard's rho with retries %i, max_steps %i and seed %i"
|
| 942 |
+
pm1_msg = "Pollard's p-1 with smoothness bound %i and seed %i"
|
| 943 |
+
ecm_msg = "Elliptic Curve with B1 bound %i, B2 bound %i, num_curves %i"
|
| 944 |
+
factor_msg = '\t%i ** %i'
|
| 945 |
+
fermat_msg = 'Close factors satisying Fermat condition found.'
|
| 946 |
+
complete_msg = 'Factorization is complete.'
|
| 947 |
+
|
| 948 |
+
|
| 949 |
+
def _factorint_small(factors, n, limit, fail_max, next_p=2):
|
| 950 |
+
"""
|
| 951 |
+
Return the value of n and either a 0 (indicating that factorization up
|
| 952 |
+
to the limit was complete) or else the next near-prime that would have
|
| 953 |
+
been tested.
|
| 954 |
+
|
| 955 |
+
Factoring stops if there are fail_max unsuccessful tests in a row.
|
| 956 |
+
|
| 957 |
+
If factors of n were found they will be in the factors dictionary as
|
| 958 |
+
{factor: multiplicity} and the returned value of n will have had those
|
| 959 |
+
factors removed. The factors dictionary is modified in-place.
|
| 960 |
+
|
| 961 |
+
"""
|
| 962 |
+
|
| 963 |
+
def done(n, d):
|
| 964 |
+
"""return n, d if the sqrt(n) was not reached yet, else
|
| 965 |
+
n, 0 indicating that factoring is done.
|
| 966 |
+
"""
|
| 967 |
+
if d*d <= n:
|
| 968 |
+
return n, d
|
| 969 |
+
return n, 0
|
| 970 |
+
|
| 971 |
+
limit2 = limit**2
|
| 972 |
+
threshold2 = min(n, limit2)
|
| 973 |
+
|
| 974 |
+
if next_p < 3:
|
| 975 |
+
if not n & 1:
|
| 976 |
+
m = bit_scan1(n)
|
| 977 |
+
factors[2] = m
|
| 978 |
+
n >>= m
|
| 979 |
+
threshold2 = min(n, limit2)
|
| 980 |
+
next_p = 3
|
| 981 |
+
if threshold2 < 9: # next_p**2 = 9
|
| 982 |
+
return done(n, next_p)
|
| 983 |
+
|
| 984 |
+
if next_p < 5:
|
| 985 |
+
if not n % 3:
|
| 986 |
+
n //= 3
|
| 987 |
+
m = 1
|
| 988 |
+
while not n % 3:
|
| 989 |
+
n //= 3
|
| 990 |
+
m += 1
|
| 991 |
+
if m == 20:
|
| 992 |
+
n, mm = remove(n, 3)
|
| 993 |
+
m += mm
|
| 994 |
+
break
|
| 995 |
+
factors[3] = m
|
| 996 |
+
threshold2 = min(n, limit2)
|
| 997 |
+
next_p = 5
|
| 998 |
+
if threshold2 < 25: # next_p**2 = 25
|
| 999 |
+
return done(n, next_p)
|
| 1000 |
+
|
| 1001 |
+
# Because of the order of checks, starting from `min_p = 6k+5`,
|
| 1002 |
+
# useless checks are caused.
|
| 1003 |
+
# We want to calculate
|
| 1004 |
+
# next_p += [-1, -2, 3, 2, 1, 0][next_p % 6]
|
| 1005 |
+
p6 = next_p % 6
|
| 1006 |
+
next_p += (-1 if p6 < 2 else 5) - p6
|
| 1007 |
+
|
| 1008 |
+
fails = 0
|
| 1009 |
+
while fails < fail_max:
|
| 1010 |
+
# next_p % 6 == 5
|
| 1011 |
+
if n % next_p:
|
| 1012 |
+
fails += 1
|
| 1013 |
+
else:
|
| 1014 |
+
n //= next_p
|
| 1015 |
+
m = 1
|
| 1016 |
+
while not n % next_p:
|
| 1017 |
+
n //= next_p
|
| 1018 |
+
m += 1
|
| 1019 |
+
if m == 20:
|
| 1020 |
+
n, mm = remove(n, next_p)
|
| 1021 |
+
m += mm
|
| 1022 |
+
break
|
| 1023 |
+
factors[next_p] = m
|
| 1024 |
+
fails = 0
|
| 1025 |
+
threshold2 = min(n, limit2)
|
| 1026 |
+
next_p += 2
|
| 1027 |
+
if threshold2 < next_p**2:
|
| 1028 |
+
return done(n, next_p)
|
| 1029 |
+
|
| 1030 |
+
# next_p % 6 == 1
|
| 1031 |
+
if n % next_p:
|
| 1032 |
+
fails += 1
|
| 1033 |
+
else:
|
| 1034 |
+
n //= next_p
|
| 1035 |
+
m = 1
|
| 1036 |
+
while not n % next_p:
|
| 1037 |
+
n //= next_p
|
| 1038 |
+
m += 1
|
| 1039 |
+
if m == 20:
|
| 1040 |
+
n, mm = remove(n, next_p)
|
| 1041 |
+
m += mm
|
| 1042 |
+
break
|
| 1043 |
+
factors[next_p] = m
|
| 1044 |
+
fails = 0
|
| 1045 |
+
threshold2 = min(n, limit2)
|
| 1046 |
+
next_p += 4
|
| 1047 |
+
if threshold2 < next_p**2:
|
| 1048 |
+
return done(n, next_p)
|
| 1049 |
+
return done(n, next_p)
|
| 1050 |
+
|
| 1051 |
+
|
| 1052 |
+
def factorint(n, limit=None, use_trial=True, use_rho=True, use_pm1=True,
|
| 1053 |
+
use_ecm=True, verbose=False, visual=None, multiple=False):
|
| 1054 |
+
r"""
|
| 1055 |
+
Given a positive integer ``n``, ``factorint(n)`` returns a dict containing
|
| 1056 |
+
the prime factors of ``n`` as keys and their respective multiplicities
|
| 1057 |
+
as values. For example:
|
| 1058 |
+
|
| 1059 |
+
>>> from sympy.ntheory import factorint
|
| 1060 |
+
>>> factorint(2000) # 2000 = (2**4) * (5**3)
|
| 1061 |
+
{2: 4, 5: 3}
|
| 1062 |
+
>>> factorint(65537) # This number is prime
|
| 1063 |
+
{65537: 1}
|
| 1064 |
+
|
| 1065 |
+
For input less than 2, factorint behaves as follows:
|
| 1066 |
+
|
| 1067 |
+
- ``factorint(1)`` returns the empty factorization, ``{}``
|
| 1068 |
+
- ``factorint(0)`` returns ``{0:1}``
|
| 1069 |
+
- ``factorint(-n)`` adds ``-1:1`` to the factors and then factors ``n``
|
| 1070 |
+
|
| 1071 |
+
Partial Factorization:
|
| 1072 |
+
|
| 1073 |
+
If ``limit`` (> 3) is specified, the search is stopped after performing
|
| 1074 |
+
trial division up to (and including) the limit (or taking a
|
| 1075 |
+
corresponding number of rho/p-1 steps). This is useful if one has
|
| 1076 |
+
a large number and only is interested in finding small factors (if
|
| 1077 |
+
any). Note that setting a limit does not prevent larger factors
|
| 1078 |
+
from being found early; it simply means that the largest factor may
|
| 1079 |
+
be composite. Since checking for perfect power is relatively cheap, it is
|
| 1080 |
+
done regardless of the limit setting.
|
| 1081 |
+
|
| 1082 |
+
This number, for example, has two small factors and a huge
|
| 1083 |
+
semi-prime factor that cannot be reduced easily:
|
| 1084 |
+
|
| 1085 |
+
>>> from sympy.ntheory import isprime
|
| 1086 |
+
>>> a = 1407633717262338957430697921446883
|
| 1087 |
+
>>> f = factorint(a, limit=10000)
|
| 1088 |
+
>>> f == {991: 1, int(202916782076162456022877024859): 1, 7: 1}
|
| 1089 |
+
True
|
| 1090 |
+
>>> isprime(max(f))
|
| 1091 |
+
False
|
| 1092 |
+
|
| 1093 |
+
This number has a small factor and a residual perfect power whose
|
| 1094 |
+
base is greater than the limit:
|
| 1095 |
+
|
| 1096 |
+
>>> factorint(3*101**7, limit=5)
|
| 1097 |
+
{3: 1, 101: 7}
|
| 1098 |
+
|
| 1099 |
+
List of Factors:
|
| 1100 |
+
|
| 1101 |
+
If ``multiple`` is set to ``True`` then a list containing the
|
| 1102 |
+
prime factors including multiplicities is returned.
|
| 1103 |
+
|
| 1104 |
+
>>> factorint(24, multiple=True)
|
| 1105 |
+
[2, 2, 2, 3]
|
| 1106 |
+
|
| 1107 |
+
Visual Factorization:
|
| 1108 |
+
|
| 1109 |
+
If ``visual`` is set to ``True``, then it will return a visual
|
| 1110 |
+
factorization of the integer. For example:
|
| 1111 |
+
|
| 1112 |
+
>>> from sympy import pprint
|
| 1113 |
+
>>> pprint(factorint(4200, visual=True))
|
| 1114 |
+
3 1 2 1
|
| 1115 |
+
2 *3 *5 *7
|
| 1116 |
+
|
| 1117 |
+
Note that this is achieved by using the evaluate=False flag in Mul
|
| 1118 |
+
and Pow. If you do other manipulations with an expression where
|
| 1119 |
+
evaluate=False, it may evaluate. Therefore, you should use the
|
| 1120 |
+
visual option only for visualization, and use the normal dictionary
|
| 1121 |
+
returned by visual=False if you want to perform operations on the
|
| 1122 |
+
factors.
|
| 1123 |
+
|
| 1124 |
+
You can easily switch between the two forms by sending them back to
|
| 1125 |
+
factorint:
|
| 1126 |
+
|
| 1127 |
+
>>> from sympy import Mul
|
| 1128 |
+
>>> regular = factorint(1764); regular
|
| 1129 |
+
{2: 2, 3: 2, 7: 2}
|
| 1130 |
+
>>> pprint(factorint(regular))
|
| 1131 |
+
2 2 2
|
| 1132 |
+
2 *3 *7
|
| 1133 |
+
|
| 1134 |
+
>>> visual = factorint(1764, visual=True); pprint(visual)
|
| 1135 |
+
2 2 2
|
| 1136 |
+
2 *3 *7
|
| 1137 |
+
>>> print(factorint(visual))
|
| 1138 |
+
{2: 2, 3: 2, 7: 2}
|
| 1139 |
+
|
| 1140 |
+
If you want to send a number to be factored in a partially factored form
|
| 1141 |
+
you can do so with a dictionary or unevaluated expression:
|
| 1142 |
+
|
| 1143 |
+
>>> factorint(factorint({4: 2, 12: 3})) # twice to toggle to dict form
|
| 1144 |
+
{2: 10, 3: 3}
|
| 1145 |
+
>>> factorint(Mul(4, 12, evaluate=False))
|
| 1146 |
+
{2: 4, 3: 1}
|
| 1147 |
+
|
| 1148 |
+
The table of the output logic is:
|
| 1149 |
+
|
| 1150 |
+
====== ====== ======= =======
|
| 1151 |
+
Visual
|
| 1152 |
+
------ ----------------------
|
| 1153 |
+
Input True False other
|
| 1154 |
+
====== ====== ======= =======
|
| 1155 |
+
dict mul dict mul
|
| 1156 |
+
n mul dict dict
|
| 1157 |
+
mul mul dict dict
|
| 1158 |
+
====== ====== ======= =======
|
| 1159 |
+
|
| 1160 |
+
Notes
|
| 1161 |
+
=====
|
| 1162 |
+
|
| 1163 |
+
Algorithm:
|
| 1164 |
+
|
| 1165 |
+
The function switches between multiple algorithms. Trial division
|
| 1166 |
+
quickly finds small factors (of the order 1-5 digits), and finds
|
| 1167 |
+
all large factors if given enough time. The Pollard rho and p-1
|
| 1168 |
+
algorithms are used to find large factors ahead of time; they
|
| 1169 |
+
will often find factors of the order of 10 digits within a few
|
| 1170 |
+
seconds:
|
| 1171 |
+
|
| 1172 |
+
>>> factors = factorint(12345678910111213141516)
|
| 1173 |
+
>>> for base, exp in sorted(factors.items()):
|
| 1174 |
+
... print('%s %s' % (base, exp))
|
| 1175 |
+
...
|
| 1176 |
+
2 2
|
| 1177 |
+
2507191691 1
|
| 1178 |
+
1231026625769 1
|
| 1179 |
+
|
| 1180 |
+
Any of these methods can optionally be disabled with the following
|
| 1181 |
+
boolean parameters:
|
| 1182 |
+
|
| 1183 |
+
- ``use_trial``: Toggle use of trial division
|
| 1184 |
+
- ``use_rho``: Toggle use of Pollard's rho method
|
| 1185 |
+
- ``use_pm1``: Toggle use of Pollard's p-1 method
|
| 1186 |
+
|
| 1187 |
+
``factorint`` also periodically checks if the remaining part is
|
| 1188 |
+
a prime number or a perfect power, and in those cases stops.
|
| 1189 |
+
|
| 1190 |
+
For unevaluated factorial, it uses Legendre's formula(theorem).
|
| 1191 |
+
|
| 1192 |
+
|
| 1193 |
+
If ``verbose`` is set to ``True``, detailed progress is printed.
|
| 1194 |
+
|
| 1195 |
+
See Also
|
| 1196 |
+
========
|
| 1197 |
+
|
| 1198 |
+
smoothness, smoothness_p, divisors
|
| 1199 |
+
|
| 1200 |
+
"""
|
| 1201 |
+
if isinstance(n, Dict):
|
| 1202 |
+
n = dict(n)
|
| 1203 |
+
if multiple:
|
| 1204 |
+
fac = factorint(n, limit=limit, use_trial=use_trial,
|
| 1205 |
+
use_rho=use_rho, use_pm1=use_pm1,
|
| 1206 |
+
verbose=verbose, visual=False, multiple=False)
|
| 1207 |
+
factorlist = sum(([p] * fac[p] if fac[p] > 0 else [S.One/p]*(-fac[p])
|
| 1208 |
+
for p in sorted(fac)), [])
|
| 1209 |
+
return factorlist
|
| 1210 |
+
|
| 1211 |
+
factordict = {}
|
| 1212 |
+
if visual and not isinstance(n, (Mul, dict)):
|
| 1213 |
+
factordict = factorint(n, limit=limit, use_trial=use_trial,
|
| 1214 |
+
use_rho=use_rho, use_pm1=use_pm1,
|
| 1215 |
+
verbose=verbose, visual=False)
|
| 1216 |
+
elif isinstance(n, Mul):
|
| 1217 |
+
factordict = {int(k): int(v) for k, v in
|
| 1218 |
+
n.as_powers_dict().items()}
|
| 1219 |
+
elif isinstance(n, dict):
|
| 1220 |
+
factordict = n
|
| 1221 |
+
if factordict and isinstance(n, (Mul, dict)):
|
| 1222 |
+
# check it
|
| 1223 |
+
for key in list(factordict.keys()):
|
| 1224 |
+
if isprime(key):
|
| 1225 |
+
continue
|
| 1226 |
+
e = factordict.pop(key)
|
| 1227 |
+
d = factorint(key, limit=limit, use_trial=use_trial, use_rho=use_rho,
|
| 1228 |
+
use_pm1=use_pm1, verbose=verbose, visual=False)
|
| 1229 |
+
for k, v in d.items():
|
| 1230 |
+
if k in factordict:
|
| 1231 |
+
factordict[k] += v*e
|
| 1232 |
+
else:
|
| 1233 |
+
factordict[k] = v*e
|
| 1234 |
+
if visual or (type(n) is dict and
|
| 1235 |
+
visual is not True and
|
| 1236 |
+
visual is not False):
|
| 1237 |
+
if factordict == {}:
|
| 1238 |
+
return S.One
|
| 1239 |
+
if -1 in factordict:
|
| 1240 |
+
factordict.pop(-1)
|
| 1241 |
+
args = [S.NegativeOne]
|
| 1242 |
+
else:
|
| 1243 |
+
args = []
|
| 1244 |
+
args.extend([Pow(*i, evaluate=False)
|
| 1245 |
+
for i in sorted(factordict.items())])
|
| 1246 |
+
return Mul(*args, evaluate=False)
|
| 1247 |
+
elif isinstance(n, (dict, Mul)):
|
| 1248 |
+
return factordict
|
| 1249 |
+
|
| 1250 |
+
assert use_trial or use_rho or use_pm1 or use_ecm
|
| 1251 |
+
|
| 1252 |
+
from sympy.functions.combinatorial.factorials import factorial
|
| 1253 |
+
if isinstance(n, factorial):
|
| 1254 |
+
x = as_int(n.args[0])
|
| 1255 |
+
if x >= 20:
|
| 1256 |
+
factors = {}
|
| 1257 |
+
m = 2 # to initialize the if condition below
|
| 1258 |
+
for p in sieve.primerange(2, x + 1):
|
| 1259 |
+
if m > 1:
|
| 1260 |
+
m, q = 0, x // p
|
| 1261 |
+
while q != 0:
|
| 1262 |
+
m += q
|
| 1263 |
+
q //= p
|
| 1264 |
+
factors[p] = m
|
| 1265 |
+
if factors and verbose:
|
| 1266 |
+
for k in sorted(factors):
|
| 1267 |
+
print(factor_msg % (k, factors[k]))
|
| 1268 |
+
if verbose:
|
| 1269 |
+
print(complete_msg)
|
| 1270 |
+
return factors
|
| 1271 |
+
else:
|
| 1272 |
+
# if n < 20!, direct computation is faster
|
| 1273 |
+
# since it uses a lookup table
|
| 1274 |
+
n = n.func(x)
|
| 1275 |
+
|
| 1276 |
+
n = as_int(n)
|
| 1277 |
+
if limit:
|
| 1278 |
+
limit = int(limit)
|
| 1279 |
+
use_ecm = False
|
| 1280 |
+
|
| 1281 |
+
# special cases
|
| 1282 |
+
if n < 0:
|
| 1283 |
+
factors = factorint(
|
| 1284 |
+
-n, limit=limit, use_trial=use_trial, use_rho=use_rho,
|
| 1285 |
+
use_pm1=use_pm1, verbose=verbose, visual=False)
|
| 1286 |
+
factors[-1] = 1
|
| 1287 |
+
return factors
|
| 1288 |
+
|
| 1289 |
+
if limit and limit < 2:
|
| 1290 |
+
if n == 1:
|
| 1291 |
+
return {}
|
| 1292 |
+
return {n: 1}
|
| 1293 |
+
elif n < 10:
|
| 1294 |
+
# doing this we are assured of getting a limit > 2
|
| 1295 |
+
# when we have to compute it later
|
| 1296 |
+
return [{0: 1}, {}, {2: 1}, {3: 1}, {2: 2}, {5: 1},
|
| 1297 |
+
{2: 1, 3: 1}, {7: 1}, {2: 3}, {3: 2}][n]
|
| 1298 |
+
|
| 1299 |
+
factors = {}
|
| 1300 |
+
|
| 1301 |
+
# do simplistic factorization
|
| 1302 |
+
if verbose:
|
| 1303 |
+
sn = str(n)
|
| 1304 |
+
if len(sn) > 50:
|
| 1305 |
+
print('Factoring %s' % sn[:5] + \
|
| 1306 |
+
'..(%i other digits)..' % (len(sn) - 10) + sn[-5:])
|
| 1307 |
+
else:
|
| 1308 |
+
print('Factoring', n)
|
| 1309 |
+
|
| 1310 |
+
# this is the preliminary factorization for small factors
|
| 1311 |
+
# We want to guarantee that there are no small prime factors,
|
| 1312 |
+
# so we run even if `use_trial` is False.
|
| 1313 |
+
small = 2**15
|
| 1314 |
+
fail_max = 600
|
| 1315 |
+
small = min(small, limit or small)
|
| 1316 |
+
if verbose:
|
| 1317 |
+
print(trial_int_msg % (2, small, fail_max))
|
| 1318 |
+
n, next_p = _factorint_small(factors, n, small, fail_max)
|
| 1319 |
+
if factors and verbose:
|
| 1320 |
+
for k in sorted(factors):
|
| 1321 |
+
print(factor_msg % (k, factors[k]))
|
| 1322 |
+
if next_p == 0:
|
| 1323 |
+
if n > 1:
|
| 1324 |
+
factors[int(n)] = 1
|
| 1325 |
+
if verbose:
|
| 1326 |
+
print(complete_msg)
|
| 1327 |
+
return factors
|
| 1328 |
+
# first check if the simplistic run didn't finish
|
| 1329 |
+
# because of the limit and check for a perfect
|
| 1330 |
+
# power before exiting
|
| 1331 |
+
if limit and next_p > limit:
|
| 1332 |
+
if verbose:
|
| 1333 |
+
print('Exceeded limit:', limit)
|
| 1334 |
+
if _check_termination(factors, n, limit, use_trial,
|
| 1335 |
+
use_rho, use_pm1, verbose, next_p):
|
| 1336 |
+
return factors
|
| 1337 |
+
if n > 1:
|
| 1338 |
+
factors[int(n)] = 1
|
| 1339 |
+
return factors
|
| 1340 |
+
if _check_termination(factors, n, limit, use_trial,
|
| 1341 |
+
use_rho, use_pm1, verbose, next_p):
|
| 1342 |
+
return factors
|
| 1343 |
+
|
| 1344 |
+
# continue with more advanced factorization methods
|
| 1345 |
+
# ...do a Fermat test since it's so easy and we need the
|
| 1346 |
+
# square root anyway. Finding 2 factors is easy if they are
|
| 1347 |
+
# "close enough." This is the big root equivalent of dividing by
|
| 1348 |
+
# 2, 3, 5.
|
| 1349 |
+
sqrt_n = isqrt(n)
|
| 1350 |
+
a = sqrt_n + 1
|
| 1351 |
+
# If `n % 4 == 1`, `a` must be odd for `a**2 - n` to be a square number.
|
| 1352 |
+
if (n % 4 == 1) ^ (a & 1):
|
| 1353 |
+
a += 1
|
| 1354 |
+
a2 = a**2
|
| 1355 |
+
b2 = a2 - n
|
| 1356 |
+
for _ in range(3):
|
| 1357 |
+
b, fermat = sqrtrem(b2)
|
| 1358 |
+
if not fermat:
|
| 1359 |
+
if verbose:
|
| 1360 |
+
print(fermat_msg)
|
| 1361 |
+
for r in [a - b, a + b]:
|
| 1362 |
+
facs = factorint(r, limit=limit, use_trial=use_trial,
|
| 1363 |
+
use_rho=use_rho, use_pm1=use_pm1,
|
| 1364 |
+
verbose=verbose)
|
| 1365 |
+
for k, v in facs.items():
|
| 1366 |
+
factors[k] = factors.get(k, 0) + v
|
| 1367 |
+
if verbose:
|
| 1368 |
+
print(complete_msg)
|
| 1369 |
+
return factors
|
| 1370 |
+
b2 += (a + 1) << 2 # equiv to (a + 2)**2 - n
|
| 1371 |
+
a += 2
|
| 1372 |
+
|
| 1373 |
+
# these are the limits for trial division which will
|
| 1374 |
+
# be attempted in parallel with pollard methods
|
| 1375 |
+
low, high = next_p, 2*next_p
|
| 1376 |
+
|
| 1377 |
+
# add 1 to make sure limit is reached in primerange calls
|
| 1378 |
+
_limit = (limit or sqrt_n) + 1
|
| 1379 |
+
iteration = 0
|
| 1380 |
+
while 1:
|
| 1381 |
+
high_ = min(high, _limit)
|
| 1382 |
+
|
| 1383 |
+
# Trial division
|
| 1384 |
+
if use_trial:
|
| 1385 |
+
if verbose:
|
| 1386 |
+
print(trial_msg % (low, high_))
|
| 1387 |
+
ps = sieve.primerange(low, high_)
|
| 1388 |
+
n, found_trial = _trial(factors, n, ps, verbose)
|
| 1389 |
+
next_p = high_
|
| 1390 |
+
if found_trial and _check_termination(factors, n, limit, use_trial,
|
| 1391 |
+
use_rho, use_pm1, verbose, next_p):
|
| 1392 |
+
return factors
|
| 1393 |
+
else:
|
| 1394 |
+
found_trial = False
|
| 1395 |
+
|
| 1396 |
+
if high > _limit:
|
| 1397 |
+
if verbose:
|
| 1398 |
+
print('Exceeded limit:', _limit)
|
| 1399 |
+
if n > 1:
|
| 1400 |
+
factors[int(n)] = 1
|
| 1401 |
+
if verbose:
|
| 1402 |
+
print(complete_msg)
|
| 1403 |
+
return factors
|
| 1404 |
+
|
| 1405 |
+
# Only used advanced methods when no small factors were found
|
| 1406 |
+
if not found_trial:
|
| 1407 |
+
# Pollard p-1
|
| 1408 |
+
if use_pm1:
|
| 1409 |
+
if verbose:
|
| 1410 |
+
print(pm1_msg % (low, high_))
|
| 1411 |
+
c = pollard_pm1(n, B=low, seed=high_)
|
| 1412 |
+
if c:
|
| 1413 |
+
if c < next_p**2 or isprime(c):
|
| 1414 |
+
ps = [c]
|
| 1415 |
+
else:
|
| 1416 |
+
ps = factorint(c, limit=limit,
|
| 1417 |
+
use_trial=use_trial,
|
| 1418 |
+
use_rho=use_rho,
|
| 1419 |
+
use_pm1=use_pm1,
|
| 1420 |
+
use_ecm=use_ecm,
|
| 1421 |
+
verbose=verbose)
|
| 1422 |
+
n, _ = _trial(factors, n, ps, verbose=False)
|
| 1423 |
+
if _check_termination(factors, n, limit, use_trial,
|
| 1424 |
+
use_rho, use_pm1, verbose, next_p):
|
| 1425 |
+
return factors
|
| 1426 |
+
|
| 1427 |
+
# Pollard rho
|
| 1428 |
+
if use_rho:
|
| 1429 |
+
if verbose:
|
| 1430 |
+
print(rho_msg % (1, low, high_))
|
| 1431 |
+
c = pollard_rho(n, retries=1, max_steps=low, seed=high_)
|
| 1432 |
+
if c:
|
| 1433 |
+
if c < next_p**2 or isprime(c):
|
| 1434 |
+
ps = [c]
|
| 1435 |
+
else:
|
| 1436 |
+
ps = factorint(c, limit=limit,
|
| 1437 |
+
use_trial=use_trial,
|
| 1438 |
+
use_rho=use_rho,
|
| 1439 |
+
use_pm1=use_pm1,
|
| 1440 |
+
use_ecm=use_ecm,
|
| 1441 |
+
verbose=verbose)
|
| 1442 |
+
n, _ = _trial(factors, n, ps, verbose=False)
|
| 1443 |
+
if _check_termination(factors, n, limit, use_trial,
|
| 1444 |
+
use_rho, use_pm1, verbose, next_p):
|
| 1445 |
+
return factors
|
| 1446 |
+
# Use subexponential algorithms if use_ecm
|
| 1447 |
+
# Use pollard algorithms for finding small factors for 3 iterations
|
| 1448 |
+
# if after small factors the number of digits of n >= 25 then use ecm
|
| 1449 |
+
iteration += 1
|
| 1450 |
+
if use_ecm and iteration >= 3 and num_digits(n) >= 24:
|
| 1451 |
+
break
|
| 1452 |
+
low, high = high, high*2
|
| 1453 |
+
|
| 1454 |
+
B1 = 10000
|
| 1455 |
+
B2 = 100*B1
|
| 1456 |
+
num_curves = 50
|
| 1457 |
+
while(1):
|
| 1458 |
+
if verbose:
|
| 1459 |
+
print(ecm_msg % (B1, B2, num_curves))
|
| 1460 |
+
factor = _ecm_one_factor(n, B1, B2, num_curves, seed=B1)
|
| 1461 |
+
if factor:
|
| 1462 |
+
if factor < next_p**2 or isprime(factor):
|
| 1463 |
+
ps = [factor]
|
| 1464 |
+
else:
|
| 1465 |
+
ps = factorint(factor, limit=limit,
|
| 1466 |
+
use_trial=use_trial,
|
| 1467 |
+
use_rho=use_rho,
|
| 1468 |
+
use_pm1=use_pm1,
|
| 1469 |
+
use_ecm=use_ecm,
|
| 1470 |
+
verbose=verbose)
|
| 1471 |
+
n, _ = _trial(factors, n, ps, verbose=False)
|
| 1472 |
+
if _check_termination(factors, n, limit, use_trial,
|
| 1473 |
+
use_rho, use_pm1, verbose, next_p):
|
| 1474 |
+
return factors
|
| 1475 |
+
B1 *= 5
|
| 1476 |
+
B2 = 100*B1
|
| 1477 |
+
num_curves *= 4
|
| 1478 |
+
|
| 1479 |
+
|
| 1480 |
+
def factorrat(rat, limit=None, use_trial=True, use_rho=True, use_pm1=True,
|
| 1481 |
+
verbose=False, visual=None, multiple=False):
|
| 1482 |
+
r"""
|
| 1483 |
+
Given a Rational ``r``, ``factorrat(r)`` returns a dict containing
|
| 1484 |
+
the prime factors of ``r`` as keys and their respective multiplicities
|
| 1485 |
+
as values. For example:
|
| 1486 |
+
|
| 1487 |
+
>>> from sympy import factorrat, S
|
| 1488 |
+
>>> factorrat(S(8)/9) # 8/9 = (2**3) * (3**-2)
|
| 1489 |
+
{2: 3, 3: -2}
|
| 1490 |
+
>>> factorrat(S(-1)/987) # -1/789 = -1 * (3**-1) * (7**-1) * (47**-1)
|
| 1491 |
+
{-1: 1, 3: -1, 7: -1, 47: -1}
|
| 1492 |
+
|
| 1493 |
+
Please see the docstring for ``factorint`` for detailed explanations
|
| 1494 |
+
and examples of the following keywords:
|
| 1495 |
+
|
| 1496 |
+
- ``limit``: Integer limit up to which trial division is done
|
| 1497 |
+
- ``use_trial``: Toggle use of trial division
|
| 1498 |
+
- ``use_rho``: Toggle use of Pollard's rho method
|
| 1499 |
+
- ``use_pm1``: Toggle use of Pollard's p-1 method
|
| 1500 |
+
- ``verbose``: Toggle detailed printing of progress
|
| 1501 |
+
- ``multiple``: Toggle returning a list of factors or dict
|
| 1502 |
+
- ``visual``: Toggle product form of output
|
| 1503 |
+
"""
|
| 1504 |
+
if multiple:
|
| 1505 |
+
fac = factorrat(rat, limit=limit, use_trial=use_trial,
|
| 1506 |
+
use_rho=use_rho, use_pm1=use_pm1,
|
| 1507 |
+
verbose=verbose, visual=False, multiple=False)
|
| 1508 |
+
factorlist = sum(([p] * fac[p] if fac[p] > 0 else [S.One/p]*(-fac[p])
|
| 1509 |
+
for p, _ in sorted(fac.items(),
|
| 1510 |
+
key=lambda elem: elem[0]
|
| 1511 |
+
if elem[1] > 0
|
| 1512 |
+
else 1/elem[0])), [])
|
| 1513 |
+
return factorlist
|
| 1514 |
+
|
| 1515 |
+
f = factorint(rat.p, limit=limit, use_trial=use_trial,
|
| 1516 |
+
use_rho=use_rho, use_pm1=use_pm1,
|
| 1517 |
+
verbose=verbose).copy()
|
| 1518 |
+
f = defaultdict(int, f)
|
| 1519 |
+
for p, e in factorint(rat.q, limit=limit,
|
| 1520 |
+
use_trial=use_trial,
|
| 1521 |
+
use_rho=use_rho,
|
| 1522 |
+
use_pm1=use_pm1,
|
| 1523 |
+
verbose=verbose).items():
|
| 1524 |
+
f[p] += -e
|
| 1525 |
+
|
| 1526 |
+
if len(f) > 1 and 1 in f:
|
| 1527 |
+
del f[1]
|
| 1528 |
+
if not visual:
|
| 1529 |
+
return dict(f)
|
| 1530 |
+
else:
|
| 1531 |
+
if -1 in f:
|
| 1532 |
+
f.pop(-1)
|
| 1533 |
+
args = [S.NegativeOne]
|
| 1534 |
+
else:
|
| 1535 |
+
args = []
|
| 1536 |
+
args.extend([Pow(*i, evaluate=False)
|
| 1537 |
+
for i in sorted(f.items())])
|
| 1538 |
+
return Mul(*args, evaluate=False)
|
| 1539 |
+
|
| 1540 |
+
|
| 1541 |
+
def primefactors(n, limit=None, verbose=False, **kwargs):
|
| 1542 |
+
"""Return a sorted list of n's prime factors, ignoring multiplicity
|
| 1543 |
+
and any composite factor that remains if the limit was set too low
|
| 1544 |
+
for complete factorization. Unlike factorint(), primefactors() does
|
| 1545 |
+
not return -1 or 0.
|
| 1546 |
+
|
| 1547 |
+
Parameters
|
| 1548 |
+
==========
|
| 1549 |
+
|
| 1550 |
+
n : integer
|
| 1551 |
+
limit, verbose, **kwargs :
|
| 1552 |
+
Additional keyword arguments to be passed to ``factorint``.
|
| 1553 |
+
Since ``kwargs`` is new in version 1.13,
|
| 1554 |
+
``limit`` and ``verbose`` are retained for compatibility purposes.
|
| 1555 |
+
|
| 1556 |
+
Returns
|
| 1557 |
+
=======
|
| 1558 |
+
|
| 1559 |
+
list(int) : List of prime numbers dividing ``n``
|
| 1560 |
+
|
| 1561 |
+
Examples
|
| 1562 |
+
========
|
| 1563 |
+
|
| 1564 |
+
>>> from sympy.ntheory import primefactors, factorint, isprime
|
| 1565 |
+
>>> primefactors(6)
|
| 1566 |
+
[2, 3]
|
| 1567 |
+
>>> primefactors(-5)
|
| 1568 |
+
[5]
|
| 1569 |
+
|
| 1570 |
+
>>> sorted(factorint(123456).items())
|
| 1571 |
+
[(2, 6), (3, 1), (643, 1)]
|
| 1572 |
+
>>> primefactors(123456)
|
| 1573 |
+
[2, 3, 643]
|
| 1574 |
+
|
| 1575 |
+
>>> sorted(factorint(10000000001, limit=200).items())
|
| 1576 |
+
[(101, 1), (99009901, 1)]
|
| 1577 |
+
>>> isprime(99009901)
|
| 1578 |
+
False
|
| 1579 |
+
>>> primefactors(10000000001, limit=300)
|
| 1580 |
+
[101]
|
| 1581 |
+
|
| 1582 |
+
See Also
|
| 1583 |
+
========
|
| 1584 |
+
|
| 1585 |
+
factorint, divisors
|
| 1586 |
+
|
| 1587 |
+
"""
|
| 1588 |
+
n = int(n)
|
| 1589 |
+
kwargs.update({"visual": None, "multiple": False,
|
| 1590 |
+
"limit": limit, "verbose": verbose})
|
| 1591 |
+
factors = sorted(factorint(n=n, **kwargs).keys())
|
| 1592 |
+
# We want to calculate
|
| 1593 |
+
# s = [f for f in factors if isprime(f)]
|
| 1594 |
+
s = [f for f in factors[:-1:] if f not in [-1, 0, 1]]
|
| 1595 |
+
if factors and isprime(factors[-1]):
|
| 1596 |
+
s += [factors[-1]]
|
| 1597 |
+
return s
|
| 1598 |
+
|
| 1599 |
+
|
| 1600 |
+
def _divisors(n, proper=False):
|
| 1601 |
+
"""Helper function for divisors which generates the divisors.
|
| 1602 |
+
|
| 1603 |
+
Parameters
|
| 1604 |
+
==========
|
| 1605 |
+
|
| 1606 |
+
n : int
|
| 1607 |
+
a nonnegative integer
|
| 1608 |
+
proper: bool
|
| 1609 |
+
If `True`, returns the generator that outputs only the proper divisor (i.e., excluding n).
|
| 1610 |
+
|
| 1611 |
+
"""
|
| 1612 |
+
if n <= 1:
|
| 1613 |
+
if not proper and n:
|
| 1614 |
+
yield 1
|
| 1615 |
+
return
|
| 1616 |
+
|
| 1617 |
+
factordict = factorint(n)
|
| 1618 |
+
ps = sorted(factordict.keys())
|
| 1619 |
+
|
| 1620 |
+
def rec_gen(n=0):
|
| 1621 |
+
if n == len(ps):
|
| 1622 |
+
yield 1
|
| 1623 |
+
else:
|
| 1624 |
+
pows = [1]
|
| 1625 |
+
for _ in range(factordict[ps[n]]):
|
| 1626 |
+
pows.append(pows[-1] * ps[n])
|
| 1627 |
+
yield from (p * q for q in rec_gen(n + 1) for p in pows)
|
| 1628 |
+
|
| 1629 |
+
if proper:
|
| 1630 |
+
yield from (p for p in rec_gen() if p != n)
|
| 1631 |
+
else:
|
| 1632 |
+
yield from rec_gen()
|
| 1633 |
+
|
| 1634 |
+
|
| 1635 |
+
def divisors(n, generator=False, proper=False):
|
| 1636 |
+
r"""
|
| 1637 |
+
Return all divisors of n sorted from 1..n by default.
|
| 1638 |
+
If generator is ``True`` an unordered generator is returned.
|
| 1639 |
+
|
| 1640 |
+
The number of divisors of n can be quite large if there are many
|
| 1641 |
+
prime factors (counting repeated factors). If only the number of
|
| 1642 |
+
factors is desired use divisor_count(n).
|
| 1643 |
+
|
| 1644 |
+
Examples
|
| 1645 |
+
========
|
| 1646 |
+
|
| 1647 |
+
>>> from sympy import divisors, divisor_count
|
| 1648 |
+
>>> divisors(24)
|
| 1649 |
+
[1, 2, 3, 4, 6, 8, 12, 24]
|
| 1650 |
+
>>> divisor_count(24)
|
| 1651 |
+
8
|
| 1652 |
+
|
| 1653 |
+
>>> list(divisors(120, generator=True))
|
| 1654 |
+
[1, 2, 4, 8, 3, 6, 12, 24, 5, 10, 20, 40, 15, 30, 60, 120]
|
| 1655 |
+
|
| 1656 |
+
Notes
|
| 1657 |
+
=====
|
| 1658 |
+
|
| 1659 |
+
This is a slightly modified version of Tim Peters referenced at:
|
| 1660 |
+
https://stackoverflow.com/questions/1010381/python-factorization
|
| 1661 |
+
|
| 1662 |
+
See Also
|
| 1663 |
+
========
|
| 1664 |
+
|
| 1665 |
+
primefactors, factorint, divisor_count
|
| 1666 |
+
"""
|
| 1667 |
+
rv = _divisors(as_int(abs(n)), proper)
|
| 1668 |
+
return rv if generator else sorted(rv)
|
| 1669 |
+
|
| 1670 |
+
|
| 1671 |
+
def divisor_count(n, modulus=1, proper=False):
|
| 1672 |
+
"""
|
| 1673 |
+
Return the number of divisors of ``n``. If ``modulus`` is not 1 then only
|
| 1674 |
+
those that are divisible by ``modulus`` are counted. If ``proper`` is True
|
| 1675 |
+
then the divisor of ``n`` will not be counted.
|
| 1676 |
+
|
| 1677 |
+
Examples
|
| 1678 |
+
========
|
| 1679 |
+
|
| 1680 |
+
>>> from sympy import divisor_count
|
| 1681 |
+
>>> divisor_count(6)
|
| 1682 |
+
4
|
| 1683 |
+
>>> divisor_count(6, 2)
|
| 1684 |
+
2
|
| 1685 |
+
>>> divisor_count(6, proper=True)
|
| 1686 |
+
3
|
| 1687 |
+
|
| 1688 |
+
See Also
|
| 1689 |
+
========
|
| 1690 |
+
|
| 1691 |
+
factorint, divisors, totient, proper_divisor_count
|
| 1692 |
+
|
| 1693 |
+
"""
|
| 1694 |
+
|
| 1695 |
+
if not modulus:
|
| 1696 |
+
return 0
|
| 1697 |
+
elif modulus != 1:
|
| 1698 |
+
n, r = divmod(n, modulus)
|
| 1699 |
+
if r:
|
| 1700 |
+
return 0
|
| 1701 |
+
if n == 0:
|
| 1702 |
+
return 0
|
| 1703 |
+
n = Mul(*[v + 1 for k, v in factorint(n).items() if k > 1])
|
| 1704 |
+
if n and proper:
|
| 1705 |
+
n -= 1
|
| 1706 |
+
return n
|
| 1707 |
+
|
| 1708 |
+
|
| 1709 |
+
def proper_divisors(n, generator=False):
|
| 1710 |
+
"""
|
| 1711 |
+
Return all divisors of n except n, sorted by default.
|
| 1712 |
+
If generator is ``True`` an unordered generator is returned.
|
| 1713 |
+
|
| 1714 |
+
Examples
|
| 1715 |
+
========
|
| 1716 |
+
|
| 1717 |
+
>>> from sympy import proper_divisors, proper_divisor_count
|
| 1718 |
+
>>> proper_divisors(24)
|
| 1719 |
+
[1, 2, 3, 4, 6, 8, 12]
|
| 1720 |
+
>>> proper_divisor_count(24)
|
| 1721 |
+
7
|
| 1722 |
+
>>> list(proper_divisors(120, generator=True))
|
| 1723 |
+
[1, 2, 4, 8, 3, 6, 12, 24, 5, 10, 20, 40, 15, 30, 60]
|
| 1724 |
+
|
| 1725 |
+
See Also
|
| 1726 |
+
========
|
| 1727 |
+
|
| 1728 |
+
factorint, divisors, proper_divisor_count
|
| 1729 |
+
|
| 1730 |
+
"""
|
| 1731 |
+
return divisors(n, generator=generator, proper=True)
|
| 1732 |
+
|
| 1733 |
+
|
| 1734 |
+
def proper_divisor_count(n, modulus=1):
|
| 1735 |
+
"""
|
| 1736 |
+
Return the number of proper divisors of ``n``.
|
| 1737 |
+
|
| 1738 |
+
Examples
|
| 1739 |
+
========
|
| 1740 |
+
|
| 1741 |
+
>>> from sympy import proper_divisor_count
|
| 1742 |
+
>>> proper_divisor_count(6)
|
| 1743 |
+
3
|
| 1744 |
+
>>> proper_divisor_count(6, modulus=2)
|
| 1745 |
+
1
|
| 1746 |
+
|
| 1747 |
+
See Also
|
| 1748 |
+
========
|
| 1749 |
+
|
| 1750 |
+
divisors, proper_divisors, divisor_count
|
| 1751 |
+
|
| 1752 |
+
"""
|
| 1753 |
+
return divisor_count(n, modulus=modulus, proper=True)
|
| 1754 |
+
|
| 1755 |
+
|
| 1756 |
+
def _udivisors(n):
|
| 1757 |
+
"""Helper function for udivisors which generates the unitary divisors.
|
| 1758 |
+
|
| 1759 |
+
Parameters
|
| 1760 |
+
==========
|
| 1761 |
+
|
| 1762 |
+
n : int
|
| 1763 |
+
a nonnegative integer
|
| 1764 |
+
|
| 1765 |
+
"""
|
| 1766 |
+
if n <= 1:
|
| 1767 |
+
if n == 1:
|
| 1768 |
+
yield 1
|
| 1769 |
+
return
|
| 1770 |
+
|
| 1771 |
+
factorpows = [p**e for p, e in factorint(n).items()]
|
| 1772 |
+
# We want to calculate
|
| 1773 |
+
# yield from (math.prod(s) for s in powersets(factorpows))
|
| 1774 |
+
for i in range(2**len(factorpows)):
|
| 1775 |
+
d = 1
|
| 1776 |
+
for k in range(i.bit_length()):
|
| 1777 |
+
if i & 1:
|
| 1778 |
+
d *= factorpows[k]
|
| 1779 |
+
i >>= 1
|
| 1780 |
+
yield d
|
| 1781 |
+
|
| 1782 |
+
|
| 1783 |
+
def udivisors(n, generator=False):
|
| 1784 |
+
r"""
|
| 1785 |
+
Return all unitary divisors of n sorted from 1..n by default.
|
| 1786 |
+
If generator is ``True`` an unordered generator is returned.
|
| 1787 |
+
|
| 1788 |
+
The number of unitary divisors of n can be quite large if there are many
|
| 1789 |
+
prime factors. If only the number of unitary divisors is desired use
|
| 1790 |
+
udivisor_count(n).
|
| 1791 |
+
|
| 1792 |
+
Examples
|
| 1793 |
+
========
|
| 1794 |
+
|
| 1795 |
+
>>> from sympy.ntheory.factor_ import udivisors, udivisor_count
|
| 1796 |
+
>>> udivisors(15)
|
| 1797 |
+
[1, 3, 5, 15]
|
| 1798 |
+
>>> udivisor_count(15)
|
| 1799 |
+
4
|
| 1800 |
+
|
| 1801 |
+
>>> sorted(udivisors(120, generator=True))
|
| 1802 |
+
[1, 3, 5, 8, 15, 24, 40, 120]
|
| 1803 |
+
|
| 1804 |
+
See Also
|
| 1805 |
+
========
|
| 1806 |
+
|
| 1807 |
+
primefactors, factorint, divisors, divisor_count, udivisor_count
|
| 1808 |
+
|
| 1809 |
+
References
|
| 1810 |
+
==========
|
| 1811 |
+
|
| 1812 |
+
.. [1] https://en.wikipedia.org/wiki/Unitary_divisor
|
| 1813 |
+
.. [2] https://mathworld.wolfram.com/UnitaryDivisor.html
|
| 1814 |
+
|
| 1815 |
+
"""
|
| 1816 |
+
rv = _udivisors(as_int(abs(n)))
|
| 1817 |
+
return rv if generator else sorted(rv)
|
| 1818 |
+
|
| 1819 |
+
|
| 1820 |
+
def udivisor_count(n):
|
| 1821 |
+
"""
|
| 1822 |
+
Return the number of unitary divisors of ``n``.
|
| 1823 |
+
|
| 1824 |
+
Parameters
|
| 1825 |
+
==========
|
| 1826 |
+
|
| 1827 |
+
n : integer
|
| 1828 |
+
|
| 1829 |
+
Examples
|
| 1830 |
+
========
|
| 1831 |
+
|
| 1832 |
+
>>> from sympy.ntheory.factor_ import udivisor_count
|
| 1833 |
+
>>> udivisor_count(120)
|
| 1834 |
+
8
|
| 1835 |
+
|
| 1836 |
+
See Also
|
| 1837 |
+
========
|
| 1838 |
+
|
| 1839 |
+
factorint, divisors, udivisors, divisor_count, totient
|
| 1840 |
+
|
| 1841 |
+
References
|
| 1842 |
+
==========
|
| 1843 |
+
|
| 1844 |
+
.. [1] https://mathworld.wolfram.com/UnitaryDivisorFunction.html
|
| 1845 |
+
|
| 1846 |
+
"""
|
| 1847 |
+
|
| 1848 |
+
if n == 0:
|
| 1849 |
+
return 0
|
| 1850 |
+
return 2**len([p for p in factorint(n) if p > 1])
|
| 1851 |
+
|
| 1852 |
+
|
| 1853 |
+
def _antidivisors(n):
|
| 1854 |
+
"""Helper function for antidivisors which generates the antidivisors.
|
| 1855 |
+
|
| 1856 |
+
Parameters
|
| 1857 |
+
==========
|
| 1858 |
+
|
| 1859 |
+
n : int
|
| 1860 |
+
a nonnegative integer
|
| 1861 |
+
|
| 1862 |
+
"""
|
| 1863 |
+
if n <= 2:
|
| 1864 |
+
return
|
| 1865 |
+
for d in _divisors(n):
|
| 1866 |
+
y = 2*d
|
| 1867 |
+
if n > y and n % y:
|
| 1868 |
+
yield y
|
| 1869 |
+
for d in _divisors(2*n-1):
|
| 1870 |
+
if n > d >= 2 and n % d:
|
| 1871 |
+
yield d
|
| 1872 |
+
for d in _divisors(2*n+1):
|
| 1873 |
+
if n > d >= 2 and n % d:
|
| 1874 |
+
yield d
|
| 1875 |
+
|
| 1876 |
+
|
| 1877 |
+
def antidivisors(n, generator=False):
|
| 1878 |
+
r"""
|
| 1879 |
+
Return all antidivisors of n sorted from 1..n by default.
|
| 1880 |
+
|
| 1881 |
+
Antidivisors [1]_ of n are numbers that do not divide n by the largest
|
| 1882 |
+
possible margin. If generator is True an unordered generator is returned.
|
| 1883 |
+
|
| 1884 |
+
Examples
|
| 1885 |
+
========
|
| 1886 |
+
|
| 1887 |
+
>>> from sympy.ntheory.factor_ import antidivisors
|
| 1888 |
+
>>> antidivisors(24)
|
| 1889 |
+
[7, 16]
|
| 1890 |
+
|
| 1891 |
+
>>> sorted(antidivisors(128, generator=True))
|
| 1892 |
+
[3, 5, 15, 17, 51, 85]
|
| 1893 |
+
|
| 1894 |
+
See Also
|
| 1895 |
+
========
|
| 1896 |
+
|
| 1897 |
+
primefactors, factorint, divisors, divisor_count, antidivisor_count
|
| 1898 |
+
|
| 1899 |
+
References
|
| 1900 |
+
==========
|
| 1901 |
+
|
| 1902 |
+
.. [1] definition is described in https://oeis.org/A066272/a066272a.html
|
| 1903 |
+
|
| 1904 |
+
"""
|
| 1905 |
+
rv = _antidivisors(as_int(abs(n)))
|
| 1906 |
+
return rv if generator else sorted(rv)
|
| 1907 |
+
|
| 1908 |
+
|
| 1909 |
+
def antidivisor_count(n):
|
| 1910 |
+
"""
|
| 1911 |
+
Return the number of antidivisors [1]_ of ``n``.
|
| 1912 |
+
|
| 1913 |
+
Parameters
|
| 1914 |
+
==========
|
| 1915 |
+
|
| 1916 |
+
n : integer
|
| 1917 |
+
|
| 1918 |
+
Examples
|
| 1919 |
+
========
|
| 1920 |
+
|
| 1921 |
+
>>> from sympy.ntheory.factor_ import antidivisor_count
|
| 1922 |
+
>>> antidivisor_count(13)
|
| 1923 |
+
4
|
| 1924 |
+
>>> antidivisor_count(27)
|
| 1925 |
+
5
|
| 1926 |
+
|
| 1927 |
+
See Also
|
| 1928 |
+
========
|
| 1929 |
+
|
| 1930 |
+
factorint, divisors, antidivisors, divisor_count, totient
|
| 1931 |
+
|
| 1932 |
+
References
|
| 1933 |
+
==========
|
| 1934 |
+
|
| 1935 |
+
.. [1] formula from https://oeis.org/A066272
|
| 1936 |
+
|
| 1937 |
+
"""
|
| 1938 |
+
|
| 1939 |
+
n = as_int(abs(n))
|
| 1940 |
+
if n <= 2:
|
| 1941 |
+
return 0
|
| 1942 |
+
return divisor_count(2*n - 1) + divisor_count(2*n + 1) + \
|
| 1943 |
+
divisor_count(n) - divisor_count(n, 2) - 5
|
| 1944 |
+
|
| 1945 |
+
@deprecated("""\
|
| 1946 |
+
The `sympy.ntheory.factor_.totient` has been moved to `sympy.functions.combinatorial.numbers.totient`.""",
|
| 1947 |
+
deprecated_since_version="1.13",
|
| 1948 |
+
active_deprecations_target='deprecated-ntheory-symbolic-functions')
|
| 1949 |
+
def totient(n):
|
| 1950 |
+
r"""
|
| 1951 |
+
Calculate the Euler totient function phi(n)
|
| 1952 |
+
|
| 1953 |
+
.. deprecated:: 1.13
|
| 1954 |
+
|
| 1955 |
+
The ``totient`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.totient`
|
| 1956 |
+
instead. See its documentation for more information. See
|
| 1957 |
+
:ref:`deprecated-ntheory-symbolic-functions` for details.
|
| 1958 |
+
|
| 1959 |
+
``totient(n)`` or `\phi(n)` is the number of positive integers `\leq` n
|
| 1960 |
+
that are relatively prime to n.
|
| 1961 |
+
|
| 1962 |
+
Parameters
|
| 1963 |
+
==========
|
| 1964 |
+
|
| 1965 |
+
n : integer
|
| 1966 |
+
|
| 1967 |
+
Examples
|
| 1968 |
+
========
|
| 1969 |
+
|
| 1970 |
+
>>> from sympy.functions.combinatorial.numbers import totient
|
| 1971 |
+
>>> totient(1)
|
| 1972 |
+
1
|
| 1973 |
+
>>> totient(25)
|
| 1974 |
+
20
|
| 1975 |
+
>>> totient(45) == totient(5)*totient(9)
|
| 1976 |
+
True
|
| 1977 |
+
|
| 1978 |
+
See Also
|
| 1979 |
+
========
|
| 1980 |
+
|
| 1981 |
+
divisor_count
|
| 1982 |
+
|
| 1983 |
+
References
|
| 1984 |
+
==========
|
| 1985 |
+
|
| 1986 |
+
.. [1] https://en.wikipedia.org/wiki/Euler%27s_totient_function
|
| 1987 |
+
.. [2] https://mathworld.wolfram.com/TotientFunction.html
|
| 1988 |
+
|
| 1989 |
+
"""
|
| 1990 |
+
from sympy.functions.combinatorial.numbers import totient as _totient
|
| 1991 |
+
return _totient(n)
|
| 1992 |
+
|
| 1993 |
+
|
| 1994 |
+
@deprecated("""\
|
| 1995 |
+
The `sympy.ntheory.factor_.reduced_totient` has been moved to `sympy.functions.combinatorial.numbers.reduced_totient`.""",
|
| 1996 |
+
deprecated_since_version="1.13",
|
| 1997 |
+
active_deprecations_target='deprecated-ntheory-symbolic-functions')
|
| 1998 |
+
def reduced_totient(n):
|
| 1999 |
+
r"""
|
| 2000 |
+
Calculate the Carmichael reduced totient function lambda(n)
|
| 2001 |
+
|
| 2002 |
+
.. deprecated:: 1.13
|
| 2003 |
+
|
| 2004 |
+
The ``reduced_totient`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.reduced_totient`
|
| 2005 |
+
instead. See its documentation for more information. See
|
| 2006 |
+
:ref:`deprecated-ntheory-symbolic-functions` for details.
|
| 2007 |
+
|
| 2008 |
+
``reduced_totient(n)`` or `\lambda(n)` is the smallest m > 0 such that
|
| 2009 |
+
`k^m \equiv 1 \mod n` for all k relatively prime to n.
|
| 2010 |
+
|
| 2011 |
+
Examples
|
| 2012 |
+
========
|
| 2013 |
+
|
| 2014 |
+
>>> from sympy.functions.combinatorial.numbers import reduced_totient
|
| 2015 |
+
>>> reduced_totient(1)
|
| 2016 |
+
1
|
| 2017 |
+
>>> reduced_totient(8)
|
| 2018 |
+
2
|
| 2019 |
+
>>> reduced_totient(30)
|
| 2020 |
+
4
|
| 2021 |
+
|
| 2022 |
+
See Also
|
| 2023 |
+
========
|
| 2024 |
+
|
| 2025 |
+
totient
|
| 2026 |
+
|
| 2027 |
+
References
|
| 2028 |
+
==========
|
| 2029 |
+
|
| 2030 |
+
.. [1] https://en.wikipedia.org/wiki/Carmichael_function
|
| 2031 |
+
.. [2] https://mathworld.wolfram.com/CarmichaelFunction.html
|
| 2032 |
+
|
| 2033 |
+
"""
|
| 2034 |
+
from sympy.functions.combinatorial.numbers import reduced_totient as _reduced_totient
|
| 2035 |
+
return _reduced_totient(n)
|
| 2036 |
+
|
| 2037 |
+
|
| 2038 |
+
@deprecated("""\
|
| 2039 |
+
The `sympy.ntheory.factor_.divisor_sigma` has been moved to `sympy.functions.combinatorial.numbers.divisor_sigma`.""",
|
| 2040 |
+
deprecated_since_version="1.13",
|
| 2041 |
+
active_deprecations_target='deprecated-ntheory-symbolic-functions')
|
| 2042 |
+
def divisor_sigma(n, k=1):
|
| 2043 |
+
r"""
|
| 2044 |
+
Calculate the divisor function `\sigma_k(n)` for positive integer n
|
| 2045 |
+
|
| 2046 |
+
.. deprecated:: 1.13
|
| 2047 |
+
|
| 2048 |
+
The ``divisor_sigma`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.divisor_sigma`
|
| 2049 |
+
instead. See its documentation for more information. See
|
| 2050 |
+
:ref:`deprecated-ntheory-symbolic-functions` for details.
|
| 2051 |
+
|
| 2052 |
+
``divisor_sigma(n, k)`` is equal to ``sum([x**k for x in divisors(n)])``
|
| 2053 |
+
|
| 2054 |
+
If n's prime factorization is:
|
| 2055 |
+
|
| 2056 |
+
.. math ::
|
| 2057 |
+
n = \prod_{i=1}^\omega p_i^{m_i},
|
| 2058 |
+
|
| 2059 |
+
then
|
| 2060 |
+
|
| 2061 |
+
.. math ::
|
| 2062 |
+
\sigma_k(n) = \prod_{i=1}^\omega (1+p_i^k+p_i^{2k}+\cdots
|
| 2063 |
+
+ p_i^{m_ik}).
|
| 2064 |
+
|
| 2065 |
+
Parameters
|
| 2066 |
+
==========
|
| 2067 |
+
|
| 2068 |
+
n : integer
|
| 2069 |
+
|
| 2070 |
+
k : integer, optional
|
| 2071 |
+
power of divisors in the sum
|
| 2072 |
+
|
| 2073 |
+
for k = 0, 1:
|
| 2074 |
+
``divisor_sigma(n, 0)`` is equal to ``divisor_count(n)``
|
| 2075 |
+
``divisor_sigma(n, 1)`` is equal to ``sum(divisors(n))``
|
| 2076 |
+
|
| 2077 |
+
Default for k is 1.
|
| 2078 |
+
|
| 2079 |
+
Examples
|
| 2080 |
+
========
|
| 2081 |
+
|
| 2082 |
+
>>> from sympy.functions.combinatorial.numbers import divisor_sigma
|
| 2083 |
+
>>> divisor_sigma(18, 0)
|
| 2084 |
+
6
|
| 2085 |
+
>>> divisor_sigma(39, 1)
|
| 2086 |
+
56
|
| 2087 |
+
>>> divisor_sigma(12, 2)
|
| 2088 |
+
210
|
| 2089 |
+
>>> divisor_sigma(37)
|
| 2090 |
+
38
|
| 2091 |
+
|
| 2092 |
+
See Also
|
| 2093 |
+
========
|
| 2094 |
+
|
| 2095 |
+
divisor_count, totient, divisors, factorint
|
| 2096 |
+
|
| 2097 |
+
References
|
| 2098 |
+
==========
|
| 2099 |
+
|
| 2100 |
+
.. [1] https://en.wikipedia.org/wiki/Divisor_function
|
| 2101 |
+
|
| 2102 |
+
"""
|
| 2103 |
+
from sympy.functions.combinatorial.numbers import divisor_sigma as func_divisor_sigma
|
| 2104 |
+
return func_divisor_sigma(n, k)
|
| 2105 |
+
|
| 2106 |
+
|
| 2107 |
+
def _divisor_sigma(n:int, k:int=1) -> int:
|
| 2108 |
+
r""" Calculate the divisor function `\sigma_k(n)` for positive integer n
|
| 2109 |
+
|
| 2110 |
+
Parameters
|
| 2111 |
+
==========
|
| 2112 |
+
|
| 2113 |
+
n : int
|
| 2114 |
+
positive integer
|
| 2115 |
+
k : int
|
| 2116 |
+
nonnegative integer
|
| 2117 |
+
|
| 2118 |
+
See Also
|
| 2119 |
+
========
|
| 2120 |
+
|
| 2121 |
+
sympy.functions.combinatorial.numbers.divisor_sigma
|
| 2122 |
+
|
| 2123 |
+
"""
|
| 2124 |
+
if k == 0:
|
| 2125 |
+
return math.prod(e + 1 for e in factorint(n).values())
|
| 2126 |
+
return math.prod((p**(k*(e + 1)) - 1)//(p**k - 1) for p, e in factorint(n).items())
|
| 2127 |
+
|
| 2128 |
+
|
| 2129 |
+
def core(n, t=2):
|
| 2130 |
+
r"""
|
| 2131 |
+
Calculate core(n, t) = `core_t(n)` of a positive integer n
|
| 2132 |
+
|
| 2133 |
+
``core_2(n)`` is equal to the squarefree part of n
|
| 2134 |
+
|
| 2135 |
+
If n's prime factorization is:
|
| 2136 |
+
|
| 2137 |
+
.. math ::
|
| 2138 |
+
n = \prod_{i=1}^\omega p_i^{m_i},
|
| 2139 |
+
|
| 2140 |
+
then
|
| 2141 |
+
|
| 2142 |
+
.. math ::
|
| 2143 |
+
core_t(n) = \prod_{i=1}^\omega p_i^{m_i \mod t}.
|
| 2144 |
+
|
| 2145 |
+
Parameters
|
| 2146 |
+
==========
|
| 2147 |
+
|
| 2148 |
+
n : integer
|
| 2149 |
+
|
| 2150 |
+
t : integer
|
| 2151 |
+
core(n, t) calculates the t-th power free part of n
|
| 2152 |
+
|
| 2153 |
+
``core(n, 2)`` is the squarefree part of ``n``
|
| 2154 |
+
``core(n, 3)`` is the cubefree part of ``n``
|
| 2155 |
+
|
| 2156 |
+
Default for t is 2.
|
| 2157 |
+
|
| 2158 |
+
Examples
|
| 2159 |
+
========
|
| 2160 |
+
|
| 2161 |
+
>>> from sympy.ntheory.factor_ import core
|
| 2162 |
+
>>> core(24, 2)
|
| 2163 |
+
6
|
| 2164 |
+
>>> core(9424, 3)
|
| 2165 |
+
1178
|
| 2166 |
+
>>> core(379238)
|
| 2167 |
+
379238
|
| 2168 |
+
>>> core(15**11, 10)
|
| 2169 |
+
15
|
| 2170 |
+
|
| 2171 |
+
See Also
|
| 2172 |
+
========
|
| 2173 |
+
|
| 2174 |
+
factorint, sympy.solvers.diophantine.diophantine.square_factor
|
| 2175 |
+
|
| 2176 |
+
References
|
| 2177 |
+
==========
|
| 2178 |
+
|
| 2179 |
+
.. [1] https://en.wikipedia.org/wiki/Square-free_integer#Squarefree_core
|
| 2180 |
+
|
| 2181 |
+
"""
|
| 2182 |
+
|
| 2183 |
+
n = as_int(n)
|
| 2184 |
+
t = as_int(t)
|
| 2185 |
+
if n <= 0:
|
| 2186 |
+
raise ValueError("n must be a positive integer")
|
| 2187 |
+
elif t <= 1:
|
| 2188 |
+
raise ValueError("t must be >= 2")
|
| 2189 |
+
else:
|
| 2190 |
+
y = 1
|
| 2191 |
+
for p, e in factorint(n).items():
|
| 2192 |
+
y *= p**(e % t)
|
| 2193 |
+
return y
|
| 2194 |
+
|
| 2195 |
+
|
| 2196 |
+
@deprecated("""\
|
| 2197 |
+
The `sympy.ntheory.factor_.udivisor_sigma` has been moved to `sympy.functions.combinatorial.numbers.udivisor_sigma`.""",
|
| 2198 |
+
deprecated_since_version="1.13",
|
| 2199 |
+
active_deprecations_target='deprecated-ntheory-symbolic-functions')
|
| 2200 |
+
def udivisor_sigma(n, k=1):
|
| 2201 |
+
r"""
|
| 2202 |
+
Calculate the unitary divisor function `\sigma_k^*(n)` for positive integer n
|
| 2203 |
+
|
| 2204 |
+
.. deprecated:: 1.13
|
| 2205 |
+
|
| 2206 |
+
The ``udivisor_sigma`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.udivisor_sigma`
|
| 2207 |
+
instead. See its documentation for more information. See
|
| 2208 |
+
:ref:`deprecated-ntheory-symbolic-functions` for details.
|
| 2209 |
+
|
| 2210 |
+
``udivisor_sigma(n, k)`` is equal to ``sum([x**k for x in udivisors(n)])``
|
| 2211 |
+
|
| 2212 |
+
If n's prime factorization is:
|
| 2213 |
+
|
| 2214 |
+
.. math ::
|
| 2215 |
+
n = \prod_{i=1}^\omega p_i^{m_i},
|
| 2216 |
+
|
| 2217 |
+
then
|
| 2218 |
+
|
| 2219 |
+
.. math ::
|
| 2220 |
+
\sigma_k^*(n) = \prod_{i=1}^\omega (1+ p_i^{m_ik}).
|
| 2221 |
+
|
| 2222 |
+
Parameters
|
| 2223 |
+
==========
|
| 2224 |
+
|
| 2225 |
+
k : power of divisors in the sum
|
| 2226 |
+
|
| 2227 |
+
for k = 0, 1:
|
| 2228 |
+
``udivisor_sigma(n, 0)`` is equal to ``udivisor_count(n)``
|
| 2229 |
+
``udivisor_sigma(n, 1)`` is equal to ``sum(udivisors(n))``
|
| 2230 |
+
|
| 2231 |
+
Default for k is 1.
|
| 2232 |
+
|
| 2233 |
+
Examples
|
| 2234 |
+
========
|
| 2235 |
+
|
| 2236 |
+
>>> from sympy.functions.combinatorial.numbers import udivisor_sigma
|
| 2237 |
+
>>> udivisor_sigma(18, 0)
|
| 2238 |
+
4
|
| 2239 |
+
>>> udivisor_sigma(74, 1)
|
| 2240 |
+
114
|
| 2241 |
+
>>> udivisor_sigma(36, 3)
|
| 2242 |
+
47450
|
| 2243 |
+
>>> udivisor_sigma(111)
|
| 2244 |
+
152
|
| 2245 |
+
|
| 2246 |
+
See Also
|
| 2247 |
+
========
|
| 2248 |
+
|
| 2249 |
+
divisor_count, totient, divisors, udivisors, udivisor_count, divisor_sigma,
|
| 2250 |
+
factorint
|
| 2251 |
+
|
| 2252 |
+
References
|
| 2253 |
+
==========
|
| 2254 |
+
|
| 2255 |
+
.. [1] https://mathworld.wolfram.com/UnitaryDivisorFunction.html
|
| 2256 |
+
|
| 2257 |
+
"""
|
| 2258 |
+
from sympy.functions.combinatorial.numbers import udivisor_sigma as _udivisor_sigma
|
| 2259 |
+
return _udivisor_sigma(n, k)
|
| 2260 |
+
|
| 2261 |
+
|
| 2262 |
+
@deprecated("""\
|
| 2263 |
+
The `sympy.ntheory.factor_.primenu` has been moved to `sympy.functions.combinatorial.numbers.primenu`.""",
|
| 2264 |
+
deprecated_since_version="1.13",
|
| 2265 |
+
active_deprecations_target='deprecated-ntheory-symbolic-functions')
|
| 2266 |
+
def primenu(n):
|
| 2267 |
+
r"""
|
| 2268 |
+
Calculate the number of distinct prime factors for a positive integer n.
|
| 2269 |
+
|
| 2270 |
+
.. deprecated:: 1.13
|
| 2271 |
+
|
| 2272 |
+
The ``primenu`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.primenu`
|
| 2273 |
+
instead. See its documentation for more information. See
|
| 2274 |
+
:ref:`deprecated-ntheory-symbolic-functions` for details.
|
| 2275 |
+
|
| 2276 |
+
If n's prime factorization is:
|
| 2277 |
+
|
| 2278 |
+
.. math ::
|
| 2279 |
+
n = \prod_{i=1}^k p_i^{m_i},
|
| 2280 |
+
|
| 2281 |
+
then ``primenu(n)`` or `\nu(n)` is:
|
| 2282 |
+
|
| 2283 |
+
.. math ::
|
| 2284 |
+
\nu(n) = k.
|
| 2285 |
+
|
| 2286 |
+
Examples
|
| 2287 |
+
========
|
| 2288 |
+
|
| 2289 |
+
>>> from sympy.functions.combinatorial.numbers import primenu
|
| 2290 |
+
>>> primenu(1)
|
| 2291 |
+
0
|
| 2292 |
+
>>> primenu(30)
|
| 2293 |
+
3
|
| 2294 |
+
|
| 2295 |
+
See Also
|
| 2296 |
+
========
|
| 2297 |
+
|
| 2298 |
+
factorint
|
| 2299 |
+
|
| 2300 |
+
References
|
| 2301 |
+
==========
|
| 2302 |
+
|
| 2303 |
+
.. [1] https://mathworld.wolfram.com/PrimeFactor.html
|
| 2304 |
+
|
| 2305 |
+
"""
|
| 2306 |
+
from sympy.functions.combinatorial.numbers import primenu as _primenu
|
| 2307 |
+
return _primenu(n)
|
| 2308 |
+
|
| 2309 |
+
|
| 2310 |
+
@deprecated("""\
|
| 2311 |
+
The `sympy.ntheory.factor_.primeomega` has been moved to `sympy.functions.combinatorial.numbers.primeomega`.""",
|
| 2312 |
+
deprecated_since_version="1.13",
|
| 2313 |
+
active_deprecations_target='deprecated-ntheory-symbolic-functions')
|
| 2314 |
+
def primeomega(n):
|
| 2315 |
+
r"""
|
| 2316 |
+
Calculate the number of prime factors counting multiplicities for a
|
| 2317 |
+
positive integer n.
|
| 2318 |
+
|
| 2319 |
+
.. deprecated:: 1.13
|
| 2320 |
+
|
| 2321 |
+
The ``primeomega`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.primeomega`
|
| 2322 |
+
instead. See its documentation for more information. See
|
| 2323 |
+
:ref:`deprecated-ntheory-symbolic-functions` for details.
|
| 2324 |
+
|
| 2325 |
+
If n's prime factorization is:
|
| 2326 |
+
|
| 2327 |
+
.. math ::
|
| 2328 |
+
n = \prod_{i=1}^k p_i^{m_i},
|
| 2329 |
+
|
| 2330 |
+
then ``primeomega(n)`` or `\Omega(n)` is:
|
| 2331 |
+
|
| 2332 |
+
.. math ::
|
| 2333 |
+
\Omega(n) = \sum_{i=1}^k m_i.
|
| 2334 |
+
|
| 2335 |
+
Examples
|
| 2336 |
+
========
|
| 2337 |
+
|
| 2338 |
+
>>> from sympy.functions.combinatorial.numbers import primeomega
|
| 2339 |
+
>>> primeomega(1)
|
| 2340 |
+
0
|
| 2341 |
+
>>> primeomega(20)
|
| 2342 |
+
3
|
| 2343 |
+
|
| 2344 |
+
See Also
|
| 2345 |
+
========
|
| 2346 |
+
|
| 2347 |
+
factorint
|
| 2348 |
+
|
| 2349 |
+
References
|
| 2350 |
+
==========
|
| 2351 |
+
|
| 2352 |
+
.. [1] https://mathworld.wolfram.com/PrimeFactor.html
|
| 2353 |
+
|
| 2354 |
+
"""
|
| 2355 |
+
from sympy.functions.combinatorial.numbers import primeomega as _primeomega
|
| 2356 |
+
return _primeomega(n)
|
| 2357 |
+
|
| 2358 |
+
|
| 2359 |
+
def mersenne_prime_exponent(nth):
|
| 2360 |
+
"""Returns the exponent ``i`` for the nth Mersenne prime (which
|
| 2361 |
+
has the form `2^i - 1`).
|
| 2362 |
+
|
| 2363 |
+
Examples
|
| 2364 |
+
========
|
| 2365 |
+
|
| 2366 |
+
>>> from sympy.ntheory.factor_ import mersenne_prime_exponent
|
| 2367 |
+
>>> mersenne_prime_exponent(1)
|
| 2368 |
+
2
|
| 2369 |
+
>>> mersenne_prime_exponent(20)
|
| 2370 |
+
4423
|
| 2371 |
+
"""
|
| 2372 |
+
n = as_int(nth)
|
| 2373 |
+
if n < 1:
|
| 2374 |
+
raise ValueError("nth must be a positive integer; mersenne_prime_exponent(1) == 2")
|
| 2375 |
+
if n > 51:
|
| 2376 |
+
raise ValueError("There are only 51 perfect numbers; nth must be less than or equal to 51")
|
| 2377 |
+
return MERSENNE_PRIME_EXPONENTS[n - 1]
|
| 2378 |
+
|
| 2379 |
+
|
| 2380 |
+
def is_perfect(n):
|
| 2381 |
+
"""Returns True if ``n`` is a perfect number, else False.
|
| 2382 |
+
|
| 2383 |
+
A perfect number is equal to the sum of its positive, proper divisors.
|
| 2384 |
+
|
| 2385 |
+
Examples
|
| 2386 |
+
========
|
| 2387 |
+
|
| 2388 |
+
>>> from sympy.functions.combinatorial.numbers import divisor_sigma
|
| 2389 |
+
>>> from sympy.ntheory.factor_ import is_perfect, divisors
|
| 2390 |
+
>>> is_perfect(20)
|
| 2391 |
+
False
|
| 2392 |
+
>>> is_perfect(6)
|
| 2393 |
+
True
|
| 2394 |
+
>>> 6 == divisor_sigma(6) - 6 == sum(divisors(6)[:-1])
|
| 2395 |
+
True
|
| 2396 |
+
|
| 2397 |
+
References
|
| 2398 |
+
==========
|
| 2399 |
+
|
| 2400 |
+
.. [1] https://mathworld.wolfram.com/PerfectNumber.html
|
| 2401 |
+
.. [2] https://en.wikipedia.org/wiki/Perfect_number
|
| 2402 |
+
|
| 2403 |
+
"""
|
| 2404 |
+
n = as_int(n)
|
| 2405 |
+
if n < 1:
|
| 2406 |
+
return False
|
| 2407 |
+
if n % 2 == 0:
|
| 2408 |
+
m = (n.bit_length() + 1) >> 1
|
| 2409 |
+
if (1 << (m - 1)) * ((1 << m) - 1) != n:
|
| 2410 |
+
# Even perfect numbers must be of the form `2^{m-1}(2^m-1)`
|
| 2411 |
+
return False
|
| 2412 |
+
return m in MERSENNE_PRIME_EXPONENTS or is_mersenne_prime(2**m - 1)
|
| 2413 |
+
|
| 2414 |
+
# n is an odd integer
|
| 2415 |
+
if n < 10**2000: # https://www.lirmm.fr/~ochem/opn/
|
| 2416 |
+
return False
|
| 2417 |
+
if n % 105 == 0: # not divis by 105
|
| 2418 |
+
return False
|
| 2419 |
+
if all(n % m != r for m, r in [(12, 1), (468, 117), (324, 81)]):
|
| 2420 |
+
return False
|
| 2421 |
+
# there are many criteria that the factor structure of n
|
| 2422 |
+
# must meet; since we will have to factor it to test the
|
| 2423 |
+
# structure we will have the factors and can then check
|
| 2424 |
+
# to see whether it is a perfect number or not. So we
|
| 2425 |
+
# skip the structure checks and go straight to the final
|
| 2426 |
+
# test below.
|
| 2427 |
+
result = abundance(n) == 0
|
| 2428 |
+
if result:
|
| 2429 |
+
raise ValueError(filldedent('''In 1888, Sylvester stated: "
|
| 2430 |
+
...a prolonged meditation on the subject has satisfied
|
| 2431 |
+
me that the existence of any one such [odd perfect number]
|
| 2432 |
+
-- its escape, so to say, from the complex web of conditions
|
| 2433 |
+
which hem it in on all sides -- would be little short of a
|
| 2434 |
+
miracle." I guess SymPy just found that miracle and it
|
| 2435 |
+
factors like this: %s''' % factorint(n)))
|
| 2436 |
+
return result
|
| 2437 |
+
|
| 2438 |
+
|
| 2439 |
+
def abundance(n):
|
| 2440 |
+
"""Returns the difference between the sum of the positive
|
| 2441 |
+
proper divisors of a number and the number.
|
| 2442 |
+
|
| 2443 |
+
Examples
|
| 2444 |
+
========
|
| 2445 |
+
|
| 2446 |
+
>>> from sympy.ntheory import abundance, is_perfect, is_abundant
|
| 2447 |
+
>>> abundance(6)
|
| 2448 |
+
0
|
| 2449 |
+
>>> is_perfect(6)
|
| 2450 |
+
True
|
| 2451 |
+
>>> abundance(10)
|
| 2452 |
+
-2
|
| 2453 |
+
>>> is_abundant(10)
|
| 2454 |
+
False
|
| 2455 |
+
"""
|
| 2456 |
+
return _divisor_sigma(n) - 2 * n
|
| 2457 |
+
|
| 2458 |
+
|
| 2459 |
+
def is_abundant(n):
|
| 2460 |
+
"""Returns True if ``n`` is an abundant number, else False.
|
| 2461 |
+
|
| 2462 |
+
A abundant number is smaller than the sum of its positive proper divisors.
|
| 2463 |
+
|
| 2464 |
+
Examples
|
| 2465 |
+
========
|
| 2466 |
+
|
| 2467 |
+
>>> from sympy.ntheory.factor_ import is_abundant
|
| 2468 |
+
>>> is_abundant(20)
|
| 2469 |
+
True
|
| 2470 |
+
>>> is_abundant(15)
|
| 2471 |
+
False
|
| 2472 |
+
|
| 2473 |
+
References
|
| 2474 |
+
==========
|
| 2475 |
+
|
| 2476 |
+
.. [1] https://mathworld.wolfram.com/AbundantNumber.html
|
| 2477 |
+
|
| 2478 |
+
"""
|
| 2479 |
+
n = as_int(n)
|
| 2480 |
+
if is_perfect(n):
|
| 2481 |
+
return False
|
| 2482 |
+
return n % 6 == 0 or bool(abundance(n) > 0)
|
| 2483 |
+
|
| 2484 |
+
|
| 2485 |
+
def is_deficient(n):
|
| 2486 |
+
"""Returns True if ``n`` is a deficient number, else False.
|
| 2487 |
+
|
| 2488 |
+
A deficient number is greater than the sum of its positive proper divisors.
|
| 2489 |
+
|
| 2490 |
+
Examples
|
| 2491 |
+
========
|
| 2492 |
+
|
| 2493 |
+
>>> from sympy.ntheory.factor_ import is_deficient
|
| 2494 |
+
>>> is_deficient(20)
|
| 2495 |
+
False
|
| 2496 |
+
>>> is_deficient(15)
|
| 2497 |
+
True
|
| 2498 |
+
|
| 2499 |
+
References
|
| 2500 |
+
==========
|
| 2501 |
+
|
| 2502 |
+
.. [1] https://mathworld.wolfram.com/DeficientNumber.html
|
| 2503 |
+
|
| 2504 |
+
"""
|
| 2505 |
+
n = as_int(n)
|
| 2506 |
+
if is_perfect(n):
|
| 2507 |
+
return False
|
| 2508 |
+
return bool(abundance(n) < 0)
|
| 2509 |
+
|
| 2510 |
+
|
| 2511 |
+
def is_amicable(m, n):
|
| 2512 |
+
"""Returns True if the numbers `m` and `n` are "amicable", else False.
|
| 2513 |
+
|
| 2514 |
+
Amicable numbers are two different numbers so related that the sum
|
| 2515 |
+
of the proper divisors of each is equal to that of the other.
|
| 2516 |
+
|
| 2517 |
+
Examples
|
| 2518 |
+
========
|
| 2519 |
+
|
| 2520 |
+
>>> from sympy.functions.combinatorial.numbers import divisor_sigma
|
| 2521 |
+
>>> from sympy.ntheory.factor_ import is_amicable
|
| 2522 |
+
>>> is_amicable(220, 284)
|
| 2523 |
+
True
|
| 2524 |
+
>>> divisor_sigma(220) == divisor_sigma(284)
|
| 2525 |
+
True
|
| 2526 |
+
|
| 2527 |
+
References
|
| 2528 |
+
==========
|
| 2529 |
+
|
| 2530 |
+
.. [1] https://en.wikipedia.org/wiki/Amicable_numbers
|
| 2531 |
+
|
| 2532 |
+
"""
|
| 2533 |
+
return m != n and m + n == _divisor_sigma(m) == _divisor_sigma(n)
|
| 2534 |
+
|
| 2535 |
+
|
| 2536 |
+
def is_carmichael(n):
|
| 2537 |
+
""" Returns True if the numbers `n` is Carmichael number, else False.
|
| 2538 |
+
|
| 2539 |
+
Parameters
|
| 2540 |
+
==========
|
| 2541 |
+
|
| 2542 |
+
n : Integer
|
| 2543 |
+
|
| 2544 |
+
References
|
| 2545 |
+
==========
|
| 2546 |
+
|
| 2547 |
+
.. [1] https://en.wikipedia.org/wiki/Carmichael_number
|
| 2548 |
+
.. [2] https://oeis.org/A002997
|
| 2549 |
+
|
| 2550 |
+
"""
|
| 2551 |
+
if n < 561:
|
| 2552 |
+
return False
|
| 2553 |
+
return n % 2 and not isprime(n) and \
|
| 2554 |
+
all(e == 1 and (n - 1) % (p - 1) == 0 for p, e in factorint(n).items())
|
| 2555 |
+
|
| 2556 |
+
|
| 2557 |
+
def find_carmichael_numbers_in_range(x, y):
|
| 2558 |
+
""" Returns a list of the number of Carmichael in the range
|
| 2559 |
+
|
| 2560 |
+
See Also
|
| 2561 |
+
========
|
| 2562 |
+
|
| 2563 |
+
is_carmichael
|
| 2564 |
+
|
| 2565 |
+
"""
|
| 2566 |
+
if 0 <= x <= y:
|
| 2567 |
+
if x % 2 == 0:
|
| 2568 |
+
return [i for i in range(x + 1, y, 2) if is_carmichael(i)]
|
| 2569 |
+
else:
|
| 2570 |
+
return [i for i in range(x, y, 2) if is_carmichael(i)]
|
| 2571 |
+
else:
|
| 2572 |
+
raise ValueError('The provided range is not valid. x and y must be non-negative integers and x <= y')
|
| 2573 |
+
|
| 2574 |
+
|
| 2575 |
+
def find_first_n_carmichaels(n):
|
| 2576 |
+
""" Returns the first n Carmichael numbers.
|
| 2577 |
+
|
| 2578 |
+
Parameters
|
| 2579 |
+
==========
|
| 2580 |
+
|
| 2581 |
+
n : Integer
|
| 2582 |
+
|
| 2583 |
+
See Also
|
| 2584 |
+
========
|
| 2585 |
+
|
| 2586 |
+
is_carmichael
|
| 2587 |
+
|
| 2588 |
+
"""
|
| 2589 |
+
i = 561
|
| 2590 |
+
carmichaels = []
|
| 2591 |
+
|
| 2592 |
+
while len(carmichaels) < n:
|
| 2593 |
+
if is_carmichael(i):
|
| 2594 |
+
carmichaels.append(i)
|
| 2595 |
+
i += 2
|
| 2596 |
+
|
| 2597 |
+
return carmichaels
|
| 2598 |
+
|
| 2599 |
+
|
| 2600 |
+
def dra(n, b):
|
| 2601 |
+
"""
|
| 2602 |
+
Returns the additive digital root of a natural number ``n`` in base ``b``
|
| 2603 |
+
which is a single digit value obtained by an iterative process of summing
|
| 2604 |
+
digits, on each iteration using the result from the previous iteration to
|
| 2605 |
+
compute a digit sum.
|
| 2606 |
+
|
| 2607 |
+
Examples
|
| 2608 |
+
========
|
| 2609 |
+
|
| 2610 |
+
>>> from sympy.ntheory.factor_ import dra
|
| 2611 |
+
>>> dra(3110, 12)
|
| 2612 |
+
8
|
| 2613 |
+
|
| 2614 |
+
References
|
| 2615 |
+
==========
|
| 2616 |
+
|
| 2617 |
+
.. [1] https://en.wikipedia.org/wiki/Digital_root
|
| 2618 |
+
|
| 2619 |
+
"""
|
| 2620 |
+
|
| 2621 |
+
num = abs(as_int(n))
|
| 2622 |
+
b = as_int(b)
|
| 2623 |
+
if b <= 1:
|
| 2624 |
+
raise ValueError("Base should be an integer greater than 1")
|
| 2625 |
+
|
| 2626 |
+
if num == 0:
|
| 2627 |
+
return 0
|
| 2628 |
+
|
| 2629 |
+
return (1 + (num - 1) % (b - 1))
|
| 2630 |
+
|
| 2631 |
+
|
| 2632 |
+
def drm(n, b):
|
| 2633 |
+
"""
|
| 2634 |
+
Returns the multiplicative digital root of a natural number ``n`` in a given
|
| 2635 |
+
base ``b`` which is a single digit value obtained by an iterative process of
|
| 2636 |
+
multiplying digits, on each iteration using the result from the previous
|
| 2637 |
+
iteration to compute the digit multiplication.
|
| 2638 |
+
|
| 2639 |
+
Examples
|
| 2640 |
+
========
|
| 2641 |
+
|
| 2642 |
+
>>> from sympy.ntheory.factor_ import drm
|
| 2643 |
+
>>> drm(9876, 10)
|
| 2644 |
+
0
|
| 2645 |
+
|
| 2646 |
+
>>> drm(49, 10)
|
| 2647 |
+
8
|
| 2648 |
+
|
| 2649 |
+
References
|
| 2650 |
+
==========
|
| 2651 |
+
|
| 2652 |
+
.. [1] https://mathworld.wolfram.com/MultiplicativeDigitalRoot.html
|
| 2653 |
+
|
| 2654 |
+
"""
|
| 2655 |
+
|
| 2656 |
+
n = abs(as_int(n))
|
| 2657 |
+
b = as_int(b)
|
| 2658 |
+
if b <= 1:
|
| 2659 |
+
raise ValueError("Base should be an integer greater than 1")
|
| 2660 |
+
while n > b:
|
| 2661 |
+
mul = 1
|
| 2662 |
+
while n > 1:
|
| 2663 |
+
n, r = divmod(n, b)
|
| 2664 |
+
if r == 0:
|
| 2665 |
+
return 0
|
| 2666 |
+
mul *= r
|
| 2667 |
+
n = mul
|
| 2668 |
+
return n
|
lib/python3.12/site-packages/sympy/ntheory/generate.py
ADDED
|
@@ -0,0 +1,1147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Generating and counting primes.
|
| 3 |
+
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
from bisect import bisect, bisect_left
|
| 7 |
+
from itertools import count
|
| 8 |
+
# Using arrays for sieving instead of lists greatly reduces
|
| 9 |
+
# memory consumption
|
| 10 |
+
from array import array as _array
|
| 11 |
+
|
| 12 |
+
from sympy.core.random import randint
|
| 13 |
+
from sympy.external.gmpy import sqrt
|
| 14 |
+
from .primetest import isprime
|
| 15 |
+
from sympy.utilities.decorator import deprecated
|
| 16 |
+
from sympy.utilities.misc import as_int
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def _as_int_ceiling(a):
|
| 20 |
+
""" Wrapping ceiling in as_int will raise an error if there was a problem
|
| 21 |
+
determining whether the expression was exactly an integer or not."""
|
| 22 |
+
from sympy.functions.elementary.integers import ceiling
|
| 23 |
+
return as_int(ceiling(a))
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
class Sieve:
|
| 27 |
+
"""A list of prime numbers, implemented as a dynamically
|
| 28 |
+
growing sieve of Eratosthenes. When a lookup is requested involving
|
| 29 |
+
an odd number that has not been sieved, the sieve is automatically
|
| 30 |
+
extended up to that number. Implementation details limit the number of
|
| 31 |
+
primes to ``2^32-1``.
|
| 32 |
+
|
| 33 |
+
Examples
|
| 34 |
+
========
|
| 35 |
+
|
| 36 |
+
>>> from sympy import sieve
|
| 37 |
+
>>> sieve._reset() # this line for doctest only
|
| 38 |
+
>>> 25 in sieve
|
| 39 |
+
False
|
| 40 |
+
>>> sieve._list
|
| 41 |
+
array('L', [2, 3, 5, 7, 11, 13, 17, 19, 23])
|
| 42 |
+
"""
|
| 43 |
+
|
| 44 |
+
# data shared (and updated) by all Sieve instances
|
| 45 |
+
def __init__(self, sieve_interval=1_000_000):
|
| 46 |
+
""" Initial parameters for the Sieve class.
|
| 47 |
+
|
| 48 |
+
Parameters
|
| 49 |
+
==========
|
| 50 |
+
|
| 51 |
+
sieve_interval (int): Amount of memory to be used
|
| 52 |
+
|
| 53 |
+
Raises
|
| 54 |
+
======
|
| 55 |
+
|
| 56 |
+
ValueError
|
| 57 |
+
If ``sieve_interval`` is not positive.
|
| 58 |
+
|
| 59 |
+
"""
|
| 60 |
+
self._n = 6
|
| 61 |
+
self._list = _array('L', [2, 3, 5, 7, 11, 13]) # primes
|
| 62 |
+
self._tlist = _array('L', [0, 1, 1, 2, 2, 4]) # totient
|
| 63 |
+
self._mlist = _array('i', [0, 1, -1, -1, 0, -1]) # mobius
|
| 64 |
+
if sieve_interval <= 0:
|
| 65 |
+
raise ValueError("sieve_interval should be a positive integer")
|
| 66 |
+
self.sieve_interval = sieve_interval
|
| 67 |
+
assert all(len(i) == self._n for i in (self._list, self._tlist, self._mlist))
|
| 68 |
+
|
| 69 |
+
def __repr__(self):
|
| 70 |
+
return ("<%s sieve (%i): %i, %i, %i, ... %i, %i\n"
|
| 71 |
+
"%s sieve (%i): %i, %i, %i, ... %i, %i\n"
|
| 72 |
+
"%s sieve (%i): %i, %i, %i, ... %i, %i>") % (
|
| 73 |
+
'prime', len(self._list),
|
| 74 |
+
self._list[0], self._list[1], self._list[2],
|
| 75 |
+
self._list[-2], self._list[-1],
|
| 76 |
+
'totient', len(self._tlist),
|
| 77 |
+
self._tlist[0], self._tlist[1],
|
| 78 |
+
self._tlist[2], self._tlist[-2], self._tlist[-1],
|
| 79 |
+
'mobius', len(self._mlist),
|
| 80 |
+
self._mlist[0], self._mlist[1],
|
| 81 |
+
self._mlist[2], self._mlist[-2], self._mlist[-1])
|
| 82 |
+
|
| 83 |
+
def _reset(self, prime=None, totient=None, mobius=None):
|
| 84 |
+
"""Reset all caches (default). To reset one or more set the
|
| 85 |
+
desired keyword to True."""
|
| 86 |
+
if all(i is None for i in (prime, totient, mobius)):
|
| 87 |
+
prime = totient = mobius = True
|
| 88 |
+
if prime:
|
| 89 |
+
self._list = self._list[:self._n]
|
| 90 |
+
if totient:
|
| 91 |
+
self._tlist = self._tlist[:self._n]
|
| 92 |
+
if mobius:
|
| 93 |
+
self._mlist = self._mlist[:self._n]
|
| 94 |
+
|
| 95 |
+
def extend(self, n):
|
| 96 |
+
"""Grow the sieve to cover all primes <= n.
|
| 97 |
+
|
| 98 |
+
Examples
|
| 99 |
+
========
|
| 100 |
+
|
| 101 |
+
>>> from sympy import sieve
|
| 102 |
+
>>> sieve._reset() # this line for doctest only
|
| 103 |
+
>>> sieve.extend(30)
|
| 104 |
+
>>> sieve[10] == 29
|
| 105 |
+
True
|
| 106 |
+
"""
|
| 107 |
+
n = int(n)
|
| 108 |
+
# `num` is even at any point in the function.
|
| 109 |
+
# This satisfies the condition required by `self._primerange`.
|
| 110 |
+
num = self._list[-1] + 1
|
| 111 |
+
if n < num:
|
| 112 |
+
return
|
| 113 |
+
num2 = num**2
|
| 114 |
+
while num2 <= n:
|
| 115 |
+
self._list += _array('L', self._primerange(num, num2))
|
| 116 |
+
num, num2 = num2, num2**2
|
| 117 |
+
# Merge the sieves
|
| 118 |
+
self._list += _array('L', self._primerange(num, n + 1))
|
| 119 |
+
|
| 120 |
+
def _primerange(self, a, b):
|
| 121 |
+
""" Generate all prime numbers in the range (a, b).
|
| 122 |
+
|
| 123 |
+
Parameters
|
| 124 |
+
==========
|
| 125 |
+
|
| 126 |
+
a, b : positive integers assuming the following conditions
|
| 127 |
+
* a is an even number
|
| 128 |
+
* 2 < self._list[-1] < a < b < nextprime(self._list[-1])**2
|
| 129 |
+
|
| 130 |
+
Yields
|
| 131 |
+
======
|
| 132 |
+
|
| 133 |
+
p (int): prime numbers such that ``a < p < b``
|
| 134 |
+
|
| 135 |
+
Examples
|
| 136 |
+
========
|
| 137 |
+
|
| 138 |
+
>>> from sympy.ntheory.generate import Sieve
|
| 139 |
+
>>> s = Sieve()
|
| 140 |
+
>>> s._list[-1]
|
| 141 |
+
13
|
| 142 |
+
>>> list(s._primerange(18, 31))
|
| 143 |
+
[19, 23, 29]
|
| 144 |
+
|
| 145 |
+
"""
|
| 146 |
+
if b % 2:
|
| 147 |
+
b -= 1
|
| 148 |
+
while a < b:
|
| 149 |
+
block_size = min(self.sieve_interval, (b - a) // 2)
|
| 150 |
+
# Create the list such that block[x] iff (a + 2x + 1) is prime.
|
| 151 |
+
# Note that even numbers are not considered here.
|
| 152 |
+
block = [True] * block_size
|
| 153 |
+
for p in self._list[1:bisect(self._list, sqrt(a + 2 * block_size + 1))]:
|
| 154 |
+
for t in range((-(a + 1 + p) // 2) % p, block_size, p):
|
| 155 |
+
block[t] = False
|
| 156 |
+
for idx, p in enumerate(block):
|
| 157 |
+
if p:
|
| 158 |
+
yield a + 2 * idx + 1
|
| 159 |
+
a += 2 * block_size
|
| 160 |
+
|
| 161 |
+
def extend_to_no(self, i):
|
| 162 |
+
"""Extend to include the ith prime number.
|
| 163 |
+
|
| 164 |
+
Parameters
|
| 165 |
+
==========
|
| 166 |
+
|
| 167 |
+
i : integer
|
| 168 |
+
|
| 169 |
+
Examples
|
| 170 |
+
========
|
| 171 |
+
|
| 172 |
+
>>> from sympy import sieve
|
| 173 |
+
>>> sieve._reset() # this line for doctest only
|
| 174 |
+
>>> sieve.extend_to_no(9)
|
| 175 |
+
>>> sieve._list
|
| 176 |
+
array('L', [2, 3, 5, 7, 11, 13, 17, 19, 23])
|
| 177 |
+
|
| 178 |
+
Notes
|
| 179 |
+
=====
|
| 180 |
+
|
| 181 |
+
The list is extended by 50% if it is too short, so it is
|
| 182 |
+
likely that it will be longer than requested.
|
| 183 |
+
"""
|
| 184 |
+
i = as_int(i)
|
| 185 |
+
while len(self._list) < i:
|
| 186 |
+
self.extend(int(self._list[-1] * 1.5))
|
| 187 |
+
|
| 188 |
+
def primerange(self, a, b=None):
|
| 189 |
+
"""Generate all prime numbers in the range [2, a) or [a, b).
|
| 190 |
+
|
| 191 |
+
Examples
|
| 192 |
+
========
|
| 193 |
+
|
| 194 |
+
>>> from sympy import sieve, prime
|
| 195 |
+
|
| 196 |
+
All primes less than 19:
|
| 197 |
+
|
| 198 |
+
>>> print([i for i in sieve.primerange(19)])
|
| 199 |
+
[2, 3, 5, 7, 11, 13, 17]
|
| 200 |
+
|
| 201 |
+
All primes greater than or equal to 7 and less than 19:
|
| 202 |
+
|
| 203 |
+
>>> print([i for i in sieve.primerange(7, 19)])
|
| 204 |
+
[7, 11, 13, 17]
|
| 205 |
+
|
| 206 |
+
All primes through the 10th prime
|
| 207 |
+
|
| 208 |
+
>>> list(sieve.primerange(prime(10) + 1))
|
| 209 |
+
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
|
| 210 |
+
|
| 211 |
+
"""
|
| 212 |
+
if b is None:
|
| 213 |
+
b = _as_int_ceiling(a)
|
| 214 |
+
a = 2
|
| 215 |
+
else:
|
| 216 |
+
a = max(2, _as_int_ceiling(a))
|
| 217 |
+
b = _as_int_ceiling(b)
|
| 218 |
+
if a >= b:
|
| 219 |
+
return
|
| 220 |
+
self.extend(b)
|
| 221 |
+
yield from self._list[bisect_left(self._list, a):
|
| 222 |
+
bisect_left(self._list, b)]
|
| 223 |
+
|
| 224 |
+
def totientrange(self, a, b):
|
| 225 |
+
"""Generate all totient numbers for the range [a, b).
|
| 226 |
+
|
| 227 |
+
Examples
|
| 228 |
+
========
|
| 229 |
+
|
| 230 |
+
>>> from sympy import sieve
|
| 231 |
+
>>> print([i for i in sieve.totientrange(7, 18)])
|
| 232 |
+
[6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16]
|
| 233 |
+
"""
|
| 234 |
+
a = max(1, _as_int_ceiling(a))
|
| 235 |
+
b = _as_int_ceiling(b)
|
| 236 |
+
n = len(self._tlist)
|
| 237 |
+
if a >= b:
|
| 238 |
+
return
|
| 239 |
+
elif b <= n:
|
| 240 |
+
for i in range(a, b):
|
| 241 |
+
yield self._tlist[i]
|
| 242 |
+
else:
|
| 243 |
+
self._tlist += _array('L', range(n, b))
|
| 244 |
+
for i in range(1, n):
|
| 245 |
+
ti = self._tlist[i]
|
| 246 |
+
if ti == i - 1:
|
| 247 |
+
startindex = (n + i - 1) // i * i
|
| 248 |
+
for j in range(startindex, b, i):
|
| 249 |
+
self._tlist[j] -= self._tlist[j] // i
|
| 250 |
+
if i >= a:
|
| 251 |
+
yield ti
|
| 252 |
+
|
| 253 |
+
for i in range(n, b):
|
| 254 |
+
ti = self._tlist[i]
|
| 255 |
+
if ti == i:
|
| 256 |
+
for j in range(i, b, i):
|
| 257 |
+
self._tlist[j] -= self._tlist[j] // i
|
| 258 |
+
if i >= a:
|
| 259 |
+
yield self._tlist[i]
|
| 260 |
+
|
| 261 |
+
def mobiusrange(self, a, b):
|
| 262 |
+
"""Generate all mobius numbers for the range [a, b).
|
| 263 |
+
|
| 264 |
+
Parameters
|
| 265 |
+
==========
|
| 266 |
+
|
| 267 |
+
a : integer
|
| 268 |
+
First number in range
|
| 269 |
+
|
| 270 |
+
b : integer
|
| 271 |
+
First number outside of range
|
| 272 |
+
|
| 273 |
+
Examples
|
| 274 |
+
========
|
| 275 |
+
|
| 276 |
+
>>> from sympy import sieve
|
| 277 |
+
>>> print([i for i in sieve.mobiusrange(7, 18)])
|
| 278 |
+
[-1, 0, 0, 1, -1, 0, -1, 1, 1, 0, -1]
|
| 279 |
+
"""
|
| 280 |
+
a = max(1, _as_int_ceiling(a))
|
| 281 |
+
b = _as_int_ceiling(b)
|
| 282 |
+
n = len(self._mlist)
|
| 283 |
+
if a >= b:
|
| 284 |
+
return
|
| 285 |
+
elif b <= n:
|
| 286 |
+
for i in range(a, b):
|
| 287 |
+
yield self._mlist[i]
|
| 288 |
+
else:
|
| 289 |
+
self._mlist += _array('i', [0]*(b - n))
|
| 290 |
+
for i in range(1, n):
|
| 291 |
+
mi = self._mlist[i]
|
| 292 |
+
startindex = (n + i - 1) // i * i
|
| 293 |
+
for j in range(startindex, b, i):
|
| 294 |
+
self._mlist[j] -= mi
|
| 295 |
+
if i >= a:
|
| 296 |
+
yield mi
|
| 297 |
+
|
| 298 |
+
for i in range(n, b):
|
| 299 |
+
mi = self._mlist[i]
|
| 300 |
+
for j in range(2 * i, b, i):
|
| 301 |
+
self._mlist[j] -= mi
|
| 302 |
+
if i >= a:
|
| 303 |
+
yield mi
|
| 304 |
+
|
| 305 |
+
def search(self, n):
|
| 306 |
+
"""Return the indices i, j of the primes that bound n.
|
| 307 |
+
|
| 308 |
+
If n is prime then i == j.
|
| 309 |
+
|
| 310 |
+
Although n can be an expression, if ceiling cannot convert
|
| 311 |
+
it to an integer then an n error will be raised.
|
| 312 |
+
|
| 313 |
+
Examples
|
| 314 |
+
========
|
| 315 |
+
|
| 316 |
+
>>> from sympy import sieve
|
| 317 |
+
>>> sieve.search(25)
|
| 318 |
+
(9, 10)
|
| 319 |
+
>>> sieve.search(23)
|
| 320 |
+
(9, 9)
|
| 321 |
+
"""
|
| 322 |
+
test = _as_int_ceiling(n)
|
| 323 |
+
n = as_int(n)
|
| 324 |
+
if n < 2:
|
| 325 |
+
raise ValueError("n should be >= 2 but got: %s" % n)
|
| 326 |
+
if n > self._list[-1]:
|
| 327 |
+
self.extend(n)
|
| 328 |
+
b = bisect(self._list, n)
|
| 329 |
+
if self._list[b - 1] == test:
|
| 330 |
+
return b, b
|
| 331 |
+
else:
|
| 332 |
+
return b, b + 1
|
| 333 |
+
|
| 334 |
+
def __contains__(self, n):
|
| 335 |
+
try:
|
| 336 |
+
n = as_int(n)
|
| 337 |
+
assert n >= 2
|
| 338 |
+
except (ValueError, AssertionError):
|
| 339 |
+
return False
|
| 340 |
+
if n % 2 == 0:
|
| 341 |
+
return n == 2
|
| 342 |
+
a, b = self.search(n)
|
| 343 |
+
return a == b
|
| 344 |
+
|
| 345 |
+
def __iter__(self):
|
| 346 |
+
for n in count(1):
|
| 347 |
+
yield self[n]
|
| 348 |
+
|
| 349 |
+
def __getitem__(self, n):
|
| 350 |
+
"""Return the nth prime number"""
|
| 351 |
+
if isinstance(n, slice):
|
| 352 |
+
self.extend_to_no(n.stop)
|
| 353 |
+
# Python 2.7 slices have 0 instead of None for start, so
|
| 354 |
+
# we can't default to 1.
|
| 355 |
+
start = n.start if n.start is not None else 0
|
| 356 |
+
if start < 1:
|
| 357 |
+
# sieve[:5] would be empty (starting at -1), let's
|
| 358 |
+
# just be explicit and raise.
|
| 359 |
+
raise IndexError("Sieve indices start at 1.")
|
| 360 |
+
return self._list[start - 1:n.stop - 1:n.step]
|
| 361 |
+
else:
|
| 362 |
+
if n < 1:
|
| 363 |
+
# offset is one, so forbid explicit access to sieve[0]
|
| 364 |
+
# (would surprisingly return the last one).
|
| 365 |
+
raise IndexError("Sieve indices start at 1.")
|
| 366 |
+
n = as_int(n)
|
| 367 |
+
self.extend_to_no(n)
|
| 368 |
+
return self._list[n - 1]
|
| 369 |
+
|
| 370 |
+
# Generate a global object for repeated use in trial division etc
|
| 371 |
+
sieve = Sieve()
|
| 372 |
+
|
| 373 |
+
|
| 374 |
+
def prime(nth):
|
| 375 |
+
r""" Return the nth prime, with the primes indexed as prime(1) = 2,
|
| 376 |
+
prime(2) = 3, etc.... The nth prime is approximately $n\log(n)$.
|
| 377 |
+
|
| 378 |
+
Logarithmic integral of $x$ is a pretty nice approximation for number of
|
| 379 |
+
primes $\le x$, i.e.
|
| 380 |
+
li(x) ~ pi(x)
|
| 381 |
+
In fact, for the numbers we are concerned about( x<1e11 ),
|
| 382 |
+
li(x) - pi(x) < 50000
|
| 383 |
+
|
| 384 |
+
Also,
|
| 385 |
+
li(x) > pi(x) can be safely assumed for the numbers which
|
| 386 |
+
can be evaluated by this function.
|
| 387 |
+
|
| 388 |
+
Here, we find the least integer m such that li(m) > n using binary search.
|
| 389 |
+
Now pi(m-1) < li(m-1) <= n,
|
| 390 |
+
|
| 391 |
+
We find pi(m - 1) using primepi function.
|
| 392 |
+
|
| 393 |
+
Starting from m, we have to find n - pi(m-1) more primes.
|
| 394 |
+
|
| 395 |
+
For the inputs this implementation can handle, we will have to test
|
| 396 |
+
primality for at max about 10**5 numbers, to get our answer.
|
| 397 |
+
|
| 398 |
+
Examples
|
| 399 |
+
========
|
| 400 |
+
|
| 401 |
+
>>> from sympy import prime
|
| 402 |
+
>>> prime(10)
|
| 403 |
+
29
|
| 404 |
+
>>> prime(1)
|
| 405 |
+
2
|
| 406 |
+
>>> prime(100000)
|
| 407 |
+
1299709
|
| 408 |
+
|
| 409 |
+
See Also
|
| 410 |
+
========
|
| 411 |
+
|
| 412 |
+
sympy.ntheory.primetest.isprime : Test if n is prime
|
| 413 |
+
primerange : Generate all primes in a given range
|
| 414 |
+
primepi : Return the number of primes less than or equal to n
|
| 415 |
+
|
| 416 |
+
References
|
| 417 |
+
==========
|
| 418 |
+
|
| 419 |
+
.. [1] https://en.wikipedia.org/wiki/Prime_number_theorem#Table_of_.CF.80.28x.29.2C_x_.2F_log_x.2C_and_li.28x.29
|
| 420 |
+
.. [2] https://en.wikipedia.org/wiki/Prime_number_theorem#Approximations_for_the_nth_prime_number
|
| 421 |
+
.. [3] https://en.wikipedia.org/wiki/Skewes%27_number
|
| 422 |
+
"""
|
| 423 |
+
n = as_int(nth)
|
| 424 |
+
if n < 1:
|
| 425 |
+
raise ValueError("nth must be a positive integer; prime(1) == 2")
|
| 426 |
+
if n <= len(sieve._list):
|
| 427 |
+
return sieve[n]
|
| 428 |
+
|
| 429 |
+
from sympy.functions.elementary.exponential import log
|
| 430 |
+
from sympy.functions.special.error_functions import li
|
| 431 |
+
a = 2 # Lower bound for binary search
|
| 432 |
+
# leave n inside int since int(i*r) != i*int(r) is not a valid property
|
| 433 |
+
# e.g. int(2*.5) != 2*int(.5)
|
| 434 |
+
b = int(n*(log(n) + log(log(n)))) # Upper bound for the search.
|
| 435 |
+
|
| 436 |
+
while a < b:
|
| 437 |
+
mid = (a + b) >> 1
|
| 438 |
+
if li(mid) > n:
|
| 439 |
+
b = mid
|
| 440 |
+
else:
|
| 441 |
+
a = mid + 1
|
| 442 |
+
n_primes = _primepi(a - 1)
|
| 443 |
+
while n_primes < n:
|
| 444 |
+
if isprime(a):
|
| 445 |
+
n_primes += 1
|
| 446 |
+
a += 1
|
| 447 |
+
return a - 1
|
| 448 |
+
|
| 449 |
+
@deprecated("""\
|
| 450 |
+
The `sympy.ntheory.generate.primepi` has been moved to `sympy.functions.combinatorial.numbers.primepi`.""",
|
| 451 |
+
deprecated_since_version="1.13",
|
| 452 |
+
active_deprecations_target='deprecated-ntheory-symbolic-functions')
|
| 453 |
+
def primepi(n):
|
| 454 |
+
r""" Represents the prime counting function pi(n) = the number
|
| 455 |
+
of prime numbers less than or equal to n.
|
| 456 |
+
|
| 457 |
+
.. deprecated:: 1.13
|
| 458 |
+
|
| 459 |
+
The ``primepi`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.primepi`
|
| 460 |
+
instead. See its documentation for more information. See
|
| 461 |
+
:ref:`deprecated-ntheory-symbolic-functions` for details.
|
| 462 |
+
|
| 463 |
+
Algorithm Description:
|
| 464 |
+
|
| 465 |
+
In sieve method, we remove all multiples of prime p
|
| 466 |
+
except p itself.
|
| 467 |
+
|
| 468 |
+
Let phi(i,j) be the number of integers 2 <= k <= i
|
| 469 |
+
which remain after sieving from primes less than
|
| 470 |
+
or equal to j.
|
| 471 |
+
Clearly, pi(n) = phi(n, sqrt(n))
|
| 472 |
+
|
| 473 |
+
If j is not a prime,
|
| 474 |
+
phi(i,j) = phi(i, j - 1)
|
| 475 |
+
|
| 476 |
+
if j is a prime,
|
| 477 |
+
We remove all numbers(except j) whose
|
| 478 |
+
smallest prime factor is j.
|
| 479 |
+
|
| 480 |
+
Let $x= j \times a$ be such a number, where $2 \le a \le i / j$
|
| 481 |
+
Now, after sieving from primes $\le j - 1$,
|
| 482 |
+
a must remain
|
| 483 |
+
(because x, and hence a has no prime factor $\le j - 1$)
|
| 484 |
+
Clearly, there are phi(i / j, j - 1) such a
|
| 485 |
+
which remain on sieving from primes $\le j - 1$
|
| 486 |
+
|
| 487 |
+
Now, if a is a prime less than equal to j - 1,
|
| 488 |
+
$x= j \times a$ has smallest prime factor = a, and
|
| 489 |
+
has already been removed(by sieving from a).
|
| 490 |
+
So, we do not need to remove it again.
|
| 491 |
+
(Note: there will be pi(j - 1) such x)
|
| 492 |
+
|
| 493 |
+
Thus, number of x, that will be removed are:
|
| 494 |
+
phi(i / j, j - 1) - phi(j - 1, j - 1)
|
| 495 |
+
(Note that pi(j - 1) = phi(j - 1, j - 1))
|
| 496 |
+
|
| 497 |
+
$\Rightarrow$ phi(i,j) = phi(i, j - 1) - phi(i / j, j - 1) + phi(j - 1, j - 1)
|
| 498 |
+
|
| 499 |
+
So,following recursion is used and implemented as dp:
|
| 500 |
+
|
| 501 |
+
phi(a, b) = phi(a, b - 1), if b is not a prime
|
| 502 |
+
phi(a, b) = phi(a, b-1)-phi(a / b, b-1) + phi(b-1, b-1), if b is prime
|
| 503 |
+
|
| 504 |
+
Clearly a is always of the form floor(n / k),
|
| 505 |
+
which can take at most $2\sqrt{n}$ values.
|
| 506 |
+
Two arrays arr1,arr2 are maintained
|
| 507 |
+
arr1[i] = phi(i, j),
|
| 508 |
+
arr2[i] = phi(n // i, j)
|
| 509 |
+
|
| 510 |
+
Finally the answer is arr2[1]
|
| 511 |
+
|
| 512 |
+
Examples
|
| 513 |
+
========
|
| 514 |
+
|
| 515 |
+
>>> from sympy import primepi, prime, prevprime, isprime
|
| 516 |
+
>>> primepi(25)
|
| 517 |
+
9
|
| 518 |
+
|
| 519 |
+
So there are 9 primes less than or equal to 25. Is 25 prime?
|
| 520 |
+
|
| 521 |
+
>>> isprime(25)
|
| 522 |
+
False
|
| 523 |
+
|
| 524 |
+
It is not. So the first prime less than 25 must be the
|
| 525 |
+
9th prime:
|
| 526 |
+
|
| 527 |
+
>>> prevprime(25) == prime(9)
|
| 528 |
+
True
|
| 529 |
+
|
| 530 |
+
See Also
|
| 531 |
+
========
|
| 532 |
+
|
| 533 |
+
sympy.ntheory.primetest.isprime : Test if n is prime
|
| 534 |
+
primerange : Generate all primes in a given range
|
| 535 |
+
prime : Return the nth prime
|
| 536 |
+
"""
|
| 537 |
+
from sympy.functions.combinatorial.numbers import primepi as func_primepi
|
| 538 |
+
return func_primepi(n)
|
| 539 |
+
|
| 540 |
+
|
| 541 |
+
def _primepi(n:int) -> int:
|
| 542 |
+
r""" Represents the prime counting function pi(n) = the number
|
| 543 |
+
of prime numbers less than or equal to n.
|
| 544 |
+
|
| 545 |
+
Explanation
|
| 546 |
+
===========
|
| 547 |
+
|
| 548 |
+
In sieve method, we remove all multiples of prime p
|
| 549 |
+
except p itself.
|
| 550 |
+
|
| 551 |
+
Let phi(i,j) be the number of integers 2 <= k <= i
|
| 552 |
+
which remain after sieving from primes less than
|
| 553 |
+
or equal to j.
|
| 554 |
+
Clearly, pi(n) = phi(n, sqrt(n))
|
| 555 |
+
|
| 556 |
+
If j is not a prime,
|
| 557 |
+
phi(i,j) = phi(i, j - 1)
|
| 558 |
+
|
| 559 |
+
if j is a prime,
|
| 560 |
+
We remove all numbers(except j) whose
|
| 561 |
+
smallest prime factor is j.
|
| 562 |
+
|
| 563 |
+
Let $x= j \times a$ be such a number, where $2 \le a \le i / j$
|
| 564 |
+
Now, after sieving from primes $\le j - 1$,
|
| 565 |
+
a must remain
|
| 566 |
+
(because x, and hence a has no prime factor $\le j - 1$)
|
| 567 |
+
Clearly, there are phi(i / j, j - 1) such a
|
| 568 |
+
which remain on sieving from primes $\le j - 1$
|
| 569 |
+
|
| 570 |
+
Now, if a is a prime less than equal to j - 1,
|
| 571 |
+
$x= j \times a$ has smallest prime factor = a, and
|
| 572 |
+
has already been removed(by sieving from a).
|
| 573 |
+
So, we do not need to remove it again.
|
| 574 |
+
(Note: there will be pi(j - 1) such x)
|
| 575 |
+
|
| 576 |
+
Thus, number of x, that will be removed are:
|
| 577 |
+
phi(i / j, j - 1) - phi(j - 1, j - 1)
|
| 578 |
+
(Note that pi(j - 1) = phi(j - 1, j - 1))
|
| 579 |
+
|
| 580 |
+
$\Rightarrow$ phi(i,j) = phi(i, j - 1) - phi(i / j, j - 1) + phi(j - 1, j - 1)
|
| 581 |
+
|
| 582 |
+
So,following recursion is used and implemented as dp:
|
| 583 |
+
|
| 584 |
+
phi(a, b) = phi(a, b - 1), if b is not a prime
|
| 585 |
+
phi(a, b) = phi(a, b-1)-phi(a / b, b-1) + phi(b-1, b-1), if b is prime
|
| 586 |
+
|
| 587 |
+
Clearly a is always of the form floor(n / k),
|
| 588 |
+
which can take at most $2\sqrt{n}$ values.
|
| 589 |
+
Two arrays arr1,arr2 are maintained
|
| 590 |
+
arr1[i] = phi(i, j),
|
| 591 |
+
arr2[i] = phi(n // i, j)
|
| 592 |
+
|
| 593 |
+
Finally the answer is arr2[1]
|
| 594 |
+
|
| 595 |
+
Parameters
|
| 596 |
+
==========
|
| 597 |
+
|
| 598 |
+
n : int
|
| 599 |
+
|
| 600 |
+
"""
|
| 601 |
+
if n < 2:
|
| 602 |
+
return 0
|
| 603 |
+
if n <= sieve._list[-1]:
|
| 604 |
+
return sieve.search(n)[0]
|
| 605 |
+
lim = sqrt(n)
|
| 606 |
+
arr1 = [0] * (lim + 1)
|
| 607 |
+
arr2 = [0] * (lim + 1)
|
| 608 |
+
for i in range(1, lim + 1):
|
| 609 |
+
arr1[i] = i - 1
|
| 610 |
+
arr2[i] = n // i - 1
|
| 611 |
+
for i in range(2, lim + 1):
|
| 612 |
+
# Presently, arr1[k]=phi(k,i - 1),
|
| 613 |
+
# arr2[k] = phi(n // k,i - 1)
|
| 614 |
+
if arr1[i] == arr1[i - 1]:
|
| 615 |
+
continue
|
| 616 |
+
p = arr1[i - 1]
|
| 617 |
+
for j in range(1, min(n // (i * i), lim) + 1):
|
| 618 |
+
st = i * j
|
| 619 |
+
if st <= lim:
|
| 620 |
+
arr2[j] -= arr2[st] - p
|
| 621 |
+
else:
|
| 622 |
+
arr2[j] -= arr1[n // st] - p
|
| 623 |
+
lim2 = min(lim, i * i - 1)
|
| 624 |
+
for j in range(lim, lim2, -1):
|
| 625 |
+
arr1[j] -= arr1[j // i] - p
|
| 626 |
+
return arr2[1]
|
| 627 |
+
|
| 628 |
+
|
| 629 |
+
def nextprime(n, ith=1):
|
| 630 |
+
""" Return the ith prime greater than n.
|
| 631 |
+
|
| 632 |
+
Parameters
|
| 633 |
+
==========
|
| 634 |
+
|
| 635 |
+
n : integer
|
| 636 |
+
ith : positive integer
|
| 637 |
+
|
| 638 |
+
Returns
|
| 639 |
+
=======
|
| 640 |
+
|
| 641 |
+
int : Return the ith prime greater than n
|
| 642 |
+
|
| 643 |
+
Raises
|
| 644 |
+
======
|
| 645 |
+
|
| 646 |
+
ValueError
|
| 647 |
+
If ``ith <= 0``.
|
| 648 |
+
If ``n`` or ``ith`` is not an integer.
|
| 649 |
+
|
| 650 |
+
Notes
|
| 651 |
+
=====
|
| 652 |
+
|
| 653 |
+
Potential primes are located at 6*j +/- 1. This
|
| 654 |
+
property is used during searching.
|
| 655 |
+
|
| 656 |
+
>>> from sympy import nextprime
|
| 657 |
+
>>> [(i, nextprime(i)) for i in range(10, 15)]
|
| 658 |
+
[(10, 11), (11, 13), (12, 13), (13, 17), (14, 17)]
|
| 659 |
+
>>> nextprime(2, ith=2) # the 2nd prime after 2
|
| 660 |
+
5
|
| 661 |
+
|
| 662 |
+
See Also
|
| 663 |
+
========
|
| 664 |
+
|
| 665 |
+
prevprime : Return the largest prime smaller than n
|
| 666 |
+
primerange : Generate all primes in a given range
|
| 667 |
+
|
| 668 |
+
"""
|
| 669 |
+
n = int(n)
|
| 670 |
+
i = as_int(ith)
|
| 671 |
+
if i <= 0:
|
| 672 |
+
raise ValueError("ith should be positive")
|
| 673 |
+
if n < 2:
|
| 674 |
+
n = 2
|
| 675 |
+
i -= 1
|
| 676 |
+
if n <= sieve._list[-2]:
|
| 677 |
+
l, _ = sieve.search(n)
|
| 678 |
+
if l + i - 1 < len(sieve._list):
|
| 679 |
+
return sieve._list[l + i - 1]
|
| 680 |
+
return nextprime(sieve._list[-1], l + i - len(sieve._list))
|
| 681 |
+
if 1 < i:
|
| 682 |
+
for _ in range(i):
|
| 683 |
+
n = nextprime(n)
|
| 684 |
+
return n
|
| 685 |
+
nn = 6*(n//6)
|
| 686 |
+
if nn == n:
|
| 687 |
+
n += 1
|
| 688 |
+
if isprime(n):
|
| 689 |
+
return n
|
| 690 |
+
n += 4
|
| 691 |
+
elif n - nn == 5:
|
| 692 |
+
n += 2
|
| 693 |
+
if isprime(n):
|
| 694 |
+
return n
|
| 695 |
+
n += 4
|
| 696 |
+
else:
|
| 697 |
+
n = nn + 5
|
| 698 |
+
while 1:
|
| 699 |
+
if isprime(n):
|
| 700 |
+
return n
|
| 701 |
+
n += 2
|
| 702 |
+
if isprime(n):
|
| 703 |
+
return n
|
| 704 |
+
n += 4
|
| 705 |
+
|
| 706 |
+
|
| 707 |
+
def prevprime(n):
|
| 708 |
+
""" Return the largest prime smaller than n.
|
| 709 |
+
|
| 710 |
+
Notes
|
| 711 |
+
=====
|
| 712 |
+
|
| 713 |
+
Potential primes are located at 6*j +/- 1. This
|
| 714 |
+
property is used during searching.
|
| 715 |
+
|
| 716 |
+
>>> from sympy import prevprime
|
| 717 |
+
>>> [(i, prevprime(i)) for i in range(10, 15)]
|
| 718 |
+
[(10, 7), (11, 7), (12, 11), (13, 11), (14, 13)]
|
| 719 |
+
|
| 720 |
+
See Also
|
| 721 |
+
========
|
| 722 |
+
|
| 723 |
+
nextprime : Return the ith prime greater than n
|
| 724 |
+
primerange : Generates all primes in a given range
|
| 725 |
+
"""
|
| 726 |
+
n = _as_int_ceiling(n)
|
| 727 |
+
if n < 3:
|
| 728 |
+
raise ValueError("no preceding primes")
|
| 729 |
+
if n < 8:
|
| 730 |
+
return {3: 2, 4: 3, 5: 3, 6: 5, 7: 5}[n]
|
| 731 |
+
if n <= sieve._list[-1]:
|
| 732 |
+
l, u = sieve.search(n)
|
| 733 |
+
if l == u:
|
| 734 |
+
return sieve[l-1]
|
| 735 |
+
else:
|
| 736 |
+
return sieve[l]
|
| 737 |
+
nn = 6*(n//6)
|
| 738 |
+
if n - nn <= 1:
|
| 739 |
+
n = nn - 1
|
| 740 |
+
if isprime(n):
|
| 741 |
+
return n
|
| 742 |
+
n -= 4
|
| 743 |
+
else:
|
| 744 |
+
n = nn + 1
|
| 745 |
+
while 1:
|
| 746 |
+
if isprime(n):
|
| 747 |
+
return n
|
| 748 |
+
n -= 2
|
| 749 |
+
if isprime(n):
|
| 750 |
+
return n
|
| 751 |
+
n -= 4
|
| 752 |
+
|
| 753 |
+
|
| 754 |
+
def primerange(a, b=None):
|
| 755 |
+
""" Generate a list of all prime numbers in the range [2, a),
|
| 756 |
+
or [a, b).
|
| 757 |
+
|
| 758 |
+
If the range exists in the default sieve, the values will
|
| 759 |
+
be returned from there; otherwise values will be returned
|
| 760 |
+
but will not modify the sieve.
|
| 761 |
+
|
| 762 |
+
Examples
|
| 763 |
+
========
|
| 764 |
+
|
| 765 |
+
>>> from sympy import primerange, prime
|
| 766 |
+
|
| 767 |
+
All primes less than 19:
|
| 768 |
+
|
| 769 |
+
>>> list(primerange(19))
|
| 770 |
+
[2, 3, 5, 7, 11, 13, 17]
|
| 771 |
+
|
| 772 |
+
All primes greater than or equal to 7 and less than 19:
|
| 773 |
+
|
| 774 |
+
>>> list(primerange(7, 19))
|
| 775 |
+
[7, 11, 13, 17]
|
| 776 |
+
|
| 777 |
+
All primes through the 10th prime
|
| 778 |
+
|
| 779 |
+
>>> list(primerange(prime(10) + 1))
|
| 780 |
+
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
|
| 781 |
+
|
| 782 |
+
The Sieve method, primerange, is generally faster but it will
|
| 783 |
+
occupy more memory as the sieve stores values. The default
|
| 784 |
+
instance of Sieve, named sieve, can be used:
|
| 785 |
+
|
| 786 |
+
>>> from sympy import sieve
|
| 787 |
+
>>> list(sieve.primerange(1, 30))
|
| 788 |
+
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
|
| 789 |
+
|
| 790 |
+
Notes
|
| 791 |
+
=====
|
| 792 |
+
|
| 793 |
+
Some famous conjectures about the occurrence of primes in a given
|
| 794 |
+
range are [1]:
|
| 795 |
+
|
| 796 |
+
- Twin primes: though often not, the following will give 2 primes
|
| 797 |
+
an infinite number of times:
|
| 798 |
+
primerange(6*n - 1, 6*n + 2)
|
| 799 |
+
- Legendre's: the following always yields at least one prime
|
| 800 |
+
primerange(n**2, (n+1)**2+1)
|
| 801 |
+
- Bertrand's (proven): there is always a prime in the range
|
| 802 |
+
primerange(n, 2*n)
|
| 803 |
+
- Brocard's: there are at least four primes in the range
|
| 804 |
+
primerange(prime(n)**2, prime(n+1)**2)
|
| 805 |
+
|
| 806 |
+
The average gap between primes is log(n) [2]; the gap between
|
| 807 |
+
primes can be arbitrarily large since sequences of composite
|
| 808 |
+
numbers are arbitrarily large, e.g. the numbers in the sequence
|
| 809 |
+
n! + 2, n! + 3 ... n! + n are all composite.
|
| 810 |
+
|
| 811 |
+
See Also
|
| 812 |
+
========
|
| 813 |
+
|
| 814 |
+
prime : Return the nth prime
|
| 815 |
+
nextprime : Return the ith prime greater than n
|
| 816 |
+
prevprime : Return the largest prime smaller than n
|
| 817 |
+
randprime : Returns a random prime in a given range
|
| 818 |
+
primorial : Returns the product of primes based on condition
|
| 819 |
+
Sieve.primerange : return range from already computed primes
|
| 820 |
+
or extend the sieve to contain the requested
|
| 821 |
+
range.
|
| 822 |
+
|
| 823 |
+
References
|
| 824 |
+
==========
|
| 825 |
+
|
| 826 |
+
.. [1] https://en.wikipedia.org/wiki/Prime_number
|
| 827 |
+
.. [2] https://primes.utm.edu/notes/gaps.html
|
| 828 |
+
"""
|
| 829 |
+
if b is None:
|
| 830 |
+
a, b = 2, a
|
| 831 |
+
if a >= b:
|
| 832 |
+
return
|
| 833 |
+
# If we already have the range, return it.
|
| 834 |
+
largest_known_prime = sieve._list[-1]
|
| 835 |
+
if b <= largest_known_prime:
|
| 836 |
+
yield from sieve.primerange(a, b)
|
| 837 |
+
return
|
| 838 |
+
# If we know some of it, return it.
|
| 839 |
+
if a <= largest_known_prime:
|
| 840 |
+
yield from sieve._list[bisect_left(sieve._list, a):]
|
| 841 |
+
a = largest_known_prime + 1
|
| 842 |
+
elif a % 2:
|
| 843 |
+
a -= 1
|
| 844 |
+
tail = min(b, (largest_known_prime)**2)
|
| 845 |
+
if a < tail:
|
| 846 |
+
yield from sieve._primerange(a, tail)
|
| 847 |
+
a = tail
|
| 848 |
+
if b <= a:
|
| 849 |
+
return
|
| 850 |
+
# otherwise compute, without storing, the desired range.
|
| 851 |
+
while 1:
|
| 852 |
+
a = nextprime(a)
|
| 853 |
+
if a < b:
|
| 854 |
+
yield a
|
| 855 |
+
else:
|
| 856 |
+
return
|
| 857 |
+
|
| 858 |
+
|
| 859 |
+
def randprime(a, b):
|
| 860 |
+
""" Return a random prime number in the range [a, b).
|
| 861 |
+
|
| 862 |
+
Bertrand's postulate assures that
|
| 863 |
+
randprime(a, 2*a) will always succeed for a > 1.
|
| 864 |
+
|
| 865 |
+
Note that due to implementation difficulties,
|
| 866 |
+
the prime numbers chosen are not uniformly random.
|
| 867 |
+
For example, there are two primes in the range [112, 128),
|
| 868 |
+
``113`` and ``127``, but ``randprime(112, 128)`` returns ``127``
|
| 869 |
+
with a probability of 15/17.
|
| 870 |
+
|
| 871 |
+
Examples
|
| 872 |
+
========
|
| 873 |
+
|
| 874 |
+
>>> from sympy import randprime, isprime
|
| 875 |
+
>>> randprime(1, 30) #doctest: +SKIP
|
| 876 |
+
13
|
| 877 |
+
>>> isprime(randprime(1, 30))
|
| 878 |
+
True
|
| 879 |
+
|
| 880 |
+
See Also
|
| 881 |
+
========
|
| 882 |
+
|
| 883 |
+
primerange : Generate all primes in a given range
|
| 884 |
+
|
| 885 |
+
References
|
| 886 |
+
==========
|
| 887 |
+
|
| 888 |
+
.. [1] https://en.wikipedia.org/wiki/Bertrand's_postulate
|
| 889 |
+
|
| 890 |
+
"""
|
| 891 |
+
if a >= b:
|
| 892 |
+
return
|
| 893 |
+
a, b = map(int, (a, b))
|
| 894 |
+
n = randint(a - 1, b)
|
| 895 |
+
p = nextprime(n)
|
| 896 |
+
if p >= b:
|
| 897 |
+
p = prevprime(b)
|
| 898 |
+
if p < a:
|
| 899 |
+
raise ValueError("no primes exist in the specified range")
|
| 900 |
+
return p
|
| 901 |
+
|
| 902 |
+
|
| 903 |
+
def primorial(n, nth=True):
|
| 904 |
+
"""
|
| 905 |
+
Returns the product of the first n primes (default) or
|
| 906 |
+
the primes less than or equal to n (when ``nth=False``).
|
| 907 |
+
|
| 908 |
+
Examples
|
| 909 |
+
========
|
| 910 |
+
|
| 911 |
+
>>> from sympy.ntheory.generate import primorial, primerange
|
| 912 |
+
>>> from sympy import factorint, Mul, primefactors, sqrt
|
| 913 |
+
>>> primorial(4) # the first 4 primes are 2, 3, 5, 7
|
| 914 |
+
210
|
| 915 |
+
>>> primorial(4, nth=False) # primes <= 4 are 2 and 3
|
| 916 |
+
6
|
| 917 |
+
>>> primorial(1)
|
| 918 |
+
2
|
| 919 |
+
>>> primorial(1, nth=False)
|
| 920 |
+
1
|
| 921 |
+
>>> primorial(sqrt(101), nth=False)
|
| 922 |
+
210
|
| 923 |
+
|
| 924 |
+
One can argue that the primes are infinite since if you take
|
| 925 |
+
a set of primes and multiply them together (e.g. the primorial) and
|
| 926 |
+
then add or subtract 1, the result cannot be divided by any of the
|
| 927 |
+
original factors, hence either 1 or more new primes must divide this
|
| 928 |
+
product of primes.
|
| 929 |
+
|
| 930 |
+
In this case, the number itself is a new prime:
|
| 931 |
+
|
| 932 |
+
>>> factorint(primorial(4) + 1)
|
| 933 |
+
{211: 1}
|
| 934 |
+
|
| 935 |
+
In this case two new primes are the factors:
|
| 936 |
+
|
| 937 |
+
>>> factorint(primorial(4) - 1)
|
| 938 |
+
{11: 1, 19: 1}
|
| 939 |
+
|
| 940 |
+
Here, some primes smaller and larger than the primes multiplied together
|
| 941 |
+
are obtained:
|
| 942 |
+
|
| 943 |
+
>>> p = list(primerange(10, 20))
|
| 944 |
+
>>> sorted(set(primefactors(Mul(*p) + 1)).difference(set(p)))
|
| 945 |
+
[2, 5, 31, 149]
|
| 946 |
+
|
| 947 |
+
See Also
|
| 948 |
+
========
|
| 949 |
+
|
| 950 |
+
primerange : Generate all primes in a given range
|
| 951 |
+
|
| 952 |
+
"""
|
| 953 |
+
if nth:
|
| 954 |
+
n = as_int(n)
|
| 955 |
+
else:
|
| 956 |
+
n = int(n)
|
| 957 |
+
if n < 1:
|
| 958 |
+
raise ValueError("primorial argument must be >= 1")
|
| 959 |
+
p = 1
|
| 960 |
+
if nth:
|
| 961 |
+
for i in range(1, n + 1):
|
| 962 |
+
p *= prime(i)
|
| 963 |
+
else:
|
| 964 |
+
for i in primerange(2, n + 1):
|
| 965 |
+
p *= i
|
| 966 |
+
return p
|
| 967 |
+
|
| 968 |
+
|
| 969 |
+
def cycle_length(f, x0, nmax=None, values=False):
|
| 970 |
+
"""For a given iterated sequence, return a generator that gives
|
| 971 |
+
the length of the iterated cycle (lambda) and the length of terms
|
| 972 |
+
before the cycle begins (mu); if ``values`` is True then the
|
| 973 |
+
terms of the sequence will be returned instead. The sequence is
|
| 974 |
+
started with value ``x0``.
|
| 975 |
+
|
| 976 |
+
Note: more than the first lambda + mu terms may be returned and this
|
| 977 |
+
is the cost of cycle detection with Brent's method; there are, however,
|
| 978 |
+
generally less terms calculated than would have been calculated if the
|
| 979 |
+
proper ending point were determined, e.g. by using Floyd's method.
|
| 980 |
+
|
| 981 |
+
>>> from sympy.ntheory.generate import cycle_length
|
| 982 |
+
|
| 983 |
+
This will yield successive values of i <-- func(i):
|
| 984 |
+
|
| 985 |
+
>>> def gen(func, i):
|
| 986 |
+
... while 1:
|
| 987 |
+
... yield i
|
| 988 |
+
... i = func(i)
|
| 989 |
+
...
|
| 990 |
+
|
| 991 |
+
A function is defined:
|
| 992 |
+
|
| 993 |
+
>>> func = lambda i: (i**2 + 1) % 51
|
| 994 |
+
|
| 995 |
+
and given a seed of 4 and the mu and lambda terms calculated:
|
| 996 |
+
|
| 997 |
+
>>> next(cycle_length(func, 4))
|
| 998 |
+
(6, 3)
|
| 999 |
+
|
| 1000 |
+
We can see what is meant by looking at the output:
|
| 1001 |
+
|
| 1002 |
+
>>> iter = cycle_length(func, 4, values=True)
|
| 1003 |
+
>>> list(iter)
|
| 1004 |
+
[4, 17, 35, 2, 5, 26, 14, 44, 50, 2, 5, 26, 14]
|
| 1005 |
+
|
| 1006 |
+
There are 6 repeating values after the first 3.
|
| 1007 |
+
|
| 1008 |
+
If a sequence is suspected of being longer than you might wish, ``nmax``
|
| 1009 |
+
can be used to exit early (and mu will be returned as None):
|
| 1010 |
+
|
| 1011 |
+
>>> next(cycle_length(func, 4, nmax = 4))
|
| 1012 |
+
(4, None)
|
| 1013 |
+
>>> list(cycle_length(func, 4, nmax = 4, values=True))
|
| 1014 |
+
[4, 17, 35, 2]
|
| 1015 |
+
|
| 1016 |
+
Code modified from:
|
| 1017 |
+
https://en.wikipedia.org/wiki/Cycle_detection.
|
| 1018 |
+
"""
|
| 1019 |
+
|
| 1020 |
+
nmax = int(nmax or 0)
|
| 1021 |
+
|
| 1022 |
+
# main phase: search successive powers of two
|
| 1023 |
+
power = lam = 1
|
| 1024 |
+
tortoise, hare = x0, f(x0) # f(x0) is the element/node next to x0.
|
| 1025 |
+
i = 1
|
| 1026 |
+
if values:
|
| 1027 |
+
yield tortoise
|
| 1028 |
+
while tortoise != hare and (not nmax or i < nmax):
|
| 1029 |
+
i += 1
|
| 1030 |
+
if power == lam: # time to start a new power of two?
|
| 1031 |
+
tortoise = hare
|
| 1032 |
+
power *= 2
|
| 1033 |
+
lam = 0
|
| 1034 |
+
if values:
|
| 1035 |
+
yield hare
|
| 1036 |
+
hare = f(hare)
|
| 1037 |
+
lam += 1
|
| 1038 |
+
if nmax and i == nmax:
|
| 1039 |
+
if values:
|
| 1040 |
+
return
|
| 1041 |
+
else:
|
| 1042 |
+
yield nmax, None
|
| 1043 |
+
return
|
| 1044 |
+
if not values:
|
| 1045 |
+
# Find the position of the first repetition of length lambda
|
| 1046 |
+
mu = 0
|
| 1047 |
+
tortoise = hare = x0
|
| 1048 |
+
for i in range(lam):
|
| 1049 |
+
hare = f(hare)
|
| 1050 |
+
while tortoise != hare:
|
| 1051 |
+
tortoise = f(tortoise)
|
| 1052 |
+
hare = f(hare)
|
| 1053 |
+
mu += 1
|
| 1054 |
+
yield lam, mu
|
| 1055 |
+
|
| 1056 |
+
|
| 1057 |
+
def composite(nth):
|
| 1058 |
+
""" Return the nth composite number, with the composite numbers indexed as
|
| 1059 |
+
composite(1) = 4, composite(2) = 6, etc....
|
| 1060 |
+
|
| 1061 |
+
Examples
|
| 1062 |
+
========
|
| 1063 |
+
|
| 1064 |
+
>>> from sympy import composite
|
| 1065 |
+
>>> composite(36)
|
| 1066 |
+
52
|
| 1067 |
+
>>> composite(1)
|
| 1068 |
+
4
|
| 1069 |
+
>>> composite(17737)
|
| 1070 |
+
20000
|
| 1071 |
+
|
| 1072 |
+
See Also
|
| 1073 |
+
========
|
| 1074 |
+
|
| 1075 |
+
sympy.ntheory.primetest.isprime : Test if n is prime
|
| 1076 |
+
primerange : Generate all primes in a given range
|
| 1077 |
+
primepi : Return the number of primes less than or equal to n
|
| 1078 |
+
prime : Return the nth prime
|
| 1079 |
+
compositepi : Return the number of positive composite numbers less than or equal to n
|
| 1080 |
+
"""
|
| 1081 |
+
n = as_int(nth)
|
| 1082 |
+
if n < 1:
|
| 1083 |
+
raise ValueError("nth must be a positive integer; composite(1) == 4")
|
| 1084 |
+
composite_arr = [4, 6, 8, 9, 10, 12, 14, 15, 16, 18]
|
| 1085 |
+
if n <= 10:
|
| 1086 |
+
return composite_arr[n - 1]
|
| 1087 |
+
|
| 1088 |
+
a, b = 4, sieve._list[-1]
|
| 1089 |
+
if n <= b - _primepi(b) - 1:
|
| 1090 |
+
while a < b - 1:
|
| 1091 |
+
mid = (a + b) >> 1
|
| 1092 |
+
if mid - _primepi(mid) - 1 > n:
|
| 1093 |
+
b = mid
|
| 1094 |
+
else:
|
| 1095 |
+
a = mid
|
| 1096 |
+
if isprime(a):
|
| 1097 |
+
a -= 1
|
| 1098 |
+
return a
|
| 1099 |
+
|
| 1100 |
+
from sympy.functions.elementary.exponential import log
|
| 1101 |
+
from sympy.functions.special.error_functions import li
|
| 1102 |
+
a = 4 # Lower bound for binary search
|
| 1103 |
+
b = int(n*(log(n) + log(log(n)))) # Upper bound for the search.
|
| 1104 |
+
|
| 1105 |
+
while a < b:
|
| 1106 |
+
mid = (a + b) >> 1
|
| 1107 |
+
if mid - li(mid) - 1 > n:
|
| 1108 |
+
b = mid
|
| 1109 |
+
else:
|
| 1110 |
+
a = mid + 1
|
| 1111 |
+
|
| 1112 |
+
n_composites = a - _primepi(a) - 1
|
| 1113 |
+
while n_composites > n:
|
| 1114 |
+
if not isprime(a):
|
| 1115 |
+
n_composites -= 1
|
| 1116 |
+
a -= 1
|
| 1117 |
+
if isprime(a):
|
| 1118 |
+
a -= 1
|
| 1119 |
+
return a
|
| 1120 |
+
|
| 1121 |
+
|
| 1122 |
+
def compositepi(n):
|
| 1123 |
+
""" Return the number of positive composite numbers less than or equal to n.
|
| 1124 |
+
The first positive composite is 4, i.e. compositepi(4) = 1.
|
| 1125 |
+
|
| 1126 |
+
Examples
|
| 1127 |
+
========
|
| 1128 |
+
|
| 1129 |
+
>>> from sympy import compositepi
|
| 1130 |
+
>>> compositepi(25)
|
| 1131 |
+
15
|
| 1132 |
+
>>> compositepi(1000)
|
| 1133 |
+
831
|
| 1134 |
+
|
| 1135 |
+
See Also
|
| 1136 |
+
========
|
| 1137 |
+
|
| 1138 |
+
sympy.ntheory.primetest.isprime : Test if n is prime
|
| 1139 |
+
primerange : Generate all primes in a given range
|
| 1140 |
+
prime : Return the nth prime
|
| 1141 |
+
primepi : Return the number of primes less than or equal to n
|
| 1142 |
+
composite : Return the nth composite number
|
| 1143 |
+
"""
|
| 1144 |
+
n = int(n)
|
| 1145 |
+
if n < 4:
|
| 1146 |
+
return 0
|
| 1147 |
+
return n - _primepi(n) - 1
|
lib/python3.12/site-packages/sympy/ntheory/modular.py
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from math import prod
|
| 2 |
+
|
| 3 |
+
from sympy.external.gmpy import gcd, gcdext
|
| 4 |
+
from sympy.ntheory.primetest import isprime
|
| 5 |
+
from sympy.polys.domains import ZZ
|
| 6 |
+
from sympy.polys.galoistools import gf_crt, gf_crt1, gf_crt2
|
| 7 |
+
from sympy.utilities.misc import as_int
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def symmetric_residue(a, m):
|
| 11 |
+
"""Return the residual mod m such that it is within half of the modulus.
|
| 12 |
+
|
| 13 |
+
>>> from sympy.ntheory.modular import symmetric_residue
|
| 14 |
+
>>> symmetric_residue(1, 6)
|
| 15 |
+
1
|
| 16 |
+
>>> symmetric_residue(4, 6)
|
| 17 |
+
-2
|
| 18 |
+
"""
|
| 19 |
+
if a <= m // 2:
|
| 20 |
+
return a
|
| 21 |
+
return a - m
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def crt(m, v, symmetric=False, check=True):
|
| 25 |
+
r"""Chinese Remainder Theorem.
|
| 26 |
+
|
| 27 |
+
The moduli in m are assumed to be pairwise coprime. The output
|
| 28 |
+
is then an integer f, such that f = v_i mod m_i for each pair out
|
| 29 |
+
of v and m. If ``symmetric`` is False a positive integer will be
|
| 30 |
+
returned, else \|f\| will be less than or equal to the LCM of the
|
| 31 |
+
moduli, and thus f may be negative.
|
| 32 |
+
|
| 33 |
+
If the moduli are not co-prime the correct result will be returned
|
| 34 |
+
if/when the test of the result is found to be incorrect. This result
|
| 35 |
+
will be None if there is no solution.
|
| 36 |
+
|
| 37 |
+
The keyword ``check`` can be set to False if it is known that the moduli
|
| 38 |
+
are coprime.
|
| 39 |
+
|
| 40 |
+
Examples
|
| 41 |
+
========
|
| 42 |
+
|
| 43 |
+
As an example consider a set of residues ``U = [49, 76, 65]``
|
| 44 |
+
and a set of moduli ``M = [99, 97, 95]``. Then we have::
|
| 45 |
+
|
| 46 |
+
>>> from sympy.ntheory.modular import crt
|
| 47 |
+
|
| 48 |
+
>>> crt([99, 97, 95], [49, 76, 65])
|
| 49 |
+
(639985, 912285)
|
| 50 |
+
|
| 51 |
+
This is the correct result because::
|
| 52 |
+
|
| 53 |
+
>>> [639985 % m for m in [99, 97, 95]]
|
| 54 |
+
[49, 76, 65]
|
| 55 |
+
|
| 56 |
+
If the moduli are not co-prime, you may receive an incorrect result
|
| 57 |
+
if you use ``check=False``:
|
| 58 |
+
|
| 59 |
+
>>> crt([12, 6, 17], [3, 4, 2], check=False)
|
| 60 |
+
(954, 1224)
|
| 61 |
+
>>> [954 % m for m in [12, 6, 17]]
|
| 62 |
+
[6, 0, 2]
|
| 63 |
+
>>> crt([12, 6, 17], [3, 4, 2]) is None
|
| 64 |
+
True
|
| 65 |
+
>>> crt([3, 6], [2, 5])
|
| 66 |
+
(5, 6)
|
| 67 |
+
|
| 68 |
+
Note: the order of gf_crt's arguments is reversed relative to crt,
|
| 69 |
+
and that solve_congruence takes residue, modulus pairs.
|
| 70 |
+
|
| 71 |
+
Programmer's note: rather than checking that all pairs of moduli share
|
| 72 |
+
no GCD (an O(n**2) test) and rather than factoring all moduli and seeing
|
| 73 |
+
that there is no factor in common, a check that the result gives the
|
| 74 |
+
indicated residuals is performed -- an O(n) operation.
|
| 75 |
+
|
| 76 |
+
See Also
|
| 77 |
+
========
|
| 78 |
+
|
| 79 |
+
solve_congruence
|
| 80 |
+
sympy.polys.galoistools.gf_crt : low level crt routine used by this routine
|
| 81 |
+
"""
|
| 82 |
+
if check:
|
| 83 |
+
m = list(map(as_int, m))
|
| 84 |
+
v = list(map(as_int, v))
|
| 85 |
+
|
| 86 |
+
result = gf_crt(v, m, ZZ)
|
| 87 |
+
mm = prod(m)
|
| 88 |
+
|
| 89 |
+
if check:
|
| 90 |
+
if not all(v % m == result % m for v, m in zip(v, m)):
|
| 91 |
+
result = solve_congruence(*list(zip(v, m)),
|
| 92 |
+
check=False, symmetric=symmetric)
|
| 93 |
+
if result is None:
|
| 94 |
+
return result
|
| 95 |
+
result, mm = result
|
| 96 |
+
|
| 97 |
+
if symmetric:
|
| 98 |
+
return int(symmetric_residue(result, mm)), int(mm)
|
| 99 |
+
return int(result), int(mm)
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def crt1(m):
|
| 103 |
+
"""First part of Chinese Remainder Theorem, for multiple application.
|
| 104 |
+
|
| 105 |
+
Examples
|
| 106 |
+
========
|
| 107 |
+
|
| 108 |
+
>>> from sympy.ntheory.modular import crt, crt1, crt2
|
| 109 |
+
>>> m = [99, 97, 95]
|
| 110 |
+
>>> v = [49, 76, 65]
|
| 111 |
+
|
| 112 |
+
The following two codes have the same result.
|
| 113 |
+
|
| 114 |
+
>>> crt(m, v)
|
| 115 |
+
(639985, 912285)
|
| 116 |
+
|
| 117 |
+
>>> mm, e, s = crt1(m)
|
| 118 |
+
>>> crt2(m, v, mm, e, s)
|
| 119 |
+
(639985, 912285)
|
| 120 |
+
|
| 121 |
+
However, it is faster when we want to fix ``m`` and
|
| 122 |
+
compute for multiple ``v``, i.e. the following cases:
|
| 123 |
+
|
| 124 |
+
>>> mm, e, s = crt1(m)
|
| 125 |
+
>>> vs = [[52, 21, 37], [19, 46, 76]]
|
| 126 |
+
>>> for v in vs:
|
| 127 |
+
... print(crt2(m, v, mm, e, s))
|
| 128 |
+
(397042, 912285)
|
| 129 |
+
(803206, 912285)
|
| 130 |
+
|
| 131 |
+
See Also
|
| 132 |
+
========
|
| 133 |
+
|
| 134 |
+
sympy.polys.galoistools.gf_crt1 : low level crt routine used by this routine
|
| 135 |
+
sympy.ntheory.modular.crt
|
| 136 |
+
sympy.ntheory.modular.crt2
|
| 137 |
+
|
| 138 |
+
"""
|
| 139 |
+
|
| 140 |
+
return gf_crt1(m, ZZ)
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
def crt2(m, v, mm, e, s, symmetric=False):
|
| 144 |
+
"""Second part of Chinese Remainder Theorem, for multiple application.
|
| 145 |
+
|
| 146 |
+
See ``crt1`` for usage.
|
| 147 |
+
|
| 148 |
+
Examples
|
| 149 |
+
========
|
| 150 |
+
|
| 151 |
+
>>> from sympy.ntheory.modular import crt1, crt2
|
| 152 |
+
>>> mm, e, s = crt1([18, 42, 6])
|
| 153 |
+
>>> crt2([18, 42, 6], [0, 0, 0], mm, e, s)
|
| 154 |
+
(0, 4536)
|
| 155 |
+
|
| 156 |
+
See Also
|
| 157 |
+
========
|
| 158 |
+
|
| 159 |
+
sympy.polys.galoistools.gf_crt2 : low level crt routine used by this routine
|
| 160 |
+
sympy.ntheory.modular.crt
|
| 161 |
+
sympy.ntheory.modular.crt1
|
| 162 |
+
|
| 163 |
+
"""
|
| 164 |
+
|
| 165 |
+
result = gf_crt2(v, m, mm, e, s, ZZ)
|
| 166 |
+
|
| 167 |
+
if symmetric:
|
| 168 |
+
return int(symmetric_residue(result, mm)), int(mm)
|
| 169 |
+
return int(result), int(mm)
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
def solve_congruence(*remainder_modulus_pairs, **hint):
|
| 173 |
+
"""Compute the integer ``n`` that has the residual ``ai`` when it is
|
| 174 |
+
divided by ``mi`` where the ``ai`` and ``mi`` are given as pairs to
|
| 175 |
+
this function: ((a1, m1), (a2, m2), ...). If there is no solution,
|
| 176 |
+
return None. Otherwise return ``n`` and its modulus.
|
| 177 |
+
|
| 178 |
+
The ``mi`` values need not be co-prime. If it is known that the moduli are
|
| 179 |
+
not co-prime then the hint ``check`` can be set to False (default=True) and
|
| 180 |
+
the check for a quicker solution via crt() (valid when the moduli are
|
| 181 |
+
co-prime) will be skipped.
|
| 182 |
+
|
| 183 |
+
If the hint ``symmetric`` is True (default is False), the value of ``n``
|
| 184 |
+
will be within 1/2 of the modulus, possibly negative.
|
| 185 |
+
|
| 186 |
+
Examples
|
| 187 |
+
========
|
| 188 |
+
|
| 189 |
+
>>> from sympy.ntheory.modular import solve_congruence
|
| 190 |
+
|
| 191 |
+
What number is 2 mod 3, 3 mod 5 and 2 mod 7?
|
| 192 |
+
|
| 193 |
+
>>> solve_congruence((2, 3), (3, 5), (2, 7))
|
| 194 |
+
(23, 105)
|
| 195 |
+
>>> [23 % m for m in [3, 5, 7]]
|
| 196 |
+
[2, 3, 2]
|
| 197 |
+
|
| 198 |
+
If you prefer to work with all remainder in one list and
|
| 199 |
+
all moduli in another, send the arguments like this:
|
| 200 |
+
|
| 201 |
+
>>> solve_congruence(*zip((2, 3, 2), (3, 5, 7)))
|
| 202 |
+
(23, 105)
|
| 203 |
+
|
| 204 |
+
The moduli need not be co-prime; in this case there may or
|
| 205 |
+
may not be a solution:
|
| 206 |
+
|
| 207 |
+
>>> solve_congruence((2, 3), (4, 6)) is None
|
| 208 |
+
True
|
| 209 |
+
|
| 210 |
+
>>> solve_congruence((2, 3), (5, 6))
|
| 211 |
+
(5, 6)
|
| 212 |
+
|
| 213 |
+
The symmetric flag will make the result be within 1/2 of the modulus:
|
| 214 |
+
|
| 215 |
+
>>> solve_congruence((2, 3), (5, 6), symmetric=True)
|
| 216 |
+
(-1, 6)
|
| 217 |
+
|
| 218 |
+
See Also
|
| 219 |
+
========
|
| 220 |
+
|
| 221 |
+
crt : high level routine implementing the Chinese Remainder Theorem
|
| 222 |
+
|
| 223 |
+
"""
|
| 224 |
+
def combine(c1, c2):
|
| 225 |
+
"""Return the tuple (a, m) which satisfies the requirement
|
| 226 |
+
that n = a + i*m satisfy n = a1 + j*m1 and n = a2 = k*m2.
|
| 227 |
+
|
| 228 |
+
References
|
| 229 |
+
==========
|
| 230 |
+
|
| 231 |
+
.. [1] https://en.wikipedia.org/wiki/Method_of_successive_substitution
|
| 232 |
+
"""
|
| 233 |
+
a1, m1 = c1
|
| 234 |
+
a2, m2 = c2
|
| 235 |
+
a, b, c = m1, a2 - a1, m2
|
| 236 |
+
g = gcd(a, b, c)
|
| 237 |
+
a, b, c = [i//g for i in [a, b, c]]
|
| 238 |
+
if a != 1:
|
| 239 |
+
g, inv_a, _ = gcdext(a, c)
|
| 240 |
+
if g != 1:
|
| 241 |
+
return None
|
| 242 |
+
b *= inv_a
|
| 243 |
+
a, m = a1 + m1*b, m1*c
|
| 244 |
+
return a, m
|
| 245 |
+
|
| 246 |
+
rm = remainder_modulus_pairs
|
| 247 |
+
symmetric = hint.get('symmetric', False)
|
| 248 |
+
|
| 249 |
+
if hint.get('check', True):
|
| 250 |
+
rm = [(as_int(r), as_int(m)) for r, m in rm]
|
| 251 |
+
|
| 252 |
+
# ignore redundant pairs but raise an error otherwise; also
|
| 253 |
+
# make sure that a unique set of bases is sent to gf_crt if
|
| 254 |
+
# they are all prime.
|
| 255 |
+
#
|
| 256 |
+
# The routine will work out less-trivial violations and
|
| 257 |
+
# return None, e.g. for the pairs (1,3) and (14,42) there
|
| 258 |
+
# is no answer because 14 mod 42 (having a gcd of 14) implies
|
| 259 |
+
# (14/2) mod (42/2), (14/7) mod (42/7) and (14/14) mod (42/14)
|
| 260 |
+
# which, being 0 mod 3, is inconsistent with 1 mod 3. But to
|
| 261 |
+
# preprocess the input beyond checking of another pair with 42
|
| 262 |
+
# or 3 as the modulus (for this example) is not necessary.
|
| 263 |
+
uniq = {}
|
| 264 |
+
for r, m in rm:
|
| 265 |
+
r %= m
|
| 266 |
+
if m in uniq:
|
| 267 |
+
if r != uniq[m]:
|
| 268 |
+
return None
|
| 269 |
+
continue
|
| 270 |
+
uniq[m] = r
|
| 271 |
+
rm = [(r, m) for m, r in uniq.items()]
|
| 272 |
+
del uniq
|
| 273 |
+
|
| 274 |
+
# if the moduli are co-prime, the crt will be significantly faster;
|
| 275 |
+
# checking all pairs for being co-prime gets to be slow but a prime
|
| 276 |
+
# test is a good trade-off
|
| 277 |
+
if all(isprime(m) for r, m in rm):
|
| 278 |
+
r, m = list(zip(*rm))
|
| 279 |
+
return crt(m, r, symmetric=symmetric, check=False)
|
| 280 |
+
|
| 281 |
+
rv = (0, 1)
|
| 282 |
+
for rmi in rm:
|
| 283 |
+
rv = combine(rv, rmi)
|
| 284 |
+
if rv is None:
|
| 285 |
+
break
|
| 286 |
+
n, m = rv
|
| 287 |
+
n = n % m
|
| 288 |
+
else:
|
| 289 |
+
if symmetric:
|
| 290 |
+
return symmetric_residue(n, m), m
|
| 291 |
+
return n, m
|
lib/python3.12/site-packages/sympy/ntheory/multinomial.py
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.utilities.misc import as_int
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def binomial_coefficients(n):
|
| 5 |
+
"""Return a dictionary containing pairs :math:`{(k1,k2) : C_kn}` where
|
| 6 |
+
:math:`C_kn` are binomial coefficients and :math:`n=k1+k2`.
|
| 7 |
+
|
| 8 |
+
Examples
|
| 9 |
+
========
|
| 10 |
+
|
| 11 |
+
>>> from sympy.ntheory import binomial_coefficients
|
| 12 |
+
>>> binomial_coefficients(9)
|
| 13 |
+
{(0, 9): 1, (1, 8): 9, (2, 7): 36, (3, 6): 84,
|
| 14 |
+
(4, 5): 126, (5, 4): 126, (6, 3): 84, (7, 2): 36, (8, 1): 9, (9, 0): 1}
|
| 15 |
+
|
| 16 |
+
See Also
|
| 17 |
+
========
|
| 18 |
+
|
| 19 |
+
binomial_coefficients_list, multinomial_coefficients
|
| 20 |
+
"""
|
| 21 |
+
n = as_int(n)
|
| 22 |
+
d = {(0, n): 1, (n, 0): 1}
|
| 23 |
+
a = 1
|
| 24 |
+
for k in range(1, n//2 + 1):
|
| 25 |
+
a = (a * (n - k + 1))//k
|
| 26 |
+
d[k, n - k] = d[n - k, k] = a
|
| 27 |
+
return d
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def binomial_coefficients_list(n):
|
| 31 |
+
""" Return a list of binomial coefficients as rows of the Pascal's
|
| 32 |
+
triangle.
|
| 33 |
+
|
| 34 |
+
Examples
|
| 35 |
+
========
|
| 36 |
+
|
| 37 |
+
>>> from sympy.ntheory import binomial_coefficients_list
|
| 38 |
+
>>> binomial_coefficients_list(9)
|
| 39 |
+
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
|
| 40 |
+
|
| 41 |
+
See Also
|
| 42 |
+
========
|
| 43 |
+
|
| 44 |
+
binomial_coefficients, multinomial_coefficients
|
| 45 |
+
"""
|
| 46 |
+
n = as_int(n)
|
| 47 |
+
d = [1] * (n + 1)
|
| 48 |
+
a = 1
|
| 49 |
+
for k in range(1, n//2 + 1):
|
| 50 |
+
a = (a * (n - k + 1))//k
|
| 51 |
+
d[k] = d[n - k] = a
|
| 52 |
+
return d
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def multinomial_coefficients(m, n):
|
| 56 |
+
r"""Return a dictionary containing pairs ``{(k1,k2,..,km) : C_kn}``
|
| 57 |
+
where ``C_kn`` are multinomial coefficients such that
|
| 58 |
+
``n=k1+k2+..+km``.
|
| 59 |
+
|
| 60 |
+
Examples
|
| 61 |
+
========
|
| 62 |
+
|
| 63 |
+
>>> from sympy.ntheory import multinomial_coefficients
|
| 64 |
+
>>> multinomial_coefficients(2, 5) # indirect doctest
|
| 65 |
+
{(0, 5): 1, (1, 4): 5, (2, 3): 10, (3, 2): 10, (4, 1): 5, (5, 0): 1}
|
| 66 |
+
|
| 67 |
+
Notes
|
| 68 |
+
=====
|
| 69 |
+
|
| 70 |
+
The algorithm is based on the following result:
|
| 71 |
+
|
| 72 |
+
.. math::
|
| 73 |
+
\binom{n}{k_1, \ldots, k_m} =
|
| 74 |
+
\frac{k_1 + 1}{n - k_1} \sum_{i=2}^m \binom{n}{k_1 + 1, \ldots, k_i - 1, \ldots}
|
| 75 |
+
|
| 76 |
+
Code contributed to Sage by Yann Laigle-Chapuy, copied with permission
|
| 77 |
+
of the author.
|
| 78 |
+
|
| 79 |
+
See Also
|
| 80 |
+
========
|
| 81 |
+
|
| 82 |
+
binomial_coefficients_list, binomial_coefficients
|
| 83 |
+
"""
|
| 84 |
+
m = as_int(m)
|
| 85 |
+
n = as_int(n)
|
| 86 |
+
if not m:
|
| 87 |
+
if n:
|
| 88 |
+
return {}
|
| 89 |
+
return {(): 1}
|
| 90 |
+
if m == 2:
|
| 91 |
+
return binomial_coefficients(n)
|
| 92 |
+
if m >= 2*n and n > 1:
|
| 93 |
+
return dict(multinomial_coefficients_iterator(m, n))
|
| 94 |
+
t = [n] + [0] * (m - 1)
|
| 95 |
+
r = {tuple(t): 1}
|
| 96 |
+
if n:
|
| 97 |
+
j = 0 # j will be the leftmost nonzero position
|
| 98 |
+
else:
|
| 99 |
+
j = m
|
| 100 |
+
# enumerate tuples in co-lex order
|
| 101 |
+
while j < m - 1:
|
| 102 |
+
# compute next tuple
|
| 103 |
+
tj = t[j]
|
| 104 |
+
if j:
|
| 105 |
+
t[j] = 0
|
| 106 |
+
t[0] = tj
|
| 107 |
+
if tj > 1:
|
| 108 |
+
t[j + 1] += 1
|
| 109 |
+
j = 0
|
| 110 |
+
start = 1
|
| 111 |
+
v = 0
|
| 112 |
+
else:
|
| 113 |
+
j += 1
|
| 114 |
+
start = j + 1
|
| 115 |
+
v = r[tuple(t)]
|
| 116 |
+
t[j] += 1
|
| 117 |
+
# compute the value
|
| 118 |
+
# NB: the initialization of v was done above
|
| 119 |
+
for k in range(start, m):
|
| 120 |
+
if t[k]:
|
| 121 |
+
t[k] -= 1
|
| 122 |
+
v += r[tuple(t)]
|
| 123 |
+
t[k] += 1
|
| 124 |
+
t[0] -= 1
|
| 125 |
+
r[tuple(t)] = (v * tj) // (n - t[0])
|
| 126 |
+
return r
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
def multinomial_coefficients_iterator(m, n, _tuple=tuple):
|
| 130 |
+
"""multinomial coefficient iterator
|
| 131 |
+
|
| 132 |
+
This routine has been optimized for `m` large with respect to `n` by taking
|
| 133 |
+
advantage of the fact that when the monomial tuples `t` are stripped of
|
| 134 |
+
zeros, their coefficient is the same as that of the monomial tuples from
|
| 135 |
+
``multinomial_coefficients(n, n)``. Therefore, the latter coefficients are
|
| 136 |
+
precomputed to save memory and time.
|
| 137 |
+
|
| 138 |
+
>>> from sympy.ntheory.multinomial import multinomial_coefficients
|
| 139 |
+
>>> m53, m33 = multinomial_coefficients(5,3), multinomial_coefficients(3,3)
|
| 140 |
+
>>> m53[(0,0,0,1,2)] == m53[(0,0,1,0,2)] == m53[(1,0,2,0,0)] == m33[(0,1,2)]
|
| 141 |
+
True
|
| 142 |
+
|
| 143 |
+
Examples
|
| 144 |
+
========
|
| 145 |
+
|
| 146 |
+
>>> from sympy.ntheory.multinomial import multinomial_coefficients_iterator
|
| 147 |
+
>>> it = multinomial_coefficients_iterator(20,3)
|
| 148 |
+
>>> next(it)
|
| 149 |
+
((3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 1)
|
| 150 |
+
"""
|
| 151 |
+
m = as_int(m)
|
| 152 |
+
n = as_int(n)
|
| 153 |
+
if m < 2*n or n == 1:
|
| 154 |
+
mc = multinomial_coefficients(m, n)
|
| 155 |
+
yield from mc.items()
|
| 156 |
+
else:
|
| 157 |
+
mc = multinomial_coefficients(n, n)
|
| 158 |
+
mc1 = {}
|
| 159 |
+
for k, v in mc.items():
|
| 160 |
+
mc1[_tuple(filter(None, k))] = v
|
| 161 |
+
mc = mc1
|
| 162 |
+
|
| 163 |
+
t = [n] + [0] * (m - 1)
|
| 164 |
+
t1 = _tuple(t)
|
| 165 |
+
b = _tuple(filter(None, t1))
|
| 166 |
+
yield (t1, mc[b])
|
| 167 |
+
if n:
|
| 168 |
+
j = 0 # j will be the leftmost nonzero position
|
| 169 |
+
else:
|
| 170 |
+
j = m
|
| 171 |
+
# enumerate tuples in co-lex order
|
| 172 |
+
while j < m - 1:
|
| 173 |
+
# compute next tuple
|
| 174 |
+
tj = t[j]
|
| 175 |
+
if j:
|
| 176 |
+
t[j] = 0
|
| 177 |
+
t[0] = tj
|
| 178 |
+
if tj > 1:
|
| 179 |
+
t[j + 1] += 1
|
| 180 |
+
j = 0
|
| 181 |
+
else:
|
| 182 |
+
j += 1
|
| 183 |
+
t[j] += 1
|
| 184 |
+
|
| 185 |
+
t[0] -= 1
|
| 186 |
+
t1 = _tuple(t)
|
| 187 |
+
b = _tuple(filter(None, t1))
|
| 188 |
+
yield (t1, mc[b])
|
lib/python3.12/site-packages/sympy/ntheory/partitions_.py
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from mpmath.libmp import (fzero, from_int, from_rational,
|
| 2 |
+
fone, fhalf, bitcount, to_int, mpf_mul, mpf_div, mpf_sub,
|
| 3 |
+
mpf_add, mpf_sqrt, mpf_pi, mpf_cosh_sinh, mpf_cos, mpf_sin)
|
| 4 |
+
from sympy.external.gmpy import gcd, legendre, jacobi
|
| 5 |
+
from .residue_ntheory import _sqrt_mod_prime_power, is_quad_residue
|
| 6 |
+
from sympy.utilities.decorator import deprecated
|
| 7 |
+
from sympy.utilities.memoization import recurrence_memo
|
| 8 |
+
|
| 9 |
+
import math
|
| 10 |
+
from itertools import count
|
| 11 |
+
|
| 12 |
+
def _pre():
|
| 13 |
+
maxn = 10**5
|
| 14 |
+
global _factor
|
| 15 |
+
global _totient
|
| 16 |
+
_factor = [0]*maxn
|
| 17 |
+
_totient = [1]*maxn
|
| 18 |
+
lim = int(maxn**0.5) + 5
|
| 19 |
+
for i in range(2, lim):
|
| 20 |
+
if _factor[i] == 0:
|
| 21 |
+
for j in range(i*i, maxn, i):
|
| 22 |
+
if _factor[j] == 0:
|
| 23 |
+
_factor[j] = i
|
| 24 |
+
for i in range(2, maxn):
|
| 25 |
+
if _factor[i] == 0:
|
| 26 |
+
_factor[i] = i
|
| 27 |
+
_totient[i] = i-1
|
| 28 |
+
continue
|
| 29 |
+
x = _factor[i]
|
| 30 |
+
y = i//x
|
| 31 |
+
if y % x == 0:
|
| 32 |
+
_totient[i] = _totient[y]*x
|
| 33 |
+
else:
|
| 34 |
+
_totient[i] = _totient[y]*(x - 1)
|
| 35 |
+
|
| 36 |
+
def _a(n, k, prec):
|
| 37 |
+
""" Compute the inner sum in HRR formula [1]_
|
| 38 |
+
|
| 39 |
+
References
|
| 40 |
+
==========
|
| 41 |
+
|
| 42 |
+
.. [1] https://msp.org/pjm/1956/6-1/pjm-v6-n1-p18-p.pdf
|
| 43 |
+
|
| 44 |
+
"""
|
| 45 |
+
if k == 1:
|
| 46 |
+
return fone
|
| 47 |
+
|
| 48 |
+
k1 = k
|
| 49 |
+
e = 0
|
| 50 |
+
p = _factor[k]
|
| 51 |
+
while k1 % p == 0:
|
| 52 |
+
k1 //= p
|
| 53 |
+
e += 1
|
| 54 |
+
k2 = k//k1 # k2 = p^e
|
| 55 |
+
v = 1 - 24*n
|
| 56 |
+
pi = mpf_pi(prec)
|
| 57 |
+
|
| 58 |
+
if k1 == 1:
|
| 59 |
+
# k = p^e
|
| 60 |
+
if p == 2:
|
| 61 |
+
mod = 8*k
|
| 62 |
+
v = mod + v % mod
|
| 63 |
+
v = (v*pow(9, k - 1, mod)) % mod
|
| 64 |
+
m = _sqrt_mod_prime_power(v, 2, e + 3)[0]
|
| 65 |
+
arg = mpf_div(mpf_mul(
|
| 66 |
+
from_int(4*m), pi, prec), from_int(mod), prec)
|
| 67 |
+
return mpf_mul(mpf_mul(
|
| 68 |
+
from_int((-1)**e*jacobi(m - 1, m)),
|
| 69 |
+
mpf_sqrt(from_int(k), prec), prec),
|
| 70 |
+
mpf_sin(arg, prec), prec)
|
| 71 |
+
if p == 3:
|
| 72 |
+
mod = 3*k
|
| 73 |
+
v = mod + v % mod
|
| 74 |
+
if e > 1:
|
| 75 |
+
v = (v*pow(64, k//3 - 1, mod)) % mod
|
| 76 |
+
m = _sqrt_mod_prime_power(v, 3, e + 1)[0]
|
| 77 |
+
arg = mpf_div(mpf_mul(from_int(4*m), pi, prec),
|
| 78 |
+
from_int(mod), prec)
|
| 79 |
+
return mpf_mul(mpf_mul(
|
| 80 |
+
from_int(2*(-1)**(e + 1)*legendre(m, 3)),
|
| 81 |
+
mpf_sqrt(from_int(k//3), prec), prec),
|
| 82 |
+
mpf_sin(arg, prec), prec)
|
| 83 |
+
v = k + v % k
|
| 84 |
+
if v % p == 0:
|
| 85 |
+
if e == 1:
|
| 86 |
+
return mpf_mul(
|
| 87 |
+
from_int(jacobi(3, k)),
|
| 88 |
+
mpf_sqrt(from_int(k), prec), prec)
|
| 89 |
+
return fzero
|
| 90 |
+
if not is_quad_residue(v, p):
|
| 91 |
+
return fzero
|
| 92 |
+
_phi = p**(e - 1)*(p - 1)
|
| 93 |
+
v = (v*pow(576, _phi - 1, k))
|
| 94 |
+
m = _sqrt_mod_prime_power(v, p, e)[0]
|
| 95 |
+
arg = mpf_div(
|
| 96 |
+
mpf_mul(from_int(4*m), pi, prec),
|
| 97 |
+
from_int(k), prec)
|
| 98 |
+
return mpf_mul(mpf_mul(
|
| 99 |
+
from_int(2*jacobi(3, k)),
|
| 100 |
+
mpf_sqrt(from_int(k), prec), prec),
|
| 101 |
+
mpf_cos(arg, prec), prec)
|
| 102 |
+
|
| 103 |
+
if p != 2 or e >= 3:
|
| 104 |
+
d1, d2 = gcd(k1, 24), gcd(k2, 24)
|
| 105 |
+
e = 24//(d1*d2)
|
| 106 |
+
n1 = ((d2*e*n + (k2**2 - 1)//d1)*
|
| 107 |
+
pow(e*k2*k2*d2, _totient[k1] - 1, k1)) % k1
|
| 108 |
+
n2 = ((d1*e*n + (k1**2 - 1)//d2)*
|
| 109 |
+
pow(e*k1*k1*d1, _totient[k2] - 1, k2)) % k2
|
| 110 |
+
return mpf_mul(_a(n1, k1, prec), _a(n2, k2, prec), prec)
|
| 111 |
+
if e == 2:
|
| 112 |
+
n1 = ((8*n + 5)*pow(128, _totient[k1] - 1, k1)) % k1
|
| 113 |
+
n2 = (4 + ((n - 2 - (k1**2 - 1)//8)*(k1**2)) % 4) % 4
|
| 114 |
+
return mpf_mul(mpf_mul(
|
| 115 |
+
from_int(-1),
|
| 116 |
+
_a(n1, k1, prec), prec),
|
| 117 |
+
_a(n2, k2, prec))
|
| 118 |
+
n1 = ((8*n + 1)*pow(32, _totient[k1] - 1, k1)) % k1
|
| 119 |
+
n2 = (2 + (n - (k1**2 - 1)//8) % 2) % 2
|
| 120 |
+
return mpf_mul(_a(n1, k1, prec), _a(n2, k2, prec), prec)
|
| 121 |
+
|
| 122 |
+
def _d(n, j, prec, sq23pi, sqrt8):
|
| 123 |
+
"""
|
| 124 |
+
Compute the sinh term in the outer sum of the HRR formula.
|
| 125 |
+
The constants sqrt(2/3*pi) and sqrt(8) must be precomputed.
|
| 126 |
+
"""
|
| 127 |
+
j = from_int(j)
|
| 128 |
+
pi = mpf_pi(prec)
|
| 129 |
+
a = mpf_div(sq23pi, j, prec)
|
| 130 |
+
b = mpf_sub(from_int(n), from_rational(1, 24, prec), prec)
|
| 131 |
+
c = mpf_sqrt(b, prec)
|
| 132 |
+
ch, sh = mpf_cosh_sinh(mpf_mul(a, c), prec)
|
| 133 |
+
D = mpf_div(
|
| 134 |
+
mpf_sqrt(j, prec),
|
| 135 |
+
mpf_mul(mpf_mul(sqrt8, b), pi), prec)
|
| 136 |
+
E = mpf_sub(mpf_mul(a, ch), mpf_div(sh, c, prec), prec)
|
| 137 |
+
return mpf_mul(D, E)
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
@recurrence_memo([1, 1])
|
| 141 |
+
def _partition_rec(n: int, prev) -> int:
|
| 142 |
+
""" Calculate the partition function P(n)
|
| 143 |
+
|
| 144 |
+
Parameters
|
| 145 |
+
==========
|
| 146 |
+
|
| 147 |
+
n : int
|
| 148 |
+
nonnegative integer
|
| 149 |
+
|
| 150 |
+
"""
|
| 151 |
+
v = 0
|
| 152 |
+
penta = 0 # pentagonal number: 1, 5, 12, ...
|
| 153 |
+
for i in count():
|
| 154 |
+
penta += 3*i + 1
|
| 155 |
+
np = n - penta
|
| 156 |
+
if np < 0:
|
| 157 |
+
break
|
| 158 |
+
s = prev[np]
|
| 159 |
+
np -= i + 1
|
| 160 |
+
# np = n - gp where gp = generalized pentagonal: 2, 7, 15, ...
|
| 161 |
+
if 0 <= np:
|
| 162 |
+
s += prev[np]
|
| 163 |
+
v += -s if i % 2 else s
|
| 164 |
+
return v
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
def _partition(n: int) -> int:
|
| 168 |
+
""" Calculate the partition function P(n)
|
| 169 |
+
|
| 170 |
+
Parameters
|
| 171 |
+
==========
|
| 172 |
+
|
| 173 |
+
n : int
|
| 174 |
+
|
| 175 |
+
"""
|
| 176 |
+
if n < 0:
|
| 177 |
+
return 0
|
| 178 |
+
if (n <= 200_000 and n - _partition_rec.cache_length() < 70 or
|
| 179 |
+
_partition_rec.cache_length() == 2 and n < 14_400):
|
| 180 |
+
# There will be 2*10**5 elements created here
|
| 181 |
+
# and n elements created by partition, so in case we
|
| 182 |
+
# are going to be working with small n, we just
|
| 183 |
+
# use partition to calculate (and cache) the values
|
| 184 |
+
# since lookup is used there while summation, using
|
| 185 |
+
# _factor and _totient, will be used below. But we
|
| 186 |
+
# only do so if n is relatively close to the length
|
| 187 |
+
# of the cache since doing 1 calculation here is about
|
| 188 |
+
# the same as adding 70 elements to the cache. In addition,
|
| 189 |
+
# the startup here costs about the same as calculating the first
|
| 190 |
+
# 14,400 values via partition, so we delay startup here unless n
|
| 191 |
+
# is smaller than that.
|
| 192 |
+
return _partition_rec(n)
|
| 193 |
+
if '_factor' not in globals():
|
| 194 |
+
_pre()
|
| 195 |
+
# Estimate number of bits in p(n). This formula could be tidied
|
| 196 |
+
pbits = int((
|
| 197 |
+
math.pi*(2*n/3.)**0.5 -
|
| 198 |
+
math.log(4*n))/math.log(10) + 1) * \
|
| 199 |
+
math.log2(10)
|
| 200 |
+
prec = p = int(pbits*1.1 + 100)
|
| 201 |
+
|
| 202 |
+
# find the number of terms needed so rounded sum will be accurate
|
| 203 |
+
# using Rademacher's bound M(n, N) for the remainder after a partial
|
| 204 |
+
# sum of N terms (https://arxiv.org/pdf/1205.5991.pdf, (1.8))
|
| 205 |
+
c1 = 44*math.pi**2/(225*math.sqrt(3))
|
| 206 |
+
c2 = math.pi*math.sqrt(2)/75
|
| 207 |
+
c3 = math.pi*math.sqrt(2/3)
|
| 208 |
+
def _M(n, N):
|
| 209 |
+
sqrt = math.sqrt
|
| 210 |
+
return c1/sqrt(N) + c2*sqrt(N/(n - 1))*math.sinh(c3*sqrt(n)/N)
|
| 211 |
+
big = max(9, math.ceil(n**0.5)) # should be too large (for n > 65, ceil should work)
|
| 212 |
+
assert _M(n, big) < 0.5 # else double big until too large
|
| 213 |
+
while big > 40 and _M(n, big) < 0.5:
|
| 214 |
+
big //= 2
|
| 215 |
+
small = big
|
| 216 |
+
big = small*2
|
| 217 |
+
while big - small > 1:
|
| 218 |
+
N = (big + small)//2
|
| 219 |
+
if (er := _M(n, N)) < 0.5:
|
| 220 |
+
big = N
|
| 221 |
+
elif er >= 0.5:
|
| 222 |
+
small = N
|
| 223 |
+
M = big # done with function M; now have value
|
| 224 |
+
|
| 225 |
+
# sanity check for expected size of answer
|
| 226 |
+
if M > 10**5: # i.e. M > maxn
|
| 227 |
+
raise ValueError("Input too big") # i.e. n > 149832547102
|
| 228 |
+
|
| 229 |
+
# calculate it
|
| 230 |
+
s = fzero
|
| 231 |
+
sq23pi = mpf_mul(mpf_sqrt(from_rational(2, 3, p), p), mpf_pi(p), p)
|
| 232 |
+
sqrt8 = mpf_sqrt(from_int(8), p)
|
| 233 |
+
for q in range(1, M):
|
| 234 |
+
a = _a(n, q, p)
|
| 235 |
+
d = _d(n, q, p, sq23pi, sqrt8)
|
| 236 |
+
s = mpf_add(s, mpf_mul(a, d), prec)
|
| 237 |
+
# On average, the terms decrease rapidly in magnitude.
|
| 238 |
+
# Dynamically reducing the precision greatly improves
|
| 239 |
+
# performance.
|
| 240 |
+
p = bitcount(abs(to_int(d))) + 50
|
| 241 |
+
return int(to_int(mpf_add(s, fhalf, prec)))
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
@deprecated("""\
|
| 245 |
+
The `sympy.ntheory.partitions_.npartitions` has been moved to `sympy.functions.combinatorial.numbers.partition`.""",
|
| 246 |
+
deprecated_since_version="1.13",
|
| 247 |
+
active_deprecations_target='deprecated-ntheory-symbolic-functions')
|
| 248 |
+
def npartitions(n, verbose=False):
|
| 249 |
+
"""
|
| 250 |
+
Calculate the partition function P(n), i.e. the number of ways that
|
| 251 |
+
n can be written as a sum of positive integers.
|
| 252 |
+
|
| 253 |
+
.. deprecated:: 1.13
|
| 254 |
+
|
| 255 |
+
The ``npartitions`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.partition`
|
| 256 |
+
instead. See its documentation for more information. See
|
| 257 |
+
:ref:`deprecated-ntheory-symbolic-functions` for details.
|
| 258 |
+
|
| 259 |
+
P(n) is computed using the Hardy-Ramanujan-Rademacher formula [1]_.
|
| 260 |
+
|
| 261 |
+
|
| 262 |
+
The correctness of this implementation has been tested through $10^{10}$.
|
| 263 |
+
|
| 264 |
+
Examples
|
| 265 |
+
========
|
| 266 |
+
|
| 267 |
+
>>> from sympy.functions.combinatorial.numbers import partition
|
| 268 |
+
>>> partition(25)
|
| 269 |
+
1958
|
| 270 |
+
|
| 271 |
+
References
|
| 272 |
+
==========
|
| 273 |
+
|
| 274 |
+
.. [1] https://mathworld.wolfram.com/PartitionFunctionP.html
|
| 275 |
+
|
| 276 |
+
"""
|
| 277 |
+
from sympy.functions.combinatorial.numbers import partition as func_partition
|
| 278 |
+
return func_partition(n)
|
lib/python3.12/site-packages/sympy/ntheory/primetest.py
ADDED
|
@@ -0,0 +1,793 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Primality testing
|
| 3 |
+
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
from itertools import count
|
| 7 |
+
|
| 8 |
+
from sympy.core.sympify import sympify
|
| 9 |
+
from sympy.external.gmpy import (gmpy as _gmpy, gcd, jacobi,
|
| 10 |
+
is_square as gmpy_is_square,
|
| 11 |
+
bit_scan1, is_fermat_prp, is_euler_prp,
|
| 12 |
+
is_selfridge_prp, is_strong_selfridge_prp,
|
| 13 |
+
is_strong_bpsw_prp)
|
| 14 |
+
from sympy.external.ntheory import _lucas_sequence
|
| 15 |
+
from sympy.utilities.misc import as_int, filldedent
|
| 16 |
+
|
| 17 |
+
# Note: This list should be updated whenever new Mersenne primes are found.
|
| 18 |
+
# Refer: https://www.mersenne.org/
|
| 19 |
+
MERSENNE_PRIME_EXPONENTS = (2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203,
|
| 20 |
+
2281, 3217, 4253, 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497, 86243, 110503, 132049,
|
| 21 |
+
216091, 756839, 859433, 1257787, 1398269, 2976221, 3021377, 6972593, 13466917, 20996011, 24036583,
|
| 22 |
+
25964951, 30402457, 32582657, 37156667, 42643801, 43112609, 57885161, 74207281, 77232917, 82589933)
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def is_fermat_pseudoprime(n, a):
|
| 26 |
+
r"""Returns True if ``n`` is prime or is an odd composite integer that
|
| 27 |
+
is coprime to ``a`` and satisfy the modular arithmetic congruence relation:
|
| 28 |
+
|
| 29 |
+
.. math ::
|
| 30 |
+
a^{n-1} \equiv 1 \pmod{n}
|
| 31 |
+
|
| 32 |
+
(where mod refers to the modulo operation).
|
| 33 |
+
|
| 34 |
+
Parameters
|
| 35 |
+
==========
|
| 36 |
+
|
| 37 |
+
n : Integer
|
| 38 |
+
``n`` is a positive integer.
|
| 39 |
+
a : Integer
|
| 40 |
+
``a`` is a positive integer.
|
| 41 |
+
``a`` and ``n`` should be relatively prime.
|
| 42 |
+
|
| 43 |
+
Returns
|
| 44 |
+
=======
|
| 45 |
+
|
| 46 |
+
bool : If ``n`` is prime, it always returns ``True``.
|
| 47 |
+
The composite number that returns ``True`` is called an Fermat pseudoprime.
|
| 48 |
+
|
| 49 |
+
Examples
|
| 50 |
+
========
|
| 51 |
+
|
| 52 |
+
>>> from sympy.ntheory.primetest import is_fermat_pseudoprime
|
| 53 |
+
>>> from sympy.ntheory.factor_ import isprime
|
| 54 |
+
>>> for n in range(1, 1000):
|
| 55 |
+
... if is_fermat_pseudoprime(n, 2) and not isprime(n):
|
| 56 |
+
... print(n)
|
| 57 |
+
341
|
| 58 |
+
561
|
| 59 |
+
645
|
| 60 |
+
|
| 61 |
+
References
|
| 62 |
+
==========
|
| 63 |
+
|
| 64 |
+
.. [1] https://en.wikipedia.org/wiki/Fermat_pseudoprime
|
| 65 |
+
"""
|
| 66 |
+
n, a = as_int(n), as_int(a)
|
| 67 |
+
if a == 1:
|
| 68 |
+
return n == 2 or bool(n % 2)
|
| 69 |
+
return is_fermat_prp(n, a)
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def is_euler_pseudoprime(n, a):
|
| 73 |
+
r"""Returns True if ``n`` is prime or is an odd composite integer that
|
| 74 |
+
is coprime to ``a`` and satisfy the modular arithmetic congruence relation:
|
| 75 |
+
|
| 76 |
+
.. math ::
|
| 77 |
+
a^{(n-1)/2} \equiv \pm 1 \pmod{n}
|
| 78 |
+
|
| 79 |
+
(where mod refers to the modulo operation).
|
| 80 |
+
|
| 81 |
+
Parameters
|
| 82 |
+
==========
|
| 83 |
+
|
| 84 |
+
n : Integer
|
| 85 |
+
``n`` is a positive integer.
|
| 86 |
+
a : Integer
|
| 87 |
+
``a`` is a positive integer.
|
| 88 |
+
``a`` and ``n`` should be relatively prime.
|
| 89 |
+
|
| 90 |
+
Returns
|
| 91 |
+
=======
|
| 92 |
+
|
| 93 |
+
bool : If ``n`` is prime, it always returns ``True``.
|
| 94 |
+
The composite number that returns ``True`` is called an Euler pseudoprime.
|
| 95 |
+
|
| 96 |
+
Examples
|
| 97 |
+
========
|
| 98 |
+
|
| 99 |
+
>>> from sympy.ntheory.primetest import is_euler_pseudoprime
|
| 100 |
+
>>> from sympy.ntheory.factor_ import isprime
|
| 101 |
+
>>> for n in range(1, 1000):
|
| 102 |
+
... if is_euler_pseudoprime(n, 2) and not isprime(n):
|
| 103 |
+
... print(n)
|
| 104 |
+
341
|
| 105 |
+
561
|
| 106 |
+
|
| 107 |
+
References
|
| 108 |
+
==========
|
| 109 |
+
|
| 110 |
+
.. [1] https://en.wikipedia.org/wiki/Euler_pseudoprime
|
| 111 |
+
"""
|
| 112 |
+
n, a = as_int(n), as_int(a)
|
| 113 |
+
if a < 1:
|
| 114 |
+
raise ValueError("a should be an integer greater than 0")
|
| 115 |
+
if n < 1:
|
| 116 |
+
raise ValueError("n should be an integer greater than 0")
|
| 117 |
+
if n == 1:
|
| 118 |
+
return False
|
| 119 |
+
if a == 1:
|
| 120 |
+
return n == 2 or bool(n % 2) # (prime or odd composite)
|
| 121 |
+
if n % 2 == 0:
|
| 122 |
+
return n == 2
|
| 123 |
+
if gcd(n, a) != 1:
|
| 124 |
+
raise ValueError("The two numbers should be relatively prime")
|
| 125 |
+
return pow(a, (n - 1) // 2, n) in [1, n - 1]
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
def is_euler_jacobi_pseudoprime(n, a):
|
| 129 |
+
r"""Returns True if ``n`` is prime or is an odd composite integer that
|
| 130 |
+
is coprime to ``a`` and satisfy the modular arithmetic congruence relation:
|
| 131 |
+
|
| 132 |
+
.. math ::
|
| 133 |
+
a^{(n-1)/2} \equiv \left(\frac{a}{n}\right) \pmod{n}
|
| 134 |
+
|
| 135 |
+
(where mod refers to the modulo operation).
|
| 136 |
+
|
| 137 |
+
Parameters
|
| 138 |
+
==========
|
| 139 |
+
|
| 140 |
+
n : Integer
|
| 141 |
+
``n`` is a positive integer.
|
| 142 |
+
a : Integer
|
| 143 |
+
``a`` is a positive integer.
|
| 144 |
+
``a`` and ``n`` should be relatively prime.
|
| 145 |
+
|
| 146 |
+
Returns
|
| 147 |
+
=======
|
| 148 |
+
|
| 149 |
+
bool : If ``n`` is prime, it always returns ``True``.
|
| 150 |
+
The composite number that returns ``True`` is called an Euler-Jacobi pseudoprime.
|
| 151 |
+
|
| 152 |
+
Examples
|
| 153 |
+
========
|
| 154 |
+
|
| 155 |
+
>>> from sympy.ntheory.primetest import is_euler_jacobi_pseudoprime
|
| 156 |
+
>>> from sympy.ntheory.factor_ import isprime
|
| 157 |
+
>>> for n in range(1, 1000):
|
| 158 |
+
... if is_euler_jacobi_pseudoprime(n, 2) and not isprime(n):
|
| 159 |
+
... print(n)
|
| 160 |
+
561
|
| 161 |
+
|
| 162 |
+
References
|
| 163 |
+
==========
|
| 164 |
+
|
| 165 |
+
.. [1] https://en.wikipedia.org/wiki/Euler%E2%80%93Jacobi_pseudoprime
|
| 166 |
+
"""
|
| 167 |
+
n, a = as_int(n), as_int(a)
|
| 168 |
+
if a == 1:
|
| 169 |
+
return n == 2 or bool(n % 2)
|
| 170 |
+
return is_euler_prp(n, a)
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def is_square(n, prep=True):
|
| 174 |
+
"""Return True if n == a * a for some integer a, else False.
|
| 175 |
+
If n is suspected of *not* being a square then this is a
|
| 176 |
+
quick method of confirming that it is not.
|
| 177 |
+
|
| 178 |
+
Examples
|
| 179 |
+
========
|
| 180 |
+
|
| 181 |
+
>>> from sympy.ntheory.primetest import is_square
|
| 182 |
+
>>> is_square(25)
|
| 183 |
+
True
|
| 184 |
+
>>> is_square(2)
|
| 185 |
+
False
|
| 186 |
+
|
| 187 |
+
References
|
| 188 |
+
==========
|
| 189 |
+
|
| 190 |
+
.. [1] https://mersenneforum.org/showpost.php?p=110896
|
| 191 |
+
|
| 192 |
+
See Also
|
| 193 |
+
========
|
| 194 |
+
sympy.core.intfunc.isqrt
|
| 195 |
+
"""
|
| 196 |
+
if prep:
|
| 197 |
+
n = as_int(n)
|
| 198 |
+
if n < 0:
|
| 199 |
+
return False
|
| 200 |
+
if n in (0, 1):
|
| 201 |
+
return True
|
| 202 |
+
return gmpy_is_square(n)
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
def _test(n, base, s, t):
|
| 206 |
+
"""Miller-Rabin strong pseudoprime test for one base.
|
| 207 |
+
Return False if n is definitely composite, True if n is
|
| 208 |
+
probably prime, with a probability greater than 3/4.
|
| 209 |
+
|
| 210 |
+
"""
|
| 211 |
+
# do the Fermat test
|
| 212 |
+
b = pow(base, t, n)
|
| 213 |
+
if b == 1 or b == n - 1:
|
| 214 |
+
return True
|
| 215 |
+
for _ in range(s - 1):
|
| 216 |
+
b = pow(b, 2, n)
|
| 217 |
+
if b == n - 1:
|
| 218 |
+
return True
|
| 219 |
+
# see I. Niven et al. "An Introduction to Theory of Numbers", page 78
|
| 220 |
+
if b == 1:
|
| 221 |
+
return False
|
| 222 |
+
return False
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
def mr(n, bases):
|
| 226 |
+
"""Perform a Miller-Rabin strong pseudoprime test on n using a
|
| 227 |
+
given list of bases/witnesses.
|
| 228 |
+
|
| 229 |
+
References
|
| 230 |
+
==========
|
| 231 |
+
|
| 232 |
+
.. [1] Richard Crandall & Carl Pomerance (2005), "Prime Numbers:
|
| 233 |
+
A Computational Perspective", Springer, 2nd edition, 135-138
|
| 234 |
+
|
| 235 |
+
A list of thresholds and the bases they require are here:
|
| 236 |
+
https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test#Deterministic_variants
|
| 237 |
+
|
| 238 |
+
Examples
|
| 239 |
+
========
|
| 240 |
+
|
| 241 |
+
>>> from sympy.ntheory.primetest import mr
|
| 242 |
+
>>> mr(1373651, [2, 3])
|
| 243 |
+
False
|
| 244 |
+
>>> mr(479001599, [31, 73])
|
| 245 |
+
True
|
| 246 |
+
|
| 247 |
+
"""
|
| 248 |
+
from sympy.polys.domains import ZZ
|
| 249 |
+
|
| 250 |
+
n = as_int(n)
|
| 251 |
+
if n < 2:
|
| 252 |
+
return False
|
| 253 |
+
# remove powers of 2 from n-1 (= t * 2**s)
|
| 254 |
+
s = bit_scan1(n - 1)
|
| 255 |
+
t = n >> s
|
| 256 |
+
for base in bases:
|
| 257 |
+
# Bases >= n are wrapped, bases < 2 are invalid
|
| 258 |
+
if base >= n:
|
| 259 |
+
base %= n
|
| 260 |
+
if base >= 2:
|
| 261 |
+
base = ZZ(base)
|
| 262 |
+
if not _test(n, base, s, t):
|
| 263 |
+
return False
|
| 264 |
+
return True
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
def _lucas_extrastrong_params(n):
|
| 268 |
+
"""Calculates the "extra strong" parameters (D, P, Q) for n.
|
| 269 |
+
|
| 270 |
+
Parameters
|
| 271 |
+
==========
|
| 272 |
+
|
| 273 |
+
n : int
|
| 274 |
+
positive odd integer
|
| 275 |
+
|
| 276 |
+
Returns
|
| 277 |
+
=======
|
| 278 |
+
|
| 279 |
+
D, P, Q: "extra strong" parameters.
|
| 280 |
+
``(0, 0, 0)`` if we find a nontrivial divisor of ``n``.
|
| 281 |
+
|
| 282 |
+
Examples
|
| 283 |
+
========
|
| 284 |
+
|
| 285 |
+
>>> from sympy.ntheory.primetest import _lucas_extrastrong_params
|
| 286 |
+
>>> _lucas_extrastrong_params(101)
|
| 287 |
+
(12, 4, 1)
|
| 288 |
+
>>> _lucas_extrastrong_params(15)
|
| 289 |
+
(0, 0, 0)
|
| 290 |
+
|
| 291 |
+
References
|
| 292 |
+
==========
|
| 293 |
+
.. [1] OEIS A217719: Extra Strong Lucas Pseudoprimes
|
| 294 |
+
https://oeis.org/A217719
|
| 295 |
+
.. [2] https://en.wikipedia.org/wiki/Lucas_pseudoprime
|
| 296 |
+
|
| 297 |
+
"""
|
| 298 |
+
for P in count(3):
|
| 299 |
+
D = P**2 - 4
|
| 300 |
+
j = jacobi(D, n)
|
| 301 |
+
if j == -1:
|
| 302 |
+
return (D, P, 1)
|
| 303 |
+
elif j == 0 and D % n:
|
| 304 |
+
return (0, 0, 0)
|
| 305 |
+
|
| 306 |
+
|
| 307 |
+
def is_lucas_prp(n):
|
| 308 |
+
"""Standard Lucas compositeness test with Selfridge parameters. Returns
|
| 309 |
+
False if n is definitely composite, and True if n is a Lucas probable
|
| 310 |
+
prime.
|
| 311 |
+
|
| 312 |
+
This is typically used in combination with the Miller-Rabin test.
|
| 313 |
+
|
| 314 |
+
References
|
| 315 |
+
==========
|
| 316 |
+
.. [1] Robert Baillie, Samuel S. Wagstaff, Lucas Pseudoprimes,
|
| 317 |
+
Math. Comp. Vol 35, Number 152 (1980), pp. 1391-1417,
|
| 318 |
+
https://doi.org/10.1090%2FS0025-5718-1980-0583518-6
|
| 319 |
+
http://mpqs.free.fr/LucasPseudoprimes.pdf
|
| 320 |
+
.. [2] OEIS A217120: Lucas Pseudoprimes
|
| 321 |
+
https://oeis.org/A217120
|
| 322 |
+
.. [3] https://en.wikipedia.org/wiki/Lucas_pseudoprime
|
| 323 |
+
|
| 324 |
+
Examples
|
| 325 |
+
========
|
| 326 |
+
|
| 327 |
+
>>> from sympy.ntheory.primetest import isprime, is_lucas_prp
|
| 328 |
+
>>> for i in range(10000):
|
| 329 |
+
... if is_lucas_prp(i) and not isprime(i):
|
| 330 |
+
... print(i)
|
| 331 |
+
323
|
| 332 |
+
377
|
| 333 |
+
1159
|
| 334 |
+
1829
|
| 335 |
+
3827
|
| 336 |
+
5459
|
| 337 |
+
5777
|
| 338 |
+
9071
|
| 339 |
+
9179
|
| 340 |
+
"""
|
| 341 |
+
n = as_int(n)
|
| 342 |
+
if n < 2:
|
| 343 |
+
return False
|
| 344 |
+
return is_selfridge_prp(n)
|
| 345 |
+
|
| 346 |
+
|
| 347 |
+
def is_strong_lucas_prp(n):
|
| 348 |
+
"""Strong Lucas compositeness test with Selfridge parameters. Returns
|
| 349 |
+
False if n is definitely composite, and True if n is a strong Lucas
|
| 350 |
+
probable prime.
|
| 351 |
+
|
| 352 |
+
This is often used in combination with the Miller-Rabin test, and
|
| 353 |
+
in particular, when combined with M-R base 2 creates the strong BPSW test.
|
| 354 |
+
|
| 355 |
+
References
|
| 356 |
+
==========
|
| 357 |
+
.. [1] Robert Baillie, Samuel S. Wagstaff, Lucas Pseudoprimes,
|
| 358 |
+
Math. Comp. Vol 35, Number 152 (1980), pp. 1391-1417,
|
| 359 |
+
https://doi.org/10.1090%2FS0025-5718-1980-0583518-6
|
| 360 |
+
http://mpqs.free.fr/LucasPseudoprimes.pdf
|
| 361 |
+
.. [2] OEIS A217255: Strong Lucas Pseudoprimes
|
| 362 |
+
https://oeis.org/A217255
|
| 363 |
+
.. [3] https://en.wikipedia.org/wiki/Lucas_pseudoprime
|
| 364 |
+
.. [4] https://en.wikipedia.org/wiki/Baillie-PSW_primality_test
|
| 365 |
+
|
| 366 |
+
Examples
|
| 367 |
+
========
|
| 368 |
+
|
| 369 |
+
>>> from sympy.ntheory.primetest import isprime, is_strong_lucas_prp
|
| 370 |
+
>>> for i in range(20000):
|
| 371 |
+
... if is_strong_lucas_prp(i) and not isprime(i):
|
| 372 |
+
... print(i)
|
| 373 |
+
5459
|
| 374 |
+
5777
|
| 375 |
+
10877
|
| 376 |
+
16109
|
| 377 |
+
18971
|
| 378 |
+
"""
|
| 379 |
+
n = as_int(n)
|
| 380 |
+
if n < 2:
|
| 381 |
+
return False
|
| 382 |
+
return is_strong_selfridge_prp(n)
|
| 383 |
+
|
| 384 |
+
|
| 385 |
+
def is_extra_strong_lucas_prp(n):
|
| 386 |
+
"""Extra Strong Lucas compositeness test. Returns False if n is
|
| 387 |
+
definitely composite, and True if n is an "extra strong" Lucas probable
|
| 388 |
+
prime.
|
| 389 |
+
|
| 390 |
+
The parameters are selected using P = 3, Q = 1, then incrementing P until
|
| 391 |
+
(D|n) == -1. The test itself is as defined in [1]_, from the
|
| 392 |
+
Mo and Jones preprint. The parameter selection and test are the same as
|
| 393 |
+
used in OEIS A217719, Perl's Math::Prime::Util, and the Lucas pseudoprime
|
| 394 |
+
page on Wikipedia.
|
| 395 |
+
|
| 396 |
+
It is 20-50% faster than the strong test.
|
| 397 |
+
|
| 398 |
+
Because of the different parameters selected, there is no relationship
|
| 399 |
+
between the strong Lucas pseudoprimes and extra strong Lucas pseudoprimes.
|
| 400 |
+
In particular, one is not a subset of the other.
|
| 401 |
+
|
| 402 |
+
References
|
| 403 |
+
==========
|
| 404 |
+
.. [1] Jon Grantham, Frobenius Pseudoprimes,
|
| 405 |
+
Math. Comp. Vol 70, Number 234 (2001), pp. 873-891,
|
| 406 |
+
https://doi.org/10.1090%2FS0025-5718-00-01197-2
|
| 407 |
+
.. [2] OEIS A217719: Extra Strong Lucas Pseudoprimes
|
| 408 |
+
https://oeis.org/A217719
|
| 409 |
+
.. [3] https://en.wikipedia.org/wiki/Lucas_pseudoprime
|
| 410 |
+
|
| 411 |
+
Examples
|
| 412 |
+
========
|
| 413 |
+
|
| 414 |
+
>>> from sympy.ntheory.primetest import isprime, is_extra_strong_lucas_prp
|
| 415 |
+
>>> for i in range(20000):
|
| 416 |
+
... if is_extra_strong_lucas_prp(i) and not isprime(i):
|
| 417 |
+
... print(i)
|
| 418 |
+
989
|
| 419 |
+
3239
|
| 420 |
+
5777
|
| 421 |
+
10877
|
| 422 |
+
"""
|
| 423 |
+
# Implementation notes:
|
| 424 |
+
# 1) the parameters differ from Thomas R. Nicely's. His parameter
|
| 425 |
+
# selection leads to pseudoprimes that overlap M-R tests, and
|
| 426 |
+
# contradict Baillie and Wagstaff's suggestion of (D|n) = -1.
|
| 427 |
+
# 2) The MathWorld page as of June 2013 specifies Q=-1. The Lucas
|
| 428 |
+
# sequence must have Q=1. See Grantham theorem 2.3, any of the
|
| 429 |
+
# references on the MathWorld page, or run it and see Q=-1 is wrong.
|
| 430 |
+
n = as_int(n)
|
| 431 |
+
if n == 2:
|
| 432 |
+
return True
|
| 433 |
+
if n < 2 or (n % 2) == 0:
|
| 434 |
+
return False
|
| 435 |
+
if gmpy_is_square(n):
|
| 436 |
+
return False
|
| 437 |
+
|
| 438 |
+
D, P, Q = _lucas_extrastrong_params(n)
|
| 439 |
+
if D == 0:
|
| 440 |
+
return False
|
| 441 |
+
|
| 442 |
+
# remove powers of 2 from n+1 (= k * 2**s)
|
| 443 |
+
s = bit_scan1(n + 1)
|
| 444 |
+
k = (n + 1) >> s
|
| 445 |
+
|
| 446 |
+
U, V, _ = _lucas_sequence(n, P, Q, k)
|
| 447 |
+
|
| 448 |
+
if U == 0 and (V == 2 or V == n - 2):
|
| 449 |
+
return True
|
| 450 |
+
for _ in range(1, s):
|
| 451 |
+
if V == 0:
|
| 452 |
+
return True
|
| 453 |
+
V = (V*V - 2) % n
|
| 454 |
+
return False
|
| 455 |
+
|
| 456 |
+
|
| 457 |
+
def proth_test(n):
|
| 458 |
+
r""" Test if the Proth number `n = k2^m + 1` is prime. where k is a positive odd number and `2^m > k`.
|
| 459 |
+
|
| 460 |
+
Parameters
|
| 461 |
+
==========
|
| 462 |
+
|
| 463 |
+
n : Integer
|
| 464 |
+
``n`` is Proth number
|
| 465 |
+
|
| 466 |
+
Returns
|
| 467 |
+
=======
|
| 468 |
+
|
| 469 |
+
bool : If ``True``, then ``n`` is the Proth prime
|
| 470 |
+
|
| 471 |
+
Raises
|
| 472 |
+
======
|
| 473 |
+
|
| 474 |
+
ValueError
|
| 475 |
+
If ``n`` is not Proth number.
|
| 476 |
+
|
| 477 |
+
Examples
|
| 478 |
+
========
|
| 479 |
+
|
| 480 |
+
>>> from sympy.ntheory.primetest import proth_test
|
| 481 |
+
>>> proth_test(41)
|
| 482 |
+
True
|
| 483 |
+
>>> proth_test(57)
|
| 484 |
+
False
|
| 485 |
+
|
| 486 |
+
References
|
| 487 |
+
==========
|
| 488 |
+
|
| 489 |
+
.. [1] https://en.wikipedia.org/wiki/Proth_prime
|
| 490 |
+
|
| 491 |
+
"""
|
| 492 |
+
n = as_int(n)
|
| 493 |
+
if n < 3:
|
| 494 |
+
raise ValueError("n is not Proth number")
|
| 495 |
+
m = bit_scan1(n - 1)
|
| 496 |
+
k = n >> m
|
| 497 |
+
if m < k.bit_length():
|
| 498 |
+
raise ValueError("n is not Proth number")
|
| 499 |
+
if n % 3 == 0:
|
| 500 |
+
return n == 3
|
| 501 |
+
if k % 3: # n % 12 == 5
|
| 502 |
+
return pow(3, n >> 1, n) == n - 1
|
| 503 |
+
# If `n` is a square number, then `jacobi(a, n) = 1` for any `a`
|
| 504 |
+
if gmpy_is_square(n):
|
| 505 |
+
return False
|
| 506 |
+
# `a` may be chosen at random.
|
| 507 |
+
# In any case, we want to find `a` such that `jacobi(a, n) = -1`.
|
| 508 |
+
for a in range(5, n):
|
| 509 |
+
j = jacobi(a, n)
|
| 510 |
+
if j == -1:
|
| 511 |
+
return pow(a, n >> 1, n) == n - 1
|
| 512 |
+
if j == 0:
|
| 513 |
+
return False
|
| 514 |
+
|
| 515 |
+
|
| 516 |
+
def _lucas_lehmer_primality_test(p):
|
| 517 |
+
r""" Test if the Mersenne number `M_p = 2^p-1` is prime.
|
| 518 |
+
|
| 519 |
+
Parameters
|
| 520 |
+
==========
|
| 521 |
+
|
| 522 |
+
p : int
|
| 523 |
+
``p`` is an odd prime number
|
| 524 |
+
|
| 525 |
+
Returns
|
| 526 |
+
=======
|
| 527 |
+
|
| 528 |
+
bool : If ``True``, then `M_p` is the Mersenne prime
|
| 529 |
+
|
| 530 |
+
Examples
|
| 531 |
+
========
|
| 532 |
+
|
| 533 |
+
>>> from sympy.ntheory.primetest import _lucas_lehmer_primality_test
|
| 534 |
+
>>> _lucas_lehmer_primality_test(5) # 2**5 - 1 = 31 is prime
|
| 535 |
+
True
|
| 536 |
+
>>> _lucas_lehmer_primality_test(11) # 2**11 - 1 = 2047 is not prime
|
| 537 |
+
False
|
| 538 |
+
|
| 539 |
+
See Also
|
| 540 |
+
========
|
| 541 |
+
|
| 542 |
+
is_mersenne_prime
|
| 543 |
+
|
| 544 |
+
References
|
| 545 |
+
==========
|
| 546 |
+
|
| 547 |
+
.. [1] https://en.wikipedia.org/wiki/Lucas%E2%80%93Lehmer_primality_test
|
| 548 |
+
|
| 549 |
+
"""
|
| 550 |
+
v = 4
|
| 551 |
+
m = 2**p - 1
|
| 552 |
+
for _ in range(p - 2):
|
| 553 |
+
v = pow(v, 2, m) - 2
|
| 554 |
+
return v == 0
|
| 555 |
+
|
| 556 |
+
|
| 557 |
+
def is_mersenne_prime(n):
|
| 558 |
+
"""Returns True if ``n`` is a Mersenne prime, else False.
|
| 559 |
+
|
| 560 |
+
A Mersenne prime is a prime number having the form `2^i - 1`.
|
| 561 |
+
|
| 562 |
+
Examples
|
| 563 |
+
========
|
| 564 |
+
|
| 565 |
+
>>> from sympy.ntheory.factor_ import is_mersenne_prime
|
| 566 |
+
>>> is_mersenne_prime(6)
|
| 567 |
+
False
|
| 568 |
+
>>> is_mersenne_prime(127)
|
| 569 |
+
True
|
| 570 |
+
|
| 571 |
+
References
|
| 572 |
+
==========
|
| 573 |
+
|
| 574 |
+
.. [1] https://mathworld.wolfram.com/MersennePrime.html
|
| 575 |
+
|
| 576 |
+
"""
|
| 577 |
+
n = as_int(n)
|
| 578 |
+
if n < 1:
|
| 579 |
+
return False
|
| 580 |
+
if n & (n + 1):
|
| 581 |
+
# n is not Mersenne number
|
| 582 |
+
return False
|
| 583 |
+
p = n.bit_length()
|
| 584 |
+
if p in MERSENNE_PRIME_EXPONENTS:
|
| 585 |
+
return True
|
| 586 |
+
if p < 65_000_000 or not isprime(p):
|
| 587 |
+
# According to GIMPS, verification was completed on September 19, 2023 for p less than 65 million.
|
| 588 |
+
# https://www.mersenne.org/report_milestones/
|
| 589 |
+
# If p is composite number, then n=2**p-1 is composite number.
|
| 590 |
+
return False
|
| 591 |
+
result = _lucas_lehmer_primality_test(p)
|
| 592 |
+
if result:
|
| 593 |
+
raise ValueError(filldedent('''
|
| 594 |
+
This Mersenne Prime, 2^%s - 1, should
|
| 595 |
+
be added to SymPy's known values.''' % p))
|
| 596 |
+
return result
|
| 597 |
+
|
| 598 |
+
|
| 599 |
+
def isprime(n):
|
| 600 |
+
"""
|
| 601 |
+
Test if n is a prime number (True) or not (False). For n < 2^64 the
|
| 602 |
+
answer is definitive; larger n values have a small probability of actually
|
| 603 |
+
being pseudoprimes.
|
| 604 |
+
|
| 605 |
+
Negative numbers (e.g. -2) are not considered prime.
|
| 606 |
+
|
| 607 |
+
The first step is looking for trivial factors, which if found enables
|
| 608 |
+
a quick return. Next, if the sieve is large enough, use bisection search
|
| 609 |
+
on the sieve. For small numbers, a set of deterministic Miller-Rabin
|
| 610 |
+
tests are performed with bases that are known to have no counterexamples
|
| 611 |
+
in their range. Finally if the number is larger than 2^64, a strong
|
| 612 |
+
BPSW test is performed. While this is a probable prime test and we
|
| 613 |
+
believe counterexamples exist, there are no known counterexamples.
|
| 614 |
+
|
| 615 |
+
Examples
|
| 616 |
+
========
|
| 617 |
+
|
| 618 |
+
>>> from sympy.ntheory import isprime
|
| 619 |
+
>>> isprime(13)
|
| 620 |
+
True
|
| 621 |
+
>>> isprime(15)
|
| 622 |
+
False
|
| 623 |
+
|
| 624 |
+
Notes
|
| 625 |
+
=====
|
| 626 |
+
|
| 627 |
+
This routine is intended only for integer input, not numerical
|
| 628 |
+
expressions which may represent numbers. Floats are also
|
| 629 |
+
rejected as input because they represent numbers of limited
|
| 630 |
+
precision. While it is tempting to permit 7.0 to represent an
|
| 631 |
+
integer there are errors that may "pass silently" if this is
|
| 632 |
+
allowed:
|
| 633 |
+
|
| 634 |
+
>>> from sympy import Float, S
|
| 635 |
+
>>> int(1e3) == 1e3 == 10**3
|
| 636 |
+
True
|
| 637 |
+
>>> int(1e23) == 1e23
|
| 638 |
+
True
|
| 639 |
+
>>> int(1e23) == 10**23
|
| 640 |
+
False
|
| 641 |
+
|
| 642 |
+
>>> near_int = 1 + S(1)/10**19
|
| 643 |
+
>>> near_int == int(near_int)
|
| 644 |
+
False
|
| 645 |
+
>>> n = Float(near_int, 10) # truncated by precision
|
| 646 |
+
>>> n % 1 == 0
|
| 647 |
+
True
|
| 648 |
+
>>> n = Float(near_int, 20)
|
| 649 |
+
>>> n % 1 == 0
|
| 650 |
+
False
|
| 651 |
+
|
| 652 |
+
See Also
|
| 653 |
+
========
|
| 654 |
+
|
| 655 |
+
sympy.ntheory.generate.primerange : Generates all primes in a given range
|
| 656 |
+
sympy.functions.combinatorial.numbers.primepi : Return the number of primes less than or equal to n
|
| 657 |
+
sympy.ntheory.generate.prime : Return the nth prime
|
| 658 |
+
|
| 659 |
+
References
|
| 660 |
+
==========
|
| 661 |
+
.. [1] https://en.wikipedia.org/wiki/Strong_pseudoprime
|
| 662 |
+
.. [2] Robert Baillie, Samuel S. Wagstaff, Lucas Pseudoprimes,
|
| 663 |
+
Math. Comp. Vol 35, Number 152 (1980), pp. 1391-1417,
|
| 664 |
+
https://doi.org/10.1090%2FS0025-5718-1980-0583518-6
|
| 665 |
+
http://mpqs.free.fr/LucasPseudoprimes.pdf
|
| 666 |
+
.. [3] https://en.wikipedia.org/wiki/Baillie-PSW_primality_test
|
| 667 |
+
"""
|
| 668 |
+
n = as_int(n)
|
| 669 |
+
|
| 670 |
+
# Step 1, do quick composite testing via trial division. The individual
|
| 671 |
+
# modulo tests benchmark faster than one or two primorial igcds for me.
|
| 672 |
+
# The point here is just to speedily handle small numbers and many
|
| 673 |
+
# composites. Step 2 only requires that n <= 2 get handled here.
|
| 674 |
+
if n in [2, 3, 5]:
|
| 675 |
+
return True
|
| 676 |
+
if n < 2 or (n % 2) == 0 or (n % 3) == 0 or (n % 5) == 0:
|
| 677 |
+
return False
|
| 678 |
+
if n < 49:
|
| 679 |
+
return True
|
| 680 |
+
if (n % 7) == 0 or (n % 11) == 0 or (n % 13) == 0 or (n % 17) == 0 or \
|
| 681 |
+
(n % 19) == 0 or (n % 23) == 0 or (n % 29) == 0 or (n % 31) == 0 or \
|
| 682 |
+
(n % 37) == 0 or (n % 41) == 0 or (n % 43) == 0 or (n % 47) == 0:
|
| 683 |
+
return False
|
| 684 |
+
if n < 2809:
|
| 685 |
+
return True
|
| 686 |
+
if n < 65077:
|
| 687 |
+
# There are only five Euler pseudoprimes with a least prime factor greater than 47
|
| 688 |
+
return pow(2, n >> 1, n) in [1, n - 1] and n not in [8321, 31621, 42799, 49141, 49981]
|
| 689 |
+
|
| 690 |
+
# bisection search on the sieve if the sieve is large enough
|
| 691 |
+
from sympy.ntheory.generate import sieve as s
|
| 692 |
+
if n <= s._list[-1]:
|
| 693 |
+
l, u = s.search(n)
|
| 694 |
+
return l == u
|
| 695 |
+
|
| 696 |
+
# If we have GMPY2, skip straight to step 3 and do a strong BPSW test.
|
| 697 |
+
# This should be a bit faster than our step 2, and for large values will
|
| 698 |
+
# be a lot faster than our step 3 (C+GMP vs. Python).
|
| 699 |
+
if _gmpy is not None:
|
| 700 |
+
return is_strong_bpsw_prp(n)
|
| 701 |
+
|
| 702 |
+
|
| 703 |
+
# Step 2: deterministic Miller-Rabin testing for numbers < 2^64. See:
|
| 704 |
+
# https://miller-rabin.appspot.com/
|
| 705 |
+
# for lists. We have made sure the M-R routine will successfully handle
|
| 706 |
+
# bases larger than n, so we can use the minimal set.
|
| 707 |
+
# In September 2015 deterministic numbers were extended to over 2^81.
|
| 708 |
+
# https://arxiv.org/pdf/1509.00864.pdf
|
| 709 |
+
# https://oeis.org/A014233
|
| 710 |
+
if n < 341531:
|
| 711 |
+
return mr(n, [9345883071009581737])
|
| 712 |
+
if n < 885594169:
|
| 713 |
+
return mr(n, [725270293939359937, 3569819667048198375])
|
| 714 |
+
if n < 350269456337:
|
| 715 |
+
return mr(n, [4230279247111683200, 14694767155120705706, 16641139526367750375])
|
| 716 |
+
if n < 55245642489451:
|
| 717 |
+
return mr(n, [2, 141889084524735, 1199124725622454117, 11096072698276303650])
|
| 718 |
+
if n < 7999252175582851:
|
| 719 |
+
return mr(n, [2, 4130806001517, 149795463772692060, 186635894390467037, 3967304179347715805])
|
| 720 |
+
if n < 585226005592931977:
|
| 721 |
+
return mr(n, [2, 123635709730000, 9233062284813009, 43835965440333360, 761179012939631437, 1263739024124850375])
|
| 722 |
+
if n < 18446744073709551616:
|
| 723 |
+
return mr(n, [2, 325, 9375, 28178, 450775, 9780504, 1795265022])
|
| 724 |
+
if n < 318665857834031151167461:
|
| 725 |
+
return mr(n, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37])
|
| 726 |
+
if n < 3317044064679887385961981:
|
| 727 |
+
return mr(n, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41])
|
| 728 |
+
|
| 729 |
+
# We could do this instead at any point:
|
| 730 |
+
#if n < 18446744073709551616:
|
| 731 |
+
# return mr(n, [2]) and is_extra_strong_lucas_prp(n)
|
| 732 |
+
|
| 733 |
+
# Here are tests that are safe for MR routines that don't understand
|
| 734 |
+
# large bases.
|
| 735 |
+
#if n < 9080191:
|
| 736 |
+
# return mr(n, [31, 73])
|
| 737 |
+
#if n < 19471033:
|
| 738 |
+
# return mr(n, [2, 299417])
|
| 739 |
+
#if n < 38010307:
|
| 740 |
+
# return mr(n, [2, 9332593])
|
| 741 |
+
#if n < 316349281:
|
| 742 |
+
# return mr(n, [11000544, 31481107])
|
| 743 |
+
#if n < 4759123141:
|
| 744 |
+
# return mr(n, [2, 7, 61])
|
| 745 |
+
#if n < 105936894253:
|
| 746 |
+
# return mr(n, [2, 1005905886, 1340600841])
|
| 747 |
+
#if n < 31858317218647:
|
| 748 |
+
# return mr(n, [2, 642735, 553174392, 3046413974])
|
| 749 |
+
#if n < 3071837692357849:
|
| 750 |
+
# return mr(n, [2, 75088, 642735, 203659041, 3613982119])
|
| 751 |
+
#if n < 18446744073709551616:
|
| 752 |
+
# return mr(n, [2, 325, 9375, 28178, 450775, 9780504, 1795265022])
|
| 753 |
+
|
| 754 |
+
# Step 3: BPSW.
|
| 755 |
+
#
|
| 756 |
+
# Time for isprime(10**2000 + 4561), no gmpy or gmpy2 installed
|
| 757 |
+
# 44.0s old isprime using 46 bases
|
| 758 |
+
# 5.3s strong BPSW + one random base
|
| 759 |
+
# 4.3s extra strong BPSW + one random base
|
| 760 |
+
# 4.1s strong BPSW
|
| 761 |
+
# 3.2s extra strong BPSW
|
| 762 |
+
|
| 763 |
+
# Classic BPSW from page 1401 of the paper. See alternate ideas below.
|
| 764 |
+
return is_strong_bpsw_prp(n)
|
| 765 |
+
|
| 766 |
+
# Using extra strong test, which is somewhat faster
|
| 767 |
+
#return mr(n, [2]) and is_extra_strong_lucas_prp(n)
|
| 768 |
+
|
| 769 |
+
# Add a random M-R base
|
| 770 |
+
#import random
|
| 771 |
+
#return mr(n, [2, random.randint(3, n-1)]) and is_strong_lucas_prp(n)
|
| 772 |
+
|
| 773 |
+
|
| 774 |
+
def is_gaussian_prime(num):
|
| 775 |
+
r"""Test if num is a Gaussian prime number.
|
| 776 |
+
|
| 777 |
+
References
|
| 778 |
+
==========
|
| 779 |
+
|
| 780 |
+
.. [1] https://oeis.org/wiki/Gaussian_primes
|
| 781 |
+
"""
|
| 782 |
+
|
| 783 |
+
num = sympify(num)
|
| 784 |
+
a, b = num.as_real_imag()
|
| 785 |
+
a = as_int(a, strict=False)
|
| 786 |
+
b = as_int(b, strict=False)
|
| 787 |
+
if a == 0:
|
| 788 |
+
b = abs(b)
|
| 789 |
+
return isprime(b) and b % 4 == 3
|
| 790 |
+
elif b == 0:
|
| 791 |
+
a = abs(a)
|
| 792 |
+
return isprime(a) and a % 4 == 3
|
| 793 |
+
return isprime(a**2 + b**2)
|
lib/python3.12/site-packages/sympy/ntheory/qs.py
ADDED
|
@@ -0,0 +1,511 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.core.random import _randint
|
| 2 |
+
from sympy.external.gmpy import gcd, invert, sqrt as isqrt
|
| 3 |
+
from sympy.ntheory.residue_ntheory import _sqrt_mod_prime_power
|
| 4 |
+
from sympy.ntheory import isprime
|
| 5 |
+
from math import log, sqrt
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class SievePolynomial:
|
| 9 |
+
def __init__(self, modified_coeff=(), a=None, b=None):
|
| 10 |
+
"""This class denotes the seive polynomial.
|
| 11 |
+
If ``g(x) = (a*x + b)**2 - N``. `g(x)` can be expanded
|
| 12 |
+
to ``a*x**2 + 2*a*b*x + b**2 - N``, so the coefficient
|
| 13 |
+
is stored in the form `[a**2, 2*a*b, b**2 - N]`. This
|
| 14 |
+
ensures faster `eval` method because we dont have to
|
| 15 |
+
perform `a**2, 2*a*b, b**2` every time we call the
|
| 16 |
+
`eval` method. As multiplication is more expensive
|
| 17 |
+
than addition, by using modified_coefficient we get
|
| 18 |
+
a faster seiving process.
|
| 19 |
+
|
| 20 |
+
Parameters
|
| 21 |
+
==========
|
| 22 |
+
|
| 23 |
+
modified_coeff : modified_coefficient of sieve polynomial
|
| 24 |
+
a : parameter of the sieve polynomial
|
| 25 |
+
b : parameter of the sieve polynomial
|
| 26 |
+
"""
|
| 27 |
+
self.modified_coeff = modified_coeff
|
| 28 |
+
self.a = a
|
| 29 |
+
self.b = b
|
| 30 |
+
|
| 31 |
+
def eval(self, x):
|
| 32 |
+
"""
|
| 33 |
+
Compute the value of the sieve polynomial at point x.
|
| 34 |
+
|
| 35 |
+
Parameters
|
| 36 |
+
==========
|
| 37 |
+
|
| 38 |
+
x : Integer parameter for sieve polynomial
|
| 39 |
+
"""
|
| 40 |
+
ans = 0
|
| 41 |
+
for coeff in self.modified_coeff:
|
| 42 |
+
ans *= x
|
| 43 |
+
ans += coeff
|
| 44 |
+
return ans
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
class FactorBaseElem:
|
| 48 |
+
"""This class stores an element of the `factor_base`.
|
| 49 |
+
"""
|
| 50 |
+
def __init__(self, prime, tmem_p, log_p):
|
| 51 |
+
"""
|
| 52 |
+
Initialization of factor_base_elem.
|
| 53 |
+
|
| 54 |
+
Parameters
|
| 55 |
+
==========
|
| 56 |
+
|
| 57 |
+
prime : prime number of the factor_base
|
| 58 |
+
tmem_p : Integer square root of x**2 = n mod prime
|
| 59 |
+
log_p : Compute Natural Logarithm of the prime
|
| 60 |
+
"""
|
| 61 |
+
self.prime = prime
|
| 62 |
+
self.tmem_p = tmem_p
|
| 63 |
+
self.log_p = log_p
|
| 64 |
+
self.soln1 = None
|
| 65 |
+
self.soln2 = None
|
| 66 |
+
self.a_inv = None
|
| 67 |
+
self.b_ainv = None
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
def _generate_factor_base(prime_bound, n):
|
| 71 |
+
"""Generate `factor_base` for Quadratic Sieve. The `factor_base`
|
| 72 |
+
consists of all the points whose ``legendre_symbol(n, p) == 1``
|
| 73 |
+
and ``p < num_primes``. Along with the prime `factor_base` also stores
|
| 74 |
+
natural logarithm of prime and the residue n modulo p.
|
| 75 |
+
It also returns the of primes numbers in the `factor_base` which are
|
| 76 |
+
close to 1000 and 5000.
|
| 77 |
+
|
| 78 |
+
Parameters
|
| 79 |
+
==========
|
| 80 |
+
|
| 81 |
+
prime_bound : upper prime bound of the factor_base
|
| 82 |
+
n : integer to be factored
|
| 83 |
+
"""
|
| 84 |
+
from sympy.ntheory.generate import sieve
|
| 85 |
+
factor_base = []
|
| 86 |
+
idx_1000, idx_5000 = None, None
|
| 87 |
+
for prime in sieve.primerange(1, prime_bound):
|
| 88 |
+
if pow(n, (prime - 1) // 2, prime) == 1:
|
| 89 |
+
if prime > 1000 and idx_1000 is None:
|
| 90 |
+
idx_1000 = len(factor_base) - 1
|
| 91 |
+
if prime > 5000 and idx_5000 is None:
|
| 92 |
+
idx_5000 = len(factor_base) - 1
|
| 93 |
+
residue = _sqrt_mod_prime_power(n, prime, 1)[0]
|
| 94 |
+
log_p = round(log(prime)*2**10)
|
| 95 |
+
factor_base.append(FactorBaseElem(prime, residue, log_p))
|
| 96 |
+
return idx_1000, idx_5000, factor_base
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
def _initialize_first_polynomial(N, M, factor_base, idx_1000, idx_5000, seed=None):
|
| 100 |
+
"""This step is the initialization of the 1st sieve polynomial.
|
| 101 |
+
Here `a` is selected as a product of several primes of the factor_base
|
| 102 |
+
such that `a` is about to ``sqrt(2*N) / M``. Other initial values of
|
| 103 |
+
factor_base elem are also initialized which includes a_inv, b_ainv, soln1,
|
| 104 |
+
soln2 which are used when the sieve polynomial is changed. The b_ainv
|
| 105 |
+
is required for fast polynomial change as we do not have to calculate
|
| 106 |
+
`2*b*invert(a, prime)` every time.
|
| 107 |
+
We also ensure that the `factor_base` primes which make `a` are between
|
| 108 |
+
1000 and 5000.
|
| 109 |
+
|
| 110 |
+
Parameters
|
| 111 |
+
==========
|
| 112 |
+
|
| 113 |
+
N : Number to be factored
|
| 114 |
+
M : sieve interval
|
| 115 |
+
factor_base : factor_base primes
|
| 116 |
+
idx_1000 : index of prime number in the factor_base near 1000
|
| 117 |
+
idx_5000 : index of prime number in the factor_base near to 5000
|
| 118 |
+
seed : Generate pseudoprime numbers
|
| 119 |
+
"""
|
| 120 |
+
randint = _randint(seed)
|
| 121 |
+
approx_val = sqrt(2*N) / M
|
| 122 |
+
# `a` is a parameter of the sieve polynomial and `q` is the prime factors of `a`
|
| 123 |
+
# randomly search for a combination of primes whose multiplication is close to approx_val
|
| 124 |
+
# This multiplication of primes will be `a` and the primes will be `q`
|
| 125 |
+
# `best_a` denotes that `a` is close to approx_val in the random search of combination
|
| 126 |
+
best_a, best_q, best_ratio = None, None, None
|
| 127 |
+
start = 0 if idx_1000 is None else idx_1000
|
| 128 |
+
end = len(factor_base) - 1 if idx_5000 is None else idx_5000
|
| 129 |
+
for _ in range(50):
|
| 130 |
+
a = 1
|
| 131 |
+
q = []
|
| 132 |
+
while(a < approx_val):
|
| 133 |
+
rand_p = 0
|
| 134 |
+
while(rand_p == 0 or rand_p in q):
|
| 135 |
+
rand_p = randint(start, end)
|
| 136 |
+
p = factor_base[rand_p].prime
|
| 137 |
+
a *= p
|
| 138 |
+
q.append(rand_p)
|
| 139 |
+
ratio = a / approx_val
|
| 140 |
+
if best_ratio is None or abs(ratio - 1) < abs(best_ratio - 1):
|
| 141 |
+
best_q = q
|
| 142 |
+
best_a = a
|
| 143 |
+
best_ratio = ratio
|
| 144 |
+
|
| 145 |
+
a = best_a
|
| 146 |
+
q = best_q
|
| 147 |
+
|
| 148 |
+
B = []
|
| 149 |
+
for val in q:
|
| 150 |
+
q_l = factor_base[val].prime
|
| 151 |
+
gamma = factor_base[val].tmem_p * invert(a // q_l, q_l) % q_l
|
| 152 |
+
if gamma > q_l / 2:
|
| 153 |
+
gamma = q_l - gamma
|
| 154 |
+
B.append(a//q_l*gamma)
|
| 155 |
+
|
| 156 |
+
b = sum(B)
|
| 157 |
+
g = SievePolynomial([a*a, 2*a*b, b*b - N], a, b)
|
| 158 |
+
|
| 159 |
+
for fb in factor_base:
|
| 160 |
+
if a % fb.prime == 0:
|
| 161 |
+
continue
|
| 162 |
+
fb.a_inv = invert(a, fb.prime)
|
| 163 |
+
fb.b_ainv = [2*b_elem*fb.a_inv % fb.prime for b_elem in B]
|
| 164 |
+
fb.soln1 = (fb.a_inv*(fb.tmem_p - b)) % fb.prime
|
| 165 |
+
fb.soln2 = (fb.a_inv*(-fb.tmem_p - b)) % fb.prime
|
| 166 |
+
return g, B
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
def _initialize_ith_poly(N, factor_base, i, g, B):
|
| 170 |
+
"""Initialization stage of ith poly. After we finish sieving 1`st polynomial
|
| 171 |
+
here we quickly change to the next polynomial from which we will again
|
| 172 |
+
start sieving. Suppose we generated ith sieve polynomial and now we
|
| 173 |
+
want to generate (i + 1)th polynomial, where ``1 <= i <= 2**(j - 1) - 1``
|
| 174 |
+
where `j` is the number of prime factors of the coefficient `a`
|
| 175 |
+
then this function can be used to go to the next polynomial. If
|
| 176 |
+
``i = 2**(j - 1) - 1`` then go to _initialize_first_polynomial stage.
|
| 177 |
+
|
| 178 |
+
Parameters
|
| 179 |
+
==========
|
| 180 |
+
|
| 181 |
+
N : number to be factored
|
| 182 |
+
factor_base : factor_base primes
|
| 183 |
+
i : integer denoting ith polynomial
|
| 184 |
+
g : (i - 1)th polynomial
|
| 185 |
+
B : array that stores a//q_l*gamma
|
| 186 |
+
"""
|
| 187 |
+
from sympy.functions.elementary.integers import ceiling
|
| 188 |
+
v = 1
|
| 189 |
+
j = i
|
| 190 |
+
while(j % 2 == 0):
|
| 191 |
+
v += 1
|
| 192 |
+
j //= 2
|
| 193 |
+
if ceiling(i / (2**v)) % 2 == 1:
|
| 194 |
+
neg_pow = -1
|
| 195 |
+
else:
|
| 196 |
+
neg_pow = 1
|
| 197 |
+
b = g.b + 2*neg_pow*B[v - 1]
|
| 198 |
+
a = g.a
|
| 199 |
+
g = SievePolynomial([a*a, 2*a*b, b*b - N], a, b)
|
| 200 |
+
for fb in factor_base:
|
| 201 |
+
if a % fb.prime == 0:
|
| 202 |
+
continue
|
| 203 |
+
fb.soln1 = (fb.soln1 - neg_pow*fb.b_ainv[v - 1]) % fb.prime
|
| 204 |
+
fb.soln2 = (fb.soln2 - neg_pow*fb.b_ainv[v - 1]) % fb.prime
|
| 205 |
+
|
| 206 |
+
return g
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
def _gen_sieve_array(M, factor_base):
|
| 210 |
+
"""Sieve Stage of the Quadratic Sieve. For every prime in the factor_base
|
| 211 |
+
that does not divide the coefficient `a` we add log_p over the sieve_array
|
| 212 |
+
such that ``-M <= soln1 + i*p <= M`` and ``-M <= soln2 + i*p <= M`` where `i`
|
| 213 |
+
is an integer. When p = 2 then log_p is only added using
|
| 214 |
+
``-M <= soln1 + i*p <= M``.
|
| 215 |
+
|
| 216 |
+
Parameters
|
| 217 |
+
==========
|
| 218 |
+
|
| 219 |
+
M : sieve interval
|
| 220 |
+
factor_base : factor_base primes
|
| 221 |
+
"""
|
| 222 |
+
sieve_array = [0]*(2*M + 1)
|
| 223 |
+
for factor in factor_base:
|
| 224 |
+
if factor.soln1 is None: #The prime does not divides a
|
| 225 |
+
continue
|
| 226 |
+
for idx in range((M + factor.soln1) % factor.prime, 2*M, factor.prime):
|
| 227 |
+
sieve_array[idx] += factor.log_p
|
| 228 |
+
if factor.prime == 2:
|
| 229 |
+
continue
|
| 230 |
+
#if prime is 2 then sieve only with soln_1_p
|
| 231 |
+
for idx in range((M + factor.soln2) % factor.prime, 2*M, factor.prime):
|
| 232 |
+
sieve_array[idx] += factor.log_p
|
| 233 |
+
return sieve_array
|
| 234 |
+
|
| 235 |
+
|
| 236 |
+
def _check_smoothness(num, factor_base):
|
| 237 |
+
"""Here we check that if `num` is a smooth number or not. If `a` is a smooth
|
| 238 |
+
number then it returns a vector of prime exponents modulo 2. For example
|
| 239 |
+
if a = 2 * 5**2 * 7**3 and the factor base contains {2, 3, 5, 7} then
|
| 240 |
+
`a` is a smooth number and this function returns ([1, 0, 0, 1], True). If
|
| 241 |
+
`a` is a partial relation which means that `a` a has one prime factor
|
| 242 |
+
greater than the `factor_base` then it returns `(a, False)` which denotes `a`
|
| 243 |
+
is a partial relation.
|
| 244 |
+
|
| 245 |
+
Parameters
|
| 246 |
+
==========
|
| 247 |
+
|
| 248 |
+
a : integer whose smootheness is to be checked
|
| 249 |
+
factor_base : factor_base primes
|
| 250 |
+
"""
|
| 251 |
+
vec = []
|
| 252 |
+
if num < 0:
|
| 253 |
+
vec.append(1)
|
| 254 |
+
num *= -1
|
| 255 |
+
else:
|
| 256 |
+
vec.append(0)
|
| 257 |
+
#-1 is not included in factor_base add -1 in vector
|
| 258 |
+
for factor in factor_base:
|
| 259 |
+
if num % factor.prime != 0:
|
| 260 |
+
vec.append(0)
|
| 261 |
+
continue
|
| 262 |
+
factor_exp = 0
|
| 263 |
+
while num % factor.prime == 0:
|
| 264 |
+
factor_exp += 1
|
| 265 |
+
num //= factor.prime
|
| 266 |
+
vec.append(factor_exp % 2)
|
| 267 |
+
if num == 1:
|
| 268 |
+
return vec, True
|
| 269 |
+
if isprime(num):
|
| 270 |
+
return num, False
|
| 271 |
+
return None, None
|
| 272 |
+
|
| 273 |
+
|
| 274 |
+
def _trial_division_stage(N, M, factor_base, sieve_array, sieve_poly, partial_relations, ERROR_TERM):
|
| 275 |
+
"""Trial division stage. Here we trial divide the values generetated
|
| 276 |
+
by sieve_poly in the sieve interval and if it is a smooth number then
|
| 277 |
+
it is stored in `smooth_relations`. Moreover, if we find two partial relations
|
| 278 |
+
with same large prime then they are combined to form a smooth relation.
|
| 279 |
+
First we iterate over sieve array and look for values which are greater
|
| 280 |
+
than accumulated_val, as these values have a high chance of being smooth
|
| 281 |
+
number. Then using these values we find smooth relations.
|
| 282 |
+
In general, let ``t**2 = u*p modN`` and ``r**2 = v*p modN`` be two partial relations
|
| 283 |
+
with the same large prime p. Then they can be combined ``(t*r/p)**2 = u*v modN``
|
| 284 |
+
to form a smooth relation.
|
| 285 |
+
|
| 286 |
+
Parameters
|
| 287 |
+
==========
|
| 288 |
+
|
| 289 |
+
N : Number to be factored
|
| 290 |
+
M : sieve interval
|
| 291 |
+
factor_base : factor_base primes
|
| 292 |
+
sieve_array : stores log_p values
|
| 293 |
+
sieve_poly : polynomial from which we find smooth relations
|
| 294 |
+
partial_relations : stores partial relations with one large prime
|
| 295 |
+
ERROR_TERM : error term for accumulated_val
|
| 296 |
+
"""
|
| 297 |
+
sqrt_n = isqrt(N)
|
| 298 |
+
accumulated_val = log(M * sqrt_n)*2**10 - ERROR_TERM
|
| 299 |
+
smooth_relations = []
|
| 300 |
+
proper_factor = set()
|
| 301 |
+
partial_relation_upper_bound = 128*factor_base[-1].prime
|
| 302 |
+
for idx, val in enumerate(sieve_array):
|
| 303 |
+
if val < accumulated_val:
|
| 304 |
+
continue
|
| 305 |
+
x = idx - M
|
| 306 |
+
v = sieve_poly.eval(x)
|
| 307 |
+
vec, is_smooth = _check_smoothness(v, factor_base)
|
| 308 |
+
if is_smooth is None:#Neither smooth nor partial
|
| 309 |
+
continue
|
| 310 |
+
u = sieve_poly.a*x + sieve_poly.b
|
| 311 |
+
# Update the partial relation
|
| 312 |
+
# If 2 partial relation with same large prime is found then generate smooth relation
|
| 313 |
+
if is_smooth is False:#partial relation found
|
| 314 |
+
large_prime = vec
|
| 315 |
+
#Consider the large_primes under 128*F
|
| 316 |
+
if large_prime > partial_relation_upper_bound:
|
| 317 |
+
continue
|
| 318 |
+
if large_prime not in partial_relations:
|
| 319 |
+
partial_relations[large_prime] = (u, v)
|
| 320 |
+
continue
|
| 321 |
+
else:
|
| 322 |
+
u_prev, v_prev = partial_relations[large_prime]
|
| 323 |
+
partial_relations.pop(large_prime)
|
| 324 |
+
try:
|
| 325 |
+
large_prime_inv = invert(large_prime, N)
|
| 326 |
+
except ZeroDivisionError:#if large_prime divides N
|
| 327 |
+
proper_factor.add(large_prime)
|
| 328 |
+
continue
|
| 329 |
+
u = u*u_prev*large_prime_inv
|
| 330 |
+
v = v*v_prev // (large_prime*large_prime)
|
| 331 |
+
vec, is_smooth = _check_smoothness(v, factor_base)
|
| 332 |
+
#assert u*u % N == v % N
|
| 333 |
+
smooth_relations.append((u, v, vec))
|
| 334 |
+
return smooth_relations, proper_factor
|
| 335 |
+
|
| 336 |
+
|
| 337 |
+
#LINEAR ALGEBRA STAGE
|
| 338 |
+
def _build_matrix(smooth_relations):
|
| 339 |
+
"""Build a 2D matrix from smooth relations.
|
| 340 |
+
|
| 341 |
+
Parameters
|
| 342 |
+
==========
|
| 343 |
+
|
| 344 |
+
smooth_relations : Stores smooth relations
|
| 345 |
+
"""
|
| 346 |
+
matrix = []
|
| 347 |
+
for s_relation in smooth_relations:
|
| 348 |
+
matrix.append(s_relation[2])
|
| 349 |
+
return matrix
|
| 350 |
+
|
| 351 |
+
|
| 352 |
+
def _gauss_mod_2(A):
|
| 353 |
+
"""Fast gaussian reduction for modulo 2 matrix.
|
| 354 |
+
|
| 355 |
+
Parameters
|
| 356 |
+
==========
|
| 357 |
+
|
| 358 |
+
A : Matrix
|
| 359 |
+
|
| 360 |
+
Examples
|
| 361 |
+
========
|
| 362 |
+
|
| 363 |
+
>>> from sympy.ntheory.qs import _gauss_mod_2
|
| 364 |
+
>>> _gauss_mod_2([[0, 1, 1], [1, 0, 1], [0, 1, 0], [1, 1, 1]])
|
| 365 |
+
([[[1, 0, 1], 3]],
|
| 366 |
+
[True, True, True, False],
|
| 367 |
+
[[0, 1, 0], [1, 0, 0], [0, 0, 1], [1, 0, 1]])
|
| 368 |
+
|
| 369 |
+
Reference
|
| 370 |
+
==========
|
| 371 |
+
|
| 372 |
+
.. [1] A fast algorithm for gaussian elimination over GF(2) and
|
| 373 |
+
its implementation on the GAPP. Cetin K.Koc, Sarath N.Arachchige"""
|
| 374 |
+
import copy
|
| 375 |
+
matrix = copy.deepcopy(A)
|
| 376 |
+
row = len(matrix)
|
| 377 |
+
col = len(matrix[0])
|
| 378 |
+
mark = [False]*row
|
| 379 |
+
for c in range(col):
|
| 380 |
+
for r in range(row):
|
| 381 |
+
if matrix[r][c] == 1:
|
| 382 |
+
break
|
| 383 |
+
mark[r] = True
|
| 384 |
+
for c1 in range(col):
|
| 385 |
+
if c1 == c:
|
| 386 |
+
continue
|
| 387 |
+
if matrix[r][c1] == 1:
|
| 388 |
+
for r2 in range(row):
|
| 389 |
+
matrix[r2][c1] = (matrix[r2][c1] + matrix[r2][c]) % 2
|
| 390 |
+
dependent_row = []
|
| 391 |
+
for idx, val in enumerate(mark):
|
| 392 |
+
if val == False:
|
| 393 |
+
dependent_row.append([matrix[idx], idx])
|
| 394 |
+
return dependent_row, mark, matrix
|
| 395 |
+
|
| 396 |
+
|
| 397 |
+
def _find_factor(dependent_rows, mark, gauss_matrix, index, smooth_relations, N):
|
| 398 |
+
"""Finds proper factor of N. Here, transform the dependent rows as a
|
| 399 |
+
combination of independent rows of the gauss_matrix to form the desired
|
| 400 |
+
relation of the form ``X**2 = Y**2 modN``. After obtaining the desired relation
|
| 401 |
+
we obtain a proper factor of N by `gcd(X - Y, N)`.
|
| 402 |
+
|
| 403 |
+
Parameters
|
| 404 |
+
==========
|
| 405 |
+
|
| 406 |
+
dependent_rows : denoted dependent rows in the reduced matrix form
|
| 407 |
+
mark : boolean array to denoted dependent and independent rows
|
| 408 |
+
gauss_matrix : Reduced form of the smooth relations matrix
|
| 409 |
+
index : denoted the index of the dependent_rows
|
| 410 |
+
smooth_relations : Smooth relations vectors matrix
|
| 411 |
+
N : Number to be factored
|
| 412 |
+
"""
|
| 413 |
+
idx_in_smooth = dependent_rows[index][1]
|
| 414 |
+
independent_u = [smooth_relations[idx_in_smooth][0]]
|
| 415 |
+
independent_v = [smooth_relations[idx_in_smooth][1]]
|
| 416 |
+
dept_row = dependent_rows[index][0]
|
| 417 |
+
|
| 418 |
+
for idx, val in enumerate(dept_row):
|
| 419 |
+
if val == 1:
|
| 420 |
+
for row in range(len(gauss_matrix)):
|
| 421 |
+
if gauss_matrix[row][idx] == 1 and mark[row] == True:
|
| 422 |
+
independent_u.append(smooth_relations[row][0])
|
| 423 |
+
independent_v.append(smooth_relations[row][1])
|
| 424 |
+
break
|
| 425 |
+
|
| 426 |
+
u = 1
|
| 427 |
+
v = 1
|
| 428 |
+
for i in independent_u:
|
| 429 |
+
u *= i
|
| 430 |
+
for i in independent_v:
|
| 431 |
+
v *= i
|
| 432 |
+
#assert u**2 % N == v % N
|
| 433 |
+
v = isqrt(v)
|
| 434 |
+
return gcd(u - v, N)
|
| 435 |
+
|
| 436 |
+
|
| 437 |
+
def qs(N, prime_bound, M, ERROR_TERM=25, seed=1234):
|
| 438 |
+
"""Performs factorization using Self-Initializing Quadratic Sieve.
|
| 439 |
+
In SIQS, let N be a number to be factored, and this N should not be a
|
| 440 |
+
perfect power. If we find two integers such that ``X**2 = Y**2 modN`` and
|
| 441 |
+
``X != +-Y modN``, then `gcd(X + Y, N)` will reveal a proper factor of N.
|
| 442 |
+
In order to find these integers X and Y we try to find relations of form
|
| 443 |
+
t**2 = u modN where u is a product of small primes. If we have enough of
|
| 444 |
+
these relations then we can form ``(t1*t2...ti)**2 = u1*u2...ui modN`` such that
|
| 445 |
+
the right hand side is a square, thus we found a relation of ``X**2 = Y**2 modN``.
|
| 446 |
+
|
| 447 |
+
Here, several optimizations are done like using multiple polynomials for
|
| 448 |
+
sieving, fast changing between polynomials and using partial relations.
|
| 449 |
+
The use of partial relations can speeds up the factoring by 2 times.
|
| 450 |
+
|
| 451 |
+
Parameters
|
| 452 |
+
==========
|
| 453 |
+
|
| 454 |
+
N : Number to be Factored
|
| 455 |
+
prime_bound : upper bound for primes in the factor base
|
| 456 |
+
M : Sieve Interval
|
| 457 |
+
ERROR_TERM : Error term for checking smoothness
|
| 458 |
+
threshold : Extra smooth relations for factorization
|
| 459 |
+
seed : generate pseudo prime numbers
|
| 460 |
+
|
| 461 |
+
Examples
|
| 462 |
+
========
|
| 463 |
+
|
| 464 |
+
>>> from sympy.ntheory import qs
|
| 465 |
+
>>> qs(25645121643901801, 2000, 10000)
|
| 466 |
+
{5394769, 4753701529}
|
| 467 |
+
>>> qs(9804659461513846513, 2000, 10000)
|
| 468 |
+
{4641991, 2112166839943}
|
| 469 |
+
|
| 470 |
+
References
|
| 471 |
+
==========
|
| 472 |
+
|
| 473 |
+
.. [1] https://pdfs.semanticscholar.org/5c52/8a975c1405bd35c65993abf5a4edb667c1db.pdf
|
| 474 |
+
.. [2] https://www.rieselprime.de/ziki/Self-initializing_quadratic_sieve
|
| 475 |
+
"""
|
| 476 |
+
ERROR_TERM*=2**10
|
| 477 |
+
idx_1000, idx_5000, factor_base = _generate_factor_base(prime_bound, N)
|
| 478 |
+
smooth_relations = []
|
| 479 |
+
ith_poly = 0
|
| 480 |
+
partial_relations = {}
|
| 481 |
+
proper_factor = set()
|
| 482 |
+
threshold = 5*len(factor_base) // 100
|
| 483 |
+
while True:
|
| 484 |
+
if ith_poly == 0:
|
| 485 |
+
ith_sieve_poly, B_array = _initialize_first_polynomial(N, M, factor_base, idx_1000, idx_5000)
|
| 486 |
+
else:
|
| 487 |
+
ith_sieve_poly = _initialize_ith_poly(N, factor_base, ith_poly, ith_sieve_poly, B_array)
|
| 488 |
+
ith_poly += 1
|
| 489 |
+
if ith_poly >= 2**(len(B_array) - 1): # time to start with a new sieve polynomial
|
| 490 |
+
ith_poly = 0
|
| 491 |
+
sieve_array = _gen_sieve_array(M, factor_base)
|
| 492 |
+
s_rel, p_f = _trial_division_stage(N, M, factor_base, sieve_array, ith_sieve_poly, partial_relations, ERROR_TERM)
|
| 493 |
+
smooth_relations += s_rel
|
| 494 |
+
proper_factor |= p_f
|
| 495 |
+
if len(smooth_relations) >= len(factor_base) + threshold:
|
| 496 |
+
break
|
| 497 |
+
matrix = _build_matrix(smooth_relations)
|
| 498 |
+
dependent_row, mark, gauss_matrix = _gauss_mod_2(matrix)
|
| 499 |
+
N_copy = N
|
| 500 |
+
for index in range(len(dependent_row)):
|
| 501 |
+
factor = _find_factor(dependent_row, mark, gauss_matrix, index, smooth_relations, N)
|
| 502 |
+
if factor > 1 and factor < N:
|
| 503 |
+
proper_factor.add(factor)
|
| 504 |
+
while(N_copy % factor == 0):
|
| 505 |
+
N_copy //= factor
|
| 506 |
+
if isprime(N_copy):
|
| 507 |
+
proper_factor.add(N_copy)
|
| 508 |
+
break
|
| 509 |
+
if(N_copy == 1):
|
| 510 |
+
break
|
| 511 |
+
return proper_factor
|
lib/python3.12/site-packages/sympy/ntheory/residue_ntheory.py
ADDED
|
@@ -0,0 +1,1954 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
from sympy.external.gmpy import (gcd, lcm, invert, sqrt, jacobi,
|
| 4 |
+
bit_scan1, remove)
|
| 5 |
+
from sympy.polys import Poly
|
| 6 |
+
from sympy.polys.domains import ZZ
|
| 7 |
+
from sympy.polys.galoistools import gf_crt1, gf_crt2, linear_congruence, gf_csolve
|
| 8 |
+
from .primetest import isprime
|
| 9 |
+
from .generate import primerange
|
| 10 |
+
from .factor_ import factorint, _perfect_power
|
| 11 |
+
from .modular import crt
|
| 12 |
+
from sympy.utilities.decorator import deprecated
|
| 13 |
+
from sympy.utilities.memoization import recurrence_memo
|
| 14 |
+
from sympy.utilities.misc import as_int
|
| 15 |
+
from sympy.utilities.iterables import iproduct
|
| 16 |
+
from sympy.core.random import _randint, randint
|
| 17 |
+
|
| 18 |
+
from itertools import product
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def n_order(a, n):
|
| 22 |
+
r""" Returns the order of ``a`` modulo ``n``.
|
| 23 |
+
|
| 24 |
+
Explanation
|
| 25 |
+
===========
|
| 26 |
+
|
| 27 |
+
The order of ``a`` modulo ``n`` is the smallest integer
|
| 28 |
+
``k`` such that `a^k` leaves a remainder of 1 with ``n``.
|
| 29 |
+
|
| 30 |
+
Parameters
|
| 31 |
+
==========
|
| 32 |
+
|
| 33 |
+
a : integer
|
| 34 |
+
n : integer, n > 1. a and n should be relatively prime
|
| 35 |
+
|
| 36 |
+
Returns
|
| 37 |
+
=======
|
| 38 |
+
|
| 39 |
+
int : the order of ``a`` modulo ``n``
|
| 40 |
+
|
| 41 |
+
Raises
|
| 42 |
+
======
|
| 43 |
+
|
| 44 |
+
ValueError
|
| 45 |
+
If `n \le 1` or `\gcd(a, n) \neq 1`.
|
| 46 |
+
If ``a`` or ``n`` is not an integer.
|
| 47 |
+
|
| 48 |
+
Examples
|
| 49 |
+
========
|
| 50 |
+
|
| 51 |
+
>>> from sympy.ntheory import n_order
|
| 52 |
+
>>> n_order(3, 7)
|
| 53 |
+
6
|
| 54 |
+
>>> n_order(4, 7)
|
| 55 |
+
3
|
| 56 |
+
|
| 57 |
+
See Also
|
| 58 |
+
========
|
| 59 |
+
|
| 60 |
+
is_primitive_root
|
| 61 |
+
We say that ``a`` is a primitive root of ``n``
|
| 62 |
+
when the order of ``a`` modulo ``n`` equals ``totient(n)``
|
| 63 |
+
|
| 64 |
+
"""
|
| 65 |
+
a, n = as_int(a), as_int(n)
|
| 66 |
+
if n <= 1:
|
| 67 |
+
raise ValueError("n should be an integer greater than 1")
|
| 68 |
+
a = a % n
|
| 69 |
+
# Trivial
|
| 70 |
+
if a == 1:
|
| 71 |
+
return 1
|
| 72 |
+
if gcd(a, n) != 1:
|
| 73 |
+
raise ValueError("The two numbers should be relatively prime")
|
| 74 |
+
a_order = 1
|
| 75 |
+
for p, e in factorint(n).items():
|
| 76 |
+
pe = p**e
|
| 77 |
+
pe_order = (p - 1) * p**(e - 1)
|
| 78 |
+
factors = factorint(p - 1)
|
| 79 |
+
if e > 1:
|
| 80 |
+
factors[p] = e - 1
|
| 81 |
+
order = 1
|
| 82 |
+
for px, ex in factors.items():
|
| 83 |
+
x = pow(a, pe_order // px**ex, pe)
|
| 84 |
+
while x != 1:
|
| 85 |
+
x = pow(x, px, pe)
|
| 86 |
+
order *= px
|
| 87 |
+
a_order = lcm(a_order, order)
|
| 88 |
+
return int(a_order)
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def _primitive_root_prime_iter(p):
|
| 92 |
+
r""" Generates the primitive roots for a prime ``p``.
|
| 93 |
+
|
| 94 |
+
Explanation
|
| 95 |
+
===========
|
| 96 |
+
|
| 97 |
+
The primitive roots generated are not necessarily sorted.
|
| 98 |
+
However, the first one is the smallest primitive root.
|
| 99 |
+
|
| 100 |
+
Find the element whose order is ``p-1`` from the smaller one.
|
| 101 |
+
If we can find the first primitive root ``g``, we can use the following theorem.
|
| 102 |
+
|
| 103 |
+
.. math ::
|
| 104 |
+
\operatorname{ord}(g^k) = \frac{\operatorname{ord}(g)}{\gcd(\operatorname{ord}(g), k)}
|
| 105 |
+
|
| 106 |
+
From the assumption that `\operatorname{ord}(g)=p-1`,
|
| 107 |
+
it is a necessary and sufficient condition for
|
| 108 |
+
`\operatorname{ord}(g^k)=p-1` that `\gcd(p-1, k)=1`.
|
| 109 |
+
|
| 110 |
+
Parameters
|
| 111 |
+
==========
|
| 112 |
+
|
| 113 |
+
p : odd prime
|
| 114 |
+
|
| 115 |
+
Yields
|
| 116 |
+
======
|
| 117 |
+
|
| 118 |
+
int
|
| 119 |
+
the primitive roots of ``p``
|
| 120 |
+
|
| 121 |
+
Examples
|
| 122 |
+
========
|
| 123 |
+
|
| 124 |
+
>>> from sympy.ntheory.residue_ntheory import _primitive_root_prime_iter
|
| 125 |
+
>>> sorted(_primitive_root_prime_iter(19))
|
| 126 |
+
[2, 3, 10, 13, 14, 15]
|
| 127 |
+
|
| 128 |
+
References
|
| 129 |
+
==========
|
| 130 |
+
|
| 131 |
+
.. [1] W. Stein "Elementary Number Theory" (2011), page 44
|
| 132 |
+
|
| 133 |
+
"""
|
| 134 |
+
if p == 3:
|
| 135 |
+
yield 2
|
| 136 |
+
return
|
| 137 |
+
# Let p = +-1 (mod 4a). Legendre symbol (a/p) = 1, so `a` is not the primitive root.
|
| 138 |
+
# Corollary : If p = +-1 (mod 8), then 2 is not the primitive root of p.
|
| 139 |
+
g_min = 3 if p % 8 in [1, 7] else 2
|
| 140 |
+
if p < 41:
|
| 141 |
+
# small case
|
| 142 |
+
g = 5 if p == 23 else g_min
|
| 143 |
+
else:
|
| 144 |
+
v = [(p - 1) // i for i in factorint(p - 1).keys()]
|
| 145 |
+
for g in range(g_min, p):
|
| 146 |
+
if all(pow(g, pw, p) != 1 for pw in v):
|
| 147 |
+
break
|
| 148 |
+
yield g
|
| 149 |
+
# g**k is the primitive root of p iff gcd(p - 1, k) = 1
|
| 150 |
+
for k in range(3, p, 2):
|
| 151 |
+
if gcd(p - 1, k) == 1:
|
| 152 |
+
yield pow(g, k, p)
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
def _primitive_root_prime_power_iter(p, e):
|
| 156 |
+
r""" Generates the primitive roots of `p^e`.
|
| 157 |
+
|
| 158 |
+
Explanation
|
| 159 |
+
===========
|
| 160 |
+
|
| 161 |
+
Let ``g`` be the primitive root of ``p``.
|
| 162 |
+
If `g^{p-1} \not\equiv 1 \pmod{p^2}`, then ``g`` is primitive root of `p^e`.
|
| 163 |
+
Thus, if we find a primitive root ``g`` of ``p``,
|
| 164 |
+
then `g, g+p, g+2p, \ldots, g+(p-1)p` are primitive roots of `p^2` except one.
|
| 165 |
+
That one satisfies `\hat{g}^{p-1} \equiv 1 \pmod{p^2}`.
|
| 166 |
+
If ``h`` is the primitive root of `p^2`,
|
| 167 |
+
then `h, h+p^2, h+2p^2, \ldots, h+(p^{e-2}-1)p^e` are primitive roots of `p^e`.
|
| 168 |
+
|
| 169 |
+
Parameters
|
| 170 |
+
==========
|
| 171 |
+
|
| 172 |
+
p : odd prime
|
| 173 |
+
e : positive integer
|
| 174 |
+
|
| 175 |
+
Yields
|
| 176 |
+
======
|
| 177 |
+
|
| 178 |
+
int
|
| 179 |
+
the primitive roots of `p^e`
|
| 180 |
+
|
| 181 |
+
Examples
|
| 182 |
+
========
|
| 183 |
+
|
| 184 |
+
>>> from sympy.ntheory.residue_ntheory import _primitive_root_prime_power_iter
|
| 185 |
+
>>> sorted(_primitive_root_prime_power_iter(5, 2))
|
| 186 |
+
[2, 3, 8, 12, 13, 17, 22, 23]
|
| 187 |
+
|
| 188 |
+
"""
|
| 189 |
+
if e == 1:
|
| 190 |
+
yield from _primitive_root_prime_iter(p)
|
| 191 |
+
else:
|
| 192 |
+
p2 = p**2
|
| 193 |
+
for g in _primitive_root_prime_iter(p):
|
| 194 |
+
t = (g - pow(g, 2 - p, p2)) % p2
|
| 195 |
+
for k in range(0, p2, p):
|
| 196 |
+
if k != t:
|
| 197 |
+
yield from (g + k + m for m in range(0, p**e, p2))
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
def _primitive_root_prime_power2_iter(p, e):
|
| 201 |
+
r""" Generates the primitive roots of `2p^e`.
|
| 202 |
+
|
| 203 |
+
Explanation
|
| 204 |
+
===========
|
| 205 |
+
|
| 206 |
+
If ``g`` is the primitive root of ``p**e``,
|
| 207 |
+
then the odd one of ``g`` and ``g+p**e`` is the primitive root of ``2*p**e``.
|
| 208 |
+
|
| 209 |
+
Parameters
|
| 210 |
+
==========
|
| 211 |
+
|
| 212 |
+
p : odd prime
|
| 213 |
+
e : positive integer
|
| 214 |
+
|
| 215 |
+
Yields
|
| 216 |
+
======
|
| 217 |
+
|
| 218 |
+
int
|
| 219 |
+
the primitive roots of `2p^e`
|
| 220 |
+
|
| 221 |
+
Examples
|
| 222 |
+
========
|
| 223 |
+
|
| 224 |
+
>>> from sympy.ntheory.residue_ntheory import _primitive_root_prime_power2_iter
|
| 225 |
+
>>> sorted(_primitive_root_prime_power2_iter(5, 2))
|
| 226 |
+
[3, 13, 17, 23, 27, 33, 37, 47]
|
| 227 |
+
|
| 228 |
+
"""
|
| 229 |
+
for g in _primitive_root_prime_power_iter(p, e):
|
| 230 |
+
if g % 2 == 1:
|
| 231 |
+
yield g
|
| 232 |
+
else:
|
| 233 |
+
yield g + p**e
|
| 234 |
+
|
| 235 |
+
|
| 236 |
+
def primitive_root(p, smallest=True):
|
| 237 |
+
r""" Returns a primitive root of ``p`` or None.
|
| 238 |
+
|
| 239 |
+
Explanation
|
| 240 |
+
===========
|
| 241 |
+
|
| 242 |
+
For the definition of primitive root,
|
| 243 |
+
see the explanation of ``is_primitive_root``.
|
| 244 |
+
|
| 245 |
+
The primitive root of ``p`` exist only for
|
| 246 |
+
`p = 2, 4, q^e, 2q^e` (``q`` is an odd prime).
|
| 247 |
+
Now, if we know the primitive root of ``q``,
|
| 248 |
+
we can calculate the primitive root of `q^e`,
|
| 249 |
+
and if we know the primitive root of `q^e`,
|
| 250 |
+
we can calculate the primitive root of `2q^e`.
|
| 251 |
+
When there is no need to find the smallest primitive root,
|
| 252 |
+
this property can be used to obtain a fast primitive root.
|
| 253 |
+
On the other hand, when we want the smallest primitive root,
|
| 254 |
+
we naively determine whether it is a primitive root or not.
|
| 255 |
+
|
| 256 |
+
Parameters
|
| 257 |
+
==========
|
| 258 |
+
|
| 259 |
+
p : integer, p > 1
|
| 260 |
+
smallest : if True the smallest primitive root is returned or None
|
| 261 |
+
|
| 262 |
+
Returns
|
| 263 |
+
=======
|
| 264 |
+
|
| 265 |
+
int | None :
|
| 266 |
+
If the primitive root exists, return the primitive root of ``p``.
|
| 267 |
+
If not, return None.
|
| 268 |
+
|
| 269 |
+
Raises
|
| 270 |
+
======
|
| 271 |
+
|
| 272 |
+
ValueError
|
| 273 |
+
If `p \le 1` or ``p`` is not an integer.
|
| 274 |
+
|
| 275 |
+
Examples
|
| 276 |
+
========
|
| 277 |
+
|
| 278 |
+
>>> from sympy.ntheory.residue_ntheory import primitive_root
|
| 279 |
+
>>> primitive_root(19)
|
| 280 |
+
2
|
| 281 |
+
>>> primitive_root(21) is None
|
| 282 |
+
True
|
| 283 |
+
>>> primitive_root(50, smallest=False)
|
| 284 |
+
27
|
| 285 |
+
|
| 286 |
+
See Also
|
| 287 |
+
========
|
| 288 |
+
|
| 289 |
+
is_primitive_root
|
| 290 |
+
|
| 291 |
+
References
|
| 292 |
+
==========
|
| 293 |
+
|
| 294 |
+
.. [1] W. Stein "Elementary Number Theory" (2011), page 44
|
| 295 |
+
.. [2] P. Hackman "Elementary Number Theory" (2009), Chapter C
|
| 296 |
+
|
| 297 |
+
"""
|
| 298 |
+
p = as_int(p)
|
| 299 |
+
if p <= 1:
|
| 300 |
+
raise ValueError("p should be an integer greater than 1")
|
| 301 |
+
if p <= 4:
|
| 302 |
+
return p - 1
|
| 303 |
+
p_even = p % 2 == 0
|
| 304 |
+
if not p_even:
|
| 305 |
+
q = p # p is odd
|
| 306 |
+
elif p % 4:
|
| 307 |
+
q = p//2 # p had 1 factor of 2
|
| 308 |
+
else:
|
| 309 |
+
return None # p had more than one factor of 2
|
| 310 |
+
if isprime(q):
|
| 311 |
+
e = 1
|
| 312 |
+
else:
|
| 313 |
+
m = _perfect_power(q, 3)
|
| 314 |
+
if not m:
|
| 315 |
+
return None
|
| 316 |
+
q, e = m
|
| 317 |
+
if not isprime(q):
|
| 318 |
+
return None
|
| 319 |
+
if not smallest:
|
| 320 |
+
if p_even:
|
| 321 |
+
return next(_primitive_root_prime_power2_iter(q, e))
|
| 322 |
+
return next(_primitive_root_prime_power_iter(q, e))
|
| 323 |
+
if p_even:
|
| 324 |
+
for i in range(3, p, 2):
|
| 325 |
+
if i % q and is_primitive_root(i, p):
|
| 326 |
+
return i
|
| 327 |
+
g = next(_primitive_root_prime_iter(q))
|
| 328 |
+
if e == 1 or pow(g, q - 1, q**2) != 1:
|
| 329 |
+
return g
|
| 330 |
+
for i in range(g + 1, p):
|
| 331 |
+
if i % q and is_primitive_root(i, p):
|
| 332 |
+
return i
|
| 333 |
+
|
| 334 |
+
|
| 335 |
+
def is_primitive_root(a, p):
|
| 336 |
+
r""" Returns True if ``a`` is a primitive root of ``p``.
|
| 337 |
+
|
| 338 |
+
Explanation
|
| 339 |
+
===========
|
| 340 |
+
|
| 341 |
+
``a`` is said to be the primitive root of ``p`` if `\gcd(a, p) = 1` and
|
| 342 |
+
`\phi(p)` is the smallest positive number s.t.
|
| 343 |
+
|
| 344 |
+
`a^{\phi(p)} \equiv 1 \pmod{p}`.
|
| 345 |
+
|
| 346 |
+
where `\phi(p)` is Euler's totient function.
|
| 347 |
+
|
| 348 |
+
The primitive root of ``p`` exist only for
|
| 349 |
+
`p = 2, 4, q^e, 2q^e` (``q`` is an odd prime).
|
| 350 |
+
Hence, if it is not such a ``p``, it returns False.
|
| 351 |
+
To determine the primitive root, we need to know
|
| 352 |
+
the prime factorization of ``q-1``.
|
| 353 |
+
The hardness of the determination depends on this complexity.
|
| 354 |
+
|
| 355 |
+
Parameters
|
| 356 |
+
==========
|
| 357 |
+
|
| 358 |
+
a : integer
|
| 359 |
+
p : integer, ``p`` > 1. ``a`` and ``p`` should be relatively prime
|
| 360 |
+
|
| 361 |
+
Returns
|
| 362 |
+
=======
|
| 363 |
+
|
| 364 |
+
bool : If True, ``a`` is the primitive root of ``p``.
|
| 365 |
+
|
| 366 |
+
Raises
|
| 367 |
+
======
|
| 368 |
+
|
| 369 |
+
ValueError
|
| 370 |
+
If `p \le 1` or `\gcd(a, p) \neq 1`.
|
| 371 |
+
If ``a`` or ``p`` is not an integer.
|
| 372 |
+
|
| 373 |
+
Examples
|
| 374 |
+
========
|
| 375 |
+
|
| 376 |
+
>>> from sympy.functions.combinatorial.numbers import totient
|
| 377 |
+
>>> from sympy.ntheory import is_primitive_root, n_order
|
| 378 |
+
>>> is_primitive_root(3, 10)
|
| 379 |
+
True
|
| 380 |
+
>>> is_primitive_root(9, 10)
|
| 381 |
+
False
|
| 382 |
+
>>> n_order(3, 10) == totient(10)
|
| 383 |
+
True
|
| 384 |
+
>>> n_order(9, 10) == totient(10)
|
| 385 |
+
False
|
| 386 |
+
|
| 387 |
+
See Also
|
| 388 |
+
========
|
| 389 |
+
|
| 390 |
+
primitive_root
|
| 391 |
+
|
| 392 |
+
"""
|
| 393 |
+
a, p = as_int(a), as_int(p)
|
| 394 |
+
if p <= 1:
|
| 395 |
+
raise ValueError("p should be an integer greater than 1")
|
| 396 |
+
a = a % p
|
| 397 |
+
if gcd(a, p) != 1:
|
| 398 |
+
raise ValueError("The two numbers should be relatively prime")
|
| 399 |
+
# Primitive root of p exist only for
|
| 400 |
+
# p = 2, 4, q**e, 2*q**e (q is odd prime)
|
| 401 |
+
if p <= 4:
|
| 402 |
+
# The primitive root is only p-1.
|
| 403 |
+
return a == p - 1
|
| 404 |
+
if p % 2:
|
| 405 |
+
q = p # p is odd
|
| 406 |
+
elif p % 4:
|
| 407 |
+
q = p//2 # p had 1 factor of 2
|
| 408 |
+
else:
|
| 409 |
+
return False # p had more than one factor of 2
|
| 410 |
+
if isprime(q):
|
| 411 |
+
group_order = q - 1
|
| 412 |
+
factors = factorint(q - 1).keys()
|
| 413 |
+
else:
|
| 414 |
+
m = _perfect_power(q, 3)
|
| 415 |
+
if not m:
|
| 416 |
+
return False
|
| 417 |
+
q, e = m
|
| 418 |
+
if not isprime(q):
|
| 419 |
+
return False
|
| 420 |
+
group_order = q**(e - 1)*(q - 1)
|
| 421 |
+
factors = set(factorint(q - 1).keys())
|
| 422 |
+
factors.add(q)
|
| 423 |
+
return all(pow(a, group_order // prime, p) != 1 for prime in factors)
|
| 424 |
+
|
| 425 |
+
|
| 426 |
+
def _sqrt_mod_tonelli_shanks(a, p):
|
| 427 |
+
"""
|
| 428 |
+
Returns the square root in the case of ``p`` prime with ``p == 1 (mod 8)``
|
| 429 |
+
|
| 430 |
+
Assume that the root exists.
|
| 431 |
+
|
| 432 |
+
Parameters
|
| 433 |
+
==========
|
| 434 |
+
|
| 435 |
+
a : int
|
| 436 |
+
p : int
|
| 437 |
+
prime number. should be ``p % 8 == 1``
|
| 438 |
+
|
| 439 |
+
Returns
|
| 440 |
+
=======
|
| 441 |
+
|
| 442 |
+
int : Generally, there are two roots, but only one is returned.
|
| 443 |
+
Which one is returned is random.
|
| 444 |
+
|
| 445 |
+
Examples
|
| 446 |
+
========
|
| 447 |
+
|
| 448 |
+
>>> from sympy.ntheory.residue_ntheory import _sqrt_mod_tonelli_shanks
|
| 449 |
+
>>> _sqrt_mod_tonelli_shanks(2, 17) in [6, 11]
|
| 450 |
+
True
|
| 451 |
+
|
| 452 |
+
References
|
| 453 |
+
==========
|
| 454 |
+
|
| 455 |
+
.. [1] Carl Pomerance, Richard Crandall, Prime Numbers: A Computational Perspective,
|
| 456 |
+
2nd Edition (2005), page 101, ISBN:978-0387252827
|
| 457 |
+
|
| 458 |
+
"""
|
| 459 |
+
s = bit_scan1(p - 1)
|
| 460 |
+
t = p >> s
|
| 461 |
+
# find a non-quadratic residue
|
| 462 |
+
if p % 12 == 5:
|
| 463 |
+
# Legendre symbol (3/p) == -1 if p % 12 in [5, 7]
|
| 464 |
+
d = 3
|
| 465 |
+
elif p % 5 in [2, 3]:
|
| 466 |
+
# Legendre symbol (5/p) == -1 if p % 5 in [2, 3]
|
| 467 |
+
d = 5
|
| 468 |
+
else:
|
| 469 |
+
while 1:
|
| 470 |
+
d = randint(6, p - 1)
|
| 471 |
+
if jacobi(d, p) == -1:
|
| 472 |
+
break
|
| 473 |
+
#assert legendre_symbol(d, p) == -1
|
| 474 |
+
A = pow(a, t, p)
|
| 475 |
+
D = pow(d, t, p)
|
| 476 |
+
m = 0
|
| 477 |
+
for i in range(s):
|
| 478 |
+
adm = A*pow(D, m, p) % p
|
| 479 |
+
adm = pow(adm, 2**(s - 1 - i), p)
|
| 480 |
+
if adm % p == p - 1:
|
| 481 |
+
m += 2**i
|
| 482 |
+
#assert A*pow(D, m, p) % p == 1
|
| 483 |
+
x = pow(a, (t + 1)//2, p)*pow(D, m//2, p) % p
|
| 484 |
+
return x
|
| 485 |
+
|
| 486 |
+
|
| 487 |
+
def sqrt_mod(a, p, all_roots=False):
|
| 488 |
+
"""
|
| 489 |
+
Find a root of ``x**2 = a mod p``.
|
| 490 |
+
|
| 491 |
+
Parameters
|
| 492 |
+
==========
|
| 493 |
+
|
| 494 |
+
a : integer
|
| 495 |
+
p : positive integer
|
| 496 |
+
all_roots : if True the list of roots is returned or None
|
| 497 |
+
|
| 498 |
+
Notes
|
| 499 |
+
=====
|
| 500 |
+
|
| 501 |
+
If there is no root it is returned None; else the returned root
|
| 502 |
+
is less or equal to ``p // 2``; in general is not the smallest one.
|
| 503 |
+
It is returned ``p // 2`` only if it is the only root.
|
| 504 |
+
|
| 505 |
+
Use ``all_roots`` only when it is expected that all the roots fit
|
| 506 |
+
in memory; otherwise use ``sqrt_mod_iter``.
|
| 507 |
+
|
| 508 |
+
Examples
|
| 509 |
+
========
|
| 510 |
+
|
| 511 |
+
>>> from sympy.ntheory import sqrt_mod
|
| 512 |
+
>>> sqrt_mod(11, 43)
|
| 513 |
+
21
|
| 514 |
+
>>> sqrt_mod(17, 32, True)
|
| 515 |
+
[7, 9, 23, 25]
|
| 516 |
+
"""
|
| 517 |
+
if all_roots:
|
| 518 |
+
return sorted(sqrt_mod_iter(a, p))
|
| 519 |
+
p = abs(as_int(p))
|
| 520 |
+
halfp = p // 2
|
| 521 |
+
x = None
|
| 522 |
+
for r in sqrt_mod_iter(a, p):
|
| 523 |
+
if r < halfp:
|
| 524 |
+
return r
|
| 525 |
+
elif r > halfp:
|
| 526 |
+
return p - r
|
| 527 |
+
else:
|
| 528 |
+
x = r
|
| 529 |
+
return x
|
| 530 |
+
|
| 531 |
+
|
| 532 |
+
def sqrt_mod_iter(a, p, domain=int):
|
| 533 |
+
"""
|
| 534 |
+
Iterate over solutions to ``x**2 = a mod p``.
|
| 535 |
+
|
| 536 |
+
Parameters
|
| 537 |
+
==========
|
| 538 |
+
|
| 539 |
+
a : integer
|
| 540 |
+
p : positive integer
|
| 541 |
+
domain : integer domain, ``int``, ``ZZ`` or ``Integer``
|
| 542 |
+
|
| 543 |
+
Examples
|
| 544 |
+
========
|
| 545 |
+
|
| 546 |
+
>>> from sympy.ntheory.residue_ntheory import sqrt_mod_iter
|
| 547 |
+
>>> list(sqrt_mod_iter(11, 43))
|
| 548 |
+
[21, 22]
|
| 549 |
+
|
| 550 |
+
See Also
|
| 551 |
+
========
|
| 552 |
+
|
| 553 |
+
sqrt_mod : Same functionality, but you want a sorted list or only one solution.
|
| 554 |
+
|
| 555 |
+
"""
|
| 556 |
+
a, p = as_int(a), abs(as_int(p))
|
| 557 |
+
v = []
|
| 558 |
+
pv = []
|
| 559 |
+
_product = product
|
| 560 |
+
for px, ex in factorint(p).items():
|
| 561 |
+
if a % px:
|
| 562 |
+
# `len(rx)` is at most 4
|
| 563 |
+
rx = _sqrt_mod_prime_power(a, px, ex)
|
| 564 |
+
else:
|
| 565 |
+
# `len(list(rx))` can be assumed to be large.
|
| 566 |
+
# The `itertools.product` is disadvantageous in terms of memory usage.
|
| 567 |
+
# It is also inferior to iproduct in speed if not all Cartesian products are needed.
|
| 568 |
+
rx = _sqrt_mod1(a, px, ex)
|
| 569 |
+
_product = iproduct
|
| 570 |
+
if not rx:
|
| 571 |
+
return
|
| 572 |
+
v.append(rx)
|
| 573 |
+
pv.append(px**ex)
|
| 574 |
+
if len(v) == 1:
|
| 575 |
+
yield from map(domain, v[0])
|
| 576 |
+
else:
|
| 577 |
+
mm, e, s = gf_crt1(pv, ZZ)
|
| 578 |
+
for vx in _product(*v):
|
| 579 |
+
yield domain(gf_crt2(vx, pv, mm, e, s, ZZ))
|
| 580 |
+
|
| 581 |
+
|
| 582 |
+
def _sqrt_mod_prime_power(a, p, k):
|
| 583 |
+
"""
|
| 584 |
+
Find the solutions to ``x**2 = a mod p**k`` when ``a % p != 0``.
|
| 585 |
+
If no solution exists, return ``None``.
|
| 586 |
+
Solutions are returned in an ascending list.
|
| 587 |
+
|
| 588 |
+
Parameters
|
| 589 |
+
==========
|
| 590 |
+
|
| 591 |
+
a : integer
|
| 592 |
+
p : prime number
|
| 593 |
+
k : positive integer
|
| 594 |
+
|
| 595 |
+
Examples
|
| 596 |
+
========
|
| 597 |
+
|
| 598 |
+
>>> from sympy.ntheory.residue_ntheory import _sqrt_mod_prime_power
|
| 599 |
+
>>> _sqrt_mod_prime_power(11, 43, 1)
|
| 600 |
+
[21, 22]
|
| 601 |
+
|
| 602 |
+
References
|
| 603 |
+
==========
|
| 604 |
+
|
| 605 |
+
.. [1] P. Hackman "Elementary Number Theory" (2009), page 160
|
| 606 |
+
.. [2] http://www.numbertheory.org/php/squareroot.html
|
| 607 |
+
.. [3] [Gathen99]_
|
| 608 |
+
"""
|
| 609 |
+
pk = p**k
|
| 610 |
+
a = a % pk
|
| 611 |
+
|
| 612 |
+
if p == 2:
|
| 613 |
+
# see Ref.[2]
|
| 614 |
+
if a % 8 != 1:
|
| 615 |
+
return None
|
| 616 |
+
# Trivial
|
| 617 |
+
if k <= 3:
|
| 618 |
+
return list(range(1, pk, 2))
|
| 619 |
+
r = 1
|
| 620 |
+
# r is one of the solutions to x**2 - a = 0 (mod 2**3).
|
| 621 |
+
# Hensel lift them to solutions of x**2 - a = 0 (mod 2**k)
|
| 622 |
+
# if r**2 - a = 0 mod 2**nx but not mod 2**(nx+1)
|
| 623 |
+
# then r + 2**(nx - 1) is a root mod 2**(nx+1)
|
| 624 |
+
for nx in range(3, k):
|
| 625 |
+
if ((r**2 - a) >> nx) % 2:
|
| 626 |
+
r += 1 << (nx - 1)
|
| 627 |
+
# r is a solution of x**2 - a = 0 (mod 2**k), and
|
| 628 |
+
# there exist other solutions -r, r+h, -(r+h), and these are all solutions.
|
| 629 |
+
h = 1 << (k - 1)
|
| 630 |
+
return sorted([r, pk - r, (r + h) % pk, -(r + h) % pk])
|
| 631 |
+
|
| 632 |
+
# If the Legendre symbol (a/p) is not 1, no solution exists.
|
| 633 |
+
if jacobi(a, p) != 1:
|
| 634 |
+
return None
|
| 635 |
+
if p % 4 == 3:
|
| 636 |
+
res = pow(a, (p + 1) // 4, p)
|
| 637 |
+
elif p % 8 == 5:
|
| 638 |
+
res = pow(a, (p + 3) // 8, p)
|
| 639 |
+
if pow(res, 2, p) != a % p:
|
| 640 |
+
res = res * pow(2, (p - 1) // 4, p) % p
|
| 641 |
+
else:
|
| 642 |
+
res = _sqrt_mod_tonelli_shanks(a, p)
|
| 643 |
+
if k > 1:
|
| 644 |
+
# Hensel lifting with Newton iteration, see Ref.[3] chapter 9
|
| 645 |
+
# with f(x) = x**2 - a; one has f'(a) != 0 (mod p) for p != 2
|
| 646 |
+
px = p
|
| 647 |
+
for _ in range(k.bit_length() - 1):
|
| 648 |
+
px = px**2
|
| 649 |
+
frinv = invert(2*res, px)
|
| 650 |
+
res = (res - (res**2 - a)*frinv) % px
|
| 651 |
+
if k & (k - 1): # If k is not a power of 2
|
| 652 |
+
frinv = invert(2*res, pk)
|
| 653 |
+
res = (res - (res**2 - a)*frinv) % pk
|
| 654 |
+
return sorted([res, pk - res])
|
| 655 |
+
|
| 656 |
+
|
| 657 |
+
def _sqrt_mod1(a, p, n):
|
| 658 |
+
"""
|
| 659 |
+
Find solution to ``x**2 == a mod p**n`` when ``a % p == 0``.
|
| 660 |
+
If no solution exists, return ``None``.
|
| 661 |
+
|
| 662 |
+
Parameters
|
| 663 |
+
==========
|
| 664 |
+
|
| 665 |
+
a : integer
|
| 666 |
+
p : prime number, p must divide a
|
| 667 |
+
n : positive integer
|
| 668 |
+
|
| 669 |
+
References
|
| 670 |
+
==========
|
| 671 |
+
|
| 672 |
+
.. [1] http://www.numbertheory.org/php/squareroot.html
|
| 673 |
+
"""
|
| 674 |
+
pn = p**n
|
| 675 |
+
a = a % pn
|
| 676 |
+
if a == 0:
|
| 677 |
+
# case gcd(a, p**k) = p**n
|
| 678 |
+
return range(0, pn, p**((n + 1) // 2))
|
| 679 |
+
# case gcd(a, p**k) = p**r, r < n
|
| 680 |
+
a, r = remove(a, p)
|
| 681 |
+
if r % 2 == 1:
|
| 682 |
+
return None
|
| 683 |
+
res = _sqrt_mod_prime_power(a, p, n - r)
|
| 684 |
+
if res is None:
|
| 685 |
+
return None
|
| 686 |
+
m = r // 2
|
| 687 |
+
return (x for rx in res for x in range(rx*p**m, pn, p**(n - m)))
|
| 688 |
+
|
| 689 |
+
|
| 690 |
+
def is_quad_residue(a, p):
|
| 691 |
+
"""
|
| 692 |
+
Returns True if ``a`` (mod ``p``) is in the set of squares mod ``p``,
|
| 693 |
+
i.e a % p in set([i**2 % p for i in range(p)]).
|
| 694 |
+
|
| 695 |
+
Parameters
|
| 696 |
+
==========
|
| 697 |
+
|
| 698 |
+
a : integer
|
| 699 |
+
p : positive integer
|
| 700 |
+
|
| 701 |
+
Returns
|
| 702 |
+
=======
|
| 703 |
+
|
| 704 |
+
bool : If True, ``x**2 == a (mod p)`` has solution.
|
| 705 |
+
|
| 706 |
+
Raises
|
| 707 |
+
======
|
| 708 |
+
|
| 709 |
+
ValueError
|
| 710 |
+
If ``a``, ``p`` is not integer.
|
| 711 |
+
If ``p`` is not positive.
|
| 712 |
+
|
| 713 |
+
Examples
|
| 714 |
+
========
|
| 715 |
+
|
| 716 |
+
>>> from sympy.ntheory import is_quad_residue
|
| 717 |
+
>>> is_quad_residue(21, 100)
|
| 718 |
+
True
|
| 719 |
+
|
| 720 |
+
Indeed, ``pow(39, 2, 100)`` would be 21.
|
| 721 |
+
|
| 722 |
+
>>> is_quad_residue(21, 120)
|
| 723 |
+
False
|
| 724 |
+
|
| 725 |
+
That is, for any integer ``x``, ``pow(x, 2, 120)`` is not 21.
|
| 726 |
+
|
| 727 |
+
If ``p`` is an odd
|
| 728 |
+
prime, an iterative method is used to make the determination:
|
| 729 |
+
|
| 730 |
+
>>> from sympy.ntheory import is_quad_residue
|
| 731 |
+
>>> sorted(set([i**2 % 7 for i in range(7)]))
|
| 732 |
+
[0, 1, 2, 4]
|
| 733 |
+
>>> [j for j in range(7) if is_quad_residue(j, 7)]
|
| 734 |
+
[0, 1, 2, 4]
|
| 735 |
+
|
| 736 |
+
See Also
|
| 737 |
+
========
|
| 738 |
+
|
| 739 |
+
legendre_symbol, jacobi_symbol, sqrt_mod
|
| 740 |
+
"""
|
| 741 |
+
a, p = as_int(a), as_int(p)
|
| 742 |
+
if p < 1:
|
| 743 |
+
raise ValueError('p must be > 0')
|
| 744 |
+
a %= p
|
| 745 |
+
if a < 2 or p < 3:
|
| 746 |
+
return True
|
| 747 |
+
# Since we want to compute the Jacobi symbol,
|
| 748 |
+
# we separate p into the odd part and the rest.
|
| 749 |
+
t = bit_scan1(p)
|
| 750 |
+
if t:
|
| 751 |
+
# The existence of a solution to a power of 2 is determined
|
| 752 |
+
# using the logic of `p==2` in `_sqrt_mod_prime_power` and `_sqrt_mod1`.
|
| 753 |
+
a_ = a % (1 << t)
|
| 754 |
+
if a_:
|
| 755 |
+
r = bit_scan1(a_)
|
| 756 |
+
if r % 2 or (a_ >> r) & 6:
|
| 757 |
+
return False
|
| 758 |
+
p >>= t
|
| 759 |
+
a %= p
|
| 760 |
+
if a < 2 or p < 3:
|
| 761 |
+
return True
|
| 762 |
+
# If Jacobi symbol is -1 or p is prime, can be determined by Jacobi symbol only
|
| 763 |
+
j = jacobi(a, p)
|
| 764 |
+
if j == -1 or isprime(p):
|
| 765 |
+
return j == 1
|
| 766 |
+
# Checks if `x**2 = a (mod p)` has a solution
|
| 767 |
+
for px, ex in factorint(p).items():
|
| 768 |
+
if a % px:
|
| 769 |
+
if jacobi(a, px) != 1:
|
| 770 |
+
return False
|
| 771 |
+
else:
|
| 772 |
+
a_ = a % px**ex
|
| 773 |
+
if a_ == 0:
|
| 774 |
+
continue
|
| 775 |
+
a_, r = remove(a_, px)
|
| 776 |
+
if r % 2 or jacobi(a_, px) != 1:
|
| 777 |
+
return False
|
| 778 |
+
return True
|
| 779 |
+
|
| 780 |
+
|
| 781 |
+
def is_nthpow_residue(a, n, m):
|
| 782 |
+
"""
|
| 783 |
+
Returns True if ``x**n == a (mod m)`` has solutions.
|
| 784 |
+
|
| 785 |
+
References
|
| 786 |
+
==========
|
| 787 |
+
|
| 788 |
+
.. [1] P. Hackman "Elementary Number Theory" (2009), page 76
|
| 789 |
+
|
| 790 |
+
"""
|
| 791 |
+
a = a % m
|
| 792 |
+
a, n, m = as_int(a), as_int(n), as_int(m)
|
| 793 |
+
if m <= 0:
|
| 794 |
+
raise ValueError('m must be > 0')
|
| 795 |
+
if n < 0:
|
| 796 |
+
raise ValueError('n must be >= 0')
|
| 797 |
+
if n == 0:
|
| 798 |
+
if m == 1:
|
| 799 |
+
return False
|
| 800 |
+
return a == 1
|
| 801 |
+
if a == 0:
|
| 802 |
+
return True
|
| 803 |
+
if n == 1:
|
| 804 |
+
return True
|
| 805 |
+
if n == 2:
|
| 806 |
+
return is_quad_residue(a, m)
|
| 807 |
+
return all(_is_nthpow_residue_bign_prime_power(a, n, p, e)
|
| 808 |
+
for p, e in factorint(m).items())
|
| 809 |
+
|
| 810 |
+
|
| 811 |
+
def _is_nthpow_residue_bign_prime_power(a, n, p, k):
|
| 812 |
+
r"""
|
| 813 |
+
Returns True if `x^n = a \pmod{p^k}` has solutions for `n > 2`.
|
| 814 |
+
|
| 815 |
+
Parameters
|
| 816 |
+
==========
|
| 817 |
+
|
| 818 |
+
a : positive integer
|
| 819 |
+
n : integer, n > 2
|
| 820 |
+
p : prime number
|
| 821 |
+
k : positive integer
|
| 822 |
+
|
| 823 |
+
"""
|
| 824 |
+
while a % p == 0:
|
| 825 |
+
a %= pow(p, k)
|
| 826 |
+
if not a:
|
| 827 |
+
return True
|
| 828 |
+
a, mu = remove(a, p)
|
| 829 |
+
if mu % n:
|
| 830 |
+
return False
|
| 831 |
+
k -= mu
|
| 832 |
+
if p != 2:
|
| 833 |
+
f = p**(k - 1)*(p - 1) # f = totient(p**k)
|
| 834 |
+
return pow(a, f // gcd(f, n), pow(p, k)) == 1
|
| 835 |
+
if n & 1:
|
| 836 |
+
return True
|
| 837 |
+
c = min(bit_scan1(n) + 2, k)
|
| 838 |
+
return a % pow(2, c) == 1
|
| 839 |
+
|
| 840 |
+
|
| 841 |
+
def _nthroot_mod1(s, q, p, all_roots):
|
| 842 |
+
"""
|
| 843 |
+
Root of ``x**q = s mod p``, ``p`` prime and ``q`` divides ``p - 1``.
|
| 844 |
+
Assume that the root exists.
|
| 845 |
+
|
| 846 |
+
Parameters
|
| 847 |
+
==========
|
| 848 |
+
|
| 849 |
+
s : integer
|
| 850 |
+
q : integer, n > 2. ``q`` divides ``p - 1``.
|
| 851 |
+
p : prime number
|
| 852 |
+
all_roots : if False returns the smallest root, else the list of roots
|
| 853 |
+
|
| 854 |
+
Returns
|
| 855 |
+
=======
|
| 856 |
+
|
| 857 |
+
list[int] | int :
|
| 858 |
+
Root of ``x**q = s mod p``. If ``all_roots == True``,
|
| 859 |
+
returned ascending list. otherwise, returned an int.
|
| 860 |
+
|
| 861 |
+
Examples
|
| 862 |
+
========
|
| 863 |
+
|
| 864 |
+
>>> from sympy.ntheory.residue_ntheory import _nthroot_mod1
|
| 865 |
+
>>> _nthroot_mod1(5, 3, 13, False)
|
| 866 |
+
7
|
| 867 |
+
>>> _nthroot_mod1(13, 4, 17, True)
|
| 868 |
+
[3, 5, 12, 14]
|
| 869 |
+
|
| 870 |
+
References
|
| 871 |
+
==========
|
| 872 |
+
|
| 873 |
+
.. [1] A. M. Johnston, A Generalized qth Root Algorithm,
|
| 874 |
+
ACM-SIAM Symposium on Discrete Algorithms (1999), pp. 929-930
|
| 875 |
+
|
| 876 |
+
"""
|
| 877 |
+
g = next(_primitive_root_prime_iter(p))
|
| 878 |
+
r = s
|
| 879 |
+
for qx, ex in factorint(q).items():
|
| 880 |
+
f = (p - 1) // qx**ex
|
| 881 |
+
while f % qx == 0:
|
| 882 |
+
f //= qx
|
| 883 |
+
z = f*invert(-f, qx)
|
| 884 |
+
x = (1 + z) // qx
|
| 885 |
+
t = discrete_log(p, pow(r, f, p), pow(g, f*qx, p))
|
| 886 |
+
for _ in range(ex):
|
| 887 |
+
# assert t == discrete_log(p, pow(r, f, p), pow(g, f*qx, p))
|
| 888 |
+
r = pow(r, x, p)*pow(g, -z*t % (p - 1), p) % p
|
| 889 |
+
t //= qx
|
| 890 |
+
res = [r]
|
| 891 |
+
h = pow(g, (p - 1) // q, p)
|
| 892 |
+
#assert pow(h, q, p) == 1
|
| 893 |
+
hx = r
|
| 894 |
+
for _ in range(q - 1):
|
| 895 |
+
hx = (hx*h) % p
|
| 896 |
+
res.append(hx)
|
| 897 |
+
if all_roots:
|
| 898 |
+
res.sort()
|
| 899 |
+
return res
|
| 900 |
+
return min(res)
|
| 901 |
+
|
| 902 |
+
|
| 903 |
+
def _nthroot_mod_prime_power(a, n, p, k):
|
| 904 |
+
""" Root of ``x**n = a mod p**k``.
|
| 905 |
+
|
| 906 |
+
Parameters
|
| 907 |
+
==========
|
| 908 |
+
|
| 909 |
+
a : integer
|
| 910 |
+
n : integer, n > 2
|
| 911 |
+
p : prime number
|
| 912 |
+
k : positive integer
|
| 913 |
+
|
| 914 |
+
Returns
|
| 915 |
+
=======
|
| 916 |
+
|
| 917 |
+
list[int] :
|
| 918 |
+
Ascending list of roots of ``x**n = a mod p**k``.
|
| 919 |
+
If no solution exists, return ``[]``.
|
| 920 |
+
|
| 921 |
+
"""
|
| 922 |
+
if not _is_nthpow_residue_bign_prime_power(a, n, p, k):
|
| 923 |
+
return []
|
| 924 |
+
a_mod_p = a % p
|
| 925 |
+
if a_mod_p == 0:
|
| 926 |
+
base_roots = [0]
|
| 927 |
+
elif (p - 1) % n == 0:
|
| 928 |
+
base_roots = _nthroot_mod1(a_mod_p, n, p, all_roots=True)
|
| 929 |
+
else:
|
| 930 |
+
# The roots of ``x**n - a = 0 (mod p)`` are roots of
|
| 931 |
+
# ``gcd(x**n - a, x**(p - 1) - 1) = 0 (mod p)``
|
| 932 |
+
pa = n
|
| 933 |
+
pb = p - 1
|
| 934 |
+
b = 1
|
| 935 |
+
if pa < pb:
|
| 936 |
+
a_mod_p, pa, b, pb = b, pb, a_mod_p, pa
|
| 937 |
+
# gcd(x**pa - a, x**pb - b) = gcd(x**pb - b, x**pc - c)
|
| 938 |
+
# where pc = pa % pb; c = b**-q * a mod p
|
| 939 |
+
while pb:
|
| 940 |
+
q, pc = divmod(pa, pb)
|
| 941 |
+
c = pow(b, -q, p) * a_mod_p % p
|
| 942 |
+
pa, pb = pb, pc
|
| 943 |
+
a_mod_p, b = b, c
|
| 944 |
+
if pa == 1:
|
| 945 |
+
base_roots = [a_mod_p]
|
| 946 |
+
elif pa == 2:
|
| 947 |
+
base_roots = sqrt_mod(a_mod_p, p, all_roots=True)
|
| 948 |
+
else:
|
| 949 |
+
base_roots = _nthroot_mod1(a_mod_p, pa, p, all_roots=True)
|
| 950 |
+
if k == 1:
|
| 951 |
+
return base_roots
|
| 952 |
+
a %= p**k
|
| 953 |
+
tot_roots = set()
|
| 954 |
+
for root in base_roots:
|
| 955 |
+
diff = pow(root, n - 1, p)*n % p
|
| 956 |
+
new_base = p
|
| 957 |
+
if diff != 0:
|
| 958 |
+
m_inv = invert(diff, p)
|
| 959 |
+
for _ in range(k - 1):
|
| 960 |
+
new_base *= p
|
| 961 |
+
tmp = pow(root, n, new_base) - a
|
| 962 |
+
tmp *= m_inv
|
| 963 |
+
root = (root - tmp) % new_base
|
| 964 |
+
tot_roots.add(root)
|
| 965 |
+
else:
|
| 966 |
+
roots_in_base = {root}
|
| 967 |
+
for _ in range(k - 1):
|
| 968 |
+
new_base *= p
|
| 969 |
+
new_roots = set()
|
| 970 |
+
for k_ in roots_in_base:
|
| 971 |
+
if pow(k_, n, new_base) != a % new_base:
|
| 972 |
+
continue
|
| 973 |
+
while k_ not in new_roots:
|
| 974 |
+
new_roots.add(k_)
|
| 975 |
+
k_ = (k_ + (new_base // p)) % new_base
|
| 976 |
+
roots_in_base = new_roots
|
| 977 |
+
tot_roots = tot_roots | roots_in_base
|
| 978 |
+
return sorted(tot_roots)
|
| 979 |
+
|
| 980 |
+
|
| 981 |
+
def nthroot_mod(a, n, p, all_roots=False):
|
| 982 |
+
"""
|
| 983 |
+
Find the solutions to ``x**n = a mod p``.
|
| 984 |
+
|
| 985 |
+
Parameters
|
| 986 |
+
==========
|
| 987 |
+
|
| 988 |
+
a : integer
|
| 989 |
+
n : positive integer
|
| 990 |
+
p : positive integer
|
| 991 |
+
all_roots : if False returns the smallest root, else the list of roots
|
| 992 |
+
|
| 993 |
+
Returns
|
| 994 |
+
=======
|
| 995 |
+
|
| 996 |
+
list[int] | int | None :
|
| 997 |
+
solutions to ``x**n = a mod p``.
|
| 998 |
+
The table of the output type is:
|
| 999 |
+
|
| 1000 |
+
========== ========== ==========
|
| 1001 |
+
all_roots has roots Returns
|
| 1002 |
+
========== ========== ==========
|
| 1003 |
+
True Yes list[int]
|
| 1004 |
+
True No []
|
| 1005 |
+
False Yes int
|
| 1006 |
+
False No None
|
| 1007 |
+
========== ========== ==========
|
| 1008 |
+
|
| 1009 |
+
Raises
|
| 1010 |
+
======
|
| 1011 |
+
|
| 1012 |
+
ValueError
|
| 1013 |
+
If ``a``, ``n`` or ``p`` is not integer.
|
| 1014 |
+
If ``n`` or ``p`` is not positive.
|
| 1015 |
+
|
| 1016 |
+
Examples
|
| 1017 |
+
========
|
| 1018 |
+
|
| 1019 |
+
>>> from sympy.ntheory.residue_ntheory import nthroot_mod
|
| 1020 |
+
>>> nthroot_mod(11, 4, 19)
|
| 1021 |
+
8
|
| 1022 |
+
>>> nthroot_mod(11, 4, 19, True)
|
| 1023 |
+
[8, 11]
|
| 1024 |
+
>>> nthroot_mod(68, 3, 109)
|
| 1025 |
+
23
|
| 1026 |
+
|
| 1027 |
+
References
|
| 1028 |
+
==========
|
| 1029 |
+
|
| 1030 |
+
.. [1] P. Hackman "Elementary Number Theory" (2009), page 76
|
| 1031 |
+
|
| 1032 |
+
"""
|
| 1033 |
+
a = a % p
|
| 1034 |
+
a, n, p = as_int(a), as_int(n), as_int(p)
|
| 1035 |
+
|
| 1036 |
+
if n < 1:
|
| 1037 |
+
raise ValueError("n should be positive")
|
| 1038 |
+
if p < 1:
|
| 1039 |
+
raise ValueError("p should be positive")
|
| 1040 |
+
if n == 1:
|
| 1041 |
+
return [a] if all_roots else a
|
| 1042 |
+
if n == 2:
|
| 1043 |
+
return sqrt_mod(a, p, all_roots)
|
| 1044 |
+
base = []
|
| 1045 |
+
prime_power = []
|
| 1046 |
+
for q, e in factorint(p).items():
|
| 1047 |
+
tot_roots = _nthroot_mod_prime_power(a, n, q, e)
|
| 1048 |
+
if not tot_roots:
|
| 1049 |
+
return [] if all_roots else None
|
| 1050 |
+
prime_power.append(q**e)
|
| 1051 |
+
base.append(sorted(tot_roots))
|
| 1052 |
+
P, E, S = gf_crt1(prime_power, ZZ)
|
| 1053 |
+
ret = sorted(map(int, {gf_crt2(c, prime_power, P, E, S, ZZ)
|
| 1054 |
+
for c in product(*base)}))
|
| 1055 |
+
if all_roots:
|
| 1056 |
+
return ret
|
| 1057 |
+
if ret:
|
| 1058 |
+
return ret[0]
|
| 1059 |
+
|
| 1060 |
+
|
| 1061 |
+
def quadratic_residues(p) -> list[int]:
|
| 1062 |
+
"""
|
| 1063 |
+
Returns the list of quadratic residues.
|
| 1064 |
+
|
| 1065 |
+
Examples
|
| 1066 |
+
========
|
| 1067 |
+
|
| 1068 |
+
>>> from sympy.ntheory.residue_ntheory import quadratic_residues
|
| 1069 |
+
>>> quadratic_residues(7)
|
| 1070 |
+
[0, 1, 2, 4]
|
| 1071 |
+
"""
|
| 1072 |
+
p = as_int(p)
|
| 1073 |
+
r = {pow(i, 2, p) for i in range(p // 2 + 1)}
|
| 1074 |
+
return sorted(r)
|
| 1075 |
+
|
| 1076 |
+
|
| 1077 |
+
@deprecated("""\
|
| 1078 |
+
The `sympy.ntheory.residue_ntheory.legendre_symbol` has been moved to `sympy.functions.combinatorial.numbers.legendre_symbol`.""",
|
| 1079 |
+
deprecated_since_version="1.13",
|
| 1080 |
+
active_deprecations_target='deprecated-ntheory-symbolic-functions')
|
| 1081 |
+
def legendre_symbol(a, p):
|
| 1082 |
+
r"""
|
| 1083 |
+
Returns the Legendre symbol `(a / p)`.
|
| 1084 |
+
|
| 1085 |
+
.. deprecated:: 1.13
|
| 1086 |
+
|
| 1087 |
+
The ``legendre_symbol`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.legendre_symbol`
|
| 1088 |
+
instead. See its documentation for more information. See
|
| 1089 |
+
:ref:`deprecated-ntheory-symbolic-functions` for details.
|
| 1090 |
+
|
| 1091 |
+
For an integer ``a`` and an odd prime ``p``, the Legendre symbol is
|
| 1092 |
+
defined as
|
| 1093 |
+
|
| 1094 |
+
.. math ::
|
| 1095 |
+
\genfrac(){}{}{a}{p} = \begin{cases}
|
| 1096 |
+
0 & \text{if } p \text{ divides } a\\
|
| 1097 |
+
1 & \text{if } a \text{ is a quadratic residue modulo } p\\
|
| 1098 |
+
-1 & \text{if } a \text{ is a quadratic nonresidue modulo } p
|
| 1099 |
+
\end{cases}
|
| 1100 |
+
|
| 1101 |
+
Parameters
|
| 1102 |
+
==========
|
| 1103 |
+
|
| 1104 |
+
a : integer
|
| 1105 |
+
p : odd prime
|
| 1106 |
+
|
| 1107 |
+
Examples
|
| 1108 |
+
========
|
| 1109 |
+
|
| 1110 |
+
>>> from sympy.functions.combinatorial.numbers import legendre_symbol
|
| 1111 |
+
>>> [legendre_symbol(i, 7) for i in range(7)]
|
| 1112 |
+
[0, 1, 1, -1, 1, -1, -1]
|
| 1113 |
+
>>> sorted(set([i**2 % 7 for i in range(7)]))
|
| 1114 |
+
[0, 1, 2, 4]
|
| 1115 |
+
|
| 1116 |
+
See Also
|
| 1117 |
+
========
|
| 1118 |
+
|
| 1119 |
+
is_quad_residue, jacobi_symbol
|
| 1120 |
+
|
| 1121 |
+
"""
|
| 1122 |
+
from sympy.functions.combinatorial.numbers import legendre_symbol as _legendre_symbol
|
| 1123 |
+
return _legendre_symbol(a, p)
|
| 1124 |
+
|
| 1125 |
+
|
| 1126 |
+
@deprecated("""\
|
| 1127 |
+
The `sympy.ntheory.residue_ntheory.jacobi_symbol` has been moved to `sympy.functions.combinatorial.numbers.jacobi_symbol`.""",
|
| 1128 |
+
deprecated_since_version="1.13",
|
| 1129 |
+
active_deprecations_target='deprecated-ntheory-symbolic-functions')
|
| 1130 |
+
def jacobi_symbol(m, n):
|
| 1131 |
+
r"""
|
| 1132 |
+
Returns the Jacobi symbol `(m / n)`.
|
| 1133 |
+
|
| 1134 |
+
.. deprecated:: 1.13
|
| 1135 |
+
|
| 1136 |
+
The ``jacobi_symbol`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.jacobi_symbol`
|
| 1137 |
+
instead. See its documentation for more information. See
|
| 1138 |
+
:ref:`deprecated-ntheory-symbolic-functions` for details.
|
| 1139 |
+
|
| 1140 |
+
For any integer ``m`` and any positive odd integer ``n`` the Jacobi symbol
|
| 1141 |
+
is defined as the product of the Legendre symbols corresponding to the
|
| 1142 |
+
prime factors of ``n``:
|
| 1143 |
+
|
| 1144 |
+
.. math ::
|
| 1145 |
+
\genfrac(){}{}{m}{n} =
|
| 1146 |
+
\genfrac(){}{}{m}{p^{1}}^{\alpha_1}
|
| 1147 |
+
\genfrac(){}{}{m}{p^{2}}^{\alpha_2}
|
| 1148 |
+
...
|
| 1149 |
+
\genfrac(){}{}{m}{p^{k}}^{\alpha_k}
|
| 1150 |
+
\text{ where } n =
|
| 1151 |
+
p_1^{\alpha_1}
|
| 1152 |
+
p_2^{\alpha_2}
|
| 1153 |
+
...
|
| 1154 |
+
p_k^{\alpha_k}
|
| 1155 |
+
|
| 1156 |
+
Like the Legendre symbol, if the Jacobi symbol `\genfrac(){}{}{m}{n} = -1`
|
| 1157 |
+
then ``m`` is a quadratic nonresidue modulo ``n``.
|
| 1158 |
+
|
| 1159 |
+
But, unlike the Legendre symbol, if the Jacobi symbol
|
| 1160 |
+
`\genfrac(){}{}{m}{n} = 1` then ``m`` may or may not be a quadratic residue
|
| 1161 |
+
modulo ``n``.
|
| 1162 |
+
|
| 1163 |
+
Parameters
|
| 1164 |
+
==========
|
| 1165 |
+
|
| 1166 |
+
m : integer
|
| 1167 |
+
n : odd positive integer
|
| 1168 |
+
|
| 1169 |
+
Examples
|
| 1170 |
+
========
|
| 1171 |
+
|
| 1172 |
+
>>> from sympy.functions.combinatorial.numbers import jacobi_symbol, legendre_symbol
|
| 1173 |
+
>>> from sympy import S
|
| 1174 |
+
>>> jacobi_symbol(45, 77)
|
| 1175 |
+
-1
|
| 1176 |
+
>>> jacobi_symbol(60, 121)
|
| 1177 |
+
1
|
| 1178 |
+
|
| 1179 |
+
The relationship between the ``jacobi_symbol`` and ``legendre_symbol`` can
|
| 1180 |
+
be demonstrated as follows:
|
| 1181 |
+
|
| 1182 |
+
>>> L = legendre_symbol
|
| 1183 |
+
>>> S(45).factors()
|
| 1184 |
+
{3: 2, 5: 1}
|
| 1185 |
+
>>> jacobi_symbol(7, 45) == L(7, 3)**2 * L(7, 5)**1
|
| 1186 |
+
True
|
| 1187 |
+
|
| 1188 |
+
See Also
|
| 1189 |
+
========
|
| 1190 |
+
|
| 1191 |
+
is_quad_residue, legendre_symbol
|
| 1192 |
+
"""
|
| 1193 |
+
from sympy.functions.combinatorial.numbers import jacobi_symbol as _jacobi_symbol
|
| 1194 |
+
return _jacobi_symbol(m, n)
|
| 1195 |
+
|
| 1196 |
+
|
| 1197 |
+
@deprecated("""\
|
| 1198 |
+
The `sympy.ntheory.residue_ntheory.mobius` has been moved to `sympy.functions.combinatorial.numbers.mobius`.""",
|
| 1199 |
+
deprecated_since_version="1.13",
|
| 1200 |
+
active_deprecations_target='deprecated-ntheory-symbolic-functions')
|
| 1201 |
+
def mobius(n):
|
| 1202 |
+
"""
|
| 1203 |
+
Mobius function maps natural number to {-1, 0, 1}
|
| 1204 |
+
|
| 1205 |
+
.. deprecated:: 1.13
|
| 1206 |
+
|
| 1207 |
+
The ``mobius`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.mobius`
|
| 1208 |
+
instead. See its documentation for more information. See
|
| 1209 |
+
:ref:`deprecated-ntheory-symbolic-functions` for details.
|
| 1210 |
+
|
| 1211 |
+
It is defined as follows:
|
| 1212 |
+
1) `1` if `n = 1`.
|
| 1213 |
+
2) `0` if `n` has a squared prime factor.
|
| 1214 |
+
3) `(-1)^k` if `n` is a square-free positive integer with `k`
|
| 1215 |
+
number of prime factors.
|
| 1216 |
+
|
| 1217 |
+
It is an important multiplicative function in number theory
|
| 1218 |
+
and combinatorics. It has applications in mathematical series,
|
| 1219 |
+
algebraic number theory and also physics (Fermion operator has very
|
| 1220 |
+
concrete realization with Mobius Function model).
|
| 1221 |
+
|
| 1222 |
+
Parameters
|
| 1223 |
+
==========
|
| 1224 |
+
|
| 1225 |
+
n : positive integer
|
| 1226 |
+
|
| 1227 |
+
Examples
|
| 1228 |
+
========
|
| 1229 |
+
|
| 1230 |
+
>>> from sympy.functions.combinatorial.numbers import mobius
|
| 1231 |
+
>>> mobius(13*7)
|
| 1232 |
+
1
|
| 1233 |
+
>>> mobius(1)
|
| 1234 |
+
1
|
| 1235 |
+
>>> mobius(13*7*5)
|
| 1236 |
+
-1
|
| 1237 |
+
>>> mobius(13**2)
|
| 1238 |
+
0
|
| 1239 |
+
|
| 1240 |
+
References
|
| 1241 |
+
==========
|
| 1242 |
+
|
| 1243 |
+
.. [1] https://en.wikipedia.org/wiki/M%C3%B6bius_function
|
| 1244 |
+
.. [2] Thomas Koshy "Elementary Number Theory with Applications"
|
| 1245 |
+
|
| 1246 |
+
"""
|
| 1247 |
+
from sympy.functions.combinatorial.numbers import mobius as _mobius
|
| 1248 |
+
return _mobius(n)
|
| 1249 |
+
|
| 1250 |
+
|
| 1251 |
+
def _discrete_log_trial_mul(n, a, b, order=None):
|
| 1252 |
+
"""
|
| 1253 |
+
Trial multiplication algorithm for computing the discrete logarithm of
|
| 1254 |
+
``a`` to the base ``b`` modulo ``n``.
|
| 1255 |
+
|
| 1256 |
+
The algorithm finds the discrete logarithm using exhaustive search. This
|
| 1257 |
+
naive method is used as fallback algorithm of ``discrete_log`` when the
|
| 1258 |
+
group order is very small.
|
| 1259 |
+
|
| 1260 |
+
Examples
|
| 1261 |
+
========
|
| 1262 |
+
|
| 1263 |
+
>>> from sympy.ntheory.residue_ntheory import _discrete_log_trial_mul
|
| 1264 |
+
>>> _discrete_log_trial_mul(41, 15, 7)
|
| 1265 |
+
3
|
| 1266 |
+
|
| 1267 |
+
See Also
|
| 1268 |
+
========
|
| 1269 |
+
|
| 1270 |
+
discrete_log
|
| 1271 |
+
|
| 1272 |
+
References
|
| 1273 |
+
==========
|
| 1274 |
+
|
| 1275 |
+
.. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., &
|
| 1276 |
+
Vanstone, S. A. (1997).
|
| 1277 |
+
"""
|
| 1278 |
+
a %= n
|
| 1279 |
+
b %= n
|
| 1280 |
+
if order is None:
|
| 1281 |
+
order = n
|
| 1282 |
+
x = 1
|
| 1283 |
+
for i in range(order):
|
| 1284 |
+
if x == a:
|
| 1285 |
+
return i
|
| 1286 |
+
x = x * b % n
|
| 1287 |
+
raise ValueError("Log does not exist")
|
| 1288 |
+
|
| 1289 |
+
|
| 1290 |
+
def _discrete_log_shanks_steps(n, a, b, order=None):
|
| 1291 |
+
"""
|
| 1292 |
+
Baby-step giant-step algorithm for computing the discrete logarithm of
|
| 1293 |
+
``a`` to the base ``b`` modulo ``n``.
|
| 1294 |
+
|
| 1295 |
+
The algorithm is a time-memory trade-off of the method of exhaustive
|
| 1296 |
+
search. It uses `O(sqrt(m))` memory, where `m` is the group order.
|
| 1297 |
+
|
| 1298 |
+
Examples
|
| 1299 |
+
========
|
| 1300 |
+
|
| 1301 |
+
>>> from sympy.ntheory.residue_ntheory import _discrete_log_shanks_steps
|
| 1302 |
+
>>> _discrete_log_shanks_steps(41, 15, 7)
|
| 1303 |
+
3
|
| 1304 |
+
|
| 1305 |
+
See Also
|
| 1306 |
+
========
|
| 1307 |
+
|
| 1308 |
+
discrete_log
|
| 1309 |
+
|
| 1310 |
+
References
|
| 1311 |
+
==========
|
| 1312 |
+
|
| 1313 |
+
.. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., &
|
| 1314 |
+
Vanstone, S. A. (1997).
|
| 1315 |
+
"""
|
| 1316 |
+
a %= n
|
| 1317 |
+
b %= n
|
| 1318 |
+
if order is None:
|
| 1319 |
+
order = n_order(b, n)
|
| 1320 |
+
m = sqrt(order) + 1
|
| 1321 |
+
T = {}
|
| 1322 |
+
x = 1
|
| 1323 |
+
for i in range(m):
|
| 1324 |
+
T[x] = i
|
| 1325 |
+
x = x * b % n
|
| 1326 |
+
z = pow(b, -m, n)
|
| 1327 |
+
x = a
|
| 1328 |
+
for i in range(m):
|
| 1329 |
+
if x in T:
|
| 1330 |
+
return i * m + T[x]
|
| 1331 |
+
x = x * z % n
|
| 1332 |
+
raise ValueError("Log does not exist")
|
| 1333 |
+
|
| 1334 |
+
|
| 1335 |
+
def _discrete_log_pollard_rho(n, a, b, order=None, retries=10, rseed=None):
|
| 1336 |
+
"""
|
| 1337 |
+
Pollard's Rho algorithm for computing the discrete logarithm of ``a`` to
|
| 1338 |
+
the base ``b`` modulo ``n``.
|
| 1339 |
+
|
| 1340 |
+
It is a randomized algorithm with the same expected running time as
|
| 1341 |
+
``_discrete_log_shanks_steps``, but requires a negligible amount of memory.
|
| 1342 |
+
|
| 1343 |
+
Examples
|
| 1344 |
+
========
|
| 1345 |
+
|
| 1346 |
+
>>> from sympy.ntheory.residue_ntheory import _discrete_log_pollard_rho
|
| 1347 |
+
>>> _discrete_log_pollard_rho(227, 3**7, 3)
|
| 1348 |
+
7
|
| 1349 |
+
|
| 1350 |
+
See Also
|
| 1351 |
+
========
|
| 1352 |
+
|
| 1353 |
+
discrete_log
|
| 1354 |
+
|
| 1355 |
+
References
|
| 1356 |
+
==========
|
| 1357 |
+
|
| 1358 |
+
.. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., &
|
| 1359 |
+
Vanstone, S. A. (1997).
|
| 1360 |
+
"""
|
| 1361 |
+
a %= n
|
| 1362 |
+
b %= n
|
| 1363 |
+
|
| 1364 |
+
if order is None:
|
| 1365 |
+
order = n_order(b, n)
|
| 1366 |
+
randint = _randint(rseed)
|
| 1367 |
+
|
| 1368 |
+
for i in range(retries):
|
| 1369 |
+
aa = randint(1, order - 1)
|
| 1370 |
+
ba = randint(1, order - 1)
|
| 1371 |
+
xa = pow(b, aa, n) * pow(a, ba, n) % n
|
| 1372 |
+
|
| 1373 |
+
c = xa % 3
|
| 1374 |
+
if c == 0:
|
| 1375 |
+
xb = a * xa % n
|
| 1376 |
+
ab = aa
|
| 1377 |
+
bb = (ba + 1) % order
|
| 1378 |
+
elif c == 1:
|
| 1379 |
+
xb = xa * xa % n
|
| 1380 |
+
ab = (aa + aa) % order
|
| 1381 |
+
bb = (ba + ba) % order
|
| 1382 |
+
else:
|
| 1383 |
+
xb = b * xa % n
|
| 1384 |
+
ab = (aa + 1) % order
|
| 1385 |
+
bb = ba
|
| 1386 |
+
|
| 1387 |
+
for j in range(order):
|
| 1388 |
+
c = xa % 3
|
| 1389 |
+
if c == 0:
|
| 1390 |
+
xa = a * xa % n
|
| 1391 |
+
ba = (ba + 1) % order
|
| 1392 |
+
elif c == 1:
|
| 1393 |
+
xa = xa * xa % n
|
| 1394 |
+
aa = (aa + aa) % order
|
| 1395 |
+
ba = (ba + ba) % order
|
| 1396 |
+
else:
|
| 1397 |
+
xa = b * xa % n
|
| 1398 |
+
aa = (aa + 1) % order
|
| 1399 |
+
|
| 1400 |
+
c = xb % 3
|
| 1401 |
+
if c == 0:
|
| 1402 |
+
xb = a * xb % n
|
| 1403 |
+
bb = (bb + 1) % order
|
| 1404 |
+
elif c == 1:
|
| 1405 |
+
xb = xb * xb % n
|
| 1406 |
+
ab = (ab + ab) % order
|
| 1407 |
+
bb = (bb + bb) % order
|
| 1408 |
+
else:
|
| 1409 |
+
xb = b * xb % n
|
| 1410 |
+
ab = (ab + 1) % order
|
| 1411 |
+
|
| 1412 |
+
c = xb % 3
|
| 1413 |
+
if c == 0:
|
| 1414 |
+
xb = a * xb % n
|
| 1415 |
+
bb = (bb + 1) % order
|
| 1416 |
+
elif c == 1:
|
| 1417 |
+
xb = xb * xb % n
|
| 1418 |
+
ab = (ab + ab) % order
|
| 1419 |
+
bb = (bb + bb) % order
|
| 1420 |
+
else:
|
| 1421 |
+
xb = b * xb % n
|
| 1422 |
+
ab = (ab + 1) % order
|
| 1423 |
+
|
| 1424 |
+
if xa == xb:
|
| 1425 |
+
r = (ba - bb) % order
|
| 1426 |
+
try:
|
| 1427 |
+
e = invert(r, order) * (ab - aa) % order
|
| 1428 |
+
if (pow(b, e, n) - a) % n == 0:
|
| 1429 |
+
return e
|
| 1430 |
+
except ZeroDivisionError:
|
| 1431 |
+
pass
|
| 1432 |
+
break
|
| 1433 |
+
raise ValueError("Pollard's Rho failed to find logarithm")
|
| 1434 |
+
|
| 1435 |
+
|
| 1436 |
+
def _discrete_log_is_smooth(n: int, factorbase: list):
|
| 1437 |
+
"""Try to factor n with respect to a given factorbase.
|
| 1438 |
+
Upon success a list of exponents with repect to the factorbase is returned.
|
| 1439 |
+
Otherwise None."""
|
| 1440 |
+
factors = [0]*len(factorbase)
|
| 1441 |
+
for i, p in enumerate(factorbase):
|
| 1442 |
+
while n % p == 0: # divide by p as many times as possible
|
| 1443 |
+
factors[i] += 1
|
| 1444 |
+
n = n // p
|
| 1445 |
+
if n != 1:
|
| 1446 |
+
return None # the number factors if at the end nothing is left
|
| 1447 |
+
return factors
|
| 1448 |
+
|
| 1449 |
+
|
| 1450 |
+
def _discrete_log_index_calculus(n, a, b, order, rseed=None):
|
| 1451 |
+
"""
|
| 1452 |
+
Index Calculus algorithm for computing the discrete logarithm of ``a`` to
|
| 1453 |
+
the base ``b`` modulo ``n``.
|
| 1454 |
+
|
| 1455 |
+
The group order must be given and prime. It is not suitable for small orders
|
| 1456 |
+
and the algorithm might fail to find a solution in such situations.
|
| 1457 |
+
|
| 1458 |
+
Examples
|
| 1459 |
+
========
|
| 1460 |
+
|
| 1461 |
+
>>> from sympy.ntheory.residue_ntheory import _discrete_log_index_calculus
|
| 1462 |
+
>>> _discrete_log_index_calculus(24570203447, 23859756228, 2, 12285101723)
|
| 1463 |
+
4519867240
|
| 1464 |
+
|
| 1465 |
+
See Also
|
| 1466 |
+
========
|
| 1467 |
+
|
| 1468 |
+
discrete_log
|
| 1469 |
+
|
| 1470 |
+
References
|
| 1471 |
+
==========
|
| 1472 |
+
|
| 1473 |
+
.. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., &
|
| 1474 |
+
Vanstone, S. A. (1997).
|
| 1475 |
+
"""
|
| 1476 |
+
randint = _randint(rseed)
|
| 1477 |
+
from math import sqrt, exp, log
|
| 1478 |
+
a %= n
|
| 1479 |
+
b %= n
|
| 1480 |
+
# assert isprime(order), "The order of the base must be prime."
|
| 1481 |
+
# First choose a heuristic the bound B for the factorbase.
|
| 1482 |
+
# We have added an extra term to the asymptotic value which
|
| 1483 |
+
# is closer to the theoretical optimum for n up to 2^70.
|
| 1484 |
+
B = int(exp(0.5 * sqrt( log(n) * log(log(n)) )*( 1 + 1/log(log(n)) )))
|
| 1485 |
+
max = 5 * B * B # expected number of trys to find a relation
|
| 1486 |
+
factorbase = list(primerange(B)) # compute the factorbase
|
| 1487 |
+
lf = len(factorbase) # length of the factorbase
|
| 1488 |
+
ordermo = order-1
|
| 1489 |
+
abx = a
|
| 1490 |
+
for x in range(order):
|
| 1491 |
+
if abx == 1:
|
| 1492 |
+
return (order - x) % order
|
| 1493 |
+
relationa = _discrete_log_is_smooth(abx, factorbase)
|
| 1494 |
+
if relationa:
|
| 1495 |
+
relationa = [r % order for r in relationa] + [x]
|
| 1496 |
+
break
|
| 1497 |
+
abx = abx * b % n # abx = a*pow(b, x, n) % n
|
| 1498 |
+
|
| 1499 |
+
else:
|
| 1500 |
+
raise ValueError("Index Calculus failed")
|
| 1501 |
+
|
| 1502 |
+
relations = [None] * lf
|
| 1503 |
+
k = 1 # number of relations found
|
| 1504 |
+
kk = 0
|
| 1505 |
+
while k < 3 * lf and kk < max: # find relations for all primes in our factor base
|
| 1506 |
+
x = randint(1,ordermo)
|
| 1507 |
+
relation = _discrete_log_is_smooth(pow(b,x,n), factorbase)
|
| 1508 |
+
if relation is None:
|
| 1509 |
+
kk += 1
|
| 1510 |
+
continue
|
| 1511 |
+
k += 1
|
| 1512 |
+
kk = 0
|
| 1513 |
+
relation += [ x ]
|
| 1514 |
+
index = lf # determine the index of the first nonzero entry
|
| 1515 |
+
for i in range(lf):
|
| 1516 |
+
ri = relation[i] % order
|
| 1517 |
+
if ri> 0 and relations[i] is not None: # make this entry zero if we can
|
| 1518 |
+
for j in range(lf+1):
|
| 1519 |
+
relation[j] = (relation[j] - ri*relations[i][j]) % order
|
| 1520 |
+
else:
|
| 1521 |
+
relation[i] = ri
|
| 1522 |
+
if relation[i] > 0 and index == lf: # is this the index of the first nonzero entry?
|
| 1523 |
+
index = i
|
| 1524 |
+
if index == lf or relations[index] is not None: # the relation contains no new information
|
| 1525 |
+
continue
|
| 1526 |
+
# the relation contains new information
|
| 1527 |
+
rinv = pow(relation[index],-1,order) # normalize the first nonzero entry
|
| 1528 |
+
for j in range(index,lf+1):
|
| 1529 |
+
relation[j] = rinv * relation[j] % order
|
| 1530 |
+
relations[index] = relation
|
| 1531 |
+
for i in range(lf): # subtract the new relation from the one for a
|
| 1532 |
+
if relationa[i] > 0 and relations[i] is not None:
|
| 1533 |
+
rbi = relationa[i]
|
| 1534 |
+
for j in range(lf+1):
|
| 1535 |
+
relationa[j] = (relationa[j] - rbi*relations[i][j]) % order
|
| 1536 |
+
if relationa[i] > 0: # the index of the first nonzero entry
|
| 1537 |
+
break # we do not need to reduce further at this point
|
| 1538 |
+
else: # all unkowns are gone
|
| 1539 |
+
#print(f"Success after {k} relations out of {lf}")
|
| 1540 |
+
x = (order -relationa[lf]) % order
|
| 1541 |
+
if pow(b,x,n) == a:
|
| 1542 |
+
return x
|
| 1543 |
+
raise ValueError("Index Calculus failed")
|
| 1544 |
+
raise ValueError("Index Calculus failed")
|
| 1545 |
+
|
| 1546 |
+
|
| 1547 |
+
def _discrete_log_pohlig_hellman(n, a, b, order=None, order_factors=None):
|
| 1548 |
+
"""
|
| 1549 |
+
Pohlig-Hellman algorithm for computing the discrete logarithm of ``a`` to
|
| 1550 |
+
the base ``b`` modulo ``n``.
|
| 1551 |
+
|
| 1552 |
+
In order to compute the discrete logarithm, the algorithm takes advantage
|
| 1553 |
+
of the factorization of the group order. It is more efficient when the
|
| 1554 |
+
group order factors into many small primes.
|
| 1555 |
+
|
| 1556 |
+
Examples
|
| 1557 |
+
========
|
| 1558 |
+
|
| 1559 |
+
>>> from sympy.ntheory.residue_ntheory import _discrete_log_pohlig_hellman
|
| 1560 |
+
>>> _discrete_log_pohlig_hellman(251, 210, 71)
|
| 1561 |
+
197
|
| 1562 |
+
|
| 1563 |
+
See Also
|
| 1564 |
+
========
|
| 1565 |
+
|
| 1566 |
+
discrete_log
|
| 1567 |
+
|
| 1568 |
+
References
|
| 1569 |
+
==========
|
| 1570 |
+
|
| 1571 |
+
.. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., &
|
| 1572 |
+
Vanstone, S. A. (1997).
|
| 1573 |
+
"""
|
| 1574 |
+
from .modular import crt
|
| 1575 |
+
a %= n
|
| 1576 |
+
b %= n
|
| 1577 |
+
|
| 1578 |
+
if order is None:
|
| 1579 |
+
order = n_order(b, n)
|
| 1580 |
+
if order_factors is None:
|
| 1581 |
+
order_factors = factorint(order)
|
| 1582 |
+
l = [0] * len(order_factors)
|
| 1583 |
+
|
| 1584 |
+
for i, (pi, ri) in enumerate(order_factors.items()):
|
| 1585 |
+
for j in range(ri):
|
| 1586 |
+
aj = pow(a * pow(b, -l[i], n), order // pi**(j + 1), n)
|
| 1587 |
+
bj = pow(b, order // pi, n)
|
| 1588 |
+
cj = discrete_log(n, aj, bj, pi, True)
|
| 1589 |
+
l[i] += cj * pi**j
|
| 1590 |
+
|
| 1591 |
+
d, _ = crt([pi**ri for pi, ri in order_factors.items()], l)
|
| 1592 |
+
return d
|
| 1593 |
+
|
| 1594 |
+
|
| 1595 |
+
def discrete_log(n, a, b, order=None, prime_order=None):
|
| 1596 |
+
"""
|
| 1597 |
+
Compute the discrete logarithm of ``a`` to the base ``b`` modulo ``n``.
|
| 1598 |
+
|
| 1599 |
+
This is a recursive function to reduce the discrete logarithm problem in
|
| 1600 |
+
cyclic groups of composite order to the problem in cyclic groups of prime
|
| 1601 |
+
order.
|
| 1602 |
+
|
| 1603 |
+
It employs different algorithms depending on the problem (subgroup order
|
| 1604 |
+
size, prime order or not):
|
| 1605 |
+
|
| 1606 |
+
* Trial multiplication
|
| 1607 |
+
* Baby-step giant-step
|
| 1608 |
+
* Pollard's Rho
|
| 1609 |
+
* Index Calculus
|
| 1610 |
+
* Pohlig-Hellman
|
| 1611 |
+
|
| 1612 |
+
Examples
|
| 1613 |
+
========
|
| 1614 |
+
|
| 1615 |
+
>>> from sympy.ntheory import discrete_log
|
| 1616 |
+
>>> discrete_log(41, 15, 7)
|
| 1617 |
+
3
|
| 1618 |
+
|
| 1619 |
+
References
|
| 1620 |
+
==========
|
| 1621 |
+
|
| 1622 |
+
.. [1] https://mathworld.wolfram.com/DiscreteLogarithm.html
|
| 1623 |
+
.. [2] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., &
|
| 1624 |
+
Vanstone, S. A. (1997).
|
| 1625 |
+
|
| 1626 |
+
"""
|
| 1627 |
+
from math import sqrt, log
|
| 1628 |
+
n, a, b = as_int(n), as_int(a), as_int(b)
|
| 1629 |
+
if order is None:
|
| 1630 |
+
# Compute the order and its factoring in one pass
|
| 1631 |
+
# order = totient(n), factors = factorint(order)
|
| 1632 |
+
factors = {}
|
| 1633 |
+
for px, kx in factorint(n).items():
|
| 1634 |
+
if kx > 1:
|
| 1635 |
+
if px in factors:
|
| 1636 |
+
factors[px] += kx - 1
|
| 1637 |
+
else:
|
| 1638 |
+
factors[px] = kx - 1
|
| 1639 |
+
for py, ky in factorint(px - 1).items():
|
| 1640 |
+
if py in factors:
|
| 1641 |
+
factors[py] += ky
|
| 1642 |
+
else:
|
| 1643 |
+
factors[py] = ky
|
| 1644 |
+
order = 1
|
| 1645 |
+
for px, kx in factors.items():
|
| 1646 |
+
order *= px**kx
|
| 1647 |
+
# Now the `order` is the order of the group and factors = factorint(order)
|
| 1648 |
+
# The order of `b` divides the order of the group.
|
| 1649 |
+
order_factors = {}
|
| 1650 |
+
for p, e in factors.items():
|
| 1651 |
+
i = 0
|
| 1652 |
+
for _ in range(e):
|
| 1653 |
+
if pow(b, order // p, n) == 1:
|
| 1654 |
+
order //= p
|
| 1655 |
+
i += 1
|
| 1656 |
+
else:
|
| 1657 |
+
break
|
| 1658 |
+
if i < e:
|
| 1659 |
+
order_factors[p] = e - i
|
| 1660 |
+
|
| 1661 |
+
if prime_order is None:
|
| 1662 |
+
prime_order = isprime(order)
|
| 1663 |
+
|
| 1664 |
+
if order < 1000:
|
| 1665 |
+
return _discrete_log_trial_mul(n, a, b, order)
|
| 1666 |
+
elif prime_order:
|
| 1667 |
+
# Shanks and Pollard rho are O(sqrt(order)) while index calculus is O(exp(2*sqrt(log(n)log(log(n)))))
|
| 1668 |
+
# we compare the expected running times to determine the algorithmus which is expected to be faster
|
| 1669 |
+
if 4*sqrt(log(n)*log(log(n))) < log(order) - 10: # the number 10 was determined experimental
|
| 1670 |
+
return _discrete_log_index_calculus(n, a, b, order)
|
| 1671 |
+
elif order < 1000000000000:
|
| 1672 |
+
# Shanks seems typically faster, but uses O(sqrt(order)) memory
|
| 1673 |
+
return _discrete_log_shanks_steps(n, a, b, order)
|
| 1674 |
+
return _discrete_log_pollard_rho(n, a, b, order)
|
| 1675 |
+
|
| 1676 |
+
return _discrete_log_pohlig_hellman(n, a, b, order, order_factors)
|
| 1677 |
+
|
| 1678 |
+
|
| 1679 |
+
|
| 1680 |
+
def quadratic_congruence(a, b, c, n):
|
| 1681 |
+
r"""
|
| 1682 |
+
Find the solutions to `a x^2 + b x + c \equiv 0 \pmod{n}`.
|
| 1683 |
+
|
| 1684 |
+
Parameters
|
| 1685 |
+
==========
|
| 1686 |
+
|
| 1687 |
+
a : int
|
| 1688 |
+
b : int
|
| 1689 |
+
c : int
|
| 1690 |
+
n : int
|
| 1691 |
+
A positive integer.
|
| 1692 |
+
|
| 1693 |
+
Returns
|
| 1694 |
+
=======
|
| 1695 |
+
|
| 1696 |
+
list[int] :
|
| 1697 |
+
A sorted list of solutions. If no solution exists, ``[]``.
|
| 1698 |
+
|
| 1699 |
+
Examples
|
| 1700 |
+
========
|
| 1701 |
+
|
| 1702 |
+
>>> from sympy.ntheory.residue_ntheory import quadratic_congruence
|
| 1703 |
+
>>> quadratic_congruence(2, 5, 3, 7) # 2x^2 + 5x + 3 = 0 (mod 7)
|
| 1704 |
+
[2, 6]
|
| 1705 |
+
>>> quadratic_congruence(8, 6, 4, 15) # No solution
|
| 1706 |
+
[]
|
| 1707 |
+
|
| 1708 |
+
See Also
|
| 1709 |
+
========
|
| 1710 |
+
|
| 1711 |
+
polynomial_congruence : Solve the polynomial congruence
|
| 1712 |
+
|
| 1713 |
+
"""
|
| 1714 |
+
a = as_int(a)
|
| 1715 |
+
b = as_int(b)
|
| 1716 |
+
c = as_int(c)
|
| 1717 |
+
n = as_int(n)
|
| 1718 |
+
if n <= 1:
|
| 1719 |
+
raise ValueError("n should be an integer greater than 1")
|
| 1720 |
+
a %= n
|
| 1721 |
+
b %= n
|
| 1722 |
+
c %= n
|
| 1723 |
+
|
| 1724 |
+
if a == 0:
|
| 1725 |
+
return linear_congruence(b, -c, n)
|
| 1726 |
+
if n == 2:
|
| 1727 |
+
# assert a == 1
|
| 1728 |
+
roots = []
|
| 1729 |
+
if c == 0:
|
| 1730 |
+
roots.append(0)
|
| 1731 |
+
if (b + c) % 2:
|
| 1732 |
+
roots.append(1)
|
| 1733 |
+
return roots
|
| 1734 |
+
if gcd(2*a, n) == 1:
|
| 1735 |
+
inv_a = invert(a, n)
|
| 1736 |
+
b *= inv_a
|
| 1737 |
+
c *= inv_a
|
| 1738 |
+
if b % 2:
|
| 1739 |
+
b += n
|
| 1740 |
+
b >>= 1
|
| 1741 |
+
return sorted((i - b) % n for i in sqrt_mod_iter(b**2 - c, n))
|
| 1742 |
+
res = set()
|
| 1743 |
+
for i in sqrt_mod_iter(b**2 - 4*a*c, 4*a*n):
|
| 1744 |
+
res.update(j % n for j in linear_congruence(2*a, i - b, 4*a*n))
|
| 1745 |
+
return sorted(res)
|
| 1746 |
+
|
| 1747 |
+
|
| 1748 |
+
def _valid_expr(expr):
|
| 1749 |
+
"""
|
| 1750 |
+
return coefficients of expr if it is a univariate polynomial
|
| 1751 |
+
with integer coefficients else raise a ValueError.
|
| 1752 |
+
"""
|
| 1753 |
+
|
| 1754 |
+
if not expr.is_polynomial():
|
| 1755 |
+
raise ValueError("The expression should be a polynomial")
|
| 1756 |
+
polynomial = Poly(expr)
|
| 1757 |
+
if not polynomial.is_univariate:
|
| 1758 |
+
raise ValueError("The expression should be univariate")
|
| 1759 |
+
if not polynomial.domain == ZZ:
|
| 1760 |
+
raise ValueError("The expression should should have integer coefficients")
|
| 1761 |
+
return polynomial.all_coeffs()
|
| 1762 |
+
|
| 1763 |
+
|
| 1764 |
+
def polynomial_congruence(expr, m):
|
| 1765 |
+
"""
|
| 1766 |
+
Find the solutions to a polynomial congruence equation modulo m.
|
| 1767 |
+
|
| 1768 |
+
Parameters
|
| 1769 |
+
==========
|
| 1770 |
+
|
| 1771 |
+
expr : integer coefficient polynomial
|
| 1772 |
+
m : positive integer
|
| 1773 |
+
|
| 1774 |
+
Examples
|
| 1775 |
+
========
|
| 1776 |
+
|
| 1777 |
+
>>> from sympy.ntheory import polynomial_congruence
|
| 1778 |
+
>>> from sympy.abc import x
|
| 1779 |
+
>>> expr = x**6 - 2*x**5 -35
|
| 1780 |
+
>>> polynomial_congruence(expr, 6125)
|
| 1781 |
+
[3257]
|
| 1782 |
+
|
| 1783 |
+
See Also
|
| 1784 |
+
========
|
| 1785 |
+
|
| 1786 |
+
sympy.polys.galoistools.gf_csolve : low level solving routine used by this routine
|
| 1787 |
+
|
| 1788 |
+
"""
|
| 1789 |
+
coefficients = _valid_expr(expr)
|
| 1790 |
+
coefficients = [num % m for num in coefficients]
|
| 1791 |
+
rank = len(coefficients)
|
| 1792 |
+
if rank == 3:
|
| 1793 |
+
return quadratic_congruence(*coefficients, m)
|
| 1794 |
+
if rank == 2:
|
| 1795 |
+
return quadratic_congruence(0, *coefficients, m)
|
| 1796 |
+
if coefficients[0] == 1 and 1 + coefficients[-1] == sum(coefficients):
|
| 1797 |
+
return nthroot_mod(-coefficients[-1], rank - 1, m, True)
|
| 1798 |
+
return gf_csolve(coefficients, m)
|
| 1799 |
+
|
| 1800 |
+
|
| 1801 |
+
def binomial_mod(n, m, k):
|
| 1802 |
+
"""Compute ``binomial(n, m) % k``.
|
| 1803 |
+
|
| 1804 |
+
Explanation
|
| 1805 |
+
===========
|
| 1806 |
+
|
| 1807 |
+
Returns ``binomial(n, m) % k`` using a generalization of Lucas'
|
| 1808 |
+
Theorem for prime powers given by Granville [1]_, in conjunction with
|
| 1809 |
+
the Chinese Remainder Theorem. The residue for each prime power
|
| 1810 |
+
is calculated in time O(log^2(n) + q^4*log(n)log(p) + q^4*p*log^3(p)).
|
| 1811 |
+
|
| 1812 |
+
Parameters
|
| 1813 |
+
==========
|
| 1814 |
+
|
| 1815 |
+
n : an integer
|
| 1816 |
+
m : an integer
|
| 1817 |
+
k : a positive integer
|
| 1818 |
+
|
| 1819 |
+
Examples
|
| 1820 |
+
========
|
| 1821 |
+
|
| 1822 |
+
>>> from sympy.ntheory.residue_ntheory import binomial_mod
|
| 1823 |
+
>>> binomial_mod(10, 2, 6) # binomial(10, 2) = 45
|
| 1824 |
+
3
|
| 1825 |
+
>>> binomial_mod(17, 9, 10) # binomial(17, 9) = 24310
|
| 1826 |
+
0
|
| 1827 |
+
|
| 1828 |
+
References
|
| 1829 |
+
==========
|
| 1830 |
+
|
| 1831 |
+
.. [1] Binomial coefficients modulo prime powers, Andrew Granville,
|
| 1832 |
+
Available: https://web.archive.org/web/20170202003812/http://www.dms.umontreal.ca/~andrew/PDF/BinCoeff.pdf
|
| 1833 |
+
"""
|
| 1834 |
+
if k < 1: raise ValueError('k is required to be positive')
|
| 1835 |
+
# We decompose q into a product of prime powers and apply
|
| 1836 |
+
# the generalization of Lucas' Theorem given by Granville
|
| 1837 |
+
# to obtain binomial(n, k) mod p^e, and then use the Chinese
|
| 1838 |
+
# Remainder Theorem to obtain the result mod q
|
| 1839 |
+
if n < 0 or m < 0 or m > n: return 0
|
| 1840 |
+
factorisation = factorint(k)
|
| 1841 |
+
residues = [_binomial_mod_prime_power(n, m, p, e) for p, e in factorisation.items()]
|
| 1842 |
+
return crt([p**pw for p, pw in factorisation.items()], residues, check=False)[0]
|
| 1843 |
+
|
| 1844 |
+
|
| 1845 |
+
def _binomial_mod_prime_power(n, m, p, q):
|
| 1846 |
+
"""Compute ``binomial(n, m) % p**q`` for a prime ``p``.
|
| 1847 |
+
|
| 1848 |
+
Parameters
|
| 1849 |
+
==========
|
| 1850 |
+
|
| 1851 |
+
n : positive integer
|
| 1852 |
+
m : a nonnegative integer
|
| 1853 |
+
p : a prime
|
| 1854 |
+
q : a positive integer (the prime exponent)
|
| 1855 |
+
|
| 1856 |
+
Examples
|
| 1857 |
+
========
|
| 1858 |
+
|
| 1859 |
+
>>> from sympy.ntheory.residue_ntheory import _binomial_mod_prime_power
|
| 1860 |
+
>>> _binomial_mod_prime_power(10, 2, 3, 2) # binomial(10, 2) = 45
|
| 1861 |
+
0
|
| 1862 |
+
>>> _binomial_mod_prime_power(17, 9, 2, 4) # binomial(17, 9) = 24310
|
| 1863 |
+
6
|
| 1864 |
+
|
| 1865 |
+
References
|
| 1866 |
+
==========
|
| 1867 |
+
|
| 1868 |
+
.. [1] Binomial coefficients modulo prime powers, Andrew Granville,
|
| 1869 |
+
Available: https://web.archive.org/web/20170202003812/http://www.dms.umontreal.ca/~andrew/PDF/BinCoeff.pdf
|
| 1870 |
+
"""
|
| 1871 |
+
# Function/variable naming within this function follows Ref.[1]
|
| 1872 |
+
# n!_p will be used to denote the product of integers <= n not divisible by
|
| 1873 |
+
# p, with binomial(n, m)_p the same as binomial(n, m), but defined using
|
| 1874 |
+
# n!_p in place of n!
|
| 1875 |
+
modulo = pow(p, q)
|
| 1876 |
+
|
| 1877 |
+
def up_factorial(u):
|
| 1878 |
+
"""Compute (u*p)!_p modulo p^q."""
|
| 1879 |
+
r = q // 2
|
| 1880 |
+
fac = prod = 1
|
| 1881 |
+
if r == 1 and p == 2 or 2*r + 1 in (p, p*p):
|
| 1882 |
+
if q % 2 == 1: r += 1
|
| 1883 |
+
modulo, div = pow(p, 2*r), pow(p, 2*r - q)
|
| 1884 |
+
else:
|
| 1885 |
+
modulo, div = pow(p, 2*r + 1), pow(p, (2*r + 1) - q)
|
| 1886 |
+
for j in range(1, r + 1):
|
| 1887 |
+
for mul in range((j - 1)*p + 1, j*p): # ignore jp itself
|
| 1888 |
+
fac *= mul
|
| 1889 |
+
fac %= modulo
|
| 1890 |
+
bj_ = bj(u, j, r)
|
| 1891 |
+
prod *= pow(fac, bj_, modulo)
|
| 1892 |
+
prod %= modulo
|
| 1893 |
+
if p == 2:
|
| 1894 |
+
sm = u // 2
|
| 1895 |
+
for j in range(1, r + 1): sm += j//2 * bj(u, j, r)
|
| 1896 |
+
if sm % 2 == 1: prod *= -1
|
| 1897 |
+
prod %= modulo//div
|
| 1898 |
+
return prod % modulo
|
| 1899 |
+
|
| 1900 |
+
def bj(u, j, r):
|
| 1901 |
+
"""Compute the exponent of (j*p)!_p in the calculation of (u*p)!_p."""
|
| 1902 |
+
prod = u
|
| 1903 |
+
for i in range(1, r + 1):
|
| 1904 |
+
if i != j: prod *= u*u - i*i
|
| 1905 |
+
for i in range(1, r + 1):
|
| 1906 |
+
if i != j: prod //= j*j - i*i
|
| 1907 |
+
return prod // j
|
| 1908 |
+
|
| 1909 |
+
def up_plus_v_binom(u, v):
|
| 1910 |
+
"""Compute binomial(u*p + v, v)_p modulo p^q."""
|
| 1911 |
+
prod = 1
|
| 1912 |
+
div = invert(factorial(v), modulo)
|
| 1913 |
+
for j in range(1, q):
|
| 1914 |
+
b = div
|
| 1915 |
+
for v_ in range(j*p + 1, j*p + v + 1):
|
| 1916 |
+
b *= v_
|
| 1917 |
+
b %= modulo
|
| 1918 |
+
aj = u
|
| 1919 |
+
for i in range(1, q):
|
| 1920 |
+
if i != j: aj *= u - i
|
| 1921 |
+
for i in range(1, q):
|
| 1922 |
+
if i != j: aj //= j - i
|
| 1923 |
+
aj //= j
|
| 1924 |
+
prod *= pow(b, aj, modulo)
|
| 1925 |
+
prod %= modulo
|
| 1926 |
+
return prod
|
| 1927 |
+
|
| 1928 |
+
@recurrence_memo([1])
|
| 1929 |
+
def factorial(v, prev):
|
| 1930 |
+
"""Compute v! modulo p^q."""
|
| 1931 |
+
return v*prev[-1] % modulo
|
| 1932 |
+
|
| 1933 |
+
def factorial_p(n):
|
| 1934 |
+
"""Compute n!_p modulo p^q."""
|
| 1935 |
+
u, v = divmod(n, p)
|
| 1936 |
+
return (factorial(v) * up_factorial(u) * up_plus_v_binom(u, v)) % modulo
|
| 1937 |
+
|
| 1938 |
+
prod = 1
|
| 1939 |
+
Nj, Mj, Rj = n, m, n - m
|
| 1940 |
+
# e0 will be the p-adic valuation of binomial(n, m) at p
|
| 1941 |
+
e0 = carry = eq_1 = j = 0
|
| 1942 |
+
while Nj:
|
| 1943 |
+
numerator = factorial_p(Nj % modulo)
|
| 1944 |
+
denominator = factorial_p(Mj % modulo) * factorial_p(Rj % modulo) % modulo
|
| 1945 |
+
Nj, (Mj, mj), (Rj, rj) = Nj//p, divmod(Mj, p), divmod(Rj, p)
|
| 1946 |
+
carry = (mj + rj + carry) // p
|
| 1947 |
+
e0 += carry
|
| 1948 |
+
if j >= q - 1: eq_1 += carry
|
| 1949 |
+
prod *= numerator * invert(denominator, modulo)
|
| 1950 |
+
prod %= modulo
|
| 1951 |
+
j += 1
|
| 1952 |
+
|
| 1953 |
+
mul = pow(1 if p == 2 and q >= 3 else -1, eq_1, modulo)
|
| 1954 |
+
return (pow(p, e0, modulo) * mul * prod) % modulo
|
lib/python3.12/site-packages/sympy/ntheory/tests/__init__.py
ADDED
|
File without changes
|
lib/python3.12/site-packages/sympy/ntheory/tests/test_bbp_pi.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.core.random import randint
|
| 2 |
+
|
| 3 |
+
from sympy.ntheory.bbp_pi import pi_hex_digits
|
| 4 |
+
from sympy.testing.pytest import raises
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
# http://www.herongyang.com/Cryptography/Blowfish-First-8366-Hex-Digits-of-PI.html
|
| 8 |
+
# There are actually 8336 listed there; with the prepended 3 there are 8337
|
| 9 |
+
# below
|
| 10 |
+
dig=''.join('''
|
| 11 |
+
3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89452821e638d013
|
| 12 |
+
77be5466cf34e90c6cc0ac29b7c97c50dd3f84d5b5b54709179216d5d98979fb1bd1310ba698dfb5
|
| 13 |
+
ac2ffd72dbd01adfb7b8e1afed6a267e96ba7c9045f12c7f9924a19947b3916cf70801f2e2858efc
|
| 14 |
+
16636920d871574e69a458fea3f4933d7e0d95748f728eb658718bcd5882154aee7b54a41dc25a59
|
| 15 |
+
b59c30d5392af26013c5d1b023286085f0ca417918b8db38ef8e79dcb0603a180e6c9e0e8bb01e8a
|
| 16 |
+
3ed71577c1bd314b2778af2fda55605c60e65525f3aa55ab945748986263e8144055ca396a2aab10
|
| 17 |
+
b6b4cc5c341141e8cea15486af7c72e993b3ee1411636fbc2a2ba9c55d741831f6ce5c3e169b8793
|
| 18 |
+
1eafd6ba336c24cf5c7a325381289586773b8f48986b4bb9afc4bfe81b6628219361d809ccfb21a9
|
| 19 |
+
91487cac605dec8032ef845d5de98575b1dc262302eb651b8823893e81d396acc50f6d6ff383f442
|
| 20 |
+
392e0b4482a484200469c8f04a9e1f9b5e21c66842f6e96c9a670c9c61abd388f06a51a0d2d8542f
|
| 21 |
+
68960fa728ab5133a36eef0b6c137a3be4ba3bf0507efb2a98a1f1651d39af017666ca593e82430e
|
| 22 |
+
888cee8619456f9fb47d84a5c33b8b5ebee06f75d885c12073401a449f56c16aa64ed3aa62363f77
|
| 23 |
+
061bfedf72429b023d37d0d724d00a1248db0fead349f1c09b075372c980991b7b25d479d8f6e8de
|
| 24 |
+
f7e3fe501ab6794c3b976ce0bd04c006bac1a94fb6409f60c45e5c9ec2196a246368fb6faf3e6c53
|
| 25 |
+
b51339b2eb3b52ec6f6dfc511f9b30952ccc814544af5ebd09bee3d004de334afd660f2807192e4b
|
| 26 |
+
b3c0cba85745c8740fd20b5f39b9d3fbdb5579c0bd1a60320ad6a100c6402c7279679f25fefb1fa3
|
| 27 |
+
cc8ea5e9f8db3222f83c7516dffd616b152f501ec8ad0552ab323db5fafd23876053317b483e00df
|
| 28 |
+
829e5c57bbca6f8ca01a87562edf1769dbd542a8f6287effc3ac6732c68c4f5573695b27b0bbca58
|
| 29 |
+
c8e1ffa35db8f011a010fa3d98fd2183b84afcb56c2dd1d35b9a53e479b6f84565d28e49bc4bfb97
|
| 30 |
+
90e1ddf2daa4cb7e3362fb1341cee4c6e8ef20cada36774c01d07e9efe2bf11fb495dbda4dae9091
|
| 31 |
+
98eaad8e716b93d5a0d08ed1d0afc725e08e3c5b2f8e7594b78ff6e2fbf2122b648888b812900df0
|
| 32 |
+
1c4fad5ea0688fc31cd1cff191b3a8c1ad2f2f2218be0e1777ea752dfe8b021fa1e5a0cc0fb56f74
|
| 33 |
+
e818acf3d6ce89e299b4a84fe0fd13e0b77cc43b81d2ada8d9165fa2668095770593cc7314211a14
|
| 34 |
+
77e6ad206577b5fa86c75442f5fb9d35cfebcdaf0c7b3e89a0d6411bd3ae1e7e4900250e2d2071b3
|
| 35 |
+
5e226800bb57b8e0af2464369bf009b91e5563911d59dfa6aa78c14389d95a537f207d5ba202e5b9
|
| 36 |
+
c5832603766295cfa911c819684e734a41b3472dca7b14a94a1b5100529a532915d60f573fbc9bc6
|
| 37 |
+
e42b60a47681e6740008ba6fb5571be91ff296ec6b2a0dd915b6636521e7b9f9b6ff34052ec58556
|
| 38 |
+
6453b02d5da99f8fa108ba47996e85076a4b7a70e9b5b32944db75092ec4192623ad6ea6b049a7df
|
| 39 |
+
7d9cee60b88fedb266ecaa8c71699a17ff5664526cc2b19ee1193602a575094c29a0591340e4183a
|
| 40 |
+
3e3f54989a5b429d656b8fe4d699f73fd6a1d29c07efe830f54d2d38e6f0255dc14cdd20868470eb
|
| 41 |
+
266382e9c6021ecc5e09686b3f3ebaefc93c9718146b6a70a1687f358452a0e286b79c5305aa5007
|
| 42 |
+
373e07841c7fdeae5c8e7d44ec5716f2b8b03ada37f0500c0df01c1f040200b3ffae0cf51a3cb574
|
| 43 |
+
b225837a58dc0921bdd19113f97ca92ff69432477322f547013ae5e58137c2dadcc8b576349af3dd
|
| 44 |
+
a7a94461460fd0030eecc8c73ea4751e41e238cd993bea0e2f3280bba1183eb3314e548b384f6db9
|
| 45 |
+
086f420d03f60a04bf2cb8129024977c795679b072bcaf89afde9a771fd9930810b38bae12dccf3f
|
| 46 |
+
2e5512721f2e6b7124501adde69f84cd877a5847187408da17bc9f9abce94b7d8cec7aec3adb851d
|
| 47 |
+
fa63094366c464c3d2ef1c18473215d908dd433b3724c2ba1612a14d432a65c45150940002133ae4
|
| 48 |
+
dd71dff89e10314e5581ac77d65f11199b043556f1d7a3c76b3c11183b5924a509f28fe6ed97f1fb
|
| 49 |
+
fa9ebabf2c1e153c6e86e34570eae96fb1860e5e0a5a3e2ab3771fe71c4e3d06fa2965dcb999e71d
|
| 50 |
+
0f803e89d65266c8252e4cc9789c10b36ac6150eba94e2ea78a5fc3c531e0a2df4f2f74ea7361d2b
|
| 51 |
+
3d1939260f19c279605223a708f71312b6ebadfe6eeac31f66e3bc4595a67bc883b17f37d1018cff
|
| 52 |
+
28c332ddefbe6c5aa56558218568ab9802eecea50fdb2f953b2aef7dad5b6e2f841521b628290761
|
| 53 |
+
70ecdd4775619f151013cca830eb61bd960334fe1eaa0363cfb5735c904c70a239d59e9e0bcbaade
|
| 54 |
+
14eecc86bc60622ca79cab5cabb2f3846e648b1eaf19bdf0caa02369b9655abb5040685a323c2ab4
|
| 55 |
+
b3319ee9d5c021b8f79b540b19875fa09995f7997e623d7da8f837889a97e32d7711ed935f166812
|
| 56 |
+
810e358829c7e61fd696dedfa17858ba9957f584a51b2272639b83c3ff1ac24696cdb30aeb532e30
|
| 57 |
+
548fd948e46dbc312858ebf2ef34c6ffeafe28ed61ee7c3c735d4a14d9e864b7e342105d14203e13
|
| 58 |
+
e045eee2b6a3aaabeadb6c4f15facb4fd0c742f442ef6abbb5654f3b1d41cd2105d81e799e86854d
|
| 59 |
+
c7e44b476a3d816250cf62a1f25b8d2646fc8883a0c1c7b6a37f1524c369cb749247848a0b5692b2
|
| 60 |
+
85095bbf00ad19489d1462b17423820e0058428d2a0c55f5ea1dadf43e233f70613372f0928d937e
|
| 61 |
+
41d65fecf16c223bdb7cde3759cbee74604085f2a7ce77326ea607808419f8509ee8efd85561d997
|
| 62 |
+
35a969a7aac50c06c25a04abfc800bcadc9e447a2ec3453484fdd567050e1e9ec9db73dbd3105588
|
| 63 |
+
cd675fda79e3674340c5c43465713e38d83d28f89ef16dff20153e21e78fb03d4ae6e39f2bdb83ad
|
| 64 |
+
f7e93d5a68948140f7f64c261c94692934411520f77602d4f7bcf46b2ed4a20068d40824713320f4
|
| 65 |
+
6a43b7d4b7500061af1e39f62e9724454614214f74bf8b88404d95fc1d96b591af70f4ddd366a02f
|
| 66 |
+
45bfbc09ec03bd97857fac6dd031cb850496eb27b355fd3941da2547e6abca0a9a28507825530429
|
| 67 |
+
f40a2c86dae9b66dfb68dc1462d7486900680ec0a427a18dee4f3ffea2e887ad8cb58ce0067af4d6
|
| 68 |
+
b6aace1e7cd3375fecce78a399406b2a4220fe9e35d9f385b9ee39d7ab3b124e8b1dc9faf74b6d18
|
| 69 |
+
5626a36631eae397b23a6efa74dd5b43326841e7f7ca7820fbfb0af54ed8feb397454056acba4895
|
| 70 |
+
2755533a3a20838d87fe6ba9b7d096954b55a867bca1159a58cca9296399e1db33a62a4a563f3125
|
| 71 |
+
f95ef47e1c9029317cfdf8e80204272f7080bb155c05282ce395c11548e4c66d2248c1133fc70f86
|
| 72 |
+
dc07f9c9ee41041f0f404779a45d886e17325f51ebd59bc0d1f2bcc18f41113564257b7834602a9c
|
| 73 |
+
60dff8e8a31f636c1b0e12b4c202e1329eaf664fd1cad181156b2395e0333e92e13b240b62eebeb9
|
| 74 |
+
2285b2a20ee6ba0d99de720c8c2da2f728d012784595b794fd647d0862e7ccf5f05449a36f877d48
|
| 75 |
+
fac39dfd27f33e8d1e0a476341992eff743a6f6eabf4f8fd37a812dc60a1ebddf8991be14cdb6e6b
|
| 76 |
+
0dc67b55106d672c372765d43bdcd0e804f1290dc7cc00ffa3b5390f92690fed0b667b9ffbcedb7d
|
| 77 |
+
9ca091cf0bd9155ea3bb132f88515bad247b9479bf763bd6eb37392eb3cc1159798026e297f42e31
|
| 78 |
+
2d6842ada7c66a2b3b12754ccc782ef11c6a124237b79251e706a1bbe64bfb63501a6b101811caed
|
| 79 |
+
fa3d25bdd8e2e1c3c9444216590a121386d90cec6ed5abea2a64af674eda86a85fbebfe98864e4c3
|
| 80 |
+
fe9dbc8057f0f7c08660787bf86003604dd1fd8346f6381fb07745ae04d736fccc83426b33f01eab
|
| 81 |
+
71b08041873c005e5f77a057bebde8ae2455464299bf582e614e58f48ff2ddfda2f474ef388789bd
|
| 82 |
+
c25366f9c3c8b38e74b475f25546fcd9b97aeb26618b1ddf84846a0e79915f95e2466e598e20b457
|
| 83 |
+
708cd55591c902de4cb90bace1bb8205d011a862487574a99eb77f19b6e0a9dc09662d09a1c43246
|
| 84 |
+
33e85a1f0209f0be8c4a99a0251d6efe101ab93d1d0ba5a4dfa186f20f2868f169dcb7da83573906
|
| 85 |
+
fea1e2ce9b4fcd7f5250115e01a70683faa002b5c40de6d0279af88c27773f8641c3604c0661a806
|
| 86 |
+
b5f0177a28c0f586e0006058aa30dc7d6211e69ed72338ea6353c2dd94c2c21634bbcbee5690bcb6
|
| 87 |
+
deebfc7da1ce591d766f05e4094b7c018839720a3d7c927c2486e3725f724d9db91ac15bb4d39eb8
|
| 88 |
+
fced54557808fca5b5d83d7cd34dad0fc41e50ef5eb161e6f8a28514d96c51133c6fd5c7e756e14e
|
| 89 |
+
c4362abfceddc6c837d79a323492638212670efa8e406000e03a39ce37d3faf5cfabc277375ac52d
|
| 90 |
+
1b5cb0679e4fa33742d382274099bc9bbed5118e9dbf0f7315d62d1c7ec700c47bb78c1b6b21a190
|
| 91 |
+
45b26eb1be6a366eb45748ab2fbc946e79c6a376d26549c2c8530ff8ee468dde7dd5730a1d4cd04d
|
| 92 |
+
c62939bbdba9ba4650ac9526e8be5ee304a1fad5f06a2d519a63ef8ce29a86ee22c089c2b843242e
|
| 93 |
+
f6a51e03aa9cf2d0a483c061ba9be96a4d8fe51550ba645bd62826a2f9a73a3ae14ba99586ef5562
|
| 94 |
+
e9c72fefd3f752f7da3f046f6977fa0a5980e4a91587b086019b09e6ad3b3ee593e990fd5a9e34d7
|
| 95 |
+
972cf0b7d9022b8b5196d5ac3a017da67dd1cf3ed67c7d2d281f9f25cfadf2b89b5ad6b4725a88f5
|
| 96 |
+
4ce029ac71e019a5e647b0acfded93fa9be8d3c48d283b57ccf8d5662979132e28785f0191ed7560
|
| 97 |
+
55f7960e44e3d35e8c15056dd488f46dba03a161250564f0bdc3eb9e153c9057a297271aeca93a07
|
| 98 |
+
2a1b3f6d9b1e6321f5f59c66fb26dcf3197533d928b155fdf5035634828aba3cbb28517711c20ad9
|
| 99 |
+
f8abcc5167ccad925f4de817513830dc8e379d58629320f991ea7a90c2fb3e7bce5121ce64774fbe
|
| 100 |
+
32a8b6e37ec3293d4648de53696413e680a2ae0810dd6db22469852dfd09072166b39a460a6445c0
|
| 101 |
+
dd586cdecf1c20c8ae5bbef7dd1b588d40ccd2017f6bb4e3bbdda26a7e3a59ff453e350a44bcb4cd
|
| 102 |
+
d572eacea8fa6484bb8d6612aebf3c6f47d29be463542f5d9eaec2771bf64e6370740e0d8de75b13
|
| 103 |
+
57f8721671af537d5d4040cb084eb4e2cc34d2466a0115af84e1b0042895983a1d06b89fb4ce6ea0
|
| 104 |
+
486f3f3b823520ab82011a1d4b277227f8611560b1e7933fdcbb3a792b344525bda08839e151ce79
|
| 105 |
+
4b2f32c9b7a01fbac9e01cc87ebcc7d1f6cf0111c3a1e8aac71a908749d44fbd9ad0dadecbd50ada
|
| 106 |
+
380339c32ac69136678df9317ce0b12b4ff79e59b743f5bb3af2d519ff27d9459cbf97222c15e6fc
|
| 107 |
+
2a0f91fc719b941525fae59361ceb69cebc2a8645912baa8d1b6c1075ee3056a0c10d25065cb03a4
|
| 108 |
+
42e0ec6e0e1698db3b4c98a0be3278e9649f1f9532e0d392dfd3a0342b8971f21e1b0a74414ba334
|
| 109 |
+
8cc5be7120c37632d8df359f8d9b992f2ee60b6f470fe3f11de54cda541edad891ce6279cfcd3e7e
|
| 110 |
+
6f1618b166fd2c1d05848fd2c5f6fb2299f523f357a632762393a8353156cccd02acf081625a75eb
|
| 111 |
+
b56e16369788d273ccde96629281b949d04c50901b71c65614e6c6c7bd327a140a45e1d006c3f27b
|
| 112 |
+
9ac9aa53fd62a80f00bb25bfe235bdd2f671126905b2040222b6cbcf7ccd769c2b53113ec01640e3
|
| 113 |
+
d338abbd602547adf0ba38209cf746ce7677afa1c52075606085cbfe4e8ae88dd87aaaf9b04cf9aa
|
| 114 |
+
7e1948c25c02fb8a8c01c36ae4d6ebe1f990d4f869a65cdea03f09252dc208e69fb74e6132ce77e2
|
| 115 |
+
5b578fdfe33ac372e6'''.split())
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
def test_hex_pi_nth_digits():
|
| 119 |
+
assert pi_hex_digits(0) == '3243f6a8885a30'
|
| 120 |
+
assert pi_hex_digits(1) == '243f6a8885a308'
|
| 121 |
+
assert pi_hex_digits(10000) == '68ac8fcfb8016c'
|
| 122 |
+
assert pi_hex_digits(13) == '08d313198a2e03'
|
| 123 |
+
assert pi_hex_digits(0, 3) == '324'
|
| 124 |
+
assert pi_hex_digits(0, 0) == ''
|
| 125 |
+
raises(ValueError, lambda: pi_hex_digits(-1))
|
| 126 |
+
raises(ValueError, lambda: pi_hex_digits(0, -1))
|
| 127 |
+
raises(ValueError, lambda: pi_hex_digits(3.14))
|
| 128 |
+
|
| 129 |
+
# this will pick a random segment to compute every time
|
| 130 |
+
# it is run. If it ever fails, there is an error in the
|
| 131 |
+
# computation.
|
| 132 |
+
n = randint(0, len(dig))
|
| 133 |
+
prec = randint(0, len(dig) - n)
|
| 134 |
+
assert pi_hex_digits(n, prec) == dig[n: n + prec]
|
lib/python3.12/site-packages/sympy/ntheory/tests/test_continued_fraction.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import itertools
|
| 2 |
+
from sympy.core import GoldenRatio as phi
|
| 3 |
+
from sympy.core.numbers import (Rational, pi)
|
| 4 |
+
from sympy.core.singleton import S
|
| 5 |
+
from sympy.functions.elementary.miscellaneous import sqrt
|
| 6 |
+
from sympy.ntheory.continued_fraction import \
|
| 7 |
+
(continued_fraction_periodic as cf_p,
|
| 8 |
+
continued_fraction_iterator as cf_i,
|
| 9 |
+
continued_fraction_convergents as cf_c,
|
| 10 |
+
continued_fraction_reduce as cf_r,
|
| 11 |
+
continued_fraction as cf)
|
| 12 |
+
from sympy.testing.pytest import raises
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def test_continued_fraction():
|
| 16 |
+
assert cf_p(1, 1, 10, 0) == cf_p(1, 1, 0, 1)
|
| 17 |
+
assert cf_p(1, -1, 10, 1) == cf_p(-1, 1, 10, -1)
|
| 18 |
+
t = sqrt(2)
|
| 19 |
+
assert cf((1 + t)*(1 - t)) == cf(-1)
|
| 20 |
+
for n in [0, 2, Rational(2, 3), sqrt(2), 3*sqrt(2), 1 + 2*sqrt(3)/5,
|
| 21 |
+
(2 - 3*sqrt(5))/7, 1 + sqrt(2), (-5 + sqrt(17))/4]:
|
| 22 |
+
assert (cf_r(cf(n)) - n).expand() == 0
|
| 23 |
+
assert (cf_r(cf(-n)) + n).expand() == 0
|
| 24 |
+
raises(ValueError, lambda: cf(sqrt(2 + sqrt(3))))
|
| 25 |
+
raises(ValueError, lambda: cf(sqrt(2) + sqrt(3)))
|
| 26 |
+
raises(ValueError, lambda: cf(pi))
|
| 27 |
+
raises(ValueError, lambda: cf(.1))
|
| 28 |
+
|
| 29 |
+
raises(ValueError, lambda: cf_p(1, 0, 0))
|
| 30 |
+
raises(ValueError, lambda: cf_p(1, 1, -1))
|
| 31 |
+
assert cf_p(4, 3, 0) == [1, 3]
|
| 32 |
+
assert cf_p(0, 3, 5) == [0, 1, [2, 1, 12, 1, 2, 2]]
|
| 33 |
+
assert cf_p(1, 1, 0) == [1]
|
| 34 |
+
assert cf_p(3, 4, 0) == [0, 1, 3]
|
| 35 |
+
assert cf_p(4, 5, 0) == [0, 1, 4]
|
| 36 |
+
assert cf_p(5, 6, 0) == [0, 1, 5]
|
| 37 |
+
assert cf_p(11, 13, 0) == [0, 1, 5, 2]
|
| 38 |
+
assert cf_p(16, 19, 0) == [0, 1, 5, 3]
|
| 39 |
+
assert cf_p(27, 32, 0) == [0, 1, 5, 2, 2]
|
| 40 |
+
assert cf_p(1, 2, 5) == [[1]]
|
| 41 |
+
assert cf_p(0, 1, 2) == [1, [2]]
|
| 42 |
+
assert cf_p(6, 7, 49) == [1, 1, 6]
|
| 43 |
+
assert cf_p(3796, 1387, 0) == [2, 1, 2, 1, 4]
|
| 44 |
+
assert cf_p(3245, 10000) == [0, 3, 12, 4, 13]
|
| 45 |
+
assert cf_p(1932, 2568) == [0, 1, 3, 26, 2]
|
| 46 |
+
assert cf_p(6589, 2569) == [2, 1, 1, 3, 2, 1, 3, 1, 23]
|
| 47 |
+
|
| 48 |
+
def take(iterator, n=7):
|
| 49 |
+
return list(itertools.islice(iterator, n))
|
| 50 |
+
|
| 51 |
+
assert take(cf_i(phi)) == [1, 1, 1, 1, 1, 1, 1]
|
| 52 |
+
assert take(cf_i(pi)) == [3, 7, 15, 1, 292, 1, 1]
|
| 53 |
+
|
| 54 |
+
assert list(cf_i(Rational(17, 12))) == [1, 2, 2, 2]
|
| 55 |
+
assert list(cf_i(Rational(-17, 12))) == [-2, 1, 1, 2, 2]
|
| 56 |
+
|
| 57 |
+
assert list(cf_c([1, 6, 1, 8])) == [S.One, Rational(7, 6), Rational(8, 7), Rational(71, 62)]
|
| 58 |
+
assert list(cf_c([2])) == [S(2)]
|
| 59 |
+
assert list(cf_c([1, 1, 1, 1, 1, 1, 1])) == [S.One, S(2), Rational(3, 2), Rational(5, 3),
|
| 60 |
+
Rational(8, 5), Rational(13, 8), Rational(21, 13)]
|
| 61 |
+
assert list(cf_c([1, 6, Rational(-1, 2), 4])) == [S.One, Rational(7, 6), Rational(5, 4), Rational(3, 2)]
|
| 62 |
+
assert take(cf_c([[1]])) == [S.One, S(2), Rational(3, 2), Rational(5, 3), Rational(8, 5),
|
| 63 |
+
Rational(13, 8), Rational(21, 13)]
|
| 64 |
+
assert take(cf_c([1, [1, 2]])) == [S.One, S(2), Rational(5, 3), Rational(7, 4), Rational(19, 11),
|
| 65 |
+
Rational(26, 15), Rational(71, 41)]
|
| 66 |
+
|
| 67 |
+
cf_iter_e = (2 if i == 1 else i // 3 * 2 if i % 3 == 0 else 1 for i in itertools.count(1))
|
| 68 |
+
assert take(cf_c(cf_iter_e)) == [S(2), S(3), Rational(8, 3), Rational(11, 4), Rational(19, 7),
|
| 69 |
+
Rational(87, 32), Rational(106, 39)]
|
| 70 |
+
|
| 71 |
+
assert cf_r([1, 6, 1, 8]) == Rational(71, 62)
|
| 72 |
+
assert cf_r([3]) == S(3)
|
| 73 |
+
assert cf_r([-1, 5, 1, 4]) == Rational(-24, 29)
|
| 74 |
+
assert (cf_r([0, 1, 1, 7, [24, 8]]) - (sqrt(3) + 2)/7).expand() == 0
|
| 75 |
+
assert cf_r([1, 5, 9]) == Rational(55, 46)
|
| 76 |
+
assert (cf_r([[1]]) - (sqrt(5) + 1)/2).expand() == 0
|
| 77 |
+
assert cf_r([-3, 1, 1, [2]]) == -1 - sqrt(2)
|
lib/python3.12/site-packages/sympy/ntheory/tests/test_digits.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.ntheory import count_digits, digits, is_palindromic
|
| 2 |
+
from sympy.core.intfunc import num_digits
|
| 3 |
+
|
| 4 |
+
from sympy.testing.pytest import raises
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def test_num_digits():
|
| 8 |
+
# depending on whether one rounds up or down or uses log or log10,
|
| 9 |
+
# one or more of these will fail if you don't check for the off-by
|
| 10 |
+
# one condition
|
| 11 |
+
assert num_digits(2, 2) == 2
|
| 12 |
+
assert num_digits(2**48 - 1, 2) == 48
|
| 13 |
+
assert num_digits(1000, 10) == 4
|
| 14 |
+
assert num_digits(125, 5) == 4
|
| 15 |
+
assert num_digits(100, 16) == 2
|
| 16 |
+
assert num_digits(-1000, 10) == 4
|
| 17 |
+
# if changes are made to the function, this structured test over
|
| 18 |
+
# this range will expose problems
|
| 19 |
+
for base in range(2, 100):
|
| 20 |
+
for e in range(1, 100):
|
| 21 |
+
n = base**e
|
| 22 |
+
assert num_digits(n, base) == e + 1
|
| 23 |
+
assert num_digits(n + 1, base) == e + 1
|
| 24 |
+
assert num_digits(n - 1, base) == e
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def test_digits():
|
| 28 |
+
assert all(digits(n, 2)[1:] == [int(d) for d in format(n, 'b')]
|
| 29 |
+
for n in range(20))
|
| 30 |
+
assert all(digits(n, 8)[1:] == [int(d) for d in format(n, 'o')]
|
| 31 |
+
for n in range(20))
|
| 32 |
+
assert all(digits(n, 16)[1:] == [int(d, 16) for d in format(n, 'x')]
|
| 33 |
+
for n in range(20))
|
| 34 |
+
assert digits(2345, 34) == [34, 2, 0, 33]
|
| 35 |
+
assert digits(384753, 71) == [71, 1, 5, 23, 4]
|
| 36 |
+
assert digits(93409, 10) == [10, 9, 3, 4, 0, 9]
|
| 37 |
+
assert digits(-92838, 11) == [-11, 6, 3, 8, 2, 9]
|
| 38 |
+
assert digits(35, 10) == [10, 3, 5]
|
| 39 |
+
assert digits(35, 10, 3) == [10, 0, 3, 5]
|
| 40 |
+
assert digits(-35, 10, 4) == [-10, 0, 0, 3, 5]
|
| 41 |
+
raises(ValueError, lambda: digits(2, 2, 1))
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def test_count_digits():
|
| 45 |
+
assert count_digits(55, 2) == {1: 5, 0: 1}
|
| 46 |
+
assert count_digits(55, 10) == {5: 2}
|
| 47 |
+
n = count_digits(123)
|
| 48 |
+
assert n[4] == 0 and type(n[4]) is int
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def test_is_palindromic():
|
| 52 |
+
assert is_palindromic(-11)
|
| 53 |
+
assert is_palindromic(11)
|
| 54 |
+
assert is_palindromic(0o121, 8)
|
| 55 |
+
assert not is_palindromic(123)
|
lib/python3.12/site-packages/sympy/ntheory/tests/test_egyptian_fraction.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.core.numbers import Rational
|
| 2 |
+
from sympy.ntheory.egyptian_fraction import egyptian_fraction
|
| 3 |
+
from sympy.core.add import Add
|
| 4 |
+
from sympy.testing.pytest import raises
|
| 5 |
+
from sympy.core.random import random_complex_number
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def test_egyptian_fraction():
|
| 9 |
+
def test_equality(r, alg="Greedy"):
|
| 10 |
+
return r == Add(*[Rational(1, i) for i in egyptian_fraction(r, alg)])
|
| 11 |
+
|
| 12 |
+
r = random_complex_number(a=0, c=1, b=0, d=0, rational=True)
|
| 13 |
+
assert test_equality(r)
|
| 14 |
+
|
| 15 |
+
assert egyptian_fraction(Rational(4, 17)) == [5, 29, 1233, 3039345]
|
| 16 |
+
assert egyptian_fraction(Rational(7, 13), "Greedy") == [2, 26]
|
| 17 |
+
assert egyptian_fraction(Rational(23, 101), "Greedy") == \
|
| 18 |
+
[5, 37, 1438, 2985448, 40108045937720]
|
| 19 |
+
assert egyptian_fraction(Rational(18, 23), "Takenouchi") == \
|
| 20 |
+
[2, 6, 12, 35, 276, 2415]
|
| 21 |
+
assert egyptian_fraction(Rational(5, 6), "Graham Jewett") == \
|
| 22 |
+
[6, 7, 8, 9, 10, 42, 43, 44, 45, 56, 57, 58, 72, 73, 90, 1806, 1807,
|
| 23 |
+
1808, 1892, 1893, 1980, 3192, 3193, 3306, 5256, 3263442, 3263443,
|
| 24 |
+
3267056, 3581556, 10192056, 10650056950806]
|
| 25 |
+
assert egyptian_fraction(Rational(5, 6), "Golomb") == [2, 6, 12, 20, 30]
|
| 26 |
+
assert egyptian_fraction(Rational(5, 121), "Golomb") == [25, 1225, 3577, 7081, 11737]
|
| 27 |
+
raises(ValueError, lambda: egyptian_fraction(Rational(-4, 9)))
|
| 28 |
+
assert egyptian_fraction(Rational(8, 3), "Golomb") == [1, 2, 3, 4, 5, 6, 7,
|
| 29 |
+
14, 574, 2788, 6460,
|
| 30 |
+
11590, 33062, 113820]
|
| 31 |
+
assert egyptian_fraction(Rational(355, 113)) == [1, 2, 3, 4, 5, 6, 7, 8, 9,
|
| 32 |
+
10, 11, 12, 27, 744, 893588,
|
| 33 |
+
1251493536607,
|
| 34 |
+
20361068938197002344405230]
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def test_input():
|
| 38 |
+
r = (2,3), Rational(2, 3), (Rational(2), Rational(3))
|
| 39 |
+
for m in ["Greedy", "Graham Jewett", "Takenouchi", "Golomb"]:
|
| 40 |
+
for i in r:
|
| 41 |
+
d = egyptian_fraction(i, m)
|
| 42 |
+
assert all(i.is_Integer for i in d)
|
| 43 |
+
if m == "Graham Jewett":
|
| 44 |
+
assert d == [3, 4, 12]
|
| 45 |
+
else:
|
| 46 |
+
assert d == [2, 6]
|
| 47 |
+
# check prefix
|
| 48 |
+
d = egyptian_fraction(Rational(5, 3))
|
| 49 |
+
assert d == [1, 2, 6] and all(i.is_Integer for i in d)
|
lib/python3.12/site-packages/sympy/ntheory/tests/test_generate.py
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from bisect import bisect, bisect_left
|
| 2 |
+
|
| 3 |
+
from sympy.functions.combinatorial.numbers import mobius, totient
|
| 4 |
+
from sympy.ntheory.generate import (sieve, Sieve)
|
| 5 |
+
|
| 6 |
+
from sympy.ntheory import isprime, randprime, nextprime, prevprime, \
|
| 7 |
+
primerange, primepi, prime, primorial, composite, compositepi
|
| 8 |
+
from sympy.ntheory.generate import cycle_length, _primepi
|
| 9 |
+
from sympy.ntheory.primetest import mr
|
| 10 |
+
from sympy.testing.pytest import raises
|
| 11 |
+
|
| 12 |
+
def test_prime():
|
| 13 |
+
assert prime(1) == 2
|
| 14 |
+
assert prime(2) == 3
|
| 15 |
+
assert prime(5) == 11
|
| 16 |
+
assert prime(11) == 31
|
| 17 |
+
assert prime(57) == 269
|
| 18 |
+
assert prime(296) == 1949
|
| 19 |
+
assert prime(559) == 4051
|
| 20 |
+
assert prime(3000) == 27449
|
| 21 |
+
assert prime(4096) == 38873
|
| 22 |
+
assert prime(9096) == 94321
|
| 23 |
+
assert prime(25023) == 287341
|
| 24 |
+
assert prime(10000000) == 179424673 # issue #20951
|
| 25 |
+
assert prime(99999999) == 2038074739
|
| 26 |
+
raises(ValueError, lambda: prime(0))
|
| 27 |
+
sieve.extend(3000)
|
| 28 |
+
assert prime(401) == 2749
|
| 29 |
+
raises(ValueError, lambda: prime(-1))
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def test__primepi():
|
| 33 |
+
assert _primepi(-1) == 0
|
| 34 |
+
assert _primepi(1) == 0
|
| 35 |
+
assert _primepi(2) == 1
|
| 36 |
+
assert _primepi(5) == 3
|
| 37 |
+
assert _primepi(11) == 5
|
| 38 |
+
assert _primepi(57) == 16
|
| 39 |
+
assert _primepi(296) == 62
|
| 40 |
+
assert _primepi(559) == 102
|
| 41 |
+
assert _primepi(3000) == 430
|
| 42 |
+
assert _primepi(4096) == 564
|
| 43 |
+
assert _primepi(9096) == 1128
|
| 44 |
+
assert _primepi(25023) == 2763
|
| 45 |
+
assert _primepi(10**8) == 5761455
|
| 46 |
+
assert _primepi(253425253) == 13856396
|
| 47 |
+
assert _primepi(8769575643) == 401464322
|
| 48 |
+
sieve.extend(3000)
|
| 49 |
+
assert _primepi(2000) == 303
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def test_composite():
|
| 53 |
+
from sympy.ntheory.generate import sieve
|
| 54 |
+
sieve._reset()
|
| 55 |
+
assert composite(1) == 4
|
| 56 |
+
assert composite(2) == 6
|
| 57 |
+
assert composite(5) == 10
|
| 58 |
+
assert composite(11) == 20
|
| 59 |
+
assert composite(41) == 58
|
| 60 |
+
assert composite(57) == 80
|
| 61 |
+
assert composite(296) == 370
|
| 62 |
+
assert composite(559) == 684
|
| 63 |
+
assert composite(3000) == 3488
|
| 64 |
+
assert composite(4096) == 4736
|
| 65 |
+
assert composite(9096) == 10368
|
| 66 |
+
assert composite(25023) == 28088
|
| 67 |
+
sieve.extend(3000)
|
| 68 |
+
assert composite(1957) == 2300
|
| 69 |
+
assert composite(2568) == 2998
|
| 70 |
+
raises(ValueError, lambda: composite(0))
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def test_compositepi():
|
| 74 |
+
assert compositepi(1) == 0
|
| 75 |
+
assert compositepi(2) == 0
|
| 76 |
+
assert compositepi(5) == 1
|
| 77 |
+
assert compositepi(11) == 5
|
| 78 |
+
assert compositepi(57) == 40
|
| 79 |
+
assert compositepi(296) == 233
|
| 80 |
+
assert compositepi(559) == 456
|
| 81 |
+
assert compositepi(3000) == 2569
|
| 82 |
+
assert compositepi(4096) == 3531
|
| 83 |
+
assert compositepi(9096) == 7967
|
| 84 |
+
assert compositepi(25023) == 22259
|
| 85 |
+
assert compositepi(10**8) == 94238544
|
| 86 |
+
assert compositepi(253425253) == 239568856
|
| 87 |
+
assert compositepi(8769575643) == 8368111320
|
| 88 |
+
sieve.extend(3000)
|
| 89 |
+
assert compositepi(2321) == 1976
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def test_generate():
|
| 93 |
+
from sympy.ntheory.generate import sieve
|
| 94 |
+
sieve._reset()
|
| 95 |
+
assert nextprime(-4) == 2
|
| 96 |
+
assert nextprime(2) == 3
|
| 97 |
+
assert nextprime(5) == 7
|
| 98 |
+
assert nextprime(12) == 13
|
| 99 |
+
assert prevprime(3) == 2
|
| 100 |
+
assert prevprime(7) == 5
|
| 101 |
+
assert prevprime(13) == 11
|
| 102 |
+
assert prevprime(19) == 17
|
| 103 |
+
assert prevprime(20) == 19
|
| 104 |
+
|
| 105 |
+
sieve.extend_to_no(9)
|
| 106 |
+
assert sieve._list[-1] == 23
|
| 107 |
+
|
| 108 |
+
assert sieve._list[-1] < 31
|
| 109 |
+
assert 31 in sieve
|
| 110 |
+
|
| 111 |
+
assert nextprime(90) == 97
|
| 112 |
+
assert nextprime(10**40) == (10**40 + 121)
|
| 113 |
+
primelist = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31,
|
| 114 |
+
37, 41, 43, 47, 53, 59, 61, 67, 71, 73,
|
| 115 |
+
79, 83, 89, 97, 101, 103, 107, 109, 113,
|
| 116 |
+
127, 131, 137, 139, 149, 151, 157, 163,
|
| 117 |
+
167, 173, 179, 181, 191, 193, 197, 199,
|
| 118 |
+
211, 223, 227, 229, 233, 239, 241, 251,
|
| 119 |
+
257, 263, 269, 271, 277, 281, 283, 293]
|
| 120 |
+
for i in range(len(primelist) - 2):
|
| 121 |
+
for j in range(2, len(primelist) - i):
|
| 122 |
+
assert nextprime(primelist[i], j) == primelist[i + j]
|
| 123 |
+
if 3 < i:
|
| 124 |
+
assert nextprime(primelist[i] - 1, j) == primelist[i + j - 1]
|
| 125 |
+
raises(ValueError, lambda: nextprime(2, 0))
|
| 126 |
+
raises(ValueError, lambda: nextprime(2, -1))
|
| 127 |
+
assert prevprime(97) == 89
|
| 128 |
+
assert prevprime(10**40) == (10**40 - 17)
|
| 129 |
+
|
| 130 |
+
raises(ValueError, lambda: Sieve(0))
|
| 131 |
+
raises(ValueError, lambda: Sieve(-1))
|
| 132 |
+
for sieve_interval in [1, 10, 11, 1_000_000]:
|
| 133 |
+
s = Sieve(sieve_interval=sieve_interval)
|
| 134 |
+
for head in range(s._list[-1] + 1, (s._list[-1] + 1)**2, 2):
|
| 135 |
+
for tail in range(head + 1, (s._list[-1] + 1)**2):
|
| 136 |
+
A = list(s._primerange(head, tail))
|
| 137 |
+
B = primelist[bisect(primelist, head):bisect_left(primelist, tail)]
|
| 138 |
+
assert A == B
|
| 139 |
+
for k in range(s._list[-1], primelist[-1] - 1, 2):
|
| 140 |
+
s = Sieve(sieve_interval=sieve_interval)
|
| 141 |
+
s.extend(k)
|
| 142 |
+
assert list(s._list) == primelist[:bisect(primelist, k)]
|
| 143 |
+
s.extend(primelist[-1])
|
| 144 |
+
assert list(s._list) == primelist
|
| 145 |
+
|
| 146 |
+
assert list(sieve.primerange(10, 1)) == []
|
| 147 |
+
assert list(sieve.primerange(5, 9)) == [5, 7]
|
| 148 |
+
sieve._reset(prime=True)
|
| 149 |
+
assert list(sieve.primerange(2, 13)) == [2, 3, 5, 7, 11]
|
| 150 |
+
assert list(sieve.primerange(13)) == [2, 3, 5, 7, 11]
|
| 151 |
+
assert list(sieve.primerange(8)) == [2, 3, 5, 7]
|
| 152 |
+
assert list(sieve.primerange(-2)) == []
|
| 153 |
+
assert list(sieve.primerange(29)) == [2, 3, 5, 7, 11, 13, 17, 19, 23]
|
| 154 |
+
assert list(sieve.primerange(34)) == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]
|
| 155 |
+
|
| 156 |
+
assert list(sieve.totientrange(5, 15)) == [4, 2, 6, 4, 6, 4, 10, 4, 12, 6]
|
| 157 |
+
sieve._reset(totient=True)
|
| 158 |
+
assert list(sieve.totientrange(3, 13)) == [2, 2, 4, 2, 6, 4, 6, 4, 10, 4]
|
| 159 |
+
assert list(sieve.totientrange(900, 1000)) == [totient(x) for x in range(900, 1000)]
|
| 160 |
+
assert list(sieve.totientrange(0, 1)) == []
|
| 161 |
+
assert list(sieve.totientrange(1, 2)) == [1]
|
| 162 |
+
|
| 163 |
+
assert list(sieve.mobiusrange(5, 15)) == [-1, 1, -1, 0, 0, 1, -1, 0, -1, 1]
|
| 164 |
+
sieve._reset(mobius=True)
|
| 165 |
+
assert list(sieve.mobiusrange(3, 13)) == [-1, 0, -1, 1, -1, 0, 0, 1, -1, 0]
|
| 166 |
+
assert list(sieve.mobiusrange(1050, 1100)) == [mobius(x) for x in range(1050, 1100)]
|
| 167 |
+
assert list(sieve.mobiusrange(0, 1)) == []
|
| 168 |
+
assert list(sieve.mobiusrange(1, 2)) == [1]
|
| 169 |
+
|
| 170 |
+
assert list(primerange(10, 1)) == []
|
| 171 |
+
assert list(primerange(2, 7)) == [2, 3, 5]
|
| 172 |
+
assert list(primerange(2, 10)) == [2, 3, 5, 7]
|
| 173 |
+
assert list(primerange(1050, 1100)) == [1051, 1061,
|
| 174 |
+
1063, 1069, 1087, 1091, 1093, 1097]
|
| 175 |
+
s = Sieve()
|
| 176 |
+
for i in range(30, 2350, 376):
|
| 177 |
+
for j in range(2, 5096, 1139):
|
| 178 |
+
A = list(s.primerange(i, i + j))
|
| 179 |
+
B = list(primerange(i, i + j))
|
| 180 |
+
assert A == B
|
| 181 |
+
s = Sieve()
|
| 182 |
+
sieve._reset(prime=True)
|
| 183 |
+
sieve.extend(13)
|
| 184 |
+
for i in range(200):
|
| 185 |
+
for j in range(i, 200):
|
| 186 |
+
A = list(s.primerange(i, j))
|
| 187 |
+
B = list(primerange(i, j))
|
| 188 |
+
assert A == B
|
| 189 |
+
sieve.extend(1000)
|
| 190 |
+
for a, b in [(901, 1103), # a < 1000 < b < 1000**2
|
| 191 |
+
(806, 1002007), # a < 1000 < 1000**2 < b
|
| 192 |
+
(2000, 30001), # 1000 < a < b < 1000**2
|
| 193 |
+
(100005, 1010001), # 1000 < a < 1000**2 < b
|
| 194 |
+
(1003003, 1005000), # 1000**2 < a < b
|
| 195 |
+
]:
|
| 196 |
+
assert list(primerange(a, b)) == list(s.primerange(a, b))
|
| 197 |
+
sieve._reset(prime=True)
|
| 198 |
+
sieve.extend(100000)
|
| 199 |
+
assert len(sieve._list) == len(set(sieve._list))
|
| 200 |
+
s = Sieve()
|
| 201 |
+
assert s[10] == 29
|
| 202 |
+
|
| 203 |
+
assert nextprime(2, 2) == 5
|
| 204 |
+
|
| 205 |
+
raises(ValueError, lambda: totient(0))
|
| 206 |
+
|
| 207 |
+
raises(ValueError, lambda: primorial(0))
|
| 208 |
+
|
| 209 |
+
assert mr(1, [2]) is False
|
| 210 |
+
|
| 211 |
+
func = lambda i: (i**2 + 1) % 51
|
| 212 |
+
assert next(cycle_length(func, 4)) == (6, 3)
|
| 213 |
+
assert list(cycle_length(func, 4, values=True)) == \
|
| 214 |
+
[4, 17, 35, 2, 5, 26, 14, 44, 50, 2, 5, 26, 14]
|
| 215 |
+
assert next(cycle_length(func, 4, nmax=5)) == (5, None)
|
| 216 |
+
assert list(cycle_length(func, 4, nmax=5, values=True)) == \
|
| 217 |
+
[4, 17, 35, 2, 5]
|
| 218 |
+
sieve.extend(3000)
|
| 219 |
+
assert nextprime(2968) == 2969
|
| 220 |
+
assert prevprime(2930) == 2927
|
| 221 |
+
raises(ValueError, lambda: prevprime(1))
|
| 222 |
+
raises(ValueError, lambda: prevprime(-4))
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
def test_randprime():
|
| 226 |
+
assert randprime(10, 1) is None
|
| 227 |
+
assert randprime(3, -3) is None
|
| 228 |
+
assert randprime(2, 3) == 2
|
| 229 |
+
assert randprime(1, 3) == 2
|
| 230 |
+
assert randprime(3, 5) == 3
|
| 231 |
+
raises(ValueError, lambda: randprime(-12, -2))
|
| 232 |
+
raises(ValueError, lambda: randprime(-10, 0))
|
| 233 |
+
raises(ValueError, lambda: randprime(20, 22))
|
| 234 |
+
raises(ValueError, lambda: randprime(0, 2))
|
| 235 |
+
raises(ValueError, lambda: randprime(1, 2))
|
| 236 |
+
for a in [100, 300, 500, 250000]:
|
| 237 |
+
for b in [100, 300, 500, 250000]:
|
| 238 |
+
p = randprime(a, a + b)
|
| 239 |
+
assert a <= p < (a + b) and isprime(p)
|
| 240 |
+
|
| 241 |
+
|
| 242 |
+
def test_primorial():
|
| 243 |
+
assert primorial(1) == 2
|
| 244 |
+
assert primorial(1, nth=0) == 1
|
| 245 |
+
assert primorial(2) == 6
|
| 246 |
+
assert primorial(2, nth=0) == 2
|
| 247 |
+
assert primorial(4, nth=0) == 6
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
def test_search():
|
| 251 |
+
assert 2 in sieve
|
| 252 |
+
assert 2.1 not in sieve
|
| 253 |
+
assert 1 not in sieve
|
| 254 |
+
assert 2**1000 not in sieve
|
| 255 |
+
raises(ValueError, lambda: sieve.search(1))
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
def test_sieve_slice():
|
| 259 |
+
assert sieve[5] == 11
|
| 260 |
+
assert list(sieve[5:10]) == [sieve[x] for x in range(5, 10)]
|
| 261 |
+
assert list(sieve[5:10:2]) == [sieve[x] for x in range(5, 10, 2)]
|
| 262 |
+
assert list(sieve[1:5]) == [2, 3, 5, 7]
|
| 263 |
+
raises(IndexError, lambda: sieve[:5])
|
| 264 |
+
raises(IndexError, lambda: sieve[0])
|
| 265 |
+
raises(IndexError, lambda: sieve[0:5])
|
| 266 |
+
|
| 267 |
+
def test_sieve_iter():
|
| 268 |
+
values = []
|
| 269 |
+
for value in sieve:
|
| 270 |
+
if value > 7:
|
| 271 |
+
break
|
| 272 |
+
values.append(value)
|
| 273 |
+
assert values == list(sieve[1:5])
|
| 274 |
+
|
| 275 |
+
|
| 276 |
+
def test_sieve_repr():
|
| 277 |
+
assert "sieve" in repr(sieve)
|
| 278 |
+
assert "prime" in repr(sieve)
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
def test_deprecated_ntheory_symbolic_functions():
|
| 282 |
+
from sympy.testing.pytest import warns_deprecated_sympy
|
| 283 |
+
|
| 284 |
+
with warns_deprecated_sympy():
|
| 285 |
+
assert primepi(0) == 0
|
lib/python3.12/site-packages/sympy/ntheory/tests/test_hypothesis.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from hypothesis import given
|
| 2 |
+
from hypothesis import strategies as st
|
| 3 |
+
from sympy import divisors
|
| 4 |
+
from sympy.functions.combinatorial.numbers import divisor_sigma, totient
|
| 5 |
+
from sympy.ntheory.primetest import is_square
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
@given(n=st.integers(1, 10**10))
|
| 9 |
+
def test_tau_hypothesis(n):
|
| 10 |
+
div = divisors(n)
|
| 11 |
+
tau_n = len(div)
|
| 12 |
+
assert is_square(n) == (tau_n % 2 == 1)
|
| 13 |
+
sigmas = [divisor_sigma(i) for i in div]
|
| 14 |
+
totients = [totient(n // i) for i in div]
|
| 15 |
+
mul = [a * b for a, b in zip(sigmas, totients)]
|
| 16 |
+
assert n * tau_n == sum(mul)
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
@given(n=st.integers(1, 10**10))
|
| 20 |
+
def test_totient_hypothesis(n):
|
| 21 |
+
assert totient(n) <= n
|
| 22 |
+
div = divisors(n)
|
| 23 |
+
totients = [totient(i) for i in div]
|
| 24 |
+
assert n == sum(totients)
|
lib/python3.12/site-packages/sympy/ntheory/tests/test_partitions.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.ntheory.partitions_ import npartitions, _partition_rec, _partition
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def test__partition_rec():
|
| 5 |
+
A000041 = [1, 1, 2, 3, 5, 7, 11, 15, 22, 30, 42, 56, 77, 101, 135,
|
| 6 |
+
176, 231, 297, 385, 490, 627, 792, 1002, 1255, 1575]
|
| 7 |
+
for n, val in enumerate(A000041):
|
| 8 |
+
assert _partition_rec(n) == val
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def test__partition():
|
| 12 |
+
assert [_partition(k) for k in range(13)] == \
|
| 13 |
+
[1, 1, 2, 3, 5, 7, 11, 15, 22, 30, 42, 56, 77]
|
| 14 |
+
assert _partition(100) == 190569292
|
| 15 |
+
assert _partition(200) == 3972999029388
|
| 16 |
+
assert _partition(1000) == 24061467864032622473692149727991
|
| 17 |
+
assert _partition(1001) == 25032297938763929621013218349796
|
| 18 |
+
assert _partition(2000) == 4720819175619413888601432406799959512200344166
|
| 19 |
+
assert _partition(10000) % 10**10 == 6916435144
|
| 20 |
+
assert _partition(100000) % 10**10 == 9421098519
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def test_deprecated_ntheory_symbolic_functions():
|
| 24 |
+
from sympy.testing.pytest import warns_deprecated_sympy
|
| 25 |
+
|
| 26 |
+
with warns_deprecated_sympy():
|
| 27 |
+
assert npartitions(0) == 1
|
lib/python3.12/site-packages/sympy/ntheory/tests/test_primetest.py
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from math import gcd
|
| 2 |
+
|
| 3 |
+
from sympy.ntheory.generate import Sieve, sieve
|
| 4 |
+
from sympy.ntheory.primetest import (mr, _lucas_extrastrong_params, is_lucas_prp, is_square,
|
| 5 |
+
is_strong_lucas_prp, is_extra_strong_lucas_prp,
|
| 6 |
+
proth_test, isprime, is_euler_pseudoprime,
|
| 7 |
+
is_gaussian_prime, is_fermat_pseudoprime, is_euler_jacobi_pseudoprime,
|
| 8 |
+
MERSENNE_PRIME_EXPONENTS, _lucas_lehmer_primality_test,
|
| 9 |
+
is_mersenne_prime)
|
| 10 |
+
|
| 11 |
+
from sympy.testing.pytest import slow, raises
|
| 12 |
+
from sympy.core.numbers import I, Float
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def test_is_fermat_pseudoprime():
|
| 16 |
+
assert is_fermat_pseudoprime(5, 1)
|
| 17 |
+
assert is_fermat_pseudoprime(9, 1)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def test_euler_pseudoprimes():
|
| 21 |
+
assert is_euler_pseudoprime(13, 1)
|
| 22 |
+
assert is_euler_pseudoprime(15, 1)
|
| 23 |
+
assert is_euler_pseudoprime(17, 6)
|
| 24 |
+
assert is_euler_pseudoprime(101, 7)
|
| 25 |
+
assert is_euler_pseudoprime(1009, 10)
|
| 26 |
+
assert is_euler_pseudoprime(11287, 41)
|
| 27 |
+
|
| 28 |
+
raises(ValueError, lambda: is_euler_pseudoprime(0, 4))
|
| 29 |
+
raises(ValueError, lambda: is_euler_pseudoprime(3, 0))
|
| 30 |
+
raises(ValueError, lambda: is_euler_pseudoprime(15, 6))
|
| 31 |
+
|
| 32 |
+
# A006970
|
| 33 |
+
euler_prp = [341, 561, 1105, 1729, 1905, 2047, 2465, 3277,
|
| 34 |
+
4033, 4681, 5461, 6601, 8321, 8481, 10261, 10585]
|
| 35 |
+
for p in euler_prp:
|
| 36 |
+
assert is_euler_pseudoprime(p, 2)
|
| 37 |
+
|
| 38 |
+
# A048950
|
| 39 |
+
euler_prp = [121, 703, 1729, 1891, 2821, 3281, 7381, 8401, 8911, 10585,
|
| 40 |
+
12403, 15457, 15841, 16531, 18721, 19345, 23521, 24661, 28009]
|
| 41 |
+
for p in euler_prp:
|
| 42 |
+
assert is_euler_pseudoprime(p, 3)
|
| 43 |
+
|
| 44 |
+
# A033181
|
| 45 |
+
absolute_euler_prp = [1729, 2465, 15841, 41041, 46657, 75361,
|
| 46 |
+
162401, 172081, 399001, 449065, 488881]
|
| 47 |
+
for p in absolute_euler_prp:
|
| 48 |
+
for a in range(2, p):
|
| 49 |
+
if gcd(a, p) != 1:
|
| 50 |
+
continue
|
| 51 |
+
assert is_euler_pseudoprime(p, a)
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def test_is_euler_jacobi_pseudoprime():
|
| 55 |
+
assert is_euler_jacobi_pseudoprime(11, 1)
|
| 56 |
+
assert is_euler_jacobi_pseudoprime(15, 1)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def test_lucas_extrastrong_params():
|
| 60 |
+
assert _lucas_extrastrong_params(3) == (5, 3, 1)
|
| 61 |
+
assert _lucas_extrastrong_params(5) == (12, 4, 1)
|
| 62 |
+
assert _lucas_extrastrong_params(7) == (5, 3, 1)
|
| 63 |
+
assert _lucas_extrastrong_params(9) == (0, 0, 0)
|
| 64 |
+
assert _lucas_extrastrong_params(11) == (21, 5, 1)
|
| 65 |
+
assert _lucas_extrastrong_params(59) == (32, 6, 1)
|
| 66 |
+
assert _lucas_extrastrong_params(479) == (117, 11, 1)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def test_is_extra_strong_lucas_prp():
|
| 70 |
+
assert is_extra_strong_lucas_prp(4) == False
|
| 71 |
+
assert is_extra_strong_lucas_prp(989) == True
|
| 72 |
+
assert is_extra_strong_lucas_prp(10877) == True
|
| 73 |
+
assert is_extra_strong_lucas_prp(9) == False
|
| 74 |
+
assert is_extra_strong_lucas_prp(16) == False
|
| 75 |
+
assert is_extra_strong_lucas_prp(169) == False
|
| 76 |
+
|
| 77 |
+
@slow
|
| 78 |
+
def test_prps():
|
| 79 |
+
oddcomposites = [n for n in range(1, 10**5) if
|
| 80 |
+
n % 2 and not isprime(n)]
|
| 81 |
+
# A checksum would be better.
|
| 82 |
+
assert sum(oddcomposites) == 2045603465
|
| 83 |
+
assert [n for n in oddcomposites if mr(n, [2])] == [
|
| 84 |
+
2047, 3277, 4033, 4681, 8321, 15841, 29341, 42799, 49141,
|
| 85 |
+
52633, 65281, 74665, 80581, 85489, 88357, 90751]
|
| 86 |
+
assert [n for n in oddcomposites if mr(n, [3])] == [
|
| 87 |
+
121, 703, 1891, 3281, 8401, 8911, 10585, 12403, 16531,
|
| 88 |
+
18721, 19345, 23521, 31621, 44287, 47197, 55969, 63139,
|
| 89 |
+
74593, 79003, 82513, 87913, 88573, 97567]
|
| 90 |
+
assert [n for n in oddcomposites if mr(n, [325])] == [
|
| 91 |
+
9, 25, 27, 49, 65, 81, 325, 341, 343, 697, 1141, 2059,
|
| 92 |
+
2149, 3097, 3537, 4033, 4681, 4941, 5833, 6517, 7987, 8911,
|
| 93 |
+
12403, 12913, 15043, 16021, 20017, 22261, 23221, 24649,
|
| 94 |
+
24929, 31841, 35371, 38503, 43213, 44173, 47197, 50041,
|
| 95 |
+
55909, 56033, 58969, 59089, 61337, 65441, 68823, 72641,
|
| 96 |
+
76793, 78409, 85879]
|
| 97 |
+
assert not any(mr(n, [9345883071009581737]) for n in oddcomposites)
|
| 98 |
+
assert [n for n in oddcomposites if is_lucas_prp(n)] == [
|
| 99 |
+
323, 377, 1159, 1829, 3827, 5459, 5777, 9071, 9179, 10877,
|
| 100 |
+
11419, 11663, 13919, 14839, 16109, 16211, 18407, 18971,
|
| 101 |
+
19043, 22499, 23407, 24569, 25199, 25877, 26069, 27323,
|
| 102 |
+
32759, 34943, 35207, 39059, 39203, 39689, 40309, 44099,
|
| 103 |
+
46979, 47879, 50183, 51983, 53663, 56279, 58519, 60377,
|
| 104 |
+
63881, 69509, 72389, 73919, 75077, 77219, 79547, 79799,
|
| 105 |
+
82983, 84419, 86063, 90287, 94667, 97019, 97439]
|
| 106 |
+
assert [n for n in oddcomposites if is_strong_lucas_prp(n)] == [
|
| 107 |
+
5459, 5777, 10877, 16109, 18971, 22499, 24569, 25199, 40309,
|
| 108 |
+
58519, 75077, 97439]
|
| 109 |
+
assert [n for n in oddcomposites if is_extra_strong_lucas_prp(n)
|
| 110 |
+
] == [
|
| 111 |
+
989, 3239, 5777, 10877, 27971, 29681, 30739, 31631, 39059,
|
| 112 |
+
72389, 73919, 75077]
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
def test_proth_test():
|
| 116 |
+
# Proth number
|
| 117 |
+
A080075 = [3, 5, 9, 13, 17, 25, 33, 41, 49, 57, 65,
|
| 118 |
+
81, 97, 113, 129, 145, 161, 177, 193]
|
| 119 |
+
# Proth prime
|
| 120 |
+
A080076 = [3, 5, 13, 17, 41, 97, 113, 193]
|
| 121 |
+
|
| 122 |
+
for n in range(200):
|
| 123 |
+
if n in A080075:
|
| 124 |
+
assert proth_test(n) == (n in A080076)
|
| 125 |
+
else:
|
| 126 |
+
raises(ValueError, lambda: proth_test(n))
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
def test_lucas_lehmer_primality_test():
|
| 130 |
+
for p in sieve.primerange(3, 100):
|
| 131 |
+
assert _lucas_lehmer_primality_test(p) == (p in MERSENNE_PRIME_EXPONENTS)
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def test_is_mersenne_prime():
|
| 135 |
+
assert is_mersenne_prime(-3) is False
|
| 136 |
+
assert is_mersenne_prime(3) is True
|
| 137 |
+
assert is_mersenne_prime(10) is False
|
| 138 |
+
assert is_mersenne_prime(127) is True
|
| 139 |
+
assert is_mersenne_prime(511) is False
|
| 140 |
+
assert is_mersenne_prime(131071) is True
|
| 141 |
+
assert is_mersenne_prime(2147483647) is True
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def test_isprime():
|
| 145 |
+
s = Sieve()
|
| 146 |
+
s.extend(100000)
|
| 147 |
+
ps = set(s.primerange(2, 100001))
|
| 148 |
+
for n in range(100001):
|
| 149 |
+
# if (n in ps) != isprime(n): print n
|
| 150 |
+
assert (n in ps) == isprime(n)
|
| 151 |
+
assert isprime(179424673)
|
| 152 |
+
assert isprime(20678048681)
|
| 153 |
+
assert isprime(1968188556461)
|
| 154 |
+
assert isprime(2614941710599)
|
| 155 |
+
assert isprime(65635624165761929287)
|
| 156 |
+
assert isprime(1162566711635022452267983)
|
| 157 |
+
assert isprime(77123077103005189615466924501)
|
| 158 |
+
assert isprime(3991617775553178702574451996736229)
|
| 159 |
+
assert isprime(273952953553395851092382714516720001799)
|
| 160 |
+
assert isprime(int('''
|
| 161 |
+
531137992816767098689588206552468627329593117727031923199444138200403\
|
| 162 |
+
559860852242739162502265229285668889329486246501015346579337652707239\
|
| 163 |
+
409519978766587351943831270835393219031728127'''))
|
| 164 |
+
|
| 165 |
+
# Some Mersenne primes
|
| 166 |
+
assert isprime(2**61 - 1)
|
| 167 |
+
assert isprime(2**89 - 1)
|
| 168 |
+
assert isprime(2**607 - 1)
|
| 169 |
+
# (but not all Mersenne's are primes
|
| 170 |
+
assert not isprime(2**601 - 1)
|
| 171 |
+
|
| 172 |
+
# pseudoprimes
|
| 173 |
+
#-------------
|
| 174 |
+
# to some small bases
|
| 175 |
+
assert not isprime(2152302898747)
|
| 176 |
+
assert not isprime(3474749660383)
|
| 177 |
+
assert not isprime(341550071728321)
|
| 178 |
+
assert not isprime(3825123056546413051)
|
| 179 |
+
# passes the base set [2, 3, 7, 61, 24251]
|
| 180 |
+
assert not isprime(9188353522314541)
|
| 181 |
+
# large examples
|
| 182 |
+
assert not isprime(877777777777777777777777)
|
| 183 |
+
# conjectured psi_12 given at http://mathworld.wolfram.com/StrongPseudoprime.html
|
| 184 |
+
assert not isprime(318665857834031151167461)
|
| 185 |
+
# conjectured psi_17 given at http://mathworld.wolfram.com/StrongPseudoprime.html
|
| 186 |
+
assert not isprime(564132928021909221014087501701)
|
| 187 |
+
# Arnault's 1993 number; a factor of it is
|
| 188 |
+
# 400958216639499605418306452084546853005188166041132508774506\
|
| 189 |
+
# 204738003217070119624271622319159721973358216316508535816696\
|
| 190 |
+
# 9145233813917169287527980445796800452592031836601
|
| 191 |
+
assert not isprime(int('''
|
| 192 |
+
803837457453639491257079614341942108138837688287558145837488917522297\
|
| 193 |
+
427376533365218650233616396004545791504202360320876656996676098728404\
|
| 194 |
+
396540823292873879185086916685732826776177102938969773947016708230428\
|
| 195 |
+
687109997439976544144845341155872450633409279022275296229414984230688\
|
| 196 |
+
1685404326457534018329786111298960644845216191652872597534901'''))
|
| 197 |
+
# Arnault's 1995 number; can be factored as
|
| 198 |
+
# p1*(313*(p1 - 1) + 1)*(353*(p1 - 1) + 1) where p1 is
|
| 199 |
+
# 296744956686855105501541746429053327307719917998530433509950\
|
| 200 |
+
# 755312768387531717701995942385964281211880336647542183455624\
|
| 201 |
+
# 93168782883
|
| 202 |
+
assert not isprime(int('''
|
| 203 |
+
288714823805077121267142959713039399197760945927972270092651602419743\
|
| 204 |
+
230379915273311632898314463922594197780311092934965557841894944174093\
|
| 205 |
+
380561511397999942154241693397290542371100275104208013496673175515285\
|
| 206 |
+
922696291677532547504444585610194940420003990443211677661994962953925\
|
| 207 |
+
045269871932907037356403227370127845389912612030924484149472897688540\
|
| 208 |
+
6024976768122077071687938121709811322297802059565867'''))
|
| 209 |
+
sieve.extend(3000)
|
| 210 |
+
assert isprime(2819)
|
| 211 |
+
assert not isprime(2931)
|
| 212 |
+
raises(ValueError, lambda: isprime(2.0))
|
| 213 |
+
raises(ValueError, lambda: isprime(Float(2)))
|
| 214 |
+
|
| 215 |
+
|
| 216 |
+
def test_is_square():
|
| 217 |
+
assert [i for i in range(25) if is_square(i)] == [0, 1, 4, 9, 16]
|
| 218 |
+
|
| 219 |
+
# issue #17044
|
| 220 |
+
assert not is_square(60 ** 3)
|
| 221 |
+
assert not is_square(60 ** 5)
|
| 222 |
+
assert not is_square(84 ** 7)
|
| 223 |
+
assert not is_square(105 ** 9)
|
| 224 |
+
assert not is_square(120 ** 3)
|
| 225 |
+
|
| 226 |
+
def test_is_gaussianprime():
|
| 227 |
+
assert is_gaussian_prime(7*I)
|
| 228 |
+
assert is_gaussian_prime(7)
|
| 229 |
+
assert is_gaussian_prime(2 + 3*I)
|
| 230 |
+
assert not is_gaussian_prime(2 + 2*I)
|
lib/python3.12/site-packages/sympy/ntheory/tests/test_qs.py
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
from sympy.ntheory import qs
|
| 4 |
+
from sympy.ntheory.qs import SievePolynomial, _generate_factor_base, \
|
| 5 |
+
_initialize_first_polynomial, _initialize_ith_poly, \
|
| 6 |
+
_gen_sieve_array, _check_smoothness, _trial_division_stage, _gauss_mod_2, \
|
| 7 |
+
_build_matrix, _find_factor
|
| 8 |
+
from sympy.testing.pytest import slow
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@slow
|
| 12 |
+
def test_qs_1():
|
| 13 |
+
assert qs(10009202107, 100, 10000) == {100043, 100049}
|
| 14 |
+
assert qs(211107295182713951054568361, 1000, 10000) == \
|
| 15 |
+
{13791315212531, 15307263442931}
|
| 16 |
+
assert qs(980835832582657*990377764891511, 3000, 50000) == \
|
| 17 |
+
{980835832582657, 990377764891511}
|
| 18 |
+
assert qs(18640889198609*20991129234731, 1000, 50000) == \
|
| 19 |
+
{18640889198609, 20991129234731}
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def test_qs_2() -> None:
|
| 23 |
+
n = 10009202107
|
| 24 |
+
M = 50
|
| 25 |
+
# a = 10, b = 15, modified_coeff = [a**2, 2*a*b, b**2 - N]
|
| 26 |
+
sieve_poly = SievePolynomial([100, 1600, -10009195707], 10, 80)
|
| 27 |
+
assert sieve_poly.eval(10) == -10009169707
|
| 28 |
+
assert sieve_poly.eval(5) == -10009185207
|
| 29 |
+
|
| 30 |
+
idx_1000, idx_5000, factor_base = _generate_factor_base(2000, n)
|
| 31 |
+
assert idx_1000 == 82
|
| 32 |
+
assert [factor_base[i].prime for i in range(15)] == \
|
| 33 |
+
[2, 3, 7, 11, 17, 19, 29, 31, 43, 59, 61, 67, 71, 73, 79]
|
| 34 |
+
assert [factor_base[i].tmem_p for i in range(15)] == \
|
| 35 |
+
[1, 1, 3, 5, 3, 6, 6, 14, 1, 16, 24, 22, 18, 22, 15]
|
| 36 |
+
assert [factor_base[i].log_p for i in range(5)] == \
|
| 37 |
+
[710, 1125, 1993, 2455, 2901]
|
| 38 |
+
|
| 39 |
+
g, B = _initialize_first_polynomial(
|
| 40 |
+
n, M, factor_base, idx_1000, idx_5000, seed=0)
|
| 41 |
+
assert g.a == 1133107
|
| 42 |
+
assert g.b == 682543
|
| 43 |
+
assert B == [272889, 409654]
|
| 44 |
+
assert [factor_base[i].soln1 for i in range(15)] == \
|
| 45 |
+
[0, 0, 3, 7, 13, 0, 8, 19, 9, 43, 27, 25, 63, 29, 19]
|
| 46 |
+
assert [factor_base[i].soln2 for i in range(15)] == \
|
| 47 |
+
[0, 1, 1, 3, 12, 16, 15, 6, 15, 1, 56, 55, 61, 58, 16]
|
| 48 |
+
assert [factor_base[i].a_inv for i in range(15)] == \
|
| 49 |
+
[1, 1, 5, 7, 3, 5, 26, 6, 40, 5, 21, 45, 4, 1, 8]
|
| 50 |
+
assert [factor_base[i].b_ainv for i in range(5)] == \
|
| 51 |
+
[[0, 0], [0, 2], [3, 0], [3, 9], [13, 13]]
|
| 52 |
+
|
| 53 |
+
g_1 = _initialize_ith_poly(n, factor_base, 1, g, B)
|
| 54 |
+
assert g_1.a == 1133107
|
| 55 |
+
assert g_1.b == 136765
|
| 56 |
+
|
| 57 |
+
sieve_array = _gen_sieve_array(M, factor_base)
|
| 58 |
+
assert sieve_array[0:5] == [8424, 13603, 1835, 5335, 710]
|
| 59 |
+
|
| 60 |
+
assert _check_smoothness(9645, factor_base) == (5, False)
|
| 61 |
+
assert _check_smoothness(210313, factor_base)[0][0:15] == \
|
| 62 |
+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1]
|
| 63 |
+
assert _check_smoothness(210313, factor_base)[1]
|
| 64 |
+
|
| 65 |
+
partial_relations: dict[int, tuple[int, int]] = {}
|
| 66 |
+
smooth_relation, partial_relation = _trial_division_stage(
|
| 67 |
+
n, M, factor_base, sieve_array, sieve_poly, partial_relations,
|
| 68 |
+
ERROR_TERM=25*2**10)
|
| 69 |
+
|
| 70 |
+
assert partial_relations == {
|
| 71 |
+
8699: (440, -10009008507),
|
| 72 |
+
166741: (490, -10008962007),
|
| 73 |
+
131449: (530, -10008921207),
|
| 74 |
+
6653: (550, -10008899607)
|
| 75 |
+
}
|
| 76 |
+
assert [smooth_relation[i][0] for i in range(5)] == [
|
| 77 |
+
-250, -670615476700, -45211565844500, -231723037747200, -1811665537200]
|
| 78 |
+
assert [smooth_relation[i][1] for i in range(5)] == [
|
| 79 |
+
-10009139607, 1133094251961, 5302606761, 53804049849, 1950723889]
|
| 80 |
+
assert smooth_relation[0][2][0:15] == [
|
| 81 |
+
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
| 82 |
+
|
| 83 |
+
assert _gauss_mod_2(
|
| 84 |
+
[[0, 0, 1], [1, 0, 1], [0, 1, 0], [0, 1, 1], [0, 1, 1]]
|
| 85 |
+
) == (
|
| 86 |
+
[[[0, 1, 1], 3], [[0, 1, 1], 4]],
|
| 87 |
+
[True, True, True, False, False],
|
| 88 |
+
[[0, 0, 1], [1, 0, 0], [0, 1, 0], [0, 1, 1], [0, 1, 1]]
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def test_qs_3():
|
| 93 |
+
N = 1817
|
| 94 |
+
smooth_relations = [
|
| 95 |
+
(2455024, 637, [0, 0, 0, 1]),
|
| 96 |
+
(-27993000, 81536, [0, 1, 0, 1]),
|
| 97 |
+
(11461840, 12544, [0, 0, 0, 0]),
|
| 98 |
+
(149, 20384, [0, 1, 0, 1]),
|
| 99 |
+
(-31138074, 19208, [0, 1, 0, 0])
|
| 100 |
+
]
|
| 101 |
+
|
| 102 |
+
matrix = _build_matrix(smooth_relations)
|
| 103 |
+
assert matrix == [
|
| 104 |
+
[0, 0, 0, 1],
|
| 105 |
+
[0, 1, 0, 1],
|
| 106 |
+
[0, 0, 0, 0],
|
| 107 |
+
[0, 1, 0, 1],
|
| 108 |
+
[0, 1, 0, 0]
|
| 109 |
+
]
|
| 110 |
+
|
| 111 |
+
dependent_row, mark, gauss_matrix = _gauss_mod_2(matrix)
|
| 112 |
+
assert dependent_row == [[[0, 0, 0, 0], 2], [[0, 1, 0, 0], 3]]
|
| 113 |
+
assert mark == [True, True, False, False, True]
|
| 114 |
+
assert gauss_matrix == [
|
| 115 |
+
[0, 0, 0, 1],
|
| 116 |
+
[0, 1, 0, 0],
|
| 117 |
+
[0, 0, 0, 0],
|
| 118 |
+
[0, 1, 0, 0],
|
| 119 |
+
[0, 1, 0, 1]
|
| 120 |
+
]
|
| 121 |
+
|
| 122 |
+
factor = _find_factor(
|
| 123 |
+
dependent_row, mark, gauss_matrix, 0, smooth_relations, N)
|
| 124 |
+
assert factor == 23
|