add read me
This commit is contained in:
67
venv/lib/python3.12/site-packages/sympy/ntheory/__init__.py
Normal file
67
venv/lib/python3.12/site-packages/sympy/ntheory/__init__.py
Normal file
@@ -0,0 +1,67 @@
|
||||
"""
|
||||
Number theory module (primes, etc)
|
||||
"""
|
||||
|
||||
from .generate import nextprime, prevprime, prime, primepi, primerange, \
|
||||
randprime, Sieve, sieve, primorial, cycle_length, composite, compositepi
|
||||
from .primetest import isprime, is_gaussian_prime, is_mersenne_prime
|
||||
from .factor_ import divisors, proper_divisors, factorint, multiplicity, \
|
||||
multiplicity_in_factorial, perfect_power, factor_cache, pollard_pm1, \
|
||||
pollard_rho, primefactors, totient, \
|
||||
divisor_count, proper_divisor_count, divisor_sigma, factorrat, \
|
||||
reduced_totient, primenu, primeomega, mersenne_prime_exponent, \
|
||||
is_perfect, is_abundant, is_deficient, is_amicable, is_carmichael, \
|
||||
abundance, dra, drm
|
||||
|
||||
from .partitions_ import npartitions
|
||||
from .residue_ntheory import is_primitive_root, is_quad_residue, \
|
||||
legendre_symbol, jacobi_symbol, n_order, sqrt_mod, quadratic_residues, \
|
||||
primitive_root, nthroot_mod, is_nthpow_residue, sqrt_mod_iter, mobius, \
|
||||
discrete_log, quadratic_congruence, polynomial_congruence
|
||||
from .multinomial import binomial_coefficients, binomial_coefficients_list, \
|
||||
multinomial_coefficients
|
||||
from .continued_fraction import continued_fraction_periodic, \
|
||||
continued_fraction_iterator, continued_fraction_reduce, \
|
||||
continued_fraction_convergents, continued_fraction
|
||||
from .digits import count_digits, digits, is_palindromic
|
||||
from .egyptian_fraction import egyptian_fraction
|
||||
from .ecm import ecm
|
||||
from .qs import qs, qs_factor
|
||||
__all__ = [
|
||||
'nextprime', 'prevprime', 'prime', 'primepi', 'primerange', 'randprime',
|
||||
'Sieve', 'sieve', 'primorial', 'cycle_length', 'composite', 'compositepi',
|
||||
|
||||
'isprime', 'is_gaussian_prime', 'is_mersenne_prime',
|
||||
|
||||
|
||||
'divisors', 'proper_divisors', 'factorint', 'multiplicity', 'perfect_power',
|
||||
'pollard_pm1', 'factor_cache', 'pollard_rho', 'primefactors', 'totient',
|
||||
'divisor_count', 'proper_divisor_count', 'divisor_sigma', 'factorrat',
|
||||
'reduced_totient', 'primenu', 'primeomega', 'mersenne_prime_exponent',
|
||||
'is_perfect', 'is_abundant', 'is_deficient', 'is_amicable',
|
||||
'is_carmichael', 'abundance', 'dra', 'drm', 'multiplicity_in_factorial',
|
||||
|
||||
'npartitions',
|
||||
|
||||
'is_primitive_root', 'is_quad_residue', 'legendre_symbol',
|
||||
'jacobi_symbol', 'n_order', 'sqrt_mod', 'quadratic_residues',
|
||||
'primitive_root', 'nthroot_mod', 'is_nthpow_residue', 'sqrt_mod_iter',
|
||||
'mobius', 'discrete_log', 'quadratic_congruence', 'polynomial_congruence',
|
||||
|
||||
'binomial_coefficients', 'binomial_coefficients_list',
|
||||
'multinomial_coefficients',
|
||||
|
||||
'continued_fraction_periodic', 'continued_fraction_iterator',
|
||||
'continued_fraction_reduce', 'continued_fraction_convergents',
|
||||
'continued_fraction',
|
||||
|
||||
'digits',
|
||||
'count_digits',
|
||||
'is_palindromic',
|
||||
|
||||
'egyptian_fraction',
|
||||
|
||||
'ecm',
|
||||
|
||||
'qs', 'qs_factor',
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
190
venv/lib/python3.12/site-packages/sympy/ntheory/bbp_pi.py
Normal file
190
venv/lib/python3.12/site-packages/sympy/ntheory/bbp_pi.py
Normal file
@@ -0,0 +1,190 @@
|
||||
'''
|
||||
This implementation is a heavily modified fixed point implementation of
|
||||
BBP_formula for calculating the nth position of pi. The original hosted
|
||||
at: https://web.archive.org/web/20151116045029/http://en.literateprograms.org/Pi_with_the_BBP_formula_(Python)
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sub-license, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Modifications:
|
||||
|
||||
1.Once the nth digit and desired number of digits is selected, the
|
||||
number of digits of working precision is calculated to ensure that
|
||||
the hexadecimal digits returned are accurate. This is calculated as
|
||||
|
||||
int(math.log(start + prec)/math.log(16) + prec + 3)
|
||||
--------------------------------------- --------
|
||||
/ /
|
||||
number of hex digits additional digits
|
||||
|
||||
This was checked by the following code which completed without
|
||||
errors (and dig are the digits included in the test_bbp.py file):
|
||||
|
||||
for i in range(0,1000):
|
||||
for j in range(1,1000):
|
||||
a, b = pi_hex_digits(i, j), dig[i:i+j]
|
||||
if a != b:
|
||||
print('%s\n%s'%(a,b))
|
||||
|
||||
Deceasing the additional digits by 1 generated errors, so '3' is
|
||||
the smallest additional precision needed to calculate the above
|
||||
loop without errors. The following trailing 10 digits were also
|
||||
checked to be accurate (and the times were slightly faster with
|
||||
some of the constant modifications that were made):
|
||||
|
||||
>> from time import time
|
||||
>> t=time();pi_hex_digits(10**2-10 + 1, 10), time()-t
|
||||
('e90c6cc0ac', 0.0)
|
||||
>> t=time();pi_hex_digits(10**4-10 + 1, 10), time()-t
|
||||
('26aab49ec6', 0.17100000381469727)
|
||||
>> t=time();pi_hex_digits(10**5-10 + 1, 10), time()-t
|
||||
('a22673c1a5', 4.7109999656677246)
|
||||
>> t=time();pi_hex_digits(10**6-10 + 1, 10), time()-t
|
||||
('9ffd342362', 59.985999822616577)
|
||||
>> t=time();pi_hex_digits(10**7-10 + 1, 10), time()-t
|
||||
('c1a42e06a1', 689.51800012588501)
|
||||
|
||||
2. The while loop to evaluate whether the series has converged quits
|
||||
when the addition amount `dt` has dropped to zero.
|
||||
|
||||
3. the formatting string to convert the decimal to hexadecimal is
|
||||
calculated for the given precision.
|
||||
|
||||
4. pi_hex_digits(n) changed to have coefficient to the formula in an
|
||||
array (perhaps just a matter of preference).
|
||||
|
||||
'''
|
||||
|
||||
from sympy.utilities.misc import as_int
|
||||
|
||||
|
||||
def _series(j, n, prec=14):
|
||||
|
||||
# Left sum from the bbp algorithm
|
||||
s = 0
|
||||
D = _dn(n, prec)
|
||||
D4 = 4 * D
|
||||
d = j
|
||||
for k in range(n + 1):
|
||||
s += (pow(16, n - k, d) << D4) // d
|
||||
d += 8
|
||||
|
||||
# Right sum iterates to infinity for full precision, but we
|
||||
# stop at the point where one iteration is beyond the precision
|
||||
# specified.
|
||||
|
||||
t = 0
|
||||
k = n + 1
|
||||
e = D4 - 4 # 4*(D + n - k)
|
||||
d = 8 * k + j
|
||||
while True:
|
||||
dt = (1 << e) // d
|
||||
if not dt:
|
||||
break
|
||||
t += dt
|
||||
# k += 1
|
||||
e -= 4
|
||||
d += 8
|
||||
total = s + t
|
||||
|
||||
return total
|
||||
|
||||
|
||||
def pi_hex_digits(n, prec=14):
|
||||
"""Returns a string containing ``prec`` (default 14) digits
|
||||
starting at the nth digit of pi in hex. Counting of digits
|
||||
starts at 0 and the decimal is not counted, so for n = 0 the
|
||||
returned value starts with 3; n = 1 corresponds to the first
|
||||
digit past the decimal point (which in hex is 2).
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n : non-negative integer
|
||||
prec : non-negative integer. default = 14
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
str : Returns a string containing ``prec`` digits
|
||||
starting at the nth digit of pi in hex.
|
||||
If ``prec`` = 0, returns empty string.
|
||||
|
||||
Raises
|
||||
======
|
||||
|
||||
ValueError
|
||||
If ``n`` < 0 or ``prec`` < 0.
|
||||
Or ``n`` or ``prec`` is not an integer.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.bbp_pi import pi_hex_digits
|
||||
>>> pi_hex_digits(0)
|
||||
'3243f6a8885a30'
|
||||
>>> pi_hex_digits(0, 3)
|
||||
'324'
|
||||
|
||||
These are consistent with the following results
|
||||
|
||||
>>> import math
|
||||
>>> hex(int(math.pi * 2**((14-1)*4)))
|
||||
'0x3243f6a8885a30'
|
||||
>>> hex(int(math.pi * 2**((3-1)*4)))
|
||||
'0x324'
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] http://www.numberworld.org/digits/Pi/
|
||||
"""
|
||||
n, prec = as_int(n), as_int(prec)
|
||||
if n < 0:
|
||||
raise ValueError('n cannot be negative')
|
||||
if prec < 0:
|
||||
raise ValueError('prec cannot be negative')
|
||||
if prec == 0:
|
||||
return ''
|
||||
|
||||
# main of implementation arrays holding formulae coefficients
|
||||
n -= 1
|
||||
a = [4, 2, 1, 1]
|
||||
j = [1, 4, 5, 6]
|
||||
|
||||
#formulae
|
||||
D = _dn(n, prec)
|
||||
x = + (a[0]*_series(j[0], n, prec)
|
||||
- a[1]*_series(j[1], n, prec)
|
||||
- a[2]*_series(j[2], n, prec)
|
||||
- a[3]*_series(j[3], n, prec)) & (16**D - 1)
|
||||
|
||||
s = ("%0" + "%ix" % prec) % (x // 16**(D - prec))
|
||||
return s
|
||||
|
||||
|
||||
def _dn(n, prec):
|
||||
# controller for n dependence on precision
|
||||
# n = starting digit index
|
||||
# prec = the number of total digits to compute
|
||||
n += 1 # because we subtract 1 for _series
|
||||
|
||||
# assert int(math.log(n + prec)/math.log(16)) ==\
|
||||
# ((n + prec).bit_length() - 1) // 4
|
||||
return ((n + prec).bit_length() - 1) // 4 + prec + 3
|
||||
@@ -0,0 +1,369 @@
|
||||
from __future__ import annotations
|
||||
import itertools
|
||||
from sympy.core.exprtools import factor_terms
|
||||
from sympy.core.numbers import Integer, Rational
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import Dummy
|
||||
from sympy.core.sympify import _sympify
|
||||
from sympy.utilities.misc import as_int
|
||||
|
||||
|
||||
def continued_fraction(a) -> list:
|
||||
"""Return the continued fraction representation of a Rational or
|
||||
quadratic irrational.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.continued_fraction import continued_fraction
|
||||
>>> from sympy import sqrt
|
||||
>>> continued_fraction((1 + 2*sqrt(3))/5)
|
||||
[0, 1, [8, 3, 34, 3]]
|
||||
|
||||
See Also
|
||||
========
|
||||
continued_fraction_periodic, continued_fraction_reduce, continued_fraction_convergents
|
||||
"""
|
||||
e = _sympify(a)
|
||||
if all(i.is_Rational for i in e.atoms()):
|
||||
if e.is_Integer:
|
||||
return continued_fraction_periodic(e, 1, 0)
|
||||
elif e.is_Rational:
|
||||
return continued_fraction_periodic(e.p, e.q, 0)
|
||||
elif e.is_Pow and e.exp is S.Half and e.base.is_Integer:
|
||||
return continued_fraction_periodic(0, 1, e.base)
|
||||
elif e.is_Mul and len(e.args) == 2 and (
|
||||
e.args[0].is_Rational and
|
||||
e.args[1].is_Pow and
|
||||
e.args[1].base.is_Integer and
|
||||
e.args[1].exp is S.Half):
|
||||
a, b = e.args
|
||||
return continued_fraction_periodic(0, a.q, b.base, a.p)
|
||||
else:
|
||||
# this should not have to work very hard- no
|
||||
# simplification, cancel, etc... which should be
|
||||
# done by the user. e.g. This is a fancy 1 but
|
||||
# the user should simplify it first:
|
||||
# sqrt(2)*(1 + sqrt(2))/(sqrt(2) + 2)
|
||||
p, d = e.expand().as_numer_denom()
|
||||
if d.is_Integer:
|
||||
if p.is_Rational:
|
||||
return continued_fraction_periodic(p, d)
|
||||
# look for a + b*c
|
||||
# with c = sqrt(s)
|
||||
if p.is_Add and len(p.args) == 2:
|
||||
a, bc = p.args
|
||||
else:
|
||||
a = S.Zero
|
||||
bc = p
|
||||
if a.is_Integer:
|
||||
b = S.NaN
|
||||
if bc.is_Mul and len(bc.args) == 2:
|
||||
b, c = bc.args
|
||||
elif bc.is_Pow:
|
||||
b = Integer(1)
|
||||
c = bc
|
||||
if b.is_Integer and (
|
||||
c.is_Pow and c.exp is S.Half and
|
||||
c.base.is_Integer):
|
||||
# (a + b*sqrt(c))/d
|
||||
c = c.base
|
||||
return continued_fraction_periodic(a, d, c, b)
|
||||
raise ValueError(
|
||||
'expecting a rational or quadratic irrational, not %s' % e)
|
||||
|
||||
|
||||
def continued_fraction_periodic(p, q, d=0, s=1) -> list:
|
||||
r"""
|
||||
Find the periodic continued fraction expansion of a quadratic irrational.
|
||||
|
||||
Compute the continued fraction expansion of a rational or a
|
||||
quadratic irrational number, i.e. `\frac{p + s\sqrt{d}}{q}`, where
|
||||
`p`, `q \ne 0` and `d \ge 0` are integers.
|
||||
|
||||
Returns the continued fraction representation (canonical form) as
|
||||
a list of integers, optionally ending (for quadratic irrationals)
|
||||
with list of integers representing the repeating digits.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
p : int
|
||||
the rational part of the number's numerator
|
||||
q : int
|
||||
the denominator of the number
|
||||
d : int, optional
|
||||
the irrational part (discriminator) of the number's numerator
|
||||
s : int, optional
|
||||
the coefficient of the irrational part
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.continued_fraction import continued_fraction_periodic
|
||||
>>> continued_fraction_periodic(3, 2, 7)
|
||||
[2, [1, 4, 1, 1]]
|
||||
|
||||
Golden ratio has the simplest continued fraction expansion:
|
||||
|
||||
>>> continued_fraction_periodic(1, 2, 5)
|
||||
[[1]]
|
||||
|
||||
If the discriminator is zero or a perfect square then the number will be a
|
||||
rational number:
|
||||
|
||||
>>> continued_fraction_periodic(4, 3, 0)
|
||||
[1, 3]
|
||||
>>> continued_fraction_periodic(4, 3, 49)
|
||||
[3, 1, 2]
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
continued_fraction_iterator, continued_fraction_reduce
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Periodic_continued_fraction
|
||||
.. [2] K. Rosen. Elementary Number theory and its applications.
|
||||
Addison-Wesley, 3 Sub edition, pages 379-381, January 1992.
|
||||
|
||||
"""
|
||||
from sympy.functions import sqrt, floor
|
||||
|
||||
p, q, d, s = list(map(as_int, [p, q, d, s]))
|
||||
|
||||
if d < 0:
|
||||
raise ValueError("expected non-negative for `d` but got %s" % d)
|
||||
|
||||
if q == 0:
|
||||
raise ValueError("The denominator cannot be 0.")
|
||||
|
||||
if not s:
|
||||
d = 0
|
||||
|
||||
# check for rational case
|
||||
sd = sqrt(d)
|
||||
if sd.is_Integer:
|
||||
return list(continued_fraction_iterator(Rational(p + s*sd, q)))
|
||||
|
||||
# irrational case with sd != Integer
|
||||
if q < 0:
|
||||
p, q, s = -p, -q, -s
|
||||
|
||||
n = (p + s*sd)/q
|
||||
if n < 0:
|
||||
w = floor(-n)
|
||||
f = -n - w
|
||||
one_f = continued_fraction(1 - f) # 1-f < 1 so cf is [0 ... [...]]
|
||||
one_f[0] -= w + 1
|
||||
return one_f
|
||||
|
||||
d *= s**2
|
||||
sd *= s
|
||||
|
||||
if (d - p**2)%q:
|
||||
d *= q**2
|
||||
sd *= q
|
||||
p *= q
|
||||
q *= q
|
||||
|
||||
terms: list[int] = []
|
||||
pq = {}
|
||||
|
||||
while (p, q) not in pq:
|
||||
pq[(p, q)] = len(terms)
|
||||
terms.append((p + sd)//q)
|
||||
p = terms[-1]*q - p
|
||||
q = (d - p**2)//q
|
||||
|
||||
i = pq[(p, q)]
|
||||
return terms[:i] + [terms[i:]] # type: ignore
|
||||
|
||||
|
||||
def continued_fraction_reduce(cf):
|
||||
"""
|
||||
Reduce a continued fraction to a rational or quadratic irrational.
|
||||
|
||||
Compute the rational or quadratic irrational number from its
|
||||
terminating or periodic continued fraction expansion. The
|
||||
continued fraction expansion (cf) should be supplied as a
|
||||
terminating iterator supplying the terms of the expansion. For
|
||||
terminating continued fractions, this is equivalent to
|
||||
``list(continued_fraction_convergents(cf))[-1]``, only a little more
|
||||
efficient. If the expansion has a repeating part, a list of the
|
||||
repeating terms should be returned as the last element from the
|
||||
iterator. This is the format returned by
|
||||
continued_fraction_periodic.
|
||||
|
||||
For quadratic irrationals, returns the largest solution found,
|
||||
which is generally the one sought, if the fraction is in canonical
|
||||
form (all terms positive except possibly the first).
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.continued_fraction import continued_fraction_reduce
|
||||
>>> continued_fraction_reduce([1, 2, 3, 4, 5])
|
||||
225/157
|
||||
>>> continued_fraction_reduce([-2, 1, 9, 7, 1, 2])
|
||||
-256/233
|
||||
>>> continued_fraction_reduce([2, 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8]).n(10)
|
||||
2.718281835
|
||||
>>> continued_fraction_reduce([1, 4, 2, [3, 1]])
|
||||
(sqrt(21) + 287)/238
|
||||
>>> continued_fraction_reduce([[1]])
|
||||
(1 + sqrt(5))/2
|
||||
>>> from sympy.ntheory.continued_fraction import continued_fraction_periodic
|
||||
>>> continued_fraction_reduce(continued_fraction_periodic(8, 5, 13))
|
||||
(sqrt(13) + 8)/5
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
continued_fraction_periodic
|
||||
|
||||
"""
|
||||
from sympy.solvers import solve
|
||||
|
||||
period = []
|
||||
x = Dummy('x')
|
||||
|
||||
def untillist(cf):
|
||||
for nxt in cf:
|
||||
if isinstance(nxt, list):
|
||||
period.extend(nxt)
|
||||
yield x
|
||||
break
|
||||
yield nxt
|
||||
|
||||
a = S.Zero
|
||||
for a in continued_fraction_convergents(untillist(cf)):
|
||||
pass
|
||||
|
||||
if period:
|
||||
y = Dummy('y')
|
||||
solns = solve(continued_fraction_reduce(period + [y]) - y, y)
|
||||
solns.sort()
|
||||
pure = solns[-1]
|
||||
rv = a.subs(x, pure).radsimp()
|
||||
else:
|
||||
rv = a
|
||||
if rv.is_Add:
|
||||
rv = factor_terms(rv)
|
||||
if rv.is_Mul and rv.args[0] == -1:
|
||||
rv = rv.func(*rv.args)
|
||||
return rv
|
||||
|
||||
|
||||
def continued_fraction_iterator(x):
|
||||
"""
|
||||
Return continued fraction expansion of x as iterator.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Rational, pi
|
||||
>>> from sympy.ntheory.continued_fraction import continued_fraction_iterator
|
||||
|
||||
>>> list(continued_fraction_iterator(Rational(3, 8)))
|
||||
[0, 2, 1, 2]
|
||||
>>> list(continued_fraction_iterator(Rational(-3, 8)))
|
||||
[-1, 1, 1, 1, 2]
|
||||
|
||||
>>> for i, v in enumerate(continued_fraction_iterator(pi)):
|
||||
... if i > 7:
|
||||
... break
|
||||
... print(v)
|
||||
3
|
||||
7
|
||||
15
|
||||
1
|
||||
292
|
||||
1
|
||||
1
|
||||
1
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Continued_fraction
|
||||
|
||||
"""
|
||||
from sympy.functions import floor
|
||||
while True:
|
||||
i = floor(x)
|
||||
yield i
|
||||
x -= i
|
||||
if not x:
|
||||
break
|
||||
x = 1/x
|
||||
|
||||
|
||||
def continued_fraction_convergents(cf):
|
||||
"""
|
||||
Return an iterator over the convergents of a continued fraction (cf).
|
||||
|
||||
The parameter should be in either of the following to forms:
|
||||
- A list of partial quotients, possibly with the last element being a list
|
||||
of repeating partial quotients, such as might be returned by
|
||||
continued_fraction and continued_fraction_periodic.
|
||||
- An iterable returning successive partial quotients of the continued
|
||||
fraction, such as might be returned by continued_fraction_iterator.
|
||||
|
||||
In computing the convergents, the continued fraction need not be strictly
|
||||
in canonical form (all integers, all but the first positive).
|
||||
Rational and negative elements may be present in the expansion.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.core import pi
|
||||
>>> from sympy import S
|
||||
>>> from sympy.ntheory.continued_fraction import \
|
||||
continued_fraction_convergents, continued_fraction_iterator
|
||||
|
||||
>>> list(continued_fraction_convergents([0, 2, 1, 2]))
|
||||
[0, 1/2, 1/3, 3/8]
|
||||
|
||||
>>> list(continued_fraction_convergents([1, S('1/2'), -7, S('1/4')]))
|
||||
[1, 3, 19/5, 7]
|
||||
|
||||
>>> it = continued_fraction_convergents(continued_fraction_iterator(pi))
|
||||
>>> for n in range(7):
|
||||
... print(next(it))
|
||||
3
|
||||
22/7
|
||||
333/106
|
||||
355/113
|
||||
103993/33102
|
||||
104348/33215
|
||||
208341/66317
|
||||
|
||||
>>> it = continued_fraction_convergents([1, [1, 2]]) # sqrt(3)
|
||||
>>> for n in range(7):
|
||||
... print(next(it))
|
||||
1
|
||||
2
|
||||
5/3
|
||||
7/4
|
||||
19/11
|
||||
26/15
|
||||
71/41
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
continued_fraction_iterator, continued_fraction, continued_fraction_periodic
|
||||
|
||||
"""
|
||||
if isinstance(cf, list) and isinstance(cf[-1], list):
|
||||
cf = itertools.chain(cf[:-1], itertools.cycle(cf[-1]))
|
||||
p_2, q_2 = S.Zero, S.One
|
||||
p_1, q_1 = S.One, S.Zero
|
||||
for a in cf:
|
||||
p, q = a*p_1 + p_2, a*q_1 + q_2
|
||||
p_2, q_2 = p_1, q_1
|
||||
p_1, q_1 = p, q
|
||||
yield p/q
|
||||
150
venv/lib/python3.12/site-packages/sympy/ntheory/digits.py
Normal file
150
venv/lib/python3.12/site-packages/sympy/ntheory/digits.py
Normal file
@@ -0,0 +1,150 @@
|
||||
from collections import defaultdict
|
||||
|
||||
from sympy.utilities.iterables import multiset, is_palindromic as _palindromic
|
||||
from sympy.utilities.misc import as_int
|
||||
|
||||
|
||||
def digits(n, b=10, digits=None):
|
||||
"""
|
||||
Return a list of the digits of ``n`` in base ``b``. The first
|
||||
element in the list is ``b`` (or ``-b`` if ``n`` is negative).
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.digits import digits
|
||||
>>> digits(35)
|
||||
[10, 3, 5]
|
||||
|
||||
If the number is negative, the negative sign will be placed on the
|
||||
base (which is the first element in the returned list):
|
||||
|
||||
>>> digits(-35)
|
||||
[-10, 3, 5]
|
||||
|
||||
Bases other than 10 (and greater than 1) can be selected with ``b``:
|
||||
|
||||
>>> digits(27, b=2)
|
||||
[2, 1, 1, 0, 1, 1]
|
||||
|
||||
Use the ``digits`` keyword if a certain number of digits is desired:
|
||||
|
||||
>>> digits(35, digits=4)
|
||||
[10, 0, 0, 3, 5]
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n: integer
|
||||
The number whose digits are returned.
|
||||
|
||||
b: integer
|
||||
The base in which digits are computed.
|
||||
|
||||
digits: integer (or None for all digits)
|
||||
The number of digits to be returned (padded with zeros, if
|
||||
necessary).
|
||||
|
||||
See Also
|
||||
========
|
||||
sympy.core.intfunc.num_digits, count_digits
|
||||
"""
|
||||
|
||||
b = as_int(b)
|
||||
n = as_int(n)
|
||||
if b < 2:
|
||||
raise ValueError("b must be greater than 1")
|
||||
else:
|
||||
x, y = abs(n), []
|
||||
while x >= b:
|
||||
x, r = divmod(x, b)
|
||||
y.append(r)
|
||||
y.append(x)
|
||||
y.append(-b if n < 0 else b)
|
||||
y.reverse()
|
||||
ndig = len(y) - 1
|
||||
if digits is not None:
|
||||
if ndig > digits:
|
||||
raise ValueError(
|
||||
"For %s, at least %s digits are needed." % (n, ndig))
|
||||
elif ndig < digits:
|
||||
y[1:1] = [0]*(digits - ndig)
|
||||
return y
|
||||
|
||||
|
||||
def count_digits(n, b=10):
|
||||
"""
|
||||
Return a dictionary whose keys are the digits of ``n`` in the
|
||||
given base, ``b``, with keys indicating the digits appearing in the
|
||||
number and values indicating how many times that digit appeared.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory import count_digits
|
||||
|
||||
>>> count_digits(1111339)
|
||||
{1: 4, 3: 2, 9: 1}
|
||||
|
||||
The digits returned are always represented in base-10
|
||||
but the number itself can be entered in any format that is
|
||||
understood by Python; the base of the number can also be
|
||||
given if it is different than 10:
|
||||
|
||||
>>> n = 0xFA; n
|
||||
250
|
||||
>>> count_digits(_)
|
||||
{0: 1, 2: 1, 5: 1}
|
||||
>>> count_digits(n, 16)
|
||||
{10: 1, 15: 1}
|
||||
|
||||
The default dictionary will return a 0 for any digit that did
|
||||
not appear in the number. For example, which digits appear 7
|
||||
times in ``77!``:
|
||||
|
||||
>>> from sympy import factorial
|
||||
>>> c77 = count_digits(factorial(77))
|
||||
>>> [i for i in range(10) if c77[i] == 7]
|
||||
[1, 3, 7, 9]
|
||||
|
||||
See Also
|
||||
========
|
||||
sympy.core.intfunc.num_digits, digits
|
||||
"""
|
||||
rv = defaultdict(int, multiset(digits(n, b)).items())
|
||||
rv.pop(b) if b in rv else rv.pop(-b) # b or -b is there
|
||||
return rv
|
||||
|
||||
|
||||
def is_palindromic(n, b=10):
|
||||
"""return True if ``n`` is the same when read from left to right
|
||||
or right to left in the given base, ``b``.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory import is_palindromic
|
||||
|
||||
>>> all(is_palindromic(i) for i in (-11, 1, 22, 121))
|
||||
True
|
||||
|
||||
The second argument allows you to test numbers in other
|
||||
bases. For example, 88 is palindromic in base-10 but not
|
||||
in base-8:
|
||||
|
||||
>>> is_palindromic(88, 8)
|
||||
False
|
||||
|
||||
On the other hand, a number can be palindromic in base-8 but
|
||||
not in base-10:
|
||||
|
||||
>>> 0o121, is_palindromic(0o121)
|
||||
(81, False)
|
||||
|
||||
Or it might be palindromic in both bases:
|
||||
|
||||
>>> oct(121), is_palindromic(121, 8) and is_palindromic(121)
|
||||
('0o171', True)
|
||||
|
||||
"""
|
||||
return _palindromic(digits(n, b), 1)
|
||||
348
venv/lib/python3.12/site-packages/sympy/ntheory/ecm.py
Normal file
348
venv/lib/python3.12/site-packages/sympy/ntheory/ecm.py
Normal file
@@ -0,0 +1,348 @@
|
||||
from math import log
|
||||
|
||||
from sympy.core.random import _randint
|
||||
from sympy.external.gmpy import gcd, invert, sqrt
|
||||
from sympy.utilities.misc import as_int
|
||||
from .generate import sieve, primerange
|
||||
from .primetest import isprime
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------#
|
||||
# #
|
||||
# Lenstra's Elliptic Curve Factorization #
|
||||
# #
|
||||
#----------------------------------------------------------------------------#
|
||||
|
||||
|
||||
class Point:
|
||||
"""Montgomery form of Points in an elliptic curve.
|
||||
In this form, the addition and doubling of points
|
||||
does not need any y-coordinate information thus
|
||||
decreasing the number of operations.
|
||||
Using Montgomery form we try to perform point addition
|
||||
and doubling in least amount of multiplications.
|
||||
|
||||
The elliptic curve used here is of the form
|
||||
(E : b*y**2*z = x**3 + a*x**2*z + x*z**2).
|
||||
The a_24 parameter is equal to (a + 2)/4.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] Kris Gaj, Soonhak Kwon, Patrick Baier, Paul Kohlbrenner, Hoang Le, Mohammed Khaleeluddin, Ramakrishna Bachimanchi,
|
||||
Implementing the Elliptic Curve Method of Factoring in Reconfigurable Hardware,
|
||||
Cryptographic Hardware and Embedded Systems - CHES 2006 (2006), pp. 119-133,
|
||||
https://doi.org/10.1007/11894063_10
|
||||
https://www.hyperelliptic.org/tanja/SHARCS/talks06/Gaj.pdf
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, x_cord, z_cord, a_24, mod):
|
||||
"""
|
||||
Initial parameters for the Point class.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
x_cord : X coordinate of the Point
|
||||
z_cord : Z coordinate of the Point
|
||||
a_24 : Parameter of the elliptic curve in Montgomery form
|
||||
mod : modulus
|
||||
"""
|
||||
self.x_cord = x_cord
|
||||
self.z_cord = z_cord
|
||||
self.a_24 = a_24
|
||||
self.mod = mod
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Two points are equal if X/Z of both points are equal
|
||||
"""
|
||||
if self.a_24 != other.a_24 or self.mod != other.mod:
|
||||
return False
|
||||
return self.x_cord * other.z_cord % self.mod ==\
|
||||
other.x_cord * self.z_cord % self.mod
|
||||
|
||||
def add(self, Q, diff):
|
||||
"""
|
||||
Add two points self and Q where diff = self - Q. Moreover the assumption
|
||||
is self.x_cord*Q.x_cord*(self.x_cord - Q.x_cord) != 0. This algorithm
|
||||
requires 6 multiplications. Here the difference between the points
|
||||
is already known and using this algorithm speeds up the addition
|
||||
by reducing the number of multiplication required. Also in the
|
||||
mont_ladder algorithm is constructed in a way so that the difference
|
||||
between intermediate points is always equal to the initial point.
|
||||
So, we always know what the difference between the point is.
|
||||
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
Q : point on the curve in Montgomery form
|
||||
diff : self - Q
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.ecm import Point
|
||||
>>> p1 = Point(11, 16, 7, 29)
|
||||
>>> p2 = Point(13, 10, 7, 29)
|
||||
>>> p3 = p2.add(p1, p1)
|
||||
>>> p3.x_cord
|
||||
23
|
||||
>>> p3.z_cord
|
||||
17
|
||||
"""
|
||||
u = (self.x_cord - self.z_cord)*(Q.x_cord + Q.z_cord)
|
||||
v = (self.x_cord + self.z_cord)*(Q.x_cord - Q.z_cord)
|
||||
add, subt = u + v, u - v
|
||||
x_cord = diff.z_cord * add * add % self.mod
|
||||
z_cord = diff.x_cord * subt * subt % self.mod
|
||||
return Point(x_cord, z_cord, self.a_24, self.mod)
|
||||
|
||||
def double(self):
|
||||
"""
|
||||
Doubles a point in an elliptic curve in Montgomery form.
|
||||
This algorithm requires 5 multiplications.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.ecm import Point
|
||||
>>> p1 = Point(11, 16, 7, 29)
|
||||
>>> p2 = p1.double()
|
||||
>>> p2.x_cord
|
||||
13
|
||||
>>> p2.z_cord
|
||||
10
|
||||
"""
|
||||
u = pow(self.x_cord + self.z_cord, 2, self.mod)
|
||||
v = pow(self.x_cord - self.z_cord, 2, self.mod)
|
||||
diff = u - v
|
||||
x_cord = u*v % self.mod
|
||||
z_cord = diff*(v + self.a_24*diff) % self.mod
|
||||
return Point(x_cord, z_cord, self.a_24, self.mod)
|
||||
|
||||
def mont_ladder(self, k):
|
||||
"""
|
||||
Scalar multiplication of a point in Montgomery form
|
||||
using Montgomery Ladder Algorithm.
|
||||
A total of 11 multiplications are required in each step of this
|
||||
algorithm.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
k : The positive integer multiplier
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.ecm import Point
|
||||
>>> p1 = Point(11, 16, 7, 29)
|
||||
>>> p3 = p1.mont_ladder(3)
|
||||
>>> p3.x_cord
|
||||
23
|
||||
>>> p3.z_cord
|
||||
17
|
||||
"""
|
||||
Q = self
|
||||
R = self.double()
|
||||
for i in bin(k)[3:]:
|
||||
if i == '1':
|
||||
Q = R.add(Q, self)
|
||||
R = R.double()
|
||||
else:
|
||||
R = Q.add(R, self)
|
||||
Q = Q.double()
|
||||
return Q
|
||||
|
||||
|
||||
def _ecm_one_factor(n, B1=10000, B2=100000, max_curve=200, seed=None):
|
||||
"""Returns one factor of n using
|
||||
Lenstra's 2 Stage Elliptic curve Factorization
|
||||
with Suyama's Parameterization. Here Montgomery
|
||||
arithmetic is used for fast computation of addition
|
||||
and doubling of points in elliptic curve.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This ECM method considers elliptic curves in Montgomery
|
||||
form (E : b*y**2*z = x**3 + a*x**2*z + x*z**2) and involves
|
||||
elliptic curve operations (mod N), where the elements in
|
||||
Z are reduced (mod N). Since N is not a prime, E over FF(N)
|
||||
is not really an elliptic curve but we can still do point additions
|
||||
and doubling as if FF(N) was a field.
|
||||
|
||||
Stage 1 : The basic algorithm involves taking a random point (P) on an
|
||||
elliptic curve in FF(N). The compute k*P using Montgomery ladder algorithm.
|
||||
Let q be an unknown factor of N. Then the order of the curve E, |E(FF(q))|,
|
||||
might be a smooth number that divides k. Then we have k = l * |E(FF(q))|
|
||||
for some l. For any point belonging to the curve E, |E(FF(q))|*P = O,
|
||||
hence k*P = l*|E(FF(q))|*P. Thus kP.z_cord = 0 (mod q), and the unknownn
|
||||
factor of N (q) can be recovered by taking gcd(kP.z_cord, N).
|
||||
|
||||
Stage 2 : This is a continuation of Stage 1 if k*P != O. The idea utilize
|
||||
the fact that even if kP != 0, the value of k might miss just one large
|
||||
prime divisor of |E(FF(q))|. In this case we only need to compute the
|
||||
scalar multiplication by p to get p*k*P = O. Here a second bound B2
|
||||
restrict the size of possible values of p.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n : Number to be Factored. Assume that it is a composite number.
|
||||
B1 : Stage 1 Bound. Must be an even number.
|
||||
B2 : Stage 2 Bound. Must be an even number.
|
||||
max_curve : Maximum number of curves generated
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
integer | None : a non-trivial divisor of ``n``. ``None`` if not found
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] Carl Pomerance, Richard Crandall, Prime Numbers: A Computational Perspective,
|
||||
2nd Edition (2005), page 344, ISBN:978-0387252827
|
||||
"""
|
||||
randint = _randint(seed)
|
||||
|
||||
# When calculating T, if (B1 - 2*D) is negative, it cannot be calculated.
|
||||
D = min(sqrt(B2), B1 // 2 - 1)
|
||||
sieve.extend(D)
|
||||
beta = [0] * D
|
||||
S = [0] * D
|
||||
k = 1
|
||||
for p in primerange(2, B1 + 1):
|
||||
k *= pow(p, int(log(B1, p)))
|
||||
|
||||
# Pre-calculate the prime numbers to be used in stage 2.
|
||||
# Using the fact that the x-coordinates of point P and its
|
||||
# inverse -P coincide, the number of primes to be checked
|
||||
# in stage 2 can be reduced.
|
||||
deltas_list = []
|
||||
for r in range(B1 + 2*D, B2 + 2*D, 4*D):
|
||||
# d in deltas iff r+(2d+1) and/or r-(2d+1) is prime
|
||||
deltas = {abs(q - r) >> 1 for q in primerange(r - 2*D, r + 2*D)}
|
||||
deltas_list.append(list(deltas))
|
||||
|
||||
for _ in range(max_curve):
|
||||
#Suyama's Parametrization
|
||||
sigma = randint(6, n - 1)
|
||||
u = (sigma**2 - 5) % n
|
||||
v = (4*sigma) % n
|
||||
u_3 = pow(u, 3, n)
|
||||
|
||||
try:
|
||||
# We use the elliptic curve y**2 = x**3 + a*x**2 + x
|
||||
# where a = pow(v - u, 3, n)*(3*u + v)*invert(4*u_3*v, n) - 2
|
||||
# However, we do not declare a because it is more convenient
|
||||
# to use a24 = (a + 2)*invert(4, n) in the calculation.
|
||||
a24 = pow(v - u, 3, n)*(3*u + v)*invert(16*u_3*v, n) % n
|
||||
except ZeroDivisionError:
|
||||
#If the invert(16*u_3*v, n) doesn't exist (i.e., g != 1)
|
||||
g = gcd(2*u_3*v, n)
|
||||
#If g = n, try another curve
|
||||
if g == n:
|
||||
continue
|
||||
return g
|
||||
|
||||
Q = Point(u_3, pow(v, 3, n), a24, n)
|
||||
Q = Q.mont_ladder(k)
|
||||
g = gcd(Q.z_cord, n)
|
||||
|
||||
#Stage 1 factor
|
||||
if g != 1 and g != n:
|
||||
return g
|
||||
#Stage 1 failure. Q.z = 0, Try another curve
|
||||
elif g == n:
|
||||
continue
|
||||
|
||||
#Stage 2 - Improved Standard Continuation
|
||||
S[0] = Q
|
||||
Q2 = Q.double()
|
||||
S[1] = Q2.add(Q, Q)
|
||||
beta[0] = (S[0].x_cord*S[0].z_cord) % n
|
||||
beta[1] = (S[1].x_cord*S[1].z_cord) % n
|
||||
for d in range(2, D):
|
||||
S[d] = S[d - 1].add(Q2, S[d - 2])
|
||||
beta[d] = (S[d].x_cord*S[d].z_cord) % n
|
||||
# i.e., S[i] = Q.mont_ladder(2*i + 1)
|
||||
|
||||
g = 1
|
||||
W = Q.mont_ladder(4*D)
|
||||
T = Q.mont_ladder(B1 - 2*D)
|
||||
R = Q.mont_ladder(B1 + 2*D)
|
||||
for deltas in deltas_list:
|
||||
# R = Q.mont_ladder(r) where r in range(B1 + 2*D, B2 + 2*D, 4*D)
|
||||
alpha = (R.x_cord*R.z_cord) % n
|
||||
for delta in deltas:
|
||||
# We want to calculate
|
||||
# f = R.x_cord * S[delta].z_cord - S[delta].x_cord * R.z_cord
|
||||
f = (R.x_cord - S[delta].x_cord)*\
|
||||
(R.z_cord + S[delta].z_cord) - alpha + beta[delta]
|
||||
g = (g*f) % n
|
||||
T, R = R, R.add(W, T)
|
||||
g = gcd(n, g)
|
||||
|
||||
#Stage 2 Factor found
|
||||
if g != 1 and g != n:
|
||||
return g
|
||||
|
||||
|
||||
def ecm(n, B1=10000, B2=100000, max_curve=200, seed=1234):
|
||||
"""Performs factorization using Lenstra's Elliptic curve method.
|
||||
|
||||
This function repeatedly calls ``_ecm_one_factor`` to compute the factors
|
||||
of n. First all the small factors are taken out using trial division.
|
||||
Then ``_ecm_one_factor`` is used to compute one factor at a time.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n : Number to be Factored
|
||||
B1 : Stage 1 Bound. Must be an even number.
|
||||
B2 : Stage 2 Bound. Must be an even number.
|
||||
max_curve : Maximum number of curves generated
|
||||
seed : Initialize pseudorandom generator
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory import ecm
|
||||
>>> ecm(25645121643901801)
|
||||
{5394769, 4753701529}
|
||||
>>> ecm(9804659461513846513)
|
||||
{4641991, 2112166839943}
|
||||
"""
|
||||
from .factor_ import _perfect_power
|
||||
n = as_int(n)
|
||||
if B1 % 2 != 0 or B2 % 2 != 0:
|
||||
raise ValueError("both bounds must be even")
|
||||
TF_LIMIT = 100000
|
||||
factors = set()
|
||||
for prime in sieve.primerange(2, TF_LIMIT):
|
||||
if n % prime == 0:
|
||||
factors.add(prime)
|
||||
while(n % prime == 0):
|
||||
n //= prime
|
||||
|
||||
queue = []
|
||||
def check(m):
|
||||
if isprime(m):
|
||||
factors.add(m)
|
||||
return
|
||||
if result := _perfect_power(m, TF_LIMIT):
|
||||
return check(result[0])
|
||||
queue.append(m)
|
||||
check(n)
|
||||
while queue:
|
||||
n = queue.pop()
|
||||
factor = _ecm_one_factor(n, B1, B2, max_curve, seed)
|
||||
if factor is None:
|
||||
raise ValueError("Increase the bounds")
|
||||
check(factor)
|
||||
check(n // factor)
|
||||
return factors
|
||||
@@ -0,0 +1,223 @@
|
||||
from sympy.core.containers import Tuple
|
||||
from sympy.core.numbers import (Integer, Rational)
|
||||
from sympy.core.singleton import S
|
||||
import sympy.polys
|
||||
|
||||
from math import gcd
|
||||
|
||||
|
||||
def egyptian_fraction(r, algorithm="Greedy"):
|
||||
"""
|
||||
Return the list of denominators of an Egyptian fraction
|
||||
expansion [1]_ of the said rational `r`.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
r : Rational or (p, q)
|
||||
a positive rational number, ``p/q``.
|
||||
algorithm : { "Greedy", "Graham Jewett", "Takenouchi", "Golomb" }, optional
|
||||
Denotes the algorithm to be used (the default is "Greedy").
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import Rational
|
||||
>>> from sympy.ntheory.egyptian_fraction import egyptian_fraction
|
||||
>>> egyptian_fraction(Rational(3, 7))
|
||||
[3, 11, 231]
|
||||
>>> egyptian_fraction((3, 7), "Graham Jewett")
|
||||
[7, 8, 9, 56, 57, 72, 3192]
|
||||
>>> egyptian_fraction((3, 7), "Takenouchi")
|
||||
[4, 7, 28]
|
||||
>>> egyptian_fraction((3, 7), "Golomb")
|
||||
[3, 15, 35]
|
||||
>>> egyptian_fraction((11, 5), "Golomb")
|
||||
[1, 2, 3, 4, 9, 234, 1118, 2580]
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.core.numbers.Rational
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
Currently the following algorithms are supported:
|
||||
|
||||
1) Greedy Algorithm
|
||||
|
||||
Also called the Fibonacci-Sylvester algorithm [2]_.
|
||||
At each step, extract the largest unit fraction less
|
||||
than the target and replace the target with the remainder.
|
||||
|
||||
It has some distinct properties:
|
||||
|
||||
a) Given `p/q` in lowest terms, generates an expansion of maximum
|
||||
length `p`. Even as the numerators get large, the number of
|
||||
terms is seldom more than a handful.
|
||||
|
||||
b) Uses minimal memory.
|
||||
|
||||
c) The terms can blow up (standard examples of this are 5/121 and
|
||||
31/311). The denominator is at most squared at each step
|
||||
(doubly-exponential growth) and typically exhibits
|
||||
singly-exponential growth.
|
||||
|
||||
2) Graham Jewett Algorithm
|
||||
|
||||
The algorithm suggested by the result of Graham and Jewett.
|
||||
Note that this has a tendency to blow up: the length of the
|
||||
resulting expansion is always ``2**(x/gcd(x, y)) - 1``. See [3]_.
|
||||
|
||||
3) Takenouchi Algorithm
|
||||
|
||||
The algorithm suggested by Takenouchi (1921).
|
||||
Differs from the Graham-Jewett algorithm only in the handling
|
||||
of duplicates. See [3]_.
|
||||
|
||||
4) Golomb's Algorithm
|
||||
|
||||
A method given by Golumb (1962), using modular arithmetic and
|
||||
inverses. It yields the same results as a method using continued
|
||||
fractions proposed by Bleicher (1972). See [4]_.
|
||||
|
||||
If the given rational is greater than or equal to 1, a greedy algorithm
|
||||
of summing the harmonic sequence 1/1 + 1/2 + 1/3 + ... is used, taking
|
||||
all the unit fractions of this sequence until adding one more would be
|
||||
greater than the given number. This list of denominators is prefixed
|
||||
to the result from the requested algorithm used on the remainder. For
|
||||
example, if r is 8/3, using the Greedy algorithm, we get [1, 2, 3, 4,
|
||||
5, 6, 7, 14, 420], where the beginning of the sequence, [1, 2, 3, 4, 5,
|
||||
6, 7] is part of the harmonic sequence summing to 363/140, leaving a
|
||||
remainder of 31/420, which yields [14, 420] by the Greedy algorithm.
|
||||
The result of egyptian_fraction(Rational(8, 3), "Golomb") is [1, 2, 3,
|
||||
4, 5, 6, 7, 14, 574, 2788, 6460, 11590, 33062, 113820], and so on.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Egyptian_fraction
|
||||
.. [2] https://en.wikipedia.org/wiki/Greedy_algorithm_for_Egyptian_fractions
|
||||
.. [3] https://www.ics.uci.edu/~eppstein/numth/egypt/conflict.html
|
||||
.. [4] https://web.archive.org/web/20180413004012/https://ami.ektf.hu/uploads/papers/finalpdf/AMI_42_from129to134.pdf
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(r, Rational):
|
||||
if isinstance(r, (Tuple, tuple)) and len(r) == 2:
|
||||
r = Rational(*r)
|
||||
else:
|
||||
raise ValueError("Value must be a Rational or tuple of ints")
|
||||
if r <= 0:
|
||||
raise ValueError("Value must be positive")
|
||||
|
||||
# common cases that all methods agree on
|
||||
x, y = r.as_numer_denom()
|
||||
if y == 1 and x == 2:
|
||||
return [Integer(i) for i in [1, 2, 3, 6]]
|
||||
if x == y + 1:
|
||||
return [S.One, y]
|
||||
|
||||
prefix, rem = egypt_harmonic(r)
|
||||
if rem == 0:
|
||||
return prefix
|
||||
# work in Python ints
|
||||
x, y = rem.p, rem.q
|
||||
# assert x < y and gcd(x, y) = 1
|
||||
|
||||
if algorithm == "Greedy":
|
||||
postfix = egypt_greedy(x, y)
|
||||
elif algorithm == "Graham Jewett":
|
||||
postfix = egypt_graham_jewett(x, y)
|
||||
elif algorithm == "Takenouchi":
|
||||
postfix = egypt_takenouchi(x, y)
|
||||
elif algorithm == "Golomb":
|
||||
postfix = egypt_golomb(x, y)
|
||||
else:
|
||||
raise ValueError("Entered invalid algorithm")
|
||||
return prefix + [Integer(i) for i in postfix]
|
||||
|
||||
|
||||
def egypt_greedy(x, y):
|
||||
# assumes gcd(x, y) == 1
|
||||
if x == 1:
|
||||
return [y]
|
||||
else:
|
||||
a = (-y) % x
|
||||
b = y*(y//x + 1)
|
||||
c = gcd(a, b)
|
||||
if c > 1:
|
||||
num, denom = a//c, b//c
|
||||
else:
|
||||
num, denom = a, b
|
||||
return [y//x + 1] + egypt_greedy(num, denom)
|
||||
|
||||
|
||||
def egypt_graham_jewett(x, y):
|
||||
# assumes gcd(x, y) == 1
|
||||
l = [y] * x
|
||||
|
||||
# l is now a list of integers whose reciprocals sum to x/y.
|
||||
# we shall now proceed to manipulate the elements of l without
|
||||
# changing the reciprocated sum until all elements are unique.
|
||||
|
||||
while len(l) != len(set(l)):
|
||||
l.sort() # so the list has duplicates. find a smallest pair
|
||||
for i in range(len(l) - 1):
|
||||
if l[i] == l[i + 1]:
|
||||
break
|
||||
# we have now identified a pair of identical
|
||||
# elements: l[i] and l[i + 1].
|
||||
# now comes the application of the result of graham and jewett:
|
||||
l[i + 1] = l[i] + 1
|
||||
# and we just iterate that until the list has no duplicates.
|
||||
l.append(l[i]*(l[i] + 1))
|
||||
return sorted(l)
|
||||
|
||||
|
||||
def egypt_takenouchi(x, y):
|
||||
# assumes gcd(x, y) == 1
|
||||
# special cases for 3/y
|
||||
if x == 3:
|
||||
if y % 2 == 0:
|
||||
return [y//2, y]
|
||||
i = (y - 1)//2
|
||||
j = i + 1
|
||||
k = j + i
|
||||
return [j, k, j*k]
|
||||
l = [y] * x
|
||||
while len(l) != len(set(l)):
|
||||
l.sort()
|
||||
for i in range(len(l) - 1):
|
||||
if l[i] == l[i + 1]:
|
||||
break
|
||||
k = l[i]
|
||||
if k % 2 == 0:
|
||||
l[i] = l[i] // 2
|
||||
del l[i + 1]
|
||||
else:
|
||||
l[i], l[i + 1] = (k + 1)//2, k*(k + 1)//2
|
||||
return sorted(l)
|
||||
|
||||
|
||||
def egypt_golomb(x, y):
|
||||
# assumes x < y and gcd(x, y) == 1
|
||||
if x == 1:
|
||||
return [y]
|
||||
xp = sympy.polys.ZZ.invert(int(x), int(y))
|
||||
rv = [xp*y]
|
||||
rv.extend(egypt_golomb((x*xp - 1)//y, xp))
|
||||
return sorted(rv)
|
||||
|
||||
|
||||
def egypt_harmonic(r):
|
||||
# assumes r is Rational
|
||||
rv = []
|
||||
d = S.One
|
||||
acc = S.Zero
|
||||
while acc + 1/d <= r:
|
||||
acc += 1/d
|
||||
rv.append(d)
|
||||
d += 1
|
||||
return (rv, r - acc)
|
||||
@@ -0,0 +1,397 @@
|
||||
from sympy.core.numbers import oo
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.polys.domains import FiniteField, QQ, RationalField, FF
|
||||
from sympy.polys.polytools import Poly
|
||||
from sympy.solvers.solvers import solve
|
||||
from sympy.utilities.iterables import is_sequence
|
||||
from sympy.utilities.misc import as_int
|
||||
from .factor_ import divisors
|
||||
from .residue_ntheory import polynomial_congruence
|
||||
|
||||
|
||||
class EllipticCurve:
|
||||
"""
|
||||
Create the following Elliptic Curve over domain.
|
||||
|
||||
`y^{2} + a_{1} x y + a_{3} y = x^{3} + a_{2} x^{2} + a_{4} x + a_{6}`
|
||||
|
||||
The default domain is ``QQ``. If no coefficient ``a1``, ``a2``, ``a3``,
|
||||
is given then it creates a curve with the following form:
|
||||
|
||||
`y^{2} = x^{3} + a_{4} x + a_{6}`
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] J. Silverman "A Friendly Introduction to Number Theory" Third Edition
|
||||
.. [2] https://mathworld.wolfram.com/EllipticDiscriminant.html
|
||||
.. [3] G. Hardy, E. Wright "An Introduction to the Theory of Numbers" Sixth Edition
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, a4, a6, a1=0, a2=0, a3=0, modulus=0):
|
||||
if modulus == 0:
|
||||
domain = QQ
|
||||
else:
|
||||
domain = FF(modulus)
|
||||
a1, a2, a3, a4, a6 = map(domain.convert, (a1, a2, a3, a4, a6))
|
||||
self._domain = domain
|
||||
self.modulus = modulus
|
||||
# Calculate discriminant
|
||||
b2 = a1**2 + 4 * a2
|
||||
b4 = 2 * a4 + a1 * a3
|
||||
b6 = a3**2 + 4 * a6
|
||||
b8 = a1**2 * a6 + 4 * a2 * a6 - a1 * a3 * a4 + a2 * a3**2 - a4**2
|
||||
self._b2, self._b4, self._b6, self._b8 = b2, b4, b6, b8
|
||||
self._discrim = -b2**2 * b8 - 8 * b4**3 - 27 * b6**2 + 9 * b2 * b4 * b6
|
||||
self._a1 = a1
|
||||
self._a2 = a2
|
||||
self._a3 = a3
|
||||
self._a4 = a4
|
||||
self._a6 = a6
|
||||
x, y, z = symbols('x y z')
|
||||
self.x, self.y, self.z = x, y, z
|
||||
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)
|
||||
if isinstance(self._domain, FiniteField):
|
||||
self._rank = 0
|
||||
elif isinstance(self._domain, RationalField):
|
||||
self._rank = None
|
||||
|
||||
def __call__(self, x, y, z=1):
|
||||
return EllipticCurvePoint(x, y, z, self)
|
||||
|
||||
def __contains__(self, point):
|
||||
if is_sequence(point):
|
||||
if len(point) == 2:
|
||||
z1 = 1
|
||||
else:
|
||||
z1 = point[2]
|
||||
x1, y1 = point[:2]
|
||||
elif isinstance(point, EllipticCurvePoint):
|
||||
x1, y1, z1 = point.x, point.y, point.z
|
||||
else:
|
||||
raise ValueError('Invalid point.')
|
||||
if self.characteristic == 0 and z1 == 0:
|
||||
return True
|
||||
return self._poly.subs({self.x: x1, self.y: y1, self.z: z1}) == 0
|
||||
|
||||
def __repr__(self):
|
||||
return self._poly.__repr__()
|
||||
|
||||
def minimal(self):
|
||||
"""
|
||||
Return minimal Weierstrass equation.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.elliptic_curve import EllipticCurve
|
||||
|
||||
>>> e1 = EllipticCurve(-10, -20, 0, -1, 1)
|
||||
>>> e1.minimal()
|
||||
Poly(-x**3 + 13392*x*z**2 + y**2*z + 1080432*z**3, x, y, z, domain='QQ')
|
||||
|
||||
"""
|
||||
char = self.characteristic
|
||||
if char == 2:
|
||||
return self
|
||||
if char == 3:
|
||||
return EllipticCurve(self._b4/2, self._b6/4, a2=self._b2/4, modulus=self.modulus)
|
||||
c4 = self._b2**2 - 24*self._b4
|
||||
c6 = -self._b2**3 + 36*self._b2*self._b4 - 216*self._b6
|
||||
return EllipticCurve(-27*c4, -54*c6, modulus=self.modulus)
|
||||
|
||||
def points(self):
|
||||
"""
|
||||
Return points of curve over Finite Field.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.elliptic_curve import EllipticCurve
|
||||
>>> e2 = EllipticCurve(1, 1, 1, 1, 1, modulus=5)
|
||||
>>> e2.points()
|
||||
{(0, 2), (1, 4), (2, 0), (2, 2), (3, 0), (3, 1), (4, 0)}
|
||||
|
||||
"""
|
||||
|
||||
char = self.characteristic
|
||||
all_pt = set()
|
||||
if char >= 1:
|
||||
for i in range(char):
|
||||
congruence_eq = self._poly.subs({self.x: i, self.z: 1}).expr
|
||||
sol = polynomial_congruence(congruence_eq, char)
|
||||
all_pt.update((i, num) for num in sol)
|
||||
return all_pt
|
||||
else:
|
||||
raise ValueError("Infinitely many points")
|
||||
|
||||
def points_x(self, x):
|
||||
"""Returns points on the curve for the given x-coordinate."""
|
||||
pt = []
|
||||
if self._domain == QQ:
|
||||
for y in solve(self._poly.subs(self.x, x)):
|
||||
pt.append((x, y))
|
||||
else:
|
||||
congruence_eq = self._poly.subs({self.x: x, self.z: 1}).expr
|
||||
for y in polynomial_congruence(congruence_eq, self.characteristic):
|
||||
pt.append((x, y))
|
||||
return pt
|
||||
|
||||
def torsion_points(self):
|
||||
"""
|
||||
Return torsion points of curve over Rational number.
|
||||
|
||||
Return point objects those are finite order.
|
||||
According to Nagell-Lutz theorem, torsion point p(x, y)
|
||||
x and y are integers, either y = 0 or y**2 is divisor
|
||||
of discriminent. According to Mazur's theorem, there are
|
||||
at most 15 points in torsion collection.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.elliptic_curve import EllipticCurve
|
||||
>>> e2 = EllipticCurve(-43, 166)
|
||||
>>> sorted(e2.torsion_points())
|
||||
[(-5, -16), (-5, 16), O, (3, -8), (3, 8), (11, -32), (11, 32)]
|
||||
|
||||
"""
|
||||
if self.characteristic > 0:
|
||||
raise ValueError("No torsion point for Finite Field.")
|
||||
l = [EllipticCurvePoint.point_at_infinity(self)]
|
||||
for xx in solve(self._poly.subs({self.y: 0, self.z: 1})):
|
||||
if xx.is_rational:
|
||||
l.append(self(xx, 0))
|
||||
for i in divisors(self.discriminant, generator=True):
|
||||
j = int(i**.5)
|
||||
if j**2 == i:
|
||||
for xx in solve(self._poly.subs({self.y: j, self.z: 1})):
|
||||
if not xx.is_rational:
|
||||
continue
|
||||
p = self(xx, j)
|
||||
if p.order() != oo:
|
||||
l.extend([p, -p])
|
||||
return l
|
||||
|
||||
@property
|
||||
def characteristic(self):
|
||||
"""
|
||||
Return domain characteristic.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.elliptic_curve import EllipticCurve
|
||||
>>> e2 = EllipticCurve(-43, 166)
|
||||
>>> e2.characteristic
|
||||
0
|
||||
|
||||
"""
|
||||
return self._domain.characteristic()
|
||||
|
||||
@property
|
||||
def discriminant(self):
|
||||
"""
|
||||
Return curve discriminant.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.elliptic_curve import EllipticCurve
|
||||
>>> e2 = EllipticCurve(0, 17)
|
||||
>>> e2.discriminant
|
||||
-124848
|
||||
|
||||
"""
|
||||
return int(self._discrim)
|
||||
|
||||
@property
|
||||
def is_singular(self):
|
||||
"""
|
||||
Return True if curve discriminant is equal to zero.
|
||||
"""
|
||||
return self.discriminant == 0
|
||||
|
||||
@property
|
||||
def j_invariant(self):
|
||||
"""
|
||||
Return curve j-invariant.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.elliptic_curve import EllipticCurve
|
||||
>>> e1 = EllipticCurve(-2, 0, 0, 1, 1)
|
||||
>>> e1.j_invariant
|
||||
1404928/389
|
||||
|
||||
"""
|
||||
c4 = self._b2**2 - 24*self._b4
|
||||
return self._domain.to_sympy(c4**3 / self._discrim)
|
||||
|
||||
@property
|
||||
def order(self):
|
||||
"""
|
||||
Number of points in Finite field.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.elliptic_curve import EllipticCurve
|
||||
>>> e2 = EllipticCurve(1, 0, modulus=19)
|
||||
>>> e2.order
|
||||
19
|
||||
|
||||
"""
|
||||
if self.characteristic == 0:
|
||||
raise NotImplementedError("Still not implemented")
|
||||
return len(self.points())
|
||||
|
||||
@property
|
||||
def rank(self):
|
||||
"""
|
||||
Number of independent points of infinite order.
|
||||
|
||||
For Finite field, it must be 0.
|
||||
"""
|
||||
if self._rank is not None:
|
||||
return self._rank
|
||||
raise NotImplementedError("Still not implemented")
|
||||
|
||||
|
||||
class EllipticCurvePoint:
|
||||
"""
|
||||
Point of Elliptic Curve
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.elliptic_curve import EllipticCurve
|
||||
>>> e1 = EllipticCurve(-17, 16)
|
||||
>>> p1 = e1(0, -4, 1)
|
||||
>>> p2 = e1(1, 0)
|
||||
>>> p1 + p2
|
||||
(15, -56)
|
||||
>>> e3 = EllipticCurve(-1, 9)
|
||||
>>> e3(1, -3) * 3
|
||||
(664/169, 17811/2197)
|
||||
>>> (e3(1, -3) * 3).order()
|
||||
oo
|
||||
>>> e2 = EllipticCurve(-2, 0, 0, 1, 1)
|
||||
>>> p = e2(-1,1)
|
||||
>>> q = e2(0, -1)
|
||||
>>> p+q
|
||||
(4, 8)
|
||||
>>> p-q
|
||||
(1, 0)
|
||||
>>> 3*p-5*q
|
||||
(328/361, -2800/6859)
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def point_at_infinity(curve):
|
||||
return EllipticCurvePoint(0, 1, 0, curve)
|
||||
|
||||
def __init__(self, x, y, z, curve):
|
||||
dom = curve._domain.convert
|
||||
self.x = dom(x)
|
||||
self.y = dom(y)
|
||||
self.z = dom(z)
|
||||
self._curve = curve
|
||||
self._domain = self._curve._domain
|
||||
if not self._curve.__contains__(self):
|
||||
raise ValueError("The curve does not contain this point")
|
||||
|
||||
def __add__(self, p):
|
||||
if self.z == 0:
|
||||
return p
|
||||
if p.z == 0:
|
||||
return self
|
||||
x1, y1 = self.x/self.z, self.y/self.z
|
||||
x2, y2 = p.x/p.z, p.y/p.z
|
||||
a1 = self._curve._a1
|
||||
a2 = self._curve._a2
|
||||
a3 = self._curve._a3
|
||||
a4 = self._curve._a4
|
||||
a6 = self._curve._a6
|
||||
if x1 != x2:
|
||||
slope = (y1 - y2) / (x1 - x2)
|
||||
yint = (y1 * x2 - y2 * x1) / (x2 - x1)
|
||||
else:
|
||||
if (y1 + y2) == 0:
|
||||
return self.point_at_infinity(self._curve)
|
||||
slope = (3 * x1**2 + 2*a2*x1 + a4 - a1*y1) / (a1 * x1 + a3 + 2 * y1)
|
||||
yint = (-x1**3 + a4*x1 + 2*a6 - a3*y1) / (a1*x1 + a3 + 2*y1)
|
||||
x3 = slope**2 + a1*slope - a2 - x1 - x2
|
||||
y3 = -(slope + a1) * x3 - yint - a3
|
||||
return self._curve(x3, y3, 1)
|
||||
|
||||
def __lt__(self, other):
|
||||
return (self.x, self.y, self.z) < (other.x, other.y, other.z)
|
||||
|
||||
def __mul__(self, n):
|
||||
n = as_int(n)
|
||||
r = self.point_at_infinity(self._curve)
|
||||
if n == 0:
|
||||
return r
|
||||
if n < 0:
|
||||
return -self * -n
|
||||
p = self
|
||||
while n:
|
||||
if n & 1:
|
||||
r = r + p
|
||||
n >>= 1
|
||||
p = p + p
|
||||
return r
|
||||
|
||||
def __rmul__(self, n):
|
||||
return self * n
|
||||
|
||||
def __neg__(self):
|
||||
return EllipticCurvePoint(self.x, -self.y - self._curve._a1*self.x - self._curve._a3, self.z, self._curve)
|
||||
|
||||
def __repr__(self):
|
||||
if self.z == 0:
|
||||
return 'O'
|
||||
dom = self._curve._domain
|
||||
try:
|
||||
return '({}, {})'.format(dom.to_sympy(self.x), dom.to_sympy(self.y))
|
||||
except TypeError:
|
||||
pass
|
||||
return '({}, {})'.format(self.x, self.y)
|
||||
|
||||
def __sub__(self, other):
|
||||
return self.__add__(-other)
|
||||
|
||||
def order(self):
|
||||
"""
|
||||
Return point order n where nP = 0.
|
||||
|
||||
"""
|
||||
if self.z == 0:
|
||||
return 1
|
||||
if self.y == 0: # P = -P
|
||||
return 2
|
||||
p = self * 2
|
||||
if p.y == -self.y: # 2P = -P
|
||||
return 3
|
||||
i = 2
|
||||
if self._domain != QQ:
|
||||
while int(p.x) == p.x and int(p.y) == p.y:
|
||||
p = self + p
|
||||
i += 1
|
||||
if p.z == 0:
|
||||
return i
|
||||
return oo
|
||||
while p.x.numerator == p.x and p.y.numerator == p.y:
|
||||
p = self + p
|
||||
i += 1
|
||||
if i > 12:
|
||||
return oo
|
||||
if p.z == 0:
|
||||
return i
|
||||
return oo
|
||||
2841
venv/lib/python3.12/site-packages/sympy/ntheory/factor_.py
Normal file
2841
venv/lib/python3.12/site-packages/sympy/ntheory/factor_.py
Normal file
File diff suppressed because it is too large
Load Diff
1157
venv/lib/python3.12/site-packages/sympy/ntheory/generate.py
Normal file
1157
venv/lib/python3.12/site-packages/sympy/ntheory/generate.py
Normal file
File diff suppressed because it is too large
Load Diff
291
venv/lib/python3.12/site-packages/sympy/ntheory/modular.py
Normal file
291
venv/lib/python3.12/site-packages/sympy/ntheory/modular.py
Normal file
@@ -0,0 +1,291 @@
|
||||
from math import prod
|
||||
|
||||
from sympy.external.gmpy import gcd, gcdext
|
||||
from sympy.ntheory.primetest import isprime
|
||||
from sympy.polys.domains import ZZ
|
||||
from sympy.polys.galoistools import gf_crt, gf_crt1, gf_crt2
|
||||
from sympy.utilities.misc import as_int
|
||||
|
||||
|
||||
def symmetric_residue(a, m):
|
||||
"""Return the residual mod m such that it is within half of the modulus.
|
||||
|
||||
>>> from sympy.ntheory.modular import symmetric_residue
|
||||
>>> symmetric_residue(1, 6)
|
||||
1
|
||||
>>> symmetric_residue(4, 6)
|
||||
-2
|
||||
"""
|
||||
if a <= m // 2:
|
||||
return a
|
||||
return a - m
|
||||
|
||||
|
||||
def crt(m, v, symmetric=False, check=True):
|
||||
r"""Chinese Remainder Theorem.
|
||||
|
||||
The moduli in m are assumed to be pairwise coprime. The output
|
||||
is then an integer f, such that f = v_i mod m_i for each pair out
|
||||
of v and m. If ``symmetric`` is False a positive integer will be
|
||||
returned, else \|f\| will be less than or equal to the LCM of the
|
||||
moduli, and thus f may be negative.
|
||||
|
||||
If the moduli are not co-prime the correct result will be returned
|
||||
if/when the test of the result is found to be incorrect. This result
|
||||
will be None if there is no solution.
|
||||
|
||||
The keyword ``check`` can be set to False if it is known that the moduli
|
||||
are coprime.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
As an example consider a set of residues ``U = [49, 76, 65]``
|
||||
and a set of moduli ``M = [99, 97, 95]``. Then we have::
|
||||
|
||||
>>> from sympy.ntheory.modular import crt
|
||||
|
||||
>>> crt([99, 97, 95], [49, 76, 65])
|
||||
(639985, 912285)
|
||||
|
||||
This is the correct result because::
|
||||
|
||||
>>> [639985 % m for m in [99, 97, 95]]
|
||||
[49, 76, 65]
|
||||
|
||||
If the moduli are not co-prime, you may receive an incorrect result
|
||||
if you use ``check=False``:
|
||||
|
||||
>>> crt([12, 6, 17], [3, 4, 2], check=False)
|
||||
(954, 1224)
|
||||
>>> [954 % m for m in [12, 6, 17]]
|
||||
[6, 0, 2]
|
||||
>>> crt([12, 6, 17], [3, 4, 2]) is None
|
||||
True
|
||||
>>> crt([3, 6], [2, 5])
|
||||
(5, 6)
|
||||
|
||||
Note: the order of gf_crt's arguments is reversed relative to crt,
|
||||
and that solve_congruence takes residue, modulus pairs.
|
||||
|
||||
Programmer's note: rather than checking that all pairs of moduli share
|
||||
no GCD (an O(n**2) test) and rather than factoring all moduli and seeing
|
||||
that there is no factor in common, a check that the result gives the
|
||||
indicated residuals is performed -- an O(n) operation.
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
solve_congruence
|
||||
sympy.polys.galoistools.gf_crt : low level crt routine used by this routine
|
||||
"""
|
||||
if check:
|
||||
m = list(map(as_int, m))
|
||||
v = list(map(as_int, v))
|
||||
|
||||
result = gf_crt(v, m, ZZ)
|
||||
mm = prod(m)
|
||||
|
||||
if check:
|
||||
if not all(v % m == result % m for v, m in zip(v, m)):
|
||||
result = solve_congruence(*list(zip(v, m)),
|
||||
check=False, symmetric=symmetric)
|
||||
if result is None:
|
||||
return result
|
||||
result, mm = result
|
||||
|
||||
if symmetric:
|
||||
return int(symmetric_residue(result, mm)), int(mm)
|
||||
return int(result), int(mm)
|
||||
|
||||
|
||||
def crt1(m):
|
||||
"""First part of Chinese Remainder Theorem, for multiple application.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.modular import crt, crt1, crt2
|
||||
>>> m = [99, 97, 95]
|
||||
>>> v = [49, 76, 65]
|
||||
|
||||
The following two codes have the same result.
|
||||
|
||||
>>> crt(m, v)
|
||||
(639985, 912285)
|
||||
|
||||
>>> mm, e, s = crt1(m)
|
||||
>>> crt2(m, v, mm, e, s)
|
||||
(639985, 912285)
|
||||
|
||||
However, it is faster when we want to fix ``m`` and
|
||||
compute for multiple ``v``, i.e. the following cases:
|
||||
|
||||
>>> mm, e, s = crt1(m)
|
||||
>>> vs = [[52, 21, 37], [19, 46, 76]]
|
||||
>>> for v in vs:
|
||||
... print(crt2(m, v, mm, e, s))
|
||||
(397042, 912285)
|
||||
(803206, 912285)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.polys.galoistools.gf_crt1 : low level crt routine used by this routine
|
||||
sympy.ntheory.modular.crt
|
||||
sympy.ntheory.modular.crt2
|
||||
|
||||
"""
|
||||
|
||||
return gf_crt1(m, ZZ)
|
||||
|
||||
|
||||
def crt2(m, v, mm, e, s, symmetric=False):
|
||||
"""Second part of Chinese Remainder Theorem, for multiple application.
|
||||
|
||||
See ``crt1`` for usage.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.modular import crt1, crt2
|
||||
>>> mm, e, s = crt1([18, 42, 6])
|
||||
>>> crt2([18, 42, 6], [0, 0, 0], mm, e, s)
|
||||
(0, 4536)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.polys.galoistools.gf_crt2 : low level crt routine used by this routine
|
||||
sympy.ntheory.modular.crt
|
||||
sympy.ntheory.modular.crt1
|
||||
|
||||
"""
|
||||
|
||||
result = gf_crt2(v, m, mm, e, s, ZZ)
|
||||
|
||||
if symmetric:
|
||||
return int(symmetric_residue(result, mm)), int(mm)
|
||||
return int(result), int(mm)
|
||||
|
||||
|
||||
def solve_congruence(*remainder_modulus_pairs, **hint):
|
||||
"""Compute the integer ``n`` that has the residual ``ai`` when it is
|
||||
divided by ``mi`` where the ``ai`` and ``mi`` are given as pairs to
|
||||
this function: ((a1, m1), (a2, m2), ...). If there is no solution,
|
||||
return None. Otherwise return ``n`` and its modulus.
|
||||
|
||||
The ``mi`` values need not be co-prime. If it is known that the moduli are
|
||||
not co-prime then the hint ``check`` can be set to False (default=True) and
|
||||
the check for a quicker solution via crt() (valid when the moduli are
|
||||
co-prime) will be skipped.
|
||||
|
||||
If the hint ``symmetric`` is True (default is False), the value of ``n``
|
||||
will be within 1/2 of the modulus, possibly negative.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.modular import solve_congruence
|
||||
|
||||
What number is 2 mod 3, 3 mod 5 and 2 mod 7?
|
||||
|
||||
>>> solve_congruence((2, 3), (3, 5), (2, 7))
|
||||
(23, 105)
|
||||
>>> [23 % m for m in [3, 5, 7]]
|
||||
[2, 3, 2]
|
||||
|
||||
If you prefer to work with all remainder in one list and
|
||||
all moduli in another, send the arguments like this:
|
||||
|
||||
>>> solve_congruence(*zip((2, 3, 2), (3, 5, 7)))
|
||||
(23, 105)
|
||||
|
||||
The moduli need not be co-prime; in this case there may or
|
||||
may not be a solution:
|
||||
|
||||
>>> solve_congruence((2, 3), (4, 6)) is None
|
||||
True
|
||||
|
||||
>>> solve_congruence((2, 3), (5, 6))
|
||||
(5, 6)
|
||||
|
||||
The symmetric flag will make the result be within 1/2 of the modulus:
|
||||
|
||||
>>> solve_congruence((2, 3), (5, 6), symmetric=True)
|
||||
(-1, 6)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
crt : high level routine implementing the Chinese Remainder Theorem
|
||||
|
||||
"""
|
||||
def combine(c1, c2):
|
||||
"""Return the tuple (a, m) which satisfies the requirement
|
||||
that n = a + i*m satisfy n = a1 + j*m1 and n = a2 = k*m2.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Method_of_successive_substitution
|
||||
"""
|
||||
a1, m1 = c1
|
||||
a2, m2 = c2
|
||||
a, b, c = m1, a2 - a1, m2
|
||||
g = gcd(a, b, c)
|
||||
a, b, c = [i//g for i in [a, b, c]]
|
||||
if a != 1:
|
||||
g, inv_a, _ = gcdext(a, c)
|
||||
if g != 1:
|
||||
return None
|
||||
b *= inv_a
|
||||
a, m = a1 + m1*b, m1*c
|
||||
return a, m
|
||||
|
||||
rm = remainder_modulus_pairs
|
||||
symmetric = hint.get('symmetric', False)
|
||||
|
||||
if hint.get('check', True):
|
||||
rm = [(as_int(r), as_int(m)) for r, m in rm]
|
||||
|
||||
# ignore redundant pairs but raise an error otherwise; also
|
||||
# make sure that a unique set of bases is sent to gf_crt if
|
||||
# they are all prime.
|
||||
#
|
||||
# The routine will work out less-trivial violations and
|
||||
# return None, e.g. for the pairs (1,3) and (14,42) there
|
||||
# is no answer because 14 mod 42 (having a gcd of 14) implies
|
||||
# (14/2) mod (42/2), (14/7) mod (42/7) and (14/14) mod (42/14)
|
||||
# which, being 0 mod 3, is inconsistent with 1 mod 3. But to
|
||||
# preprocess the input beyond checking of another pair with 42
|
||||
# or 3 as the modulus (for this example) is not necessary.
|
||||
uniq = {}
|
||||
for r, m in rm:
|
||||
r %= m
|
||||
if m in uniq:
|
||||
if r != uniq[m]:
|
||||
return None
|
||||
continue
|
||||
uniq[m] = r
|
||||
rm = [(r, m) for m, r in uniq.items()]
|
||||
del uniq
|
||||
|
||||
# if the moduli are co-prime, the crt will be significantly faster;
|
||||
# checking all pairs for being co-prime gets to be slow but a prime
|
||||
# test is a good trade-off
|
||||
if all(isprime(m) for r, m in rm):
|
||||
r, m = list(zip(*rm))
|
||||
return crt(m, r, symmetric=symmetric, check=False)
|
||||
|
||||
rv = (0, 1)
|
||||
for rmi in rm:
|
||||
rv = combine(rv, rmi)
|
||||
if rv is None:
|
||||
break
|
||||
n, m = rv
|
||||
n = n % m
|
||||
else:
|
||||
if symmetric:
|
||||
return symmetric_residue(n, m), m
|
||||
return n, m
|
||||
188
venv/lib/python3.12/site-packages/sympy/ntheory/multinomial.py
Normal file
188
venv/lib/python3.12/site-packages/sympy/ntheory/multinomial.py
Normal file
@@ -0,0 +1,188 @@
|
||||
from sympy.utilities.misc import as_int
|
||||
|
||||
|
||||
def binomial_coefficients(n):
|
||||
"""Return a dictionary containing pairs :math:`{(k1,k2) : C_kn}` where
|
||||
:math:`C_kn` are binomial coefficients and :math:`n=k1+k2`.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory import binomial_coefficients
|
||||
>>> binomial_coefficients(9)
|
||||
{(0, 9): 1, (1, 8): 9, (2, 7): 36, (3, 6): 84,
|
||||
(4, 5): 126, (5, 4): 126, (6, 3): 84, (7, 2): 36, (8, 1): 9, (9, 0): 1}
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
binomial_coefficients_list, multinomial_coefficients
|
||||
"""
|
||||
n = as_int(n)
|
||||
d = {(0, n): 1, (n, 0): 1}
|
||||
a = 1
|
||||
for k in range(1, n//2 + 1):
|
||||
a = (a * (n - k + 1))//k
|
||||
d[k, n - k] = d[n - k, k] = a
|
||||
return d
|
||||
|
||||
|
||||
def binomial_coefficients_list(n):
|
||||
""" Return a list of binomial coefficients as rows of the Pascal's
|
||||
triangle.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory import binomial_coefficients_list
|
||||
>>> binomial_coefficients_list(9)
|
||||
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
binomial_coefficients, multinomial_coefficients
|
||||
"""
|
||||
n = as_int(n)
|
||||
d = [1] * (n + 1)
|
||||
a = 1
|
||||
for k in range(1, n//2 + 1):
|
||||
a = (a * (n - k + 1))//k
|
||||
d[k] = d[n - k] = a
|
||||
return d
|
||||
|
||||
|
||||
def multinomial_coefficients(m, n):
|
||||
r"""Return a dictionary containing pairs ``{(k1,k2,..,km) : C_kn}``
|
||||
where ``C_kn`` are multinomial coefficients such that
|
||||
``n=k1+k2+..+km``.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory import multinomial_coefficients
|
||||
>>> multinomial_coefficients(2, 5) # indirect doctest
|
||||
{(0, 5): 1, (1, 4): 5, (2, 3): 10, (3, 2): 10, (4, 1): 5, (5, 0): 1}
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
The algorithm is based on the following result:
|
||||
|
||||
.. math::
|
||||
\binom{n}{k_1, \ldots, k_m} =
|
||||
\frac{k_1 + 1}{n - k_1} \sum_{i=2}^m \binom{n}{k_1 + 1, \ldots, k_i - 1, \ldots}
|
||||
|
||||
Code contributed to Sage by Yann Laigle-Chapuy, copied with permission
|
||||
of the author.
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
binomial_coefficients_list, binomial_coefficients
|
||||
"""
|
||||
m = as_int(m)
|
||||
n = as_int(n)
|
||||
if not m:
|
||||
if n:
|
||||
return {}
|
||||
return {(): 1}
|
||||
if m == 2:
|
||||
return binomial_coefficients(n)
|
||||
if m >= 2*n and n > 1:
|
||||
return dict(multinomial_coefficients_iterator(m, n))
|
||||
t = [n] + [0] * (m - 1)
|
||||
r = {tuple(t): 1}
|
||||
if n:
|
||||
j = 0 # j will be the leftmost nonzero position
|
||||
else:
|
||||
j = m
|
||||
# enumerate tuples in co-lex order
|
||||
while j < m - 1:
|
||||
# compute next tuple
|
||||
tj = t[j]
|
||||
if j:
|
||||
t[j] = 0
|
||||
t[0] = tj
|
||||
if tj > 1:
|
||||
t[j + 1] += 1
|
||||
j = 0
|
||||
start = 1
|
||||
v = 0
|
||||
else:
|
||||
j += 1
|
||||
start = j + 1
|
||||
v = r[tuple(t)]
|
||||
t[j] += 1
|
||||
# compute the value
|
||||
# NB: the initialization of v was done above
|
||||
for k in range(start, m):
|
||||
if t[k]:
|
||||
t[k] -= 1
|
||||
v += r[tuple(t)]
|
||||
t[k] += 1
|
||||
t[0] -= 1
|
||||
r[tuple(t)] = (v * tj) // (n - t[0])
|
||||
return r
|
||||
|
||||
|
||||
def multinomial_coefficients_iterator(m, n, _tuple=tuple):
|
||||
"""multinomial coefficient iterator
|
||||
|
||||
This routine has been optimized for `m` large with respect to `n` by taking
|
||||
advantage of the fact that when the monomial tuples `t` are stripped of
|
||||
zeros, their coefficient is the same as that of the monomial tuples from
|
||||
``multinomial_coefficients(n, n)``. Therefore, the latter coefficients are
|
||||
precomputed to save memory and time.
|
||||
|
||||
>>> from sympy.ntheory.multinomial import multinomial_coefficients
|
||||
>>> m53, m33 = multinomial_coefficients(5,3), multinomial_coefficients(3,3)
|
||||
>>> m53[(0,0,0,1,2)] == m53[(0,0,1,0,2)] == m53[(1,0,2,0,0)] == m33[(0,1,2)]
|
||||
True
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.multinomial import multinomial_coefficients_iterator
|
||||
>>> it = multinomial_coefficients_iterator(20,3)
|
||||
>>> next(it)
|
||||
((3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 1)
|
||||
"""
|
||||
m = as_int(m)
|
||||
n = as_int(n)
|
||||
if m < 2*n or n == 1:
|
||||
mc = multinomial_coefficients(m, n)
|
||||
yield from mc.items()
|
||||
else:
|
||||
mc = multinomial_coefficients(n, n)
|
||||
mc1 = {}
|
||||
for k, v in mc.items():
|
||||
mc1[_tuple(filter(None, k))] = v
|
||||
mc = mc1
|
||||
|
||||
t = [n] + [0] * (m - 1)
|
||||
t1 = _tuple(t)
|
||||
b = _tuple(filter(None, t1))
|
||||
yield (t1, mc[b])
|
||||
if n:
|
||||
j = 0 # j will be the leftmost nonzero position
|
||||
else:
|
||||
j = m
|
||||
# enumerate tuples in co-lex order
|
||||
while j < m - 1:
|
||||
# compute next tuple
|
||||
tj = t[j]
|
||||
if j:
|
||||
t[j] = 0
|
||||
t[0] = tj
|
||||
if tj > 1:
|
||||
t[j + 1] += 1
|
||||
j = 0
|
||||
else:
|
||||
j += 1
|
||||
t[j] += 1
|
||||
|
||||
t[0] -= 1
|
||||
t1 = _tuple(t)
|
||||
b = _tuple(filter(None, t1))
|
||||
yield (t1, mc[b])
|
||||
277
venv/lib/python3.12/site-packages/sympy/ntheory/partitions_.py
Normal file
277
venv/lib/python3.12/site-packages/sympy/ntheory/partitions_.py
Normal file
@@ -0,0 +1,277 @@
|
||||
from mpmath.libmp import (fzero, from_int, from_rational,
|
||||
fone, fhalf, bitcount, to_int, mpf_mul, mpf_div, mpf_sub,
|
||||
mpf_add, mpf_sqrt, mpf_pi, mpf_cosh_sinh, mpf_cos, mpf_sin)
|
||||
from .residue_ntheory import _sqrt_mod_prime_power, is_quad_residue
|
||||
from sympy.utilities.decorator import deprecated
|
||||
from sympy.utilities.memoization import recurrence_memo
|
||||
|
||||
import math
|
||||
from itertools import count
|
||||
|
||||
def _pre():
|
||||
maxn = 10**5
|
||||
global _factor, _totient
|
||||
_factor = [0]*maxn
|
||||
_totient = [1]*maxn
|
||||
lim = int(maxn**0.5) + 5
|
||||
for i in range(2, lim):
|
||||
if _factor[i] == 0:
|
||||
for j in range(i*i, maxn, i):
|
||||
if _factor[j] == 0:
|
||||
_factor[j] = i
|
||||
for i in range(2, maxn):
|
||||
if _factor[i] == 0:
|
||||
_factor[i] = i
|
||||
_totient[i] = i-1
|
||||
continue
|
||||
x = _factor[i]
|
||||
y = i//x
|
||||
if y % x == 0:
|
||||
_totient[i] = _totient[y]*x
|
||||
else:
|
||||
_totient[i] = _totient[y]*(x - 1)
|
||||
|
||||
def _a(n, k, prec):
|
||||
""" Compute the inner sum in HRR formula [1]_
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://msp.org/pjm/1956/6-1/pjm-v6-n1-p18-p.pdf
|
||||
|
||||
"""
|
||||
if k == 1:
|
||||
return fone
|
||||
|
||||
k1 = k
|
||||
e = 0
|
||||
p = _factor[k]
|
||||
while k1 % p == 0:
|
||||
k1 //= p
|
||||
e += 1
|
||||
k2 = k//k1 # k2 = p^e
|
||||
v = 1 - 24*n
|
||||
pi = mpf_pi(prec)
|
||||
|
||||
if k1 == 1:
|
||||
# k = p^e
|
||||
if p == 2:
|
||||
mod = 8*k
|
||||
v = mod + v % mod
|
||||
v = (v*pow(9, k - 1, mod)) % mod
|
||||
m = _sqrt_mod_prime_power(v, 2, e + 3)[0]
|
||||
arg = mpf_div(mpf_mul(
|
||||
from_int(4*m), pi, prec), from_int(mod), prec)
|
||||
return mpf_mul(mpf_mul(
|
||||
from_int((-1)**e*(2 - (m % 4))),
|
||||
mpf_sqrt(from_int(k), prec), prec),
|
||||
mpf_sin(arg, prec), prec)
|
||||
if p == 3:
|
||||
mod = 3*k
|
||||
v = mod + v % mod
|
||||
if e > 1:
|
||||
v = (v*pow(64, k//3 - 1, mod)) % mod
|
||||
m = _sqrt_mod_prime_power(v, 3, e + 1)[0]
|
||||
arg = mpf_div(mpf_mul(from_int(4*m), pi, prec),
|
||||
from_int(mod), prec)
|
||||
return mpf_mul(mpf_mul(
|
||||
from_int(2*(-1)**(e + 1)*(3 - 2*(m % 3))),
|
||||
mpf_sqrt(from_int(k//3), prec), prec),
|
||||
mpf_sin(arg, prec), prec)
|
||||
v = k + v % k
|
||||
jacobi3 = -1 if k % 12 in [5, 7] else 1
|
||||
if v % p == 0:
|
||||
if e == 1:
|
||||
return mpf_mul(
|
||||
from_int(jacobi3),
|
||||
mpf_sqrt(from_int(k), prec), prec)
|
||||
return fzero
|
||||
if not is_quad_residue(v, p):
|
||||
return fzero
|
||||
_phi = p**(e - 1)*(p - 1)
|
||||
v = (v*pow(576, _phi - 1, k))
|
||||
m = _sqrt_mod_prime_power(v, p, e)[0]
|
||||
arg = mpf_div(
|
||||
mpf_mul(from_int(4*m), pi, prec),
|
||||
from_int(k), prec)
|
||||
return mpf_mul(mpf_mul(
|
||||
from_int(2*jacobi3),
|
||||
mpf_sqrt(from_int(k), prec), prec),
|
||||
mpf_cos(arg, prec), prec)
|
||||
|
||||
if p != 2 or e >= 3:
|
||||
d1, d2 = math.gcd(k1, 24), math.gcd(k2, 24)
|
||||
e = 24//(d1*d2)
|
||||
n1 = ((d2*e*n + (k2**2 - 1)//d1)*
|
||||
pow(e*k2*k2*d2, _totient[k1] - 1, k1)) % k1
|
||||
n2 = ((d1*e*n + (k1**2 - 1)//d2)*
|
||||
pow(e*k1*k1*d1, _totient[k2] - 1, k2)) % k2
|
||||
return mpf_mul(_a(n1, k1, prec), _a(n2, k2, prec), prec)
|
||||
if e == 2:
|
||||
n1 = ((8*n + 5)*pow(128, _totient[k1] - 1, k1)) % k1
|
||||
n2 = (4 + ((n - 2 - (k1**2 - 1)//8)*(k1**2)) % 4) % 4
|
||||
return mpf_mul(mpf_mul(
|
||||
from_int(-1),
|
||||
_a(n1, k1, prec), prec),
|
||||
_a(n2, k2, prec))
|
||||
n1 = ((8*n + 1)*pow(32, _totient[k1] - 1, k1)) % k1
|
||||
n2 = (2 + (n - (k1**2 - 1)//8) % 2) % 2
|
||||
return mpf_mul(_a(n1, k1, prec), _a(n2, k2, prec), prec)
|
||||
|
||||
def _d(n, j, prec, sq23pi, sqrt8):
|
||||
"""
|
||||
Compute the sinh term in the outer sum of the HRR formula.
|
||||
The constants sqrt(2/3*pi) and sqrt(8) must be precomputed.
|
||||
"""
|
||||
j = from_int(j)
|
||||
pi = mpf_pi(prec)
|
||||
a = mpf_div(sq23pi, j, prec)
|
||||
b = mpf_sub(from_int(n), from_rational(1, 24, prec), prec)
|
||||
c = mpf_sqrt(b, prec)
|
||||
ch, sh = mpf_cosh_sinh(mpf_mul(a, c), prec)
|
||||
D = mpf_div(
|
||||
mpf_sqrt(j, prec),
|
||||
mpf_mul(mpf_mul(sqrt8, b), pi), prec)
|
||||
E = mpf_sub(mpf_mul(a, ch), mpf_div(sh, c, prec), prec)
|
||||
return mpf_mul(D, E)
|
||||
|
||||
|
||||
@recurrence_memo([1, 1])
|
||||
def _partition_rec(n: int, prev) -> int:
|
||||
""" Calculate the partition function P(n)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n : int
|
||||
nonnegative integer
|
||||
|
||||
"""
|
||||
v = 0
|
||||
penta = 0 # pentagonal number: 1, 5, 12, ...
|
||||
for i in count():
|
||||
penta += 3*i + 1
|
||||
np = n - penta
|
||||
if np < 0:
|
||||
break
|
||||
s = prev[np]
|
||||
np -= i + 1
|
||||
# np = n - gp where gp = generalized pentagonal: 2, 7, 15, ...
|
||||
if 0 <= np:
|
||||
s += prev[np]
|
||||
v += -s if i % 2 else s
|
||||
return v
|
||||
|
||||
|
||||
def _partition(n: int) -> int:
|
||||
""" Calculate the partition function P(n)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n : int
|
||||
|
||||
"""
|
||||
if n < 0:
|
||||
return 0
|
||||
if (n <= 200_000 and n - _partition_rec.cache_length() < 70 or
|
||||
_partition_rec.cache_length() == 2 and n < 14_400):
|
||||
# There will be 2*10**5 elements created here
|
||||
# and n elements created by partition, so in case we
|
||||
# are going to be working with small n, we just
|
||||
# use partition to calculate (and cache) the values
|
||||
# since lookup is used there while summation, using
|
||||
# _factor and _totient, will be used below. But we
|
||||
# only do so if n is relatively close to the length
|
||||
# of the cache since doing 1 calculation here is about
|
||||
# the same as adding 70 elements to the cache. In addition,
|
||||
# the startup here costs about the same as calculating the first
|
||||
# 14,400 values via partition, so we delay startup here unless n
|
||||
# is smaller than that.
|
||||
return _partition_rec(n)
|
||||
if '_factor' not in globals():
|
||||
_pre()
|
||||
# Estimate number of bits in p(n). This formula could be tidied
|
||||
pbits = int((
|
||||
math.pi*(2*n/3.)**0.5 -
|
||||
math.log(4*n))/math.log(10) + 1) * \
|
||||
math.log2(10)
|
||||
prec = p = int(pbits*1.1 + 100)
|
||||
|
||||
# find the number of terms needed so rounded sum will be accurate
|
||||
# using Rademacher's bound M(n, N) for the remainder after a partial
|
||||
# sum of N terms (https://arxiv.org/pdf/1205.5991.pdf, (1.8))
|
||||
c1 = 44*math.pi**2/(225*math.sqrt(3))
|
||||
c2 = math.pi*math.sqrt(2)/75
|
||||
c3 = math.pi*math.sqrt(2/3)
|
||||
def _M(n, N):
|
||||
sqrt = math.sqrt
|
||||
return c1/sqrt(N) + c2*sqrt(N/(n - 1))*math.sinh(c3*sqrt(n)/N)
|
||||
big = max(9, math.ceil(n**0.5)) # should be too large (for n > 65, ceil should work)
|
||||
assert _M(n, big) < 0.5 # else double big until too large
|
||||
while big > 40 and _M(n, big) < 0.5:
|
||||
big //= 2
|
||||
small = big
|
||||
big = small*2
|
||||
while big - small > 1:
|
||||
N = (big + small)//2
|
||||
if (er := _M(n, N)) < 0.5:
|
||||
big = N
|
||||
elif er >= 0.5:
|
||||
small = N
|
||||
M = big # done with function M; now have value
|
||||
|
||||
# sanity check for expected size of answer
|
||||
if M > 10**5: # i.e. M > maxn
|
||||
raise ValueError("Input too big") # i.e. n > 149832547102
|
||||
|
||||
# calculate it
|
||||
s = fzero
|
||||
sq23pi = mpf_mul(mpf_sqrt(from_rational(2, 3, p), p), mpf_pi(p), p)
|
||||
sqrt8 = mpf_sqrt(from_int(8), p)
|
||||
for q in range(1, M):
|
||||
a = _a(n, q, p)
|
||||
d = _d(n, q, p, sq23pi, sqrt8)
|
||||
s = mpf_add(s, mpf_mul(a, d), prec)
|
||||
# On average, the terms decrease rapidly in magnitude.
|
||||
# Dynamically reducing the precision greatly improves
|
||||
# performance.
|
||||
p = bitcount(abs(to_int(d))) + 50
|
||||
return int(to_int(mpf_add(s, fhalf, prec)))
|
||||
|
||||
|
||||
@deprecated("""\
|
||||
The `sympy.ntheory.partitions_.npartitions` has been moved to `sympy.functions.combinatorial.numbers.partition`.""",
|
||||
deprecated_since_version="1.13",
|
||||
active_deprecations_target='deprecated-ntheory-symbolic-functions')
|
||||
def npartitions(n, verbose=False):
|
||||
"""
|
||||
Calculate the partition function P(n), i.e. the number of ways that
|
||||
n can be written as a sum of positive integers.
|
||||
|
||||
.. deprecated:: 1.13
|
||||
|
||||
The ``npartitions`` function is deprecated. Use :class:`sympy.functions.combinatorial.numbers.partition`
|
||||
instead. See its documentation for more information. See
|
||||
:ref:`deprecated-ntheory-symbolic-functions` for details.
|
||||
|
||||
P(n) is computed using the Hardy-Ramanujan-Rademacher formula [1]_.
|
||||
|
||||
|
||||
The correctness of this implementation has been tested through $10^{10}$.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.functions.combinatorial.numbers import partition
|
||||
>>> partition(25)
|
||||
1958
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://mathworld.wolfram.com/PartitionFunctionP.html
|
||||
|
||||
"""
|
||||
from sympy.functions.combinatorial.numbers import partition as func_partition
|
||||
return func_partition(n)
|
||||
830
venv/lib/python3.12/site-packages/sympy/ntheory/primetest.py
Normal file
830
venv/lib/python3.12/site-packages/sympy/ntheory/primetest.py
Normal file
@@ -0,0 +1,830 @@
|
||||
"""
|
||||
Primality testing
|
||||
|
||||
"""
|
||||
|
||||
from itertools import count
|
||||
|
||||
from sympy.core.sympify import sympify
|
||||
from sympy.external.gmpy import (gmpy as _gmpy, gcd, jacobi,
|
||||
is_square as gmpy_is_square,
|
||||
bit_scan1, is_fermat_prp, is_euler_prp,
|
||||
is_selfridge_prp, is_strong_selfridge_prp,
|
||||
is_strong_bpsw_prp)
|
||||
from sympy.external.ntheory import _lucas_sequence
|
||||
from sympy.utilities.misc import as_int, filldedent
|
||||
|
||||
# Note: This list should be updated whenever new Mersenne primes are found.
|
||||
# Refer: https://www.mersenne.org/
|
||||
MERSENNE_PRIME_EXPONENTS = (2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203,
|
||||
2281, 3217, 4253, 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497, 86243, 110503, 132049,
|
||||
216091, 756839, 859433, 1257787, 1398269, 2976221, 3021377, 6972593, 13466917, 20996011, 24036583,
|
||||
25964951, 30402457, 32582657, 37156667, 42643801, 43112609, 57885161, 74207281, 77232917, 82589933,
|
||||
136279841)
|
||||
|
||||
|
||||
def is_fermat_pseudoprime(n, a):
|
||||
r"""Returns True if ``n`` is prime or is an odd composite integer that
|
||||
is coprime to ``a`` and satisfy the modular arithmetic congruence relation:
|
||||
|
||||
.. math ::
|
||||
a^{n-1} \equiv 1 \pmod{n}
|
||||
|
||||
(where mod refers to the modulo operation).
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n : Integer
|
||||
``n`` is a positive integer.
|
||||
a : Integer
|
||||
``a`` is a positive integer.
|
||||
``a`` and ``n`` should be relatively prime.
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
bool : If ``n`` is prime, it always returns ``True``.
|
||||
The composite number that returns ``True`` is called an Fermat pseudoprime.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.primetest import is_fermat_pseudoprime
|
||||
>>> from sympy.ntheory.factor_ import isprime
|
||||
>>> for n in range(1, 1000):
|
||||
... if is_fermat_pseudoprime(n, 2) and not isprime(n):
|
||||
... print(n)
|
||||
341
|
||||
561
|
||||
645
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Fermat_pseudoprime
|
||||
"""
|
||||
n, a = as_int(n), as_int(a)
|
||||
if a == 1:
|
||||
return n == 2 or bool(n % 2)
|
||||
return is_fermat_prp(n, a)
|
||||
|
||||
|
||||
def is_euler_pseudoprime(n, a):
|
||||
r"""Returns True if ``n`` is prime or is an odd composite integer that
|
||||
is coprime to ``a`` and satisfy the modular arithmetic congruence relation:
|
||||
|
||||
.. math ::
|
||||
a^{(n-1)/2} \equiv \pm 1 \pmod{n}
|
||||
|
||||
(where mod refers to the modulo operation).
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n : Integer
|
||||
``n`` is a positive integer.
|
||||
a : Integer
|
||||
``a`` is a positive integer.
|
||||
``a`` and ``n`` should be relatively prime.
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
bool : If ``n`` is prime, it always returns ``True``.
|
||||
The composite number that returns ``True`` is called an Euler pseudoprime.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.primetest import is_euler_pseudoprime
|
||||
>>> from sympy.ntheory.factor_ import isprime
|
||||
>>> for n in range(1, 1000):
|
||||
... if is_euler_pseudoprime(n, 2) and not isprime(n):
|
||||
... print(n)
|
||||
341
|
||||
561
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Euler_pseudoprime
|
||||
"""
|
||||
n, a = as_int(n), as_int(a)
|
||||
if a < 1:
|
||||
raise ValueError("a should be an integer greater than 0")
|
||||
if n < 1:
|
||||
raise ValueError("n should be an integer greater than 0")
|
||||
if n == 1:
|
||||
return False
|
||||
if a == 1:
|
||||
return n == 2 or bool(n % 2) # (prime or odd composite)
|
||||
if n % 2 == 0:
|
||||
return n == 2
|
||||
if gcd(n, a) != 1:
|
||||
raise ValueError("The two numbers should be relatively prime")
|
||||
return pow(a, (n - 1) // 2, n) in [1, n - 1]
|
||||
|
||||
|
||||
def is_euler_jacobi_pseudoprime(n, a):
|
||||
r"""Returns True if ``n`` is prime or is an odd composite integer that
|
||||
is coprime to ``a`` and satisfy the modular arithmetic congruence relation:
|
||||
|
||||
.. math ::
|
||||
a^{(n-1)/2} \equiv \left(\frac{a}{n}\right) \pmod{n}
|
||||
|
||||
(where mod refers to the modulo operation).
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n : Integer
|
||||
``n`` is a positive integer.
|
||||
a : Integer
|
||||
``a`` is a positive integer.
|
||||
``a`` and ``n`` should be relatively prime.
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
bool : If ``n`` is prime, it always returns ``True``.
|
||||
The composite number that returns ``True`` is called an Euler-Jacobi pseudoprime.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.primetest import is_euler_jacobi_pseudoprime
|
||||
>>> from sympy.ntheory.factor_ import isprime
|
||||
>>> for n in range(1, 1000):
|
||||
... if is_euler_jacobi_pseudoprime(n, 2) and not isprime(n):
|
||||
... print(n)
|
||||
561
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Euler%E2%80%93Jacobi_pseudoprime
|
||||
"""
|
||||
n, a = as_int(n), as_int(a)
|
||||
if a == 1:
|
||||
return n == 2 or bool(n % 2)
|
||||
return is_euler_prp(n, a)
|
||||
|
||||
|
||||
def is_square(n, prep=True):
|
||||
"""Return True if n == a * a for some integer a, else False.
|
||||
If n is suspected of *not* being a square then this is a
|
||||
quick method of confirming that it is not.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.primetest import is_square
|
||||
>>> is_square(25)
|
||||
True
|
||||
>>> is_square(2)
|
||||
False
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://mersenneforum.org/showpost.php?p=110896
|
||||
|
||||
See Also
|
||||
========
|
||||
sympy.core.intfunc.isqrt
|
||||
"""
|
||||
if prep:
|
||||
n = as_int(n)
|
||||
if n < 0:
|
||||
return False
|
||||
if n in (0, 1):
|
||||
return True
|
||||
return gmpy_is_square(n)
|
||||
|
||||
|
||||
def _test(n, base, s, t):
|
||||
"""Miller-Rabin strong pseudoprime test for one base.
|
||||
Return False if n is definitely composite, True if n is
|
||||
probably prime, with a probability greater than 3/4.
|
||||
|
||||
"""
|
||||
# do the Fermat test
|
||||
b = pow(base, t, n)
|
||||
if b == 1 or b == n - 1:
|
||||
return True
|
||||
for _ in range(s - 1):
|
||||
b = pow(b, 2, n)
|
||||
if b == n - 1:
|
||||
return True
|
||||
# see I. Niven et al. "An Introduction to Theory of Numbers", page 78
|
||||
if b == 1:
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
def mr(n, bases):
|
||||
"""Perform a Miller-Rabin strong pseudoprime test on n using a
|
||||
given list of bases/witnesses.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] Richard Crandall & Carl Pomerance (2005), "Prime Numbers:
|
||||
A Computational Perspective", Springer, 2nd edition, 135-138
|
||||
|
||||
A list of thresholds and the bases they require are here:
|
||||
https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test#Deterministic_variants
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.primetest import mr
|
||||
>>> mr(1373651, [2, 3])
|
||||
False
|
||||
>>> mr(479001599, [31, 73])
|
||||
True
|
||||
|
||||
"""
|
||||
from sympy.polys.domains import ZZ
|
||||
|
||||
n = as_int(n)
|
||||
if n < 2 or (n > 2 and n % 2 == 0):
|
||||
return False
|
||||
# remove powers of 2 from n-1 (= t * 2**s)
|
||||
s = bit_scan1(n - 1)
|
||||
t = n >> s
|
||||
for base in bases:
|
||||
# Bases >= n are wrapped, bases < 2 are invalid
|
||||
if base >= n:
|
||||
base %= n
|
||||
if base >= 2:
|
||||
base = ZZ(base)
|
||||
if not _test(n, base, s, t):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _lucas_extrastrong_params(n):
|
||||
"""Calculates the "extra strong" parameters (D, P, Q) for n.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n : int
|
||||
positive odd integer
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
D, P, Q: "extra strong" parameters.
|
||||
``(0, 0, 0)`` if we find a nontrivial divisor of ``n``.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.primetest import _lucas_extrastrong_params
|
||||
>>> _lucas_extrastrong_params(101)
|
||||
(12, 4, 1)
|
||||
>>> _lucas_extrastrong_params(15)
|
||||
(0, 0, 0)
|
||||
|
||||
References
|
||||
==========
|
||||
.. [1] OEIS A217719: Extra Strong Lucas Pseudoprimes
|
||||
https://oeis.org/A217719
|
||||
.. [2] https://en.wikipedia.org/wiki/Lucas_pseudoprime
|
||||
|
||||
"""
|
||||
for P in count(3):
|
||||
D = P**2 - 4
|
||||
j = jacobi(D, n)
|
||||
if j == -1:
|
||||
return (D, P, 1)
|
||||
elif j == 0 and D % n:
|
||||
return (0, 0, 0)
|
||||
|
||||
|
||||
def is_lucas_prp(n):
|
||||
"""Standard Lucas compositeness test with Selfridge parameters. Returns
|
||||
False if n is definitely composite, and True if n is a Lucas probable
|
||||
prime.
|
||||
|
||||
This is typically used in combination with the Miller-Rabin test.
|
||||
|
||||
References
|
||||
==========
|
||||
.. [1] Robert Baillie, Samuel S. Wagstaff, Lucas Pseudoprimes,
|
||||
Math. Comp. Vol 35, Number 152 (1980), pp. 1391-1417,
|
||||
https://doi.org/10.1090%2FS0025-5718-1980-0583518-6
|
||||
http://mpqs.free.fr/LucasPseudoprimes.pdf
|
||||
.. [2] OEIS A217120: Lucas Pseudoprimes
|
||||
https://oeis.org/A217120
|
||||
.. [3] https://en.wikipedia.org/wiki/Lucas_pseudoprime
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.primetest import isprime, is_lucas_prp
|
||||
>>> for i in range(10000):
|
||||
... if is_lucas_prp(i) and not isprime(i):
|
||||
... print(i)
|
||||
323
|
||||
377
|
||||
1159
|
||||
1829
|
||||
3827
|
||||
5459
|
||||
5777
|
||||
9071
|
||||
9179
|
||||
"""
|
||||
n = as_int(n)
|
||||
if n < 2:
|
||||
return False
|
||||
return is_selfridge_prp(n)
|
||||
|
||||
|
||||
def is_strong_lucas_prp(n):
|
||||
"""Strong Lucas compositeness test with Selfridge parameters. Returns
|
||||
False if n is definitely composite, and True if n is a strong Lucas
|
||||
probable prime.
|
||||
|
||||
This is often used in combination with the Miller-Rabin test, and
|
||||
in particular, when combined with M-R base 2 creates the strong BPSW test.
|
||||
|
||||
References
|
||||
==========
|
||||
.. [1] Robert Baillie, Samuel S. Wagstaff, Lucas Pseudoprimes,
|
||||
Math. Comp. Vol 35, Number 152 (1980), pp. 1391-1417,
|
||||
https://doi.org/10.1090%2FS0025-5718-1980-0583518-6
|
||||
http://mpqs.free.fr/LucasPseudoprimes.pdf
|
||||
.. [2] OEIS A217255: Strong Lucas Pseudoprimes
|
||||
https://oeis.org/A217255
|
||||
.. [3] https://en.wikipedia.org/wiki/Lucas_pseudoprime
|
||||
.. [4] https://en.wikipedia.org/wiki/Baillie-PSW_primality_test
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.primetest import isprime, is_strong_lucas_prp
|
||||
>>> for i in range(20000):
|
||||
... if is_strong_lucas_prp(i) and not isprime(i):
|
||||
... print(i)
|
||||
5459
|
||||
5777
|
||||
10877
|
||||
16109
|
||||
18971
|
||||
"""
|
||||
n = as_int(n)
|
||||
if n < 2:
|
||||
return False
|
||||
return is_strong_selfridge_prp(n)
|
||||
|
||||
|
||||
def is_extra_strong_lucas_prp(n):
|
||||
"""Extra Strong Lucas compositeness test. Returns False if n is
|
||||
definitely composite, and True if n is an "extra strong" Lucas probable
|
||||
prime.
|
||||
|
||||
The parameters are selected using P = 3, Q = 1, then incrementing P until
|
||||
(D|n) == -1. The test itself is as defined in [1]_, from the
|
||||
Mo and Jones preprint. The parameter selection and test are the same as
|
||||
used in OEIS A217719, Perl's Math::Prime::Util, and the Lucas pseudoprime
|
||||
page on Wikipedia.
|
||||
|
||||
It is 20-50% faster than the strong test.
|
||||
|
||||
Because of the different parameters selected, there is no relationship
|
||||
between the strong Lucas pseudoprimes and extra strong Lucas pseudoprimes.
|
||||
In particular, one is not a subset of the other.
|
||||
|
||||
References
|
||||
==========
|
||||
.. [1] Jon Grantham, Frobenius Pseudoprimes,
|
||||
Math. Comp. Vol 70, Number 234 (2001), pp. 873-891,
|
||||
https://doi.org/10.1090%2FS0025-5718-00-01197-2
|
||||
.. [2] OEIS A217719: Extra Strong Lucas Pseudoprimes
|
||||
https://oeis.org/A217719
|
||||
.. [3] https://en.wikipedia.org/wiki/Lucas_pseudoprime
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.primetest import isprime, is_extra_strong_lucas_prp
|
||||
>>> for i in range(20000):
|
||||
... if is_extra_strong_lucas_prp(i) and not isprime(i):
|
||||
... print(i)
|
||||
989
|
||||
3239
|
||||
5777
|
||||
10877
|
||||
"""
|
||||
# Implementation notes:
|
||||
# 1) the parameters differ from Thomas R. Nicely's. His parameter
|
||||
# selection leads to pseudoprimes that overlap M-R tests, and
|
||||
# contradict Baillie and Wagstaff's suggestion of (D|n) = -1.
|
||||
# 2) The MathWorld page as of June 2013 specifies Q=-1. The Lucas
|
||||
# sequence must have Q=1. See Grantham theorem 2.3, any of the
|
||||
# references on the MathWorld page, or run it and see Q=-1 is wrong.
|
||||
n = as_int(n)
|
||||
if n == 2:
|
||||
return True
|
||||
if n < 2 or (n % 2) == 0:
|
||||
return False
|
||||
if gmpy_is_square(n):
|
||||
return False
|
||||
|
||||
D, P, Q = _lucas_extrastrong_params(n)
|
||||
if D == 0:
|
||||
return False
|
||||
|
||||
# remove powers of 2 from n+1 (= k * 2**s)
|
||||
s = bit_scan1(n + 1)
|
||||
k = (n + 1) >> s
|
||||
|
||||
U, V, _ = _lucas_sequence(n, P, Q, k)
|
||||
|
||||
if U == 0 and (V == 2 or V == n - 2):
|
||||
return True
|
||||
for _ in range(1, s):
|
||||
if V == 0:
|
||||
return True
|
||||
V = (V*V - 2) % n
|
||||
return False
|
||||
|
||||
|
||||
def proth_test(n):
|
||||
r""" Test if the Proth number `n = k2^m + 1` is prime. where k is a positive odd number and `2^m > k`.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n : Integer
|
||||
``n`` is Proth number
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
bool : If ``True``, then ``n`` is the Proth prime
|
||||
|
||||
Raises
|
||||
======
|
||||
|
||||
ValueError
|
||||
If ``n`` is not Proth number.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.primetest import proth_test
|
||||
>>> proth_test(41)
|
||||
True
|
||||
>>> proth_test(57)
|
||||
False
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Proth_prime
|
||||
|
||||
"""
|
||||
n = as_int(n)
|
||||
if n < 3:
|
||||
raise ValueError("n is not Proth number")
|
||||
m = bit_scan1(n - 1)
|
||||
k = n >> m
|
||||
if m < k.bit_length():
|
||||
raise ValueError("n is not Proth number")
|
||||
if n % 3 == 0:
|
||||
return n == 3
|
||||
if k % 3: # n % 12 == 5
|
||||
return pow(3, n >> 1, n) == n - 1
|
||||
# If `n` is a square number, then `jacobi(a, n) = 1` for any `a`
|
||||
if gmpy_is_square(n):
|
||||
return False
|
||||
# `a` may be chosen at random.
|
||||
# In any case, we want to find `a` such that `jacobi(a, n) = -1`.
|
||||
for a in range(5, n):
|
||||
j = jacobi(a, n)
|
||||
if j == -1:
|
||||
return pow(a, n >> 1, n) == n - 1
|
||||
if j == 0:
|
||||
return False
|
||||
|
||||
|
||||
def _lucas_lehmer_primality_test(p):
|
||||
r""" Test if the Mersenne number `M_p = 2^p-1` is prime.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
p : int
|
||||
``p`` is an odd prime number
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
bool : If ``True``, then `M_p` is the Mersenne prime
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.primetest import _lucas_lehmer_primality_test
|
||||
>>> _lucas_lehmer_primality_test(5) # 2**5 - 1 = 31 is prime
|
||||
True
|
||||
>>> _lucas_lehmer_primality_test(11) # 2**11 - 1 = 2047 is not prime
|
||||
False
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
is_mersenne_prime
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Lucas%E2%80%93Lehmer_primality_test
|
||||
|
||||
"""
|
||||
v = 4
|
||||
m = 2**p - 1
|
||||
for _ in range(p - 2):
|
||||
v = pow(v, 2, m) - 2
|
||||
return v == 0
|
||||
|
||||
|
||||
def is_mersenne_prime(n):
|
||||
"""Returns True if ``n`` is a Mersenne prime, else False.
|
||||
|
||||
A Mersenne prime is a prime number having the form `2^i - 1`.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory.factor_ import is_mersenne_prime
|
||||
>>> is_mersenne_prime(6)
|
||||
False
|
||||
>>> is_mersenne_prime(127)
|
||||
True
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://mathworld.wolfram.com/MersennePrime.html
|
||||
|
||||
"""
|
||||
n = as_int(n)
|
||||
if n < 1:
|
||||
return False
|
||||
if n & (n + 1):
|
||||
# n is not Mersenne number
|
||||
return False
|
||||
p = n.bit_length()
|
||||
if p in MERSENNE_PRIME_EXPONENTS:
|
||||
return True
|
||||
if p < 65_000_000 or not isprime(p):
|
||||
# According to GIMPS, verification was completed on September 19, 2023 for p less than 65 million.
|
||||
# https://www.mersenne.org/report_milestones/
|
||||
# If p is composite number, then n=2**p-1 is composite number.
|
||||
return False
|
||||
result = _lucas_lehmer_primality_test(p)
|
||||
if result:
|
||||
raise ValueError(filldedent('''
|
||||
This Mersenne Prime, 2^%s - 1, should
|
||||
be added to SymPy's known values.''' % p))
|
||||
return result
|
||||
|
||||
|
||||
_MR_BASES_32 = [15591, 2018, 166, 7429, 8064, 16045, 10503, 4399, 1949, 1295,
|
||||
2776, 3620, 560, 3128, 5212, 2657, 2300, 2021, 4652, 1471,
|
||||
9336, 4018, 2398, 20462, 10277, 8028, 2213, 6219, 620, 3763,
|
||||
4852, 5012, 3185, 1333, 6227,5298, 1074, 2391, 5113, 7061,
|
||||
803, 1269, 3875, 422, 751, 580, 4729, 10239, 746, 2951, 556,
|
||||
2206, 3778, 481, 1522, 3476, 481, 2487, 3266, 5633, 488, 3373,
|
||||
6441, 3344, 17, 15105, 1490, 4154, 2036, 1882, 1813, 467,
|
||||
3307, 14042, 6371, 658, 1005, 903, 737, 1887, 7447, 1888,
|
||||
2848, 1784, 7559, 3400, 951, 13969, 4304, 177, 41, 19875,
|
||||
3110, 13221, 8726, 571, 7043, 6943, 1199, 352, 6435, 165,
|
||||
1169, 3315, 978, 233, 3003, 2562, 2994, 10587, 10030, 2377,
|
||||
1902, 5354, 4447, 1555, 263, 27027, 2283, 305, 669, 1912, 601,
|
||||
6186, 429, 1930, 14873, 1784, 1661, 524, 3577, 236, 2360,
|
||||
6146, 2850, 55637, 1753, 4178, 8466, 222, 2579, 2743, 2031,
|
||||
2226, 2276, 374, 2132, 813, 23788, 1610, 4422, 5159, 1725,
|
||||
3597, 3366, 14336, 579, 165, 1375, 10018, 12616, 9816, 1371,
|
||||
536, 1867, 10864, 857, 2206, 5788, 434, 8085, 17618, 727,
|
||||
3639, 1595, 4944, 2129, 2029, 8195, 8344, 6232, 9183, 8126,
|
||||
1870, 3296, 7455, 8947, 25017, 541, 19115, 368, 566, 5674,
|
||||
411, 522, 1027, 8215, 2050, 6544, 10049, 614, 774, 2333, 3007,
|
||||
35201, 4706, 1152, 1785, 1028, 1540, 3743, 493, 4474, 2521,
|
||||
26845, 8354, 864, 18915, 5465, 2447, 42, 4511, 1660, 166,
|
||||
1249, 6259, 2553, 304, 272, 7286, 73, 6554, 899, 2816, 5197,
|
||||
13330, 7054, 2818, 3199, 811, 922, 350, 7514, 4452, 3449,
|
||||
2663, 4708, 418, 1621, 1171, 3471, 88, 11345, 412, 1559, 194]
|
||||
|
||||
|
||||
def isprime(n):
|
||||
"""
|
||||
Test if n is a prime number (True) or not (False). For n < 2^64 the
|
||||
answer is definitive; larger n values have a small probability of actually
|
||||
being pseudoprimes.
|
||||
|
||||
Negative numbers (e.g. -2) are not considered prime.
|
||||
|
||||
The first step is looking for trivial factors, which if found enables
|
||||
a quick return. Next, if the sieve is large enough, use bisection search
|
||||
on the sieve. For small numbers, a set of deterministic Miller-Rabin
|
||||
tests are performed with bases that are known to have no counterexamples
|
||||
in their range. Finally if the number is larger than 2^64, a strong
|
||||
BPSW test is performed. While this is a probable prime test and we
|
||||
believe counterexamples exist, there are no known counterexamples.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory import isprime
|
||||
>>> isprime(13)
|
||||
True
|
||||
>>> isprime(15)
|
||||
False
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
This routine is intended only for integer input, not numerical
|
||||
expressions which may represent numbers. Floats are also
|
||||
rejected as input because they represent numbers of limited
|
||||
precision. While it is tempting to permit 7.0 to represent an
|
||||
integer there are errors that may "pass silently" if this is
|
||||
allowed:
|
||||
|
||||
>>> from sympy import Float, S
|
||||
>>> int(1e3) == 1e3 == 10**3
|
||||
True
|
||||
>>> int(1e23) == 1e23
|
||||
True
|
||||
>>> int(1e23) == 10**23
|
||||
False
|
||||
|
||||
>>> near_int = 1 + S(1)/10**19
|
||||
>>> near_int == int(near_int)
|
||||
False
|
||||
>>> n = Float(near_int, 10) # truncated by precision
|
||||
>>> n % 1 == 0
|
||||
True
|
||||
>>> n = Float(near_int, 20)
|
||||
>>> n % 1 == 0
|
||||
False
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.ntheory.generate.primerange : Generates all primes in a given range
|
||||
sympy.functions.combinatorial.numbers.primepi : Return the number of primes less than or equal to n
|
||||
sympy.ntheory.generate.prime : Return the nth prime
|
||||
|
||||
References
|
||||
==========
|
||||
.. [1] https://en.wikipedia.org/wiki/Strong_pseudoprime
|
||||
.. [2] Robert Baillie, Samuel S. Wagstaff, Lucas Pseudoprimes,
|
||||
Math. Comp. Vol 35, Number 152 (1980), pp. 1391-1417,
|
||||
https://doi.org/10.1090%2FS0025-5718-1980-0583518-6
|
||||
http://mpqs.free.fr/LucasPseudoprimes.pdf
|
||||
.. [3] https://en.wikipedia.org/wiki/Baillie-PSW_primality_test
|
||||
"""
|
||||
n = as_int(n)
|
||||
|
||||
# Step 1, do quick composite testing via trial division. The individual
|
||||
# modulo tests benchmark faster than one or two primorial igcds for me.
|
||||
# The point here is just to speedily handle small numbers and many
|
||||
# composites. Step 2 only requires that n <= 2 get handled here.
|
||||
if n in [2, 3, 5]:
|
||||
return True
|
||||
if n < 2 or (n % 2) == 0 or (n % 3) == 0 or (n % 5) == 0:
|
||||
return False
|
||||
if n < 49:
|
||||
return True
|
||||
if (n % 7) == 0 or (n % 11) == 0 or (n % 13) == 0 or (n % 17) == 0 or \
|
||||
(n % 19) == 0 or (n % 23) == 0 or (n % 29) == 0 or (n % 31) == 0 or \
|
||||
(n % 37) == 0 or (n % 41) == 0 or (n % 43) == 0 or (n % 47) == 0:
|
||||
return False
|
||||
if n < 2809:
|
||||
return True
|
||||
if n < 65077:
|
||||
# There are only five Euler pseudoprimes with a least prime factor greater than 47
|
||||
return pow(2, n >> 1, n) in [1, n - 1] and n not in [8321, 31621, 42799, 49141, 49981]
|
||||
|
||||
# bisection search on the sieve if the sieve is large enough
|
||||
from sympy.ntheory.generate import sieve as s
|
||||
if n <= s._list[-1]:
|
||||
l, u = s.search(n)
|
||||
return l == u
|
||||
from sympy.ntheory.factor_ import factor_cache
|
||||
if (ret := factor_cache.get(n)) is not None:
|
||||
return ret == n
|
||||
|
||||
# If we have GMPY2, skip straight to step 3 and do a strong BPSW test.
|
||||
# This should be a bit faster than our step 2, and for large values will
|
||||
# be a lot faster than our step 3 (C+GMP vs. Python).
|
||||
if _gmpy is not None:
|
||||
return is_strong_bpsw_prp(n)
|
||||
|
||||
|
||||
# Step 2: deterministic Miller-Rabin testing for numbers < 2^64. See:
|
||||
# https://miller-rabin.appspot.com/
|
||||
# for lists. We have made sure the M-R routine will successfully handle
|
||||
# bases larger than n, so we can use the minimal set.
|
||||
# In September 2015 deterministic numbers were extended to over 2^81.
|
||||
# https://arxiv.org/pdf/1509.00864.pdf
|
||||
# https://oeis.org/A014233
|
||||
if n < 341531:
|
||||
return mr(n, [9345883071009581737])
|
||||
if n < 4296595241:
|
||||
# Michal Forisek and Jakub Jancina,
|
||||
# Fast Primality Testing for Integers That Fit into a Machine Word
|
||||
# https://ceur-ws.org/Vol-1326/020-Forisek.pdf
|
||||
h = ((n >> 16) ^ n) * 0x45d9f3b
|
||||
h = ((h >> 16) ^ h) * 0x45d9f3b
|
||||
h = ((h >> 16) ^ h) & 255
|
||||
return mr(n, [_MR_BASES_32[h]])
|
||||
if n < 350269456337:
|
||||
return mr(n, [4230279247111683200, 14694767155120705706, 16641139526367750375])
|
||||
if n < 55245642489451:
|
||||
return mr(n, [2, 141889084524735, 1199124725622454117, 11096072698276303650])
|
||||
if n < 7999252175582851:
|
||||
return mr(n, [2, 4130806001517, 149795463772692060, 186635894390467037, 3967304179347715805])
|
||||
if n < 585226005592931977:
|
||||
return mr(n, [2, 123635709730000, 9233062284813009, 43835965440333360, 761179012939631437, 1263739024124850375])
|
||||
if n < 18446744073709551616:
|
||||
return mr(n, [2, 325, 9375, 28178, 450775, 9780504, 1795265022])
|
||||
if n < 318665857834031151167461:
|
||||
return mr(n, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37])
|
||||
if n < 3317044064679887385961981:
|
||||
return mr(n, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41])
|
||||
|
||||
# We could do this instead at any point:
|
||||
#if n < 18446744073709551616:
|
||||
# return mr(n, [2]) and is_extra_strong_lucas_prp(n)
|
||||
|
||||
# Here are tests that are safe for MR routines that don't understand
|
||||
# large bases.
|
||||
#if n < 9080191:
|
||||
# return mr(n, [31, 73])
|
||||
#if n < 19471033:
|
||||
# return mr(n, [2, 299417])
|
||||
#if n < 38010307:
|
||||
# return mr(n, [2, 9332593])
|
||||
#if n < 316349281:
|
||||
# return mr(n, [11000544, 31481107])
|
||||
#if n < 4759123141:
|
||||
# return mr(n, [2, 7, 61])
|
||||
#if n < 105936894253:
|
||||
# return mr(n, [2, 1005905886, 1340600841])
|
||||
#if n < 31858317218647:
|
||||
# return mr(n, [2, 642735, 553174392, 3046413974])
|
||||
#if n < 3071837692357849:
|
||||
# return mr(n, [2, 75088, 642735, 203659041, 3613982119])
|
||||
#if n < 18446744073709551616:
|
||||
# return mr(n, [2, 325, 9375, 28178, 450775, 9780504, 1795265022])
|
||||
|
||||
# Step 3: BPSW.
|
||||
#
|
||||
# Time for isprime(10**2000 + 4561), no gmpy or gmpy2 installed
|
||||
# 44.0s old isprime using 46 bases
|
||||
# 5.3s strong BPSW + one random base
|
||||
# 4.3s extra strong BPSW + one random base
|
||||
# 4.1s strong BPSW
|
||||
# 3.2s extra strong BPSW
|
||||
|
||||
# Classic BPSW from page 1401 of the paper. See alternate ideas below.
|
||||
return is_strong_bpsw_prp(n)
|
||||
|
||||
# Using extra strong test, which is somewhat faster
|
||||
#return mr(n, [2]) and is_extra_strong_lucas_prp(n)
|
||||
|
||||
# Add a random M-R base
|
||||
#import random
|
||||
#return mr(n, [2, random.randint(3, n-1)]) and is_strong_lucas_prp(n)
|
||||
|
||||
|
||||
def is_gaussian_prime(num):
|
||||
r"""Test if num is a Gaussian prime number.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://oeis.org/wiki/Gaussian_primes
|
||||
"""
|
||||
|
||||
num = sympify(num)
|
||||
a, b = num.as_real_imag()
|
||||
a = as_int(a, strict=False)
|
||||
b = as_int(b, strict=False)
|
||||
if a == 0:
|
||||
b = abs(b)
|
||||
return isprime(b) and b % 4 == 3
|
||||
elif b == 0:
|
||||
a = abs(a)
|
||||
return isprime(a) and a % 4 == 3
|
||||
return isprime(a**2 + b**2)
|
||||
451
venv/lib/python3.12/site-packages/sympy/ntheory/qs.py
Normal file
451
venv/lib/python3.12/site-packages/sympy/ntheory/qs.py
Normal file
@@ -0,0 +1,451 @@
|
||||
from math import exp, log
|
||||
from sympy.core.random import _randint
|
||||
from sympy.external.gmpy import bit_scan1, gcd, invert, sqrt as isqrt
|
||||
from sympy.ntheory.factor_ import _perfect_power
|
||||
from sympy.ntheory.primetest import isprime
|
||||
from sympy.ntheory.residue_ntheory import _sqrt_mod_prime_power
|
||||
|
||||
|
||||
class SievePolynomial:
|
||||
def __init__(self, a, b, N):
|
||||
"""This class denotes the sieve polynomial.
|
||||
Provide methods to compute `(a*x + b)**2 - N` and
|
||||
`a*x + b` when given `x`.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
a : parameter of the sieve polynomial
|
||||
b : parameter of the sieve polynomial
|
||||
N : number to be factored
|
||||
|
||||
"""
|
||||
self.a = a
|
||||
self.b = b
|
||||
self.a2 = a**2
|
||||
self.ab = 2*a*b
|
||||
self.b2 = b**2 - N
|
||||
|
||||
def eval_u(self, x):
|
||||
return self.a*x + self.b
|
||||
|
||||
def eval_v(self, x):
|
||||
return (self.a2*x + self.ab)*x + self.b2
|
||||
|
||||
|
||||
class FactorBaseElem:
|
||||
"""This class stores an element of the `factor_base`.
|
||||
"""
|
||||
def __init__(self, prime, tmem_p, log_p):
|
||||
"""
|
||||
Initialization of factor_base_elem.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
prime : prime number of the factor_base
|
||||
tmem_p : Integer square root of x**2 = n mod prime
|
||||
log_p : Compute Natural Logarithm of the prime
|
||||
"""
|
||||
self.prime = prime
|
||||
self.tmem_p = tmem_p
|
||||
self.log_p = log_p
|
||||
# `soln1` and `soln2` are solutions to
|
||||
# the equation `(a*x + b)**2 - N = 0 (mod p)`.
|
||||
self.soln1 = None
|
||||
self.soln2 = None
|
||||
self.b_ainv = None
|
||||
|
||||
|
||||
def _generate_factor_base(prime_bound, n):
|
||||
"""Generate `factor_base` for Quadratic Sieve. The `factor_base`
|
||||
consists of all the points whose ``legendre_symbol(n, p) == 1``
|
||||
and ``p < num_primes``. Along with the prime `factor_base` also stores
|
||||
natural logarithm of prime and the residue n modulo p.
|
||||
It also returns the of primes numbers in the `factor_base` which are
|
||||
close to 1000 and 5000.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
prime_bound : upper prime bound of the factor_base
|
||||
n : integer to be factored
|
||||
"""
|
||||
from sympy.ntheory.generate import sieve
|
||||
factor_base = []
|
||||
idx_1000, idx_5000 = None, None
|
||||
for prime in sieve.primerange(1, prime_bound):
|
||||
if pow(n, (prime - 1) // 2, prime) == 1:
|
||||
if prime > 1000 and idx_1000 is None:
|
||||
idx_1000 = len(factor_base) - 1
|
||||
if prime > 5000 and idx_5000 is None:
|
||||
idx_5000 = len(factor_base) - 1
|
||||
residue = _sqrt_mod_prime_power(n, prime, 1)[0]
|
||||
log_p = round(log(prime)*2**10)
|
||||
factor_base.append(FactorBaseElem(prime, residue, log_p))
|
||||
return idx_1000, idx_5000, factor_base
|
||||
|
||||
|
||||
def _generate_polynomial(N, M, factor_base, idx_1000, idx_5000, randint):
|
||||
""" Generate sieve polynomials indefinitely.
|
||||
Information such as `soln1` in the `factor_base` associated with
|
||||
the polynomial is modified in place.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
N : Number to be factored
|
||||
M : sieve interval
|
||||
factor_base : factor_base primes
|
||||
idx_1000 : index of prime number in the factor_base near 1000
|
||||
idx_5000 : index of prime number in the factor_base near to 5000
|
||||
randint : A callable that takes two integers (a, b) and returns a random integer
|
||||
n such that a <= n <= b, similar to `random.randint`.
|
||||
"""
|
||||
approx_val = log(2*N)/2 - log(M)
|
||||
start = idx_1000 or 0
|
||||
end = idx_5000 or (len(factor_base) - 1)
|
||||
while True:
|
||||
# Choose `a` that is close to `sqrt(2*N) / M`
|
||||
best_a, best_q, best_ratio = None, None, None
|
||||
for _ in range(50):
|
||||
a = 1
|
||||
q = []
|
||||
while log(a) < approx_val:
|
||||
rand_p = 0
|
||||
while(rand_p == 0 or rand_p in q):
|
||||
rand_p = randint(start, end)
|
||||
p = factor_base[rand_p].prime
|
||||
a *= p
|
||||
q.append(rand_p)
|
||||
ratio = exp(log(a) - approx_val)
|
||||
if best_ratio is None or abs(ratio - 1) < abs(best_ratio - 1):
|
||||
best_q = q
|
||||
best_a = a
|
||||
best_ratio = ratio
|
||||
|
||||
# Set `b` using the Chinese remainder theorem
|
||||
a = best_a
|
||||
q = best_q
|
||||
B = []
|
||||
for val in q:
|
||||
q_l = factor_base[val].prime
|
||||
gamma = factor_base[val].tmem_p * invert(a // q_l, q_l) % q_l
|
||||
if 2*gamma > q_l:
|
||||
gamma = q_l - gamma
|
||||
B.append(a//q_l*gamma)
|
||||
b = sum(B)
|
||||
g = SievePolynomial(a, b, N)
|
||||
for fb in factor_base:
|
||||
if a % fb.prime == 0:
|
||||
fb.soln1 = None
|
||||
continue
|
||||
a_inv = invert(a, fb.prime)
|
||||
fb.b_ainv = [2*b_elem*a_inv % fb.prime for b_elem in B]
|
||||
fb.soln1 = (a_inv*(fb.tmem_p - b)) % fb.prime
|
||||
fb.soln2 = (a_inv*(-fb.tmem_p - b)) % fb.prime
|
||||
yield g
|
||||
|
||||
# Update `b` with Gray code
|
||||
for i in range(1, 2**(len(B)-1)):
|
||||
v = bit_scan1(i)
|
||||
neg_pow = 2*((i >> (v + 1)) % 2) - 1
|
||||
b = g.b + 2*neg_pow*B[v]
|
||||
a = g.a
|
||||
g = SievePolynomial(a, b, N)
|
||||
for fb in factor_base:
|
||||
if fb.soln1 is None:
|
||||
continue
|
||||
fb.soln1 = (fb.soln1 - neg_pow*fb.b_ainv[v]) % fb.prime
|
||||
fb.soln2 = (fb.soln2 - neg_pow*fb.b_ainv[v]) % fb.prime
|
||||
yield g
|
||||
|
||||
|
||||
def _gen_sieve_array(M, factor_base):
|
||||
"""Sieve Stage of the Quadratic Sieve. For every prime in the factor_base
|
||||
that does not divide the coefficient `a` we add log_p over the sieve_array
|
||||
such that ``-M <= soln1 + i*p <= M`` and ``-M <= soln2 + i*p <= M`` where `i`
|
||||
is an integer. When p = 2 then log_p is only added using
|
||||
``-M <= soln1 + i*p <= M``.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
M : sieve interval
|
||||
factor_base : factor_base primes
|
||||
"""
|
||||
sieve_array = [0]*(2*M + 1)
|
||||
for factor in factor_base:
|
||||
if factor.soln1 is None: #The prime does not divides a
|
||||
continue
|
||||
for idx in range((M + factor.soln1) % factor.prime, 2*M, factor.prime):
|
||||
sieve_array[idx] += factor.log_p
|
||||
if factor.prime == 2:
|
||||
continue
|
||||
#if prime is 2 then sieve only with soln_1_p
|
||||
for idx in range((M + factor.soln2) % factor.prime, 2*M, factor.prime):
|
||||
sieve_array[idx] += factor.log_p
|
||||
return sieve_array
|
||||
|
||||
|
||||
def _check_smoothness(num, factor_base):
|
||||
r""" Check if `num` is smooth with respect to the given `factor_base`
|
||||
and compute its factorization vector.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
num : integer whose smootheness is to be checked
|
||||
factor_base : factor_base primes
|
||||
"""
|
||||
if num < 0:
|
||||
num *= -1
|
||||
vec = 1
|
||||
else:
|
||||
vec = 0
|
||||
for i, fb in enumerate(factor_base, 1):
|
||||
if num % fb.prime:
|
||||
continue
|
||||
e = 1
|
||||
num //= fb.prime
|
||||
while num % fb.prime == 0:
|
||||
e += 1
|
||||
num //= fb.prime
|
||||
if e % 2:
|
||||
vec += 1 << i
|
||||
return vec, num
|
||||
|
||||
|
||||
def _trial_division_stage(N, M, factor_base, sieve_array, sieve_poly, partial_relations, ERROR_TERM):
|
||||
"""Trial division stage. Here we trial divide the values generetated
|
||||
by sieve_poly in the sieve interval and if it is a smooth number then
|
||||
it is stored in `smooth_relations`. Moreover, if we find two partial relations
|
||||
with same large prime then they are combined to form a smooth relation.
|
||||
First we iterate over sieve array and look for values which are greater
|
||||
than accumulated_val, as these values have a high chance of being smooth
|
||||
number. Then using these values we find smooth relations.
|
||||
In general, let ``t**2 = u*p modN`` and ``r**2 = v*p modN`` be two partial relations
|
||||
with the same large prime p. Then they can be combined ``(t*r/p)**2 = u*v modN``
|
||||
to form a smooth relation.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
N : Number to be factored
|
||||
M : sieve interval
|
||||
factor_base : factor_base primes
|
||||
sieve_array : stores log_p values
|
||||
sieve_poly : polynomial from which we find smooth relations
|
||||
partial_relations : stores partial relations with one large prime
|
||||
ERROR_TERM : error term for accumulated_val
|
||||
"""
|
||||
accumulated_val = (log(M) + log(N)/2 - ERROR_TERM) * 2**10
|
||||
smooth_relations = []
|
||||
proper_factor = set()
|
||||
partial_relation_upper_bound = 128*factor_base[-1].prime
|
||||
for x, val in enumerate(sieve_array, -M):
|
||||
if val < accumulated_val:
|
||||
continue
|
||||
v = sieve_poly.eval_v(x)
|
||||
vec, num = _check_smoothness(v, factor_base)
|
||||
if num == 1:
|
||||
smooth_relations.append((sieve_poly.eval_u(x), v, vec))
|
||||
elif num < partial_relation_upper_bound and isprime(num):
|
||||
if N % num == 0:
|
||||
proper_factor.add(num)
|
||||
continue
|
||||
u = sieve_poly.eval_u(x)
|
||||
if num in partial_relations:
|
||||
u_prev, v_prev, vec_prev = partial_relations.pop(num)
|
||||
u = u*u_prev*invert(num, N) % N
|
||||
v = v*v_prev // num**2
|
||||
vec ^= vec_prev
|
||||
smooth_relations.append((u, v, vec))
|
||||
else:
|
||||
partial_relations[num] = (u, v, vec)
|
||||
return smooth_relations, proper_factor
|
||||
|
||||
|
||||
def _find_factor(N, smooth_relations, col):
|
||||
""" Finds proper factor of N using fast gaussian reduction for modulo 2 matrix.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
N : Number to be factored
|
||||
smooth_relations : Smooth relations vectors matrix
|
||||
col : Number of columns in the matrix
|
||||
|
||||
Reference
|
||||
==========
|
||||
|
||||
.. [1] A fast algorithm for gaussian elimination over GF(2) and
|
||||
its implementation on the GAPP. Cetin K.Koc, Sarath N.Arachchige
|
||||
"""
|
||||
matrix = [s_relation[2] for s_relation in smooth_relations]
|
||||
row = len(matrix)
|
||||
mark = [False] * row
|
||||
for pos in range(col):
|
||||
m = 1 << pos
|
||||
for i in range(row):
|
||||
if p := matrix[i] & m:
|
||||
add_col = p ^ matrix[i]
|
||||
matrix[i] = m
|
||||
mark[i] = True
|
||||
for j in range(i + 1, row):
|
||||
if matrix[j] & m:
|
||||
matrix[j] ^= add_col
|
||||
break
|
||||
|
||||
for m, mat, rel in zip(mark, matrix, smooth_relations):
|
||||
if m:
|
||||
continue
|
||||
u, v = rel[0], rel[1]
|
||||
for m1, mat1, rel1 in zip(mark, matrix, smooth_relations):
|
||||
if m1 and mat & mat1:
|
||||
u *= rel1[0]
|
||||
v *= rel1[1]
|
||||
# assert is_square(v)
|
||||
v = isqrt(v)
|
||||
if 1 < (g := gcd(u - v, N)) < N:
|
||||
yield g
|
||||
|
||||
|
||||
def qs(N, prime_bound, M, ERROR_TERM=25, seed=1234):
|
||||
"""Performs factorization using Self-Initializing Quadratic Sieve.
|
||||
In SIQS, let N be a number to be factored, and this N should not be a
|
||||
perfect power. If we find two integers such that ``X**2 = Y**2 modN`` and
|
||||
``X != +-Y modN``, then `gcd(X + Y, N)` will reveal a proper factor of N.
|
||||
In order to find these integers X and Y we try to find relations of form
|
||||
t**2 = u modN where u is a product of small primes. If we have enough of
|
||||
these relations then we can form ``(t1*t2...ti)**2 = u1*u2...ui modN`` such that
|
||||
the right hand side is a square, thus we found a relation of ``X**2 = Y**2 modN``.
|
||||
|
||||
Here, several optimizations are done like using multiple polynomials for
|
||||
sieving, fast changing between polynomials and using partial relations.
|
||||
The use of partial relations can speeds up the factoring by 2 times.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
N : Number to be Factored
|
||||
prime_bound : upper bound for primes in the factor base
|
||||
M : Sieve Interval
|
||||
ERROR_TERM : Error term for checking smoothness
|
||||
seed : seed of random number generator
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
set(int) : A set of factors of N without considering multiplicity.
|
||||
Returns ``{N}`` if factorization fails.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory import qs
|
||||
>>> qs(25645121643901801, 2000, 10000)
|
||||
{5394769, 4753701529}
|
||||
>>> qs(9804659461513846513, 2000, 10000)
|
||||
{4641991, 2112166839943}
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
qs_factor
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://pdfs.semanticscholar.org/5c52/8a975c1405bd35c65993abf5a4edb667c1db.pdf
|
||||
.. [2] https://www.rieselprime.de/ziki/Self-initializing_quadratic_sieve
|
||||
"""
|
||||
return set(qs_factor(N, prime_bound, M, ERROR_TERM, seed))
|
||||
|
||||
|
||||
def qs_factor(N, prime_bound, M, ERROR_TERM=25, seed=1234):
|
||||
""" Performs factorization using Self-Initializing Quadratic Sieve.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
N : Number to be Factored
|
||||
prime_bound : upper bound for primes in the factor base
|
||||
M : Sieve Interval
|
||||
ERROR_TERM : Error term for checking smoothness
|
||||
seed : seed of random number generator
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
dict[int, int] : Factors of N.
|
||||
Returns ``{N: 1}`` if factorization fails.
|
||||
Note that the key is not always a prime number.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.ntheory import qs_factor
|
||||
>>> qs_factor(1009 * 100003, 2000, 10000)
|
||||
{1009: 1, 100003: 1}
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
qs
|
||||
|
||||
"""
|
||||
if N < 2:
|
||||
raise ValueError("N should be greater than 1")
|
||||
factors = {}
|
||||
smooth_relations = []
|
||||
partial_relations = {}
|
||||
# Eliminate the possibility of even numbers,
|
||||
# prime numbers, and perfect powers.
|
||||
if N % 2 == 0:
|
||||
e = 1
|
||||
N //= 2
|
||||
while N % 2 == 0:
|
||||
N //= 2
|
||||
e += 1
|
||||
factors[2] = e
|
||||
if isprime(N):
|
||||
factors[N] = 1
|
||||
return factors
|
||||
if result := _perfect_power(N, 3):
|
||||
n, e = result
|
||||
factors[n] = e
|
||||
return factors
|
||||
N_copy = N
|
||||
randint = _randint(seed)
|
||||
idx_1000, idx_5000, factor_base = _generate_factor_base(prime_bound, N)
|
||||
threshold = len(factor_base) * 105//100
|
||||
for g in _generate_polynomial(N, M, factor_base, idx_1000, idx_5000, randint):
|
||||
sieve_array = _gen_sieve_array(M, factor_base)
|
||||
s_rel, p_f = _trial_division_stage(N, M, factor_base, sieve_array, g, partial_relations, ERROR_TERM)
|
||||
smooth_relations += s_rel
|
||||
for p in p_f:
|
||||
if N_copy % p:
|
||||
continue
|
||||
e = 1
|
||||
N_copy //= p
|
||||
while N_copy % p == 0:
|
||||
N_copy //= p
|
||||
e += 1
|
||||
factors[p] = e
|
||||
if threshold <= len(smooth_relations):
|
||||
break
|
||||
|
||||
for factor in _find_factor(N, smooth_relations, len(factor_base) + 1):
|
||||
if N_copy % factor == 0:
|
||||
e = 1
|
||||
N_copy //= factor
|
||||
while N_copy % factor == 0:
|
||||
N_copy //= factor
|
||||
e += 1
|
||||
factors[factor] = e
|
||||
if N_copy == 1 or isprime(N_copy):
|
||||
break
|
||||
if N_copy != 1:
|
||||
factors[N_copy] = 1
|
||||
return factors
|
||||
1963
venv/lib/python3.12/site-packages/sympy/ntheory/residue_ntheory.py
Normal file
1963
venv/lib/python3.12/site-packages/sympy/ntheory/residue_ntheory.py
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,134 @@
|
||||
from sympy.core.random import randint
|
||||
|
||||
from sympy.ntheory.bbp_pi import pi_hex_digits
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
# http://www.herongyang.com/Cryptography/Blowfish-First-8366-Hex-Digits-of-PI.html
|
||||
# There are actually 8336 listed there; with the prepended 3 there are 8337
|
||||
# below
|
||||
dig=''.join('''
|
||||
3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89452821e638d013
|
||||
77be5466cf34e90c6cc0ac29b7c97c50dd3f84d5b5b54709179216d5d98979fb1bd1310ba698dfb5
|
||||
ac2ffd72dbd01adfb7b8e1afed6a267e96ba7c9045f12c7f9924a19947b3916cf70801f2e2858efc
|
||||
16636920d871574e69a458fea3f4933d7e0d95748f728eb658718bcd5882154aee7b54a41dc25a59
|
||||
b59c30d5392af26013c5d1b023286085f0ca417918b8db38ef8e79dcb0603a180e6c9e0e8bb01e8a
|
||||
3ed71577c1bd314b2778af2fda55605c60e65525f3aa55ab945748986263e8144055ca396a2aab10
|
||||
b6b4cc5c341141e8cea15486af7c72e993b3ee1411636fbc2a2ba9c55d741831f6ce5c3e169b8793
|
||||
1eafd6ba336c24cf5c7a325381289586773b8f48986b4bb9afc4bfe81b6628219361d809ccfb21a9
|
||||
91487cac605dec8032ef845d5de98575b1dc262302eb651b8823893e81d396acc50f6d6ff383f442
|
||||
392e0b4482a484200469c8f04a9e1f9b5e21c66842f6e96c9a670c9c61abd388f06a51a0d2d8542f
|
||||
68960fa728ab5133a36eef0b6c137a3be4ba3bf0507efb2a98a1f1651d39af017666ca593e82430e
|
||||
888cee8619456f9fb47d84a5c33b8b5ebee06f75d885c12073401a449f56c16aa64ed3aa62363f77
|
||||
061bfedf72429b023d37d0d724d00a1248db0fead349f1c09b075372c980991b7b25d479d8f6e8de
|
||||
f7e3fe501ab6794c3b976ce0bd04c006bac1a94fb6409f60c45e5c9ec2196a246368fb6faf3e6c53
|
||||
b51339b2eb3b52ec6f6dfc511f9b30952ccc814544af5ebd09bee3d004de334afd660f2807192e4b
|
||||
b3c0cba85745c8740fd20b5f39b9d3fbdb5579c0bd1a60320ad6a100c6402c7279679f25fefb1fa3
|
||||
cc8ea5e9f8db3222f83c7516dffd616b152f501ec8ad0552ab323db5fafd23876053317b483e00df
|
||||
829e5c57bbca6f8ca01a87562edf1769dbd542a8f6287effc3ac6732c68c4f5573695b27b0bbca58
|
||||
c8e1ffa35db8f011a010fa3d98fd2183b84afcb56c2dd1d35b9a53e479b6f84565d28e49bc4bfb97
|
||||
90e1ddf2daa4cb7e3362fb1341cee4c6e8ef20cada36774c01d07e9efe2bf11fb495dbda4dae9091
|
||||
98eaad8e716b93d5a0d08ed1d0afc725e08e3c5b2f8e7594b78ff6e2fbf2122b648888b812900df0
|
||||
1c4fad5ea0688fc31cd1cff191b3a8c1ad2f2f2218be0e1777ea752dfe8b021fa1e5a0cc0fb56f74
|
||||
e818acf3d6ce89e299b4a84fe0fd13e0b77cc43b81d2ada8d9165fa2668095770593cc7314211a14
|
||||
77e6ad206577b5fa86c75442f5fb9d35cfebcdaf0c7b3e89a0d6411bd3ae1e7e4900250e2d2071b3
|
||||
5e226800bb57b8e0af2464369bf009b91e5563911d59dfa6aa78c14389d95a537f207d5ba202e5b9
|
||||
c5832603766295cfa911c819684e734a41b3472dca7b14a94a1b5100529a532915d60f573fbc9bc6
|
||||
e42b60a47681e6740008ba6fb5571be91ff296ec6b2a0dd915b6636521e7b9f9b6ff34052ec58556
|
||||
6453b02d5da99f8fa108ba47996e85076a4b7a70e9b5b32944db75092ec4192623ad6ea6b049a7df
|
||||
7d9cee60b88fedb266ecaa8c71699a17ff5664526cc2b19ee1193602a575094c29a0591340e4183a
|
||||
3e3f54989a5b429d656b8fe4d699f73fd6a1d29c07efe830f54d2d38e6f0255dc14cdd20868470eb
|
||||
266382e9c6021ecc5e09686b3f3ebaefc93c9718146b6a70a1687f358452a0e286b79c5305aa5007
|
||||
373e07841c7fdeae5c8e7d44ec5716f2b8b03ada37f0500c0df01c1f040200b3ffae0cf51a3cb574
|
||||
b225837a58dc0921bdd19113f97ca92ff69432477322f547013ae5e58137c2dadcc8b576349af3dd
|
||||
a7a94461460fd0030eecc8c73ea4751e41e238cd993bea0e2f3280bba1183eb3314e548b384f6db9
|
||||
086f420d03f60a04bf2cb8129024977c795679b072bcaf89afde9a771fd9930810b38bae12dccf3f
|
||||
2e5512721f2e6b7124501adde69f84cd877a5847187408da17bc9f9abce94b7d8cec7aec3adb851d
|
||||
fa63094366c464c3d2ef1c18473215d908dd433b3724c2ba1612a14d432a65c45150940002133ae4
|
||||
dd71dff89e10314e5581ac77d65f11199b043556f1d7a3c76b3c11183b5924a509f28fe6ed97f1fb
|
||||
fa9ebabf2c1e153c6e86e34570eae96fb1860e5e0a5a3e2ab3771fe71c4e3d06fa2965dcb999e71d
|
||||
0f803e89d65266c8252e4cc9789c10b36ac6150eba94e2ea78a5fc3c531e0a2df4f2f74ea7361d2b
|
||||
3d1939260f19c279605223a708f71312b6ebadfe6eeac31f66e3bc4595a67bc883b17f37d1018cff
|
||||
28c332ddefbe6c5aa56558218568ab9802eecea50fdb2f953b2aef7dad5b6e2f841521b628290761
|
||||
70ecdd4775619f151013cca830eb61bd960334fe1eaa0363cfb5735c904c70a239d59e9e0bcbaade
|
||||
14eecc86bc60622ca79cab5cabb2f3846e648b1eaf19bdf0caa02369b9655abb5040685a323c2ab4
|
||||
b3319ee9d5c021b8f79b540b19875fa09995f7997e623d7da8f837889a97e32d7711ed935f166812
|
||||
810e358829c7e61fd696dedfa17858ba9957f584a51b2272639b83c3ff1ac24696cdb30aeb532e30
|
||||
548fd948e46dbc312858ebf2ef34c6ffeafe28ed61ee7c3c735d4a14d9e864b7e342105d14203e13
|
||||
e045eee2b6a3aaabeadb6c4f15facb4fd0c742f442ef6abbb5654f3b1d41cd2105d81e799e86854d
|
||||
c7e44b476a3d816250cf62a1f25b8d2646fc8883a0c1c7b6a37f1524c369cb749247848a0b5692b2
|
||||
85095bbf00ad19489d1462b17423820e0058428d2a0c55f5ea1dadf43e233f70613372f0928d937e
|
||||
41d65fecf16c223bdb7cde3759cbee74604085f2a7ce77326ea607808419f8509ee8efd85561d997
|
||||
35a969a7aac50c06c25a04abfc800bcadc9e447a2ec3453484fdd567050e1e9ec9db73dbd3105588
|
||||
cd675fda79e3674340c5c43465713e38d83d28f89ef16dff20153e21e78fb03d4ae6e39f2bdb83ad
|
||||
f7e93d5a68948140f7f64c261c94692934411520f77602d4f7bcf46b2ed4a20068d40824713320f4
|
||||
6a43b7d4b7500061af1e39f62e9724454614214f74bf8b88404d95fc1d96b591af70f4ddd366a02f
|
||||
45bfbc09ec03bd97857fac6dd031cb850496eb27b355fd3941da2547e6abca0a9a28507825530429
|
||||
f40a2c86dae9b66dfb68dc1462d7486900680ec0a427a18dee4f3ffea2e887ad8cb58ce0067af4d6
|
||||
b6aace1e7cd3375fecce78a399406b2a4220fe9e35d9f385b9ee39d7ab3b124e8b1dc9faf74b6d18
|
||||
5626a36631eae397b23a6efa74dd5b43326841e7f7ca7820fbfb0af54ed8feb397454056acba4895
|
||||
2755533a3a20838d87fe6ba9b7d096954b55a867bca1159a58cca9296399e1db33a62a4a563f3125
|
||||
f95ef47e1c9029317cfdf8e80204272f7080bb155c05282ce395c11548e4c66d2248c1133fc70f86
|
||||
dc07f9c9ee41041f0f404779a45d886e17325f51ebd59bc0d1f2bcc18f41113564257b7834602a9c
|
||||
60dff8e8a31f636c1b0e12b4c202e1329eaf664fd1cad181156b2395e0333e92e13b240b62eebeb9
|
||||
2285b2a20ee6ba0d99de720c8c2da2f728d012784595b794fd647d0862e7ccf5f05449a36f877d48
|
||||
fac39dfd27f33e8d1e0a476341992eff743a6f6eabf4f8fd37a812dc60a1ebddf8991be14cdb6e6b
|
||||
0dc67b55106d672c372765d43bdcd0e804f1290dc7cc00ffa3b5390f92690fed0b667b9ffbcedb7d
|
||||
9ca091cf0bd9155ea3bb132f88515bad247b9479bf763bd6eb37392eb3cc1159798026e297f42e31
|
||||
2d6842ada7c66a2b3b12754ccc782ef11c6a124237b79251e706a1bbe64bfb63501a6b101811caed
|
||||
fa3d25bdd8e2e1c3c9444216590a121386d90cec6ed5abea2a64af674eda86a85fbebfe98864e4c3
|
||||
fe9dbc8057f0f7c08660787bf86003604dd1fd8346f6381fb07745ae04d736fccc83426b33f01eab
|
||||
71b08041873c005e5f77a057bebde8ae2455464299bf582e614e58f48ff2ddfda2f474ef388789bd
|
||||
c25366f9c3c8b38e74b475f25546fcd9b97aeb26618b1ddf84846a0e79915f95e2466e598e20b457
|
||||
708cd55591c902de4cb90bace1bb8205d011a862487574a99eb77f19b6e0a9dc09662d09a1c43246
|
||||
33e85a1f0209f0be8c4a99a0251d6efe101ab93d1d0ba5a4dfa186f20f2868f169dcb7da83573906
|
||||
fea1e2ce9b4fcd7f5250115e01a70683faa002b5c40de6d0279af88c27773f8641c3604c0661a806
|
||||
b5f0177a28c0f586e0006058aa30dc7d6211e69ed72338ea6353c2dd94c2c21634bbcbee5690bcb6
|
||||
deebfc7da1ce591d766f05e4094b7c018839720a3d7c927c2486e3725f724d9db91ac15bb4d39eb8
|
||||
fced54557808fca5b5d83d7cd34dad0fc41e50ef5eb161e6f8a28514d96c51133c6fd5c7e756e14e
|
||||
c4362abfceddc6c837d79a323492638212670efa8e406000e03a39ce37d3faf5cfabc277375ac52d
|
||||
1b5cb0679e4fa33742d382274099bc9bbed5118e9dbf0f7315d62d1c7ec700c47bb78c1b6b21a190
|
||||
45b26eb1be6a366eb45748ab2fbc946e79c6a376d26549c2c8530ff8ee468dde7dd5730a1d4cd04d
|
||||
c62939bbdba9ba4650ac9526e8be5ee304a1fad5f06a2d519a63ef8ce29a86ee22c089c2b843242e
|
||||
f6a51e03aa9cf2d0a483c061ba9be96a4d8fe51550ba645bd62826a2f9a73a3ae14ba99586ef5562
|
||||
e9c72fefd3f752f7da3f046f6977fa0a5980e4a91587b086019b09e6ad3b3ee593e990fd5a9e34d7
|
||||
972cf0b7d9022b8b5196d5ac3a017da67dd1cf3ed67c7d2d281f9f25cfadf2b89b5ad6b4725a88f5
|
||||
4ce029ac71e019a5e647b0acfded93fa9be8d3c48d283b57ccf8d5662979132e28785f0191ed7560
|
||||
55f7960e44e3d35e8c15056dd488f46dba03a161250564f0bdc3eb9e153c9057a297271aeca93a07
|
||||
2a1b3f6d9b1e6321f5f59c66fb26dcf3197533d928b155fdf5035634828aba3cbb28517711c20ad9
|
||||
f8abcc5167ccad925f4de817513830dc8e379d58629320f991ea7a90c2fb3e7bce5121ce64774fbe
|
||||
32a8b6e37ec3293d4648de53696413e680a2ae0810dd6db22469852dfd09072166b39a460a6445c0
|
||||
dd586cdecf1c20c8ae5bbef7dd1b588d40ccd2017f6bb4e3bbdda26a7e3a59ff453e350a44bcb4cd
|
||||
d572eacea8fa6484bb8d6612aebf3c6f47d29be463542f5d9eaec2771bf64e6370740e0d8de75b13
|
||||
57f8721671af537d5d4040cb084eb4e2cc34d2466a0115af84e1b0042895983a1d06b89fb4ce6ea0
|
||||
486f3f3b823520ab82011a1d4b277227f8611560b1e7933fdcbb3a792b344525bda08839e151ce79
|
||||
4b2f32c9b7a01fbac9e01cc87ebcc7d1f6cf0111c3a1e8aac71a908749d44fbd9ad0dadecbd50ada
|
||||
380339c32ac69136678df9317ce0b12b4ff79e59b743f5bb3af2d519ff27d9459cbf97222c15e6fc
|
||||
2a0f91fc719b941525fae59361ceb69cebc2a8645912baa8d1b6c1075ee3056a0c10d25065cb03a4
|
||||
42e0ec6e0e1698db3b4c98a0be3278e9649f1f9532e0d392dfd3a0342b8971f21e1b0a74414ba334
|
||||
8cc5be7120c37632d8df359f8d9b992f2ee60b6f470fe3f11de54cda541edad891ce6279cfcd3e7e
|
||||
6f1618b166fd2c1d05848fd2c5f6fb2299f523f357a632762393a8353156cccd02acf081625a75eb
|
||||
b56e16369788d273ccde96629281b949d04c50901b71c65614e6c6c7bd327a140a45e1d006c3f27b
|
||||
9ac9aa53fd62a80f00bb25bfe235bdd2f671126905b2040222b6cbcf7ccd769c2b53113ec01640e3
|
||||
d338abbd602547adf0ba38209cf746ce7677afa1c52075606085cbfe4e8ae88dd87aaaf9b04cf9aa
|
||||
7e1948c25c02fb8a8c01c36ae4d6ebe1f990d4f869a65cdea03f09252dc208e69fb74e6132ce77e2
|
||||
5b578fdfe33ac372e6'''.split())
|
||||
|
||||
|
||||
def test_hex_pi_nth_digits():
|
||||
assert pi_hex_digits(0) == '3243f6a8885a30'
|
||||
assert pi_hex_digits(1) == '243f6a8885a308'
|
||||
assert pi_hex_digits(10000) == '68ac8fcfb8016c'
|
||||
assert pi_hex_digits(13) == '08d313198a2e03'
|
||||
assert pi_hex_digits(0, 3) == '324'
|
||||
assert pi_hex_digits(0, 0) == ''
|
||||
raises(ValueError, lambda: pi_hex_digits(-1))
|
||||
raises(ValueError, lambda: pi_hex_digits(0, -1))
|
||||
raises(ValueError, lambda: pi_hex_digits(3.14))
|
||||
|
||||
# this will pick a random segment to compute every time
|
||||
# it is run. If it ever fails, there is an error in the
|
||||
# computation.
|
||||
n = randint(0, len(dig))
|
||||
prec = randint(0, len(dig) - n)
|
||||
assert pi_hex_digits(n, prec) == dig[n: n + prec]
|
||||
@@ -0,0 +1,77 @@
|
||||
import itertools
|
||||
from sympy.core import GoldenRatio as phi
|
||||
from sympy.core.numbers import (Rational, pi)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.ntheory.continued_fraction import \
|
||||
(continued_fraction_periodic as cf_p,
|
||||
continued_fraction_iterator as cf_i,
|
||||
continued_fraction_convergents as cf_c,
|
||||
continued_fraction_reduce as cf_r,
|
||||
continued_fraction as cf)
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_continued_fraction():
|
||||
assert cf_p(1, 1, 10, 0) == cf_p(1, 1, 0, 1)
|
||||
assert cf_p(1, -1, 10, 1) == cf_p(-1, 1, 10, -1)
|
||||
t = sqrt(2)
|
||||
assert cf((1 + t)*(1 - t)) == cf(-1)
|
||||
for n in [0, 2, Rational(2, 3), sqrt(2), 3*sqrt(2), 1 + 2*sqrt(3)/5,
|
||||
(2 - 3*sqrt(5))/7, 1 + sqrt(2), (-5 + sqrt(17))/4]:
|
||||
assert (cf_r(cf(n)) - n).expand() == 0
|
||||
assert (cf_r(cf(-n)) + n).expand() == 0
|
||||
raises(ValueError, lambda: cf(sqrt(2 + sqrt(3))))
|
||||
raises(ValueError, lambda: cf(sqrt(2) + sqrt(3)))
|
||||
raises(ValueError, lambda: cf(pi))
|
||||
raises(ValueError, lambda: cf(.1))
|
||||
|
||||
raises(ValueError, lambda: cf_p(1, 0, 0))
|
||||
raises(ValueError, lambda: cf_p(1, 1, -1))
|
||||
assert cf_p(4, 3, 0) == [1, 3]
|
||||
assert cf_p(0, 3, 5) == [0, 1, [2, 1, 12, 1, 2, 2]]
|
||||
assert cf_p(1, 1, 0) == [1]
|
||||
assert cf_p(3, 4, 0) == [0, 1, 3]
|
||||
assert cf_p(4, 5, 0) == [0, 1, 4]
|
||||
assert cf_p(5, 6, 0) == [0, 1, 5]
|
||||
assert cf_p(11, 13, 0) == [0, 1, 5, 2]
|
||||
assert cf_p(16, 19, 0) == [0, 1, 5, 3]
|
||||
assert cf_p(27, 32, 0) == [0, 1, 5, 2, 2]
|
||||
assert cf_p(1, 2, 5) == [[1]]
|
||||
assert cf_p(0, 1, 2) == [1, [2]]
|
||||
assert cf_p(6, 7, 49) == [1, 1, 6]
|
||||
assert cf_p(3796, 1387, 0) == [2, 1, 2, 1, 4]
|
||||
assert cf_p(3245, 10000) == [0, 3, 12, 4, 13]
|
||||
assert cf_p(1932, 2568) == [0, 1, 3, 26, 2]
|
||||
assert cf_p(6589, 2569) == [2, 1, 1, 3, 2, 1, 3, 1, 23]
|
||||
|
||||
def take(iterator, n=7):
|
||||
return list(itertools.islice(iterator, n))
|
||||
|
||||
assert take(cf_i(phi)) == [1, 1, 1, 1, 1, 1, 1]
|
||||
assert take(cf_i(pi)) == [3, 7, 15, 1, 292, 1, 1]
|
||||
|
||||
assert list(cf_i(Rational(17, 12))) == [1, 2, 2, 2]
|
||||
assert list(cf_i(Rational(-17, 12))) == [-2, 1, 1, 2, 2]
|
||||
|
||||
assert list(cf_c([1, 6, 1, 8])) == [S.One, Rational(7, 6), Rational(8, 7), Rational(71, 62)]
|
||||
assert list(cf_c([2])) == [S(2)]
|
||||
assert list(cf_c([1, 1, 1, 1, 1, 1, 1])) == [S.One, S(2), Rational(3, 2), Rational(5, 3),
|
||||
Rational(8, 5), Rational(13, 8), Rational(21, 13)]
|
||||
assert list(cf_c([1, 6, Rational(-1, 2), 4])) == [S.One, Rational(7, 6), Rational(5, 4), Rational(3, 2)]
|
||||
assert take(cf_c([[1]])) == [S.One, S(2), Rational(3, 2), Rational(5, 3), Rational(8, 5),
|
||||
Rational(13, 8), Rational(21, 13)]
|
||||
assert take(cf_c([1, [1, 2]])) == [S.One, S(2), Rational(5, 3), Rational(7, 4), Rational(19, 11),
|
||||
Rational(26, 15), Rational(71, 41)]
|
||||
|
||||
cf_iter_e = (2 if i == 1 else i // 3 * 2 if i % 3 == 0 else 1 for i in itertools.count(1))
|
||||
assert take(cf_c(cf_iter_e)) == [S(2), S(3), Rational(8, 3), Rational(11, 4), Rational(19, 7),
|
||||
Rational(87, 32), Rational(106, 39)]
|
||||
|
||||
assert cf_r([1, 6, 1, 8]) == Rational(71, 62)
|
||||
assert cf_r([3]) == S(3)
|
||||
assert cf_r([-1, 5, 1, 4]) == Rational(-24, 29)
|
||||
assert (cf_r([0, 1, 1, 7, [24, 8]]) - (sqrt(3) + 2)/7).expand() == 0
|
||||
assert cf_r([1, 5, 9]) == Rational(55, 46)
|
||||
assert (cf_r([[1]]) - (sqrt(5) + 1)/2).expand() == 0
|
||||
assert cf_r([-3, 1, 1, [2]]) == -1 - sqrt(2)
|
||||
@@ -0,0 +1,55 @@
|
||||
from sympy.ntheory import count_digits, digits, is_palindromic
|
||||
from sympy.core.intfunc import num_digits
|
||||
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_num_digits():
|
||||
# depending on whether one rounds up or down or uses log or log10,
|
||||
# one or more of these will fail if you don't check for the off-by
|
||||
# one condition
|
||||
assert num_digits(2, 2) == 2
|
||||
assert num_digits(2**48 - 1, 2) == 48
|
||||
assert num_digits(1000, 10) == 4
|
||||
assert num_digits(125, 5) == 4
|
||||
assert num_digits(100, 16) == 2
|
||||
assert num_digits(-1000, 10) == 4
|
||||
# if changes are made to the function, this structured test over
|
||||
# this range will expose problems
|
||||
for base in range(2, 100):
|
||||
for e in range(1, 100):
|
||||
n = base**e
|
||||
assert num_digits(n, base) == e + 1
|
||||
assert num_digits(n + 1, base) == e + 1
|
||||
assert num_digits(n - 1, base) == e
|
||||
|
||||
|
||||
def test_digits():
|
||||
assert all(digits(n, 2)[1:] == [int(d) for d in format(n, 'b')]
|
||||
for n in range(20))
|
||||
assert all(digits(n, 8)[1:] == [int(d) for d in format(n, 'o')]
|
||||
for n in range(20))
|
||||
assert all(digits(n, 16)[1:] == [int(d, 16) for d in format(n, 'x')]
|
||||
for n in range(20))
|
||||
assert digits(2345, 34) == [34, 2, 0, 33]
|
||||
assert digits(384753, 71) == [71, 1, 5, 23, 4]
|
||||
assert digits(93409, 10) == [10, 9, 3, 4, 0, 9]
|
||||
assert digits(-92838, 11) == [-11, 6, 3, 8, 2, 9]
|
||||
assert digits(35, 10) == [10, 3, 5]
|
||||
assert digits(35, 10, 3) == [10, 0, 3, 5]
|
||||
assert digits(-35, 10, 4) == [-10, 0, 0, 3, 5]
|
||||
raises(ValueError, lambda: digits(2, 2, 1))
|
||||
|
||||
|
||||
def test_count_digits():
|
||||
assert count_digits(55, 2) == {1: 5, 0: 1}
|
||||
assert count_digits(55, 10) == {5: 2}
|
||||
n = count_digits(123)
|
||||
assert n[4] == 0 and type(n[4]) is int
|
||||
|
||||
|
||||
def test_is_palindromic():
|
||||
assert is_palindromic(-11)
|
||||
assert is_palindromic(11)
|
||||
assert is_palindromic(0o121, 8)
|
||||
assert not is_palindromic(123)
|
||||
@@ -0,0 +1,63 @@
|
||||
from sympy.external.gmpy import invert
|
||||
from sympy.ntheory.ecm import ecm, Point
|
||||
from sympy.testing.pytest import slow
|
||||
|
||||
@slow
|
||||
def test_ecm():
|
||||
assert ecm(3146531246531241245132451321) == {3, 100327907731, 10454157497791297}
|
||||
assert ecm(46167045131415113) == {43, 2634823, 407485517}
|
||||
assert ecm(631211032315670776841) == {9312934919, 67777885039}
|
||||
assert ecm(398883434337287) == {99476569, 4009823}
|
||||
assert ecm(64211816600515193) == {281719, 359641, 633767}
|
||||
assert ecm(4269021180054189416198169786894227) == {184039, 241603, 333331, 477973, 618619, 974123}
|
||||
assert ecm(4516511326451341281684513) == {3, 39869, 131743543, 95542348571}
|
||||
assert ecm(4132846513818654136451) == {47, 160343, 2802377, 195692803}
|
||||
assert ecm(168541512131094651323) == {79, 113, 11011069, 1714635721}
|
||||
#This takes ~10secs while factorint is not able to factorize this even in ~10mins
|
||||
assert ecm(7060005655815754299976961394452809, B1=100000, B2=1000000) == {6988699669998001, 1010203040506070809}
|
||||
|
||||
|
||||
def test_Point():
|
||||
#The curve is of the form y**2 = x**3 + a*x**2 + x
|
||||
mod = 101
|
||||
a = 10
|
||||
a_24 = (a + 2)*invert(4, mod)
|
||||
p1 = Point(10, 17, a_24, mod)
|
||||
p2 = p1.double()
|
||||
assert p2 == Point(68, 56, a_24, mod)
|
||||
p4 = p2.double()
|
||||
assert p4 == Point(22, 64, a_24, mod)
|
||||
p8 = p4.double()
|
||||
assert p8 == Point(71, 95, a_24, mod)
|
||||
p16 = p8.double()
|
||||
assert p16 == Point(5, 16, a_24, mod)
|
||||
p32 = p16.double()
|
||||
assert p32 == Point(33, 96, a_24, mod)
|
||||
|
||||
# p3 = p2 + p1
|
||||
p3 = p2.add(p1, p1)
|
||||
assert p3 == Point(1, 61, a_24, mod)
|
||||
# p5 = p3 + p2 or p4 + p1
|
||||
p5 = p3.add(p2, p1)
|
||||
assert p5 == Point(49, 90, a_24, mod)
|
||||
assert p5 == p4.add(p1, p3)
|
||||
# p6 = 2*p3
|
||||
p6 = p3.double()
|
||||
assert p6 == Point(87, 43, a_24, mod)
|
||||
assert p6 == p4.add(p2, p2)
|
||||
# p7 = p5 + p2
|
||||
p7 = p5.add(p2, p3)
|
||||
assert p7 == Point(69, 23, a_24, mod)
|
||||
assert p7 == p4.add(p3, p1)
|
||||
assert p7 == p6.add(p1, p5)
|
||||
# p9 = p5 + p4
|
||||
p9 = p5.add(p4, p1)
|
||||
assert p9 == Point(56, 99, a_24, mod)
|
||||
assert p9 == p6.add(p3, p3)
|
||||
assert p9 == p7.add(p2, p5)
|
||||
assert p9 == p8.add(p1, p7)
|
||||
|
||||
assert p5 == p1.mont_ladder(5)
|
||||
assert p9 == p1.mont_ladder(9)
|
||||
assert p16 == p1.mont_ladder(16)
|
||||
assert p9 == p3.mont_ladder(3)
|
||||
@@ -0,0 +1,49 @@
|
||||
from sympy.core.numbers import Rational
|
||||
from sympy.ntheory.egyptian_fraction import egyptian_fraction
|
||||
from sympy.core.add import Add
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.core.random import random_complex_number
|
||||
|
||||
|
||||
def test_egyptian_fraction():
|
||||
def test_equality(r, alg="Greedy"):
|
||||
return r == Add(*[Rational(1, i) for i in egyptian_fraction(r, alg)])
|
||||
|
||||
r = random_complex_number(a=0, c=1, b=0, d=0, rational=True)
|
||||
assert test_equality(r)
|
||||
|
||||
assert egyptian_fraction(Rational(4, 17)) == [5, 29, 1233, 3039345]
|
||||
assert egyptian_fraction(Rational(7, 13), "Greedy") == [2, 26]
|
||||
assert egyptian_fraction(Rational(23, 101), "Greedy") == \
|
||||
[5, 37, 1438, 2985448, 40108045937720]
|
||||
assert egyptian_fraction(Rational(18, 23), "Takenouchi") == \
|
||||
[2, 6, 12, 35, 276, 2415]
|
||||
assert egyptian_fraction(Rational(5, 6), "Graham Jewett") == \
|
||||
[6, 7, 8, 9, 10, 42, 43, 44, 45, 56, 57, 58, 72, 73, 90, 1806, 1807,
|
||||
1808, 1892, 1893, 1980, 3192, 3193, 3306, 5256, 3263442, 3263443,
|
||||
3267056, 3581556, 10192056, 10650056950806]
|
||||
assert egyptian_fraction(Rational(5, 6), "Golomb") == [2, 6, 12, 20, 30]
|
||||
assert egyptian_fraction(Rational(5, 121), "Golomb") == [25, 1225, 3577, 7081, 11737]
|
||||
raises(ValueError, lambda: egyptian_fraction(Rational(-4, 9)))
|
||||
assert egyptian_fraction(Rational(8, 3), "Golomb") == [1, 2, 3, 4, 5, 6, 7,
|
||||
14, 574, 2788, 6460,
|
||||
11590, 33062, 113820]
|
||||
assert egyptian_fraction(Rational(355, 113)) == [1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
10, 11, 12, 27, 744, 893588,
|
||||
1251493536607,
|
||||
20361068938197002344405230]
|
||||
|
||||
|
||||
def test_input():
|
||||
r = (2,3), Rational(2, 3), (Rational(2), Rational(3))
|
||||
for m in ["Greedy", "Graham Jewett", "Takenouchi", "Golomb"]:
|
||||
for i in r:
|
||||
d = egyptian_fraction(i, m)
|
||||
assert all(i.is_Integer for i in d)
|
||||
if m == "Graham Jewett":
|
||||
assert d == [3, 4, 12]
|
||||
else:
|
||||
assert d == [2, 6]
|
||||
# check prefix
|
||||
d = egyptian_fraction(Rational(5, 3))
|
||||
assert d == [1, 2, 6] and all(i.is_Integer for i in d)
|
||||
@@ -0,0 +1,20 @@
|
||||
from sympy.ntheory.elliptic_curve import EllipticCurve
|
||||
|
||||
|
||||
def test_elliptic_curve():
|
||||
# Point addition and multiplication
|
||||
e3 = EllipticCurve(-1, 9)
|
||||
p = e3(0, 3)
|
||||
q = e3(-1, 3)
|
||||
r = p + q
|
||||
assert r.x == 1 and r.y == -3
|
||||
r = 2*p + q
|
||||
assert r.x == 35 and r.y == 207
|
||||
r = -p + q
|
||||
assert r.x == 37 and r.y == 225
|
||||
# Verify result in http://www.lmfdb.org/EllipticCurve/Q
|
||||
# Discriminant
|
||||
assert EllipticCurve(-1, 9).discriminant == -34928
|
||||
assert EllipticCurve(-2731, -55146, 1, 0, 1).discriminant == 25088
|
||||
# Torsion points
|
||||
assert len(EllipticCurve(0, 1).torsion_points()) == 6
|
||||
@@ -0,0 +1,702 @@
|
||||
from sympy.core.containers import Dict
|
||||
from sympy.core.mul import Mul
|
||||
from sympy.core.power import Pow
|
||||
from sympy.core.singleton import S
|
||||
from sympy.functions.combinatorial.factorials import factorial as fac
|
||||
from sympy.core.numbers import Integer, Rational
|
||||
from sympy.external.gmpy import gcd
|
||||
|
||||
from sympy.ntheory import (totient,
|
||||
factorint, primefactors, divisors, nextprime,
|
||||
pollard_rho, perfect_power, multiplicity, multiplicity_in_factorial,
|
||||
divisor_count, primorial, pollard_pm1, divisor_sigma,
|
||||
factorrat, reduced_totient)
|
||||
from sympy.ntheory.factor_ import (smoothness, smoothness_p, proper_divisors,
|
||||
antidivisors, antidivisor_count, _divisor_sigma, core, udivisors, udivisor_sigma,
|
||||
udivisor_count, proper_divisor_count, primenu, primeomega,
|
||||
mersenne_prime_exponent, is_perfect, is_abundant,
|
||||
is_deficient, is_amicable, is_carmichael, find_carmichael_numbers_in_range,
|
||||
find_first_n_carmichaels, dra, drm, _perfect_power, factor_cache)
|
||||
|
||||
from sympy.testing.pytest import raises, slow
|
||||
|
||||
from sympy.utilities.iterables import capture
|
||||
|
||||
|
||||
def fac_multiplicity(n, p):
|
||||
"""Return the power of the prime number p in the
|
||||
factorization of n!"""
|
||||
if p > n:
|
||||
return 0
|
||||
if p > n//2:
|
||||
return 1
|
||||
q, m = n, 0
|
||||
while q >= p:
|
||||
q //= p
|
||||
m += q
|
||||
return m
|
||||
|
||||
|
||||
def multiproduct(seq=(), start=1):
|
||||
"""
|
||||
Return the product of a sequence of factors with multiplicities,
|
||||
times the value of the parameter ``start``. The input may be a
|
||||
sequence of (factor, exponent) pairs or a dict of such pairs.
|
||||
|
||||
>>> multiproduct({3:7, 2:5}, 4) # = 3**7 * 2**5 * 4
|
||||
279936
|
||||
|
||||
"""
|
||||
if not seq:
|
||||
return start
|
||||
if isinstance(seq, dict):
|
||||
seq = iter(seq.items())
|
||||
units = start
|
||||
multi = []
|
||||
for base, exp in seq:
|
||||
if not exp:
|
||||
continue
|
||||
elif exp == 1:
|
||||
units *= base
|
||||
else:
|
||||
if exp % 2:
|
||||
units *= base
|
||||
multi.append((base, exp//2))
|
||||
return units * multiproduct(multi)**2
|
||||
|
||||
|
||||
def test_multiplicity():
|
||||
for b in range(2, 20):
|
||||
for i in range(100):
|
||||
assert multiplicity(b, b**i) == i
|
||||
assert multiplicity(b, (b**i) * 23) == i
|
||||
assert multiplicity(b, (b**i) * 1000249) == i
|
||||
# Should be fast
|
||||
assert multiplicity(10, 10**10023) == 10023
|
||||
# Should exit quickly
|
||||
assert multiplicity(10**10, 10**10) == 1
|
||||
# Should raise errors for bad input
|
||||
raises(ValueError, lambda: multiplicity(1, 1))
|
||||
raises(ValueError, lambda: multiplicity(1, 2))
|
||||
raises(ValueError, lambda: multiplicity(1.3, 2))
|
||||
raises(ValueError, lambda: multiplicity(2, 0))
|
||||
raises(ValueError, lambda: multiplicity(1.3, 0))
|
||||
|
||||
# handles Rationals
|
||||
assert multiplicity(10, Rational(30, 7)) == 1
|
||||
assert multiplicity(Rational(2, 7), Rational(4, 7)) == 1
|
||||
assert multiplicity(Rational(1, 7), Rational(3, 49)) == 2
|
||||
assert multiplicity(Rational(2, 7), Rational(7, 2)) == -1
|
||||
assert multiplicity(3, Rational(1, 9)) == -2
|
||||
|
||||
|
||||
def test_multiplicity_in_factorial():
|
||||
n = fac(1000)
|
||||
for i in (2, 4, 6, 12, 30, 36, 48, 60, 72, 96):
|
||||
assert multiplicity(i, n) == multiplicity_in_factorial(i, 1000)
|
||||
|
||||
|
||||
def test_private_perfect_power():
|
||||
assert _perfect_power(0) is False
|
||||
assert _perfect_power(1) is False
|
||||
assert _perfect_power(2) is False
|
||||
assert _perfect_power(3) is False
|
||||
for x in [2, 3, 5, 6, 7, 12, 15, 105, 100003]:
|
||||
for y in range(2, 100):
|
||||
assert _perfect_power(x**y) == (x, y)
|
||||
if x & 1:
|
||||
assert _perfect_power(x**y, next_p=3) == (x, y)
|
||||
if x == 100003:
|
||||
assert _perfect_power(x**y, next_p=100003) == (x, y)
|
||||
assert _perfect_power(101*x**y) == False
|
||||
# Catalan's conjecture
|
||||
if x**y not in [8, 9]:
|
||||
assert _perfect_power(x**y + 1) == False
|
||||
assert _perfect_power(x**y - 1) == False
|
||||
for x in range(1, 10):
|
||||
for y in range(1, 10):
|
||||
g = gcd(x, y)
|
||||
if g == 1:
|
||||
assert _perfect_power(5**x * 101**y) == False
|
||||
else:
|
||||
assert _perfect_power(5**x * 101**y) == (5**(x//g) * 101**(y//g), g)
|
||||
|
||||
|
||||
def test_perfect_power():
|
||||
raises(ValueError, lambda: perfect_power(0.1))
|
||||
assert perfect_power(0) is False
|
||||
assert perfect_power(1) is False
|
||||
assert perfect_power(2) is False
|
||||
assert perfect_power(3) is False
|
||||
assert perfect_power(4) == (2, 2)
|
||||
assert perfect_power(14) is False
|
||||
assert perfect_power(25) == (5, 2)
|
||||
assert perfect_power(22) is False
|
||||
assert perfect_power(22, [2]) is False
|
||||
assert perfect_power(137**(3*5*13)) == (137, 3*5*13)
|
||||
assert perfect_power(137**(3*5*13) + 1) is False
|
||||
assert perfect_power(137**(3*5*13) - 1) is False
|
||||
assert perfect_power(103005006004**7) == (103005006004, 7)
|
||||
assert perfect_power(103005006004**7 + 1) is False
|
||||
assert perfect_power(103005006004**7 - 1) is False
|
||||
assert perfect_power(103005006004**12) == (103005006004, 12)
|
||||
assert perfect_power(103005006004**12 + 1) is False
|
||||
assert perfect_power(103005006004**12 - 1) is False
|
||||
assert perfect_power(2**10007) == (2, 10007)
|
||||
assert perfect_power(2**10007 + 1) is False
|
||||
assert perfect_power(2**10007 - 1) is False
|
||||
assert perfect_power((9**99 + 1)**60) == (9**99 + 1, 60)
|
||||
assert perfect_power((9**99 + 1)**60 + 1) is False
|
||||
assert perfect_power((9**99 + 1)**60 - 1) is False
|
||||
assert perfect_power((10**40000)**2, big=False) == (10**40000, 2)
|
||||
assert perfect_power(10**100000) == (10, 100000)
|
||||
assert perfect_power(10**100001) == (10, 100001)
|
||||
assert perfect_power(13**4, [3, 5]) is False
|
||||
assert perfect_power(3**4, [3, 10], factor=0) is False
|
||||
assert perfect_power(3**3*5**3) == (15, 3)
|
||||
assert perfect_power(2**3*5**5) is False
|
||||
assert perfect_power(2*13**4) is False
|
||||
assert perfect_power(2**5*3**3) is False
|
||||
t = 2**24
|
||||
for d in divisors(24):
|
||||
m = perfect_power(t*3**d)
|
||||
assert m and m[1] == d or d == 1
|
||||
m = perfect_power(t*3**d, big=False)
|
||||
assert m and m[1] == 2 or d == 1 or d == 3, (d, m)
|
||||
|
||||
# negatives and non-integer rationals
|
||||
assert perfect_power(-4) is False
|
||||
assert perfect_power(-8) == (-2, 3)
|
||||
assert perfect_power(-S(1)/8) == (-S(1)/2, 3)
|
||||
assert perfect_power(S(1)/3) == False
|
||||
assert perfect_power(-5**15) == (-5, 15)
|
||||
assert perfect_power(-5**15, big=False) == (-3125, 3)
|
||||
assert perfect_power(-5**15, [15]) == (-5, 15)
|
||||
|
||||
n = -3 ** 60
|
||||
assert perfect_power(n) == (-81, 15)
|
||||
assert perfect_power(n, big=False) == (-3486784401, 3)
|
||||
assert perfect_power(n, [3, 5], big=True) == (-531441, 5)
|
||||
assert perfect_power(n, [3, 5], big=False) == (-3486784401, 3)
|
||||
assert perfect_power(n, [2]) == False
|
||||
assert perfect_power(n, [2, 15]) == (-81, 15)
|
||||
assert perfect_power(n, [2, 13]) == False
|
||||
assert perfect_power(n, [17]) == False
|
||||
assert perfect_power(n, [3]) == (-3486784401, 3)
|
||||
assert perfect_power(n + 1) == False
|
||||
|
||||
r = S(2) ** (2 * 5 * 7) / S(3) ** (2 * 7)
|
||||
assert perfect_power(r) == (S(32) / 3, 14)
|
||||
assert perfect_power(-r) == (-S(1024) / 9, 7)
|
||||
assert perfect_power(r, big=False) == (S(34359738368) / 2187, 2)
|
||||
assert perfect_power(r, [2, 5]) == (S(34359738368) / 2187, 2)
|
||||
assert perfect_power(r, [5, 7]) == (S(1024) / 9, 7)
|
||||
assert perfect_power(r, [5, 7], big=False) == (S(1024) / 9, 7)
|
||||
assert perfect_power(r, [2, 5, 7], big=False) == (S(34359738368) / 2187, 2)
|
||||
assert perfect_power(-r, [5, 7], big=False) == (-S(1024) / 9, 7)
|
||||
|
||||
assert perfect_power(-S(1) / 8) == (-S(1) / 2, 3)
|
||||
|
||||
assert perfect_power((-3)**60) == (3, 60)
|
||||
assert perfect_power((-3)**61) == (-3, 61)
|
||||
|
||||
assert perfect_power(S(2 ** 9) / 3 ** 12) == (S(8)/81, 3)
|
||||
assert perfect_power(Rational(1, 2)**3) == (S.Half, 3)
|
||||
assert perfect_power(Rational(-3, 2)**3) == (-3*S.Half, 3)
|
||||
|
||||
|
||||
def test_factor_cache():
|
||||
factor_cache.cache_clear()
|
||||
raises(ValueError, lambda: factor_cache.__setitem__(1, 5))
|
||||
raises(ValueError, lambda: factor_cache.__setitem__(10, 1))
|
||||
raises(ValueError, lambda: factor_cache.__setitem__(10, 10))
|
||||
raises(ValueError, lambda: factor_cache.__setitem__(10, 3))
|
||||
raises(ValueError, lambda: factor_cache.__setitem__(20, 4))
|
||||
factor_cache.maxsize = 3
|
||||
for i in range(2, 10):
|
||||
factor_cache[5*i] = 5
|
||||
assert len(factor_cache) == 3
|
||||
factor_cache.maxsize = 5
|
||||
for i in range(2, 10):
|
||||
factor_cache[5*i] = 5
|
||||
assert len(factor_cache) == 5
|
||||
factor_cache.maxsize = 2
|
||||
assert len(factor_cache) == 2
|
||||
factor_cache.maxsize =1000
|
||||
|
||||
factor_cache.cache_clear()
|
||||
factor_cache[40] = 5
|
||||
assert factor_cache.get(40) == 5
|
||||
assert factor_cache.get(20) is None
|
||||
assert factor_cache[40] == 5
|
||||
raises(KeyError, lambda: factor_cache[10])
|
||||
del factor_cache[40]
|
||||
assert len(factor_cache) == 0
|
||||
raises(KeyError, lambda: factor_cache.__delitem__(40))
|
||||
factor_cache.add(100, [5, 2])
|
||||
assert len(factor_cache) == 2
|
||||
assert factor_cache[100] == 5
|
||||
|
||||
for n in [1000000007, 10000019*20000003]:
|
||||
factorint(n)
|
||||
assert n in factor_cache
|
||||
|
||||
# Restore the initial state
|
||||
factor_cache.cache_clear()
|
||||
factor_cache.maxsize = 1000
|
||||
|
||||
|
||||
@slow
|
||||
def test_factorint():
|
||||
assert primefactors(123456) == [2, 3, 643]
|
||||
assert factorint(0) == {0: 1}
|
||||
assert factorint(1) == {}
|
||||
assert factorint(-1) == {-1: 1}
|
||||
assert factorint(-2) == {-1: 1, 2: 1}
|
||||
assert factorint(-16) == {-1: 1, 2: 4}
|
||||
assert factorint(2) == {2: 1}
|
||||
assert factorint(126) == {2: 1, 3: 2, 7: 1}
|
||||
assert factorint(123456) == {2: 6, 3: 1, 643: 1}
|
||||
assert factorint(5951757) == {3: 1, 7: 1, 29: 2, 337: 1}
|
||||
assert factorint(64015937) == {7993: 1, 8009: 1}
|
||||
assert factorint(2**(2**6) + 1) == {274177: 1, 67280421310721: 1}
|
||||
#issue 19683
|
||||
assert factorint(10**38 - 1) == {3: 2, 11: 1, 909090909090909091: 1, 1111111111111111111: 1}
|
||||
#issue 17676
|
||||
assert factorint(28300421052393658575) == {3: 1, 5: 2, 11: 2, 43: 1, 2063: 2, 4127: 1, 4129: 1}
|
||||
assert factorint(2063**2 * 4127**1 * 4129**1) == {2063: 2, 4127: 1, 4129: 1}
|
||||
assert factorint(2347**2 * 7039**1 * 7043**1) == {2347: 2, 7039: 1, 7043: 1}
|
||||
|
||||
assert factorint(0, multiple=True) == [0]
|
||||
assert factorint(1, multiple=True) == []
|
||||
assert factorint(-1, multiple=True) == [-1]
|
||||
assert factorint(-2, multiple=True) == [-1, 2]
|
||||
assert factorint(-16, multiple=True) == [-1, 2, 2, 2, 2]
|
||||
assert factorint(2, multiple=True) == [2]
|
||||
assert factorint(24, multiple=True) == [2, 2, 2, 3]
|
||||
assert factorint(126, multiple=True) == [2, 3, 3, 7]
|
||||
assert factorint(123456, multiple=True) == [2, 2, 2, 2, 2, 2, 3, 643]
|
||||
assert factorint(5951757, multiple=True) == [3, 7, 29, 29, 337]
|
||||
assert factorint(64015937, multiple=True) == [7993, 8009]
|
||||
assert factorint(2**(2**6) + 1, multiple=True) == [274177, 67280421310721]
|
||||
|
||||
assert factorint(fac(1, evaluate=False)) == {}
|
||||
assert factorint(fac(7, evaluate=False)) == {2: 4, 3: 2, 5: 1, 7: 1}
|
||||
assert factorint(fac(15, evaluate=False)) == \
|
||||
{2: 11, 3: 6, 5: 3, 7: 2, 11: 1, 13: 1}
|
||||
assert factorint(fac(20, evaluate=False)) == \
|
||||
{2: 18, 3: 8, 5: 4, 7: 2, 11: 1, 13: 1, 17: 1, 19: 1}
|
||||
assert factorint(fac(23, evaluate=False)) == \
|
||||
{2: 19, 3: 9, 5: 4, 7: 3, 11: 2, 13: 1, 17: 1, 19: 1, 23: 1}
|
||||
|
||||
assert multiproduct(factorint(fac(200))) == fac(200)
|
||||
assert multiproduct(factorint(fac(200, evaluate=False))) == fac(200)
|
||||
for b, e in factorint(fac(150)).items():
|
||||
assert e == fac_multiplicity(150, b)
|
||||
for b, e in factorint(fac(150, evaluate=False)).items():
|
||||
assert e == fac_multiplicity(150, b)
|
||||
assert factorint(103005006059**7) == {103005006059: 7}
|
||||
assert factorint(31337**191) == {31337: 191}
|
||||
assert factorint(2**1000 * 3**500 * 257**127 * 383**60) == \
|
||||
{2: 1000, 3: 500, 257: 127, 383: 60}
|
||||
assert len(factorint(fac(10000))) == 1229
|
||||
assert len(factorint(fac(10000, evaluate=False))) == 1229
|
||||
assert factorint(12932983746293756928584532764589230) == \
|
||||
{2: 1, 5: 1, 73: 1, 727719592270351: 1, 63564265087747: 1, 383: 1}
|
||||
assert factorint(727719592270351) == {727719592270351: 1}
|
||||
assert factorint(2**64 + 1, use_trial=False) == factorint(2**64 + 1)
|
||||
for n in range(60000):
|
||||
assert multiproduct(factorint(n)) == n
|
||||
assert pollard_rho(2**64 + 1, seed=1) == 274177
|
||||
assert pollard_rho(19, seed=1) is None
|
||||
assert factorint(3, limit=2) == {3: 1}
|
||||
assert factorint(12345) == {3: 1, 5: 1, 823: 1}
|
||||
assert factorint(
|
||||
12345, limit=3) == {4115: 1, 3: 1} # the 5 is greater than the limit
|
||||
assert factorint(1, limit=1) == {}
|
||||
assert factorint(0, 3) == {0: 1}
|
||||
assert factorint(12, limit=1) == {12: 1}
|
||||
assert factorint(30, limit=2) == {2: 1, 15: 1}
|
||||
assert factorint(16, limit=2) == {2: 4}
|
||||
assert factorint(124, limit=3) == {2: 2, 31: 1}
|
||||
assert factorint(4*31**2, limit=3) == {2: 2, 31: 2}
|
||||
p1 = nextprime(2**32)
|
||||
p2 = nextprime(2**16)
|
||||
p3 = nextprime(p2)
|
||||
assert factorint(p1*p2*p3) == {p1: 1, p2: 1, p3: 1}
|
||||
assert factorint(13*17*19, limit=15) == {13: 1, 17*19: 1}
|
||||
assert factorint(1951*15013*15053, limit=2000) == {225990689: 1, 1951: 1}
|
||||
assert factorint(primorial(17) + 1, use_pm1=0) == \
|
||||
{int(19026377261): 1, 3467: 1, 277: 1, 105229: 1}
|
||||
# when prime b is closer than approx sqrt(8*p) to prime p then they are
|
||||
# "close" and have a trivial factorization
|
||||
a = nextprime(2**2**8) # 78 digits
|
||||
b = nextprime(a + 2**2**4)
|
||||
assert 'Fermat' in capture(lambda: factorint(a*b, verbose=1))
|
||||
|
||||
raises(ValueError, lambda: pollard_rho(4))
|
||||
raises(ValueError, lambda: pollard_pm1(3))
|
||||
raises(ValueError, lambda: pollard_pm1(10, B=2))
|
||||
# verbose coverage
|
||||
n = nextprime(2**16)*nextprime(2**17)*nextprime(1901)
|
||||
assert 'with primes' in capture(lambda: factorint(n, verbose=1))
|
||||
capture(lambda: factorint(nextprime(2**16)*1012, verbose=1))
|
||||
|
||||
n = nextprime(2**17)
|
||||
capture(lambda: factorint(n**3, verbose=1)) # perfect power termination
|
||||
capture(lambda: factorint(2*n, verbose=1)) # factoring complete msg
|
||||
|
||||
# exceed 1st
|
||||
n = nextprime(2**17)
|
||||
n *= nextprime(n)
|
||||
assert '1000' in capture(lambda: factorint(n, limit=1000, verbose=1))
|
||||
n *= nextprime(n)
|
||||
assert len(factorint(n)) == 3
|
||||
assert len(factorint(n, limit=p1)) == 3
|
||||
n *= nextprime(2*n)
|
||||
# exceed 2nd
|
||||
assert '2001' in capture(lambda: factorint(n, limit=2000, verbose=1))
|
||||
assert capture(
|
||||
lambda: factorint(n, limit=4000, verbose=1)).count('Pollard') == 2
|
||||
# non-prime pm1 result
|
||||
n = nextprime(8069)
|
||||
n *= nextprime(2*n)*nextprime(2*n, 2)
|
||||
capture(lambda: factorint(n, verbose=1)) # non-prime pm1 result
|
||||
# factor fermat composite
|
||||
p1 = nextprime(2**17)
|
||||
p2 = nextprime(2*p1)
|
||||
assert factorint((p1*p2**2)**3) == {p1: 3, p2: 6}
|
||||
# Test for non integer input
|
||||
raises(ValueError, lambda: factorint(4.5))
|
||||
# test dict/Dict input
|
||||
sans = '2**10*3**3'
|
||||
n = {4: 2, 12: 3}
|
||||
assert str(factorint(n)) == sans
|
||||
assert str(factorint(Dict(n))) == sans
|
||||
|
||||
|
||||
def test_divisors_and_divisor_count():
|
||||
assert divisors(-1) == [1]
|
||||
assert divisors(0) == []
|
||||
assert divisors(1) == [1]
|
||||
assert divisors(2) == [1, 2]
|
||||
assert divisors(3) == [1, 3]
|
||||
assert divisors(17) == [1, 17]
|
||||
assert divisors(10) == [1, 2, 5, 10]
|
||||
assert divisors(100) == [1, 2, 4, 5, 10, 20, 25, 50, 100]
|
||||
assert divisors(101) == [1, 101]
|
||||
assert type(divisors(2, generator=True)) is not list
|
||||
|
||||
assert divisor_count(0) == 0
|
||||
assert divisor_count(-1) == 1
|
||||
assert divisor_count(1) == 1
|
||||
assert divisor_count(6) == 4
|
||||
assert divisor_count(12) == 6
|
||||
|
||||
assert divisor_count(180, 3) == divisor_count(180//3)
|
||||
assert divisor_count(2*3*5, 7) == 0
|
||||
|
||||
|
||||
def test_proper_divisors_and_proper_divisor_count():
|
||||
assert proper_divisors(-1) == []
|
||||
assert proper_divisors(0) == []
|
||||
assert proper_divisors(1) == []
|
||||
assert proper_divisors(2) == [1]
|
||||
assert proper_divisors(3) == [1]
|
||||
assert proper_divisors(17) == [1]
|
||||
assert proper_divisors(10) == [1, 2, 5]
|
||||
assert proper_divisors(100) == [1, 2, 4, 5, 10, 20, 25, 50]
|
||||
assert proper_divisors(1000000007) == [1]
|
||||
assert type(proper_divisors(2, generator=True)) is not list
|
||||
|
||||
assert proper_divisor_count(0) == 0
|
||||
assert proper_divisor_count(-1) == 0
|
||||
assert proper_divisor_count(1) == 0
|
||||
assert proper_divisor_count(36) == 8
|
||||
assert proper_divisor_count(2*3*5) == 7
|
||||
|
||||
|
||||
def test_udivisors_and_udivisor_count():
|
||||
assert udivisors(-1) == [1]
|
||||
assert udivisors(0) == []
|
||||
assert udivisors(1) == [1]
|
||||
assert udivisors(2) == [1, 2]
|
||||
assert udivisors(3) == [1, 3]
|
||||
assert udivisors(17) == [1, 17]
|
||||
assert udivisors(10) == [1, 2, 5, 10]
|
||||
assert udivisors(100) == [1, 4, 25, 100]
|
||||
assert udivisors(101) == [1, 101]
|
||||
assert udivisors(1000) == [1, 8, 125, 1000]
|
||||
assert type(udivisors(2, generator=True)) is not list
|
||||
|
||||
assert udivisor_count(0) == 0
|
||||
assert udivisor_count(-1) == 1
|
||||
assert udivisor_count(1) == 1
|
||||
assert udivisor_count(6) == 4
|
||||
assert udivisor_count(12) == 4
|
||||
|
||||
assert udivisor_count(180) == 8
|
||||
assert udivisor_count(2*3*5*7) == 16
|
||||
|
||||
|
||||
def test_issue_6981():
|
||||
S = set(divisors(4)).union(set(divisors(Integer(2))))
|
||||
assert S == {1,2,4}
|
||||
|
||||
|
||||
def test_issue_4356():
|
||||
assert factorint(1030903) == {53: 2, 367: 1}
|
||||
|
||||
|
||||
def test_divisors():
|
||||
assert divisors(28) == [1, 2, 4, 7, 14, 28]
|
||||
assert list(divisors(3*5*7, 1)) == [1, 3, 5, 15, 7, 21, 35, 105]
|
||||
assert divisors(0) == []
|
||||
|
||||
|
||||
def test_divisor_count():
|
||||
assert divisor_count(0) == 0
|
||||
assert divisor_count(6) == 4
|
||||
|
||||
|
||||
def test_proper_divisors():
|
||||
assert proper_divisors(-1) == []
|
||||
assert proper_divisors(28) == [1, 2, 4, 7, 14]
|
||||
assert list(proper_divisors(3*5*7, True)) == [1, 3, 5, 15, 7, 21, 35]
|
||||
|
||||
|
||||
def test_proper_divisor_count():
|
||||
assert proper_divisor_count(6) == 3
|
||||
assert proper_divisor_count(108) == 11
|
||||
|
||||
|
||||
def test_antidivisors():
|
||||
assert antidivisors(-1) == []
|
||||
assert antidivisors(-3) == [2]
|
||||
assert antidivisors(14) == [3, 4, 9]
|
||||
assert antidivisors(237) == [2, 5, 6, 11, 19, 25, 43, 95, 158]
|
||||
assert antidivisors(12345) == [2, 6, 7, 10, 30, 1646, 3527, 4938, 8230]
|
||||
assert antidivisors(393216) == [262144]
|
||||
assert sorted(x for x in antidivisors(3*5*7, 1)) == \
|
||||
[2, 6, 10, 11, 14, 19, 30, 42, 70]
|
||||
assert antidivisors(1) == []
|
||||
assert type(antidivisors(2, generator=True)) is not list
|
||||
|
||||
def test_antidivisor_count():
|
||||
assert antidivisor_count(0) == 0
|
||||
assert antidivisor_count(-1) == 0
|
||||
assert antidivisor_count(-4) == 1
|
||||
assert antidivisor_count(20) == 3
|
||||
assert antidivisor_count(25) == 5
|
||||
assert antidivisor_count(38) == 7
|
||||
assert antidivisor_count(180) == 6
|
||||
assert antidivisor_count(2*3*5) == 3
|
||||
|
||||
|
||||
def test_smoothness_and_smoothness_p():
|
||||
assert smoothness(1) == (1, 1)
|
||||
assert smoothness(2**4*3**2) == (3, 16)
|
||||
|
||||
assert smoothness_p(10431, m=1) == \
|
||||
(1, [(3, (2, 2, 4)), (19, (1, 5, 5)), (61, (1, 31, 31))])
|
||||
assert smoothness_p(10431) == \
|
||||
(-1, [(3, (2, 2, 2)), (19, (1, 3, 9)), (61, (1, 5, 5))])
|
||||
assert smoothness_p(10431, power=1) == \
|
||||
(-1, [(3, (2, 2, 2)), (61, (1, 5, 5)), (19, (1, 3, 9))])
|
||||
assert smoothness_p(21477639576571, visual=1) == \
|
||||
'p**i=4410317**1 has p-1 B=1787, B-pow=1787\n' + \
|
||||
'p**i=4869863**1 has p-1 B=2434931, B-pow=2434931'
|
||||
|
||||
|
||||
def test_visual_factorint():
|
||||
assert factorint(1, visual=1) == 1
|
||||
forty2 = factorint(42, visual=True)
|
||||
assert type(forty2) == Mul
|
||||
assert str(forty2) == '2**1*3**1*7**1'
|
||||
assert factorint(1, visual=True) is S.One
|
||||
no = {"evaluate": False}
|
||||
assert factorint(42**2, visual=True) == Mul(Pow(2, 2, **no),
|
||||
Pow(3, 2, **no),
|
||||
Pow(7, 2, **no), **no)
|
||||
assert -1 in factorint(-42, visual=True).args
|
||||
|
||||
|
||||
def test_factorrat():
|
||||
assert str(factorrat(S(12)/1, visual=True)) == '2**2*3**1'
|
||||
assert str(factorrat(Rational(1, 1), visual=True)) == '1'
|
||||
assert str(factorrat(S(25)/14, visual=True)) == '5**2/(2*7)'
|
||||
assert str(factorrat(Rational(25, 14), visual=True)) == '5**2/(2*7)'
|
||||
assert str(factorrat(S(-25)/14/9, visual=True)) == '-1*5**2/(2*3**2*7)'
|
||||
|
||||
assert factorrat(S(12)/1, multiple=True) == [2, 2, 3]
|
||||
assert factorrat(Rational(1, 1), multiple=True) == []
|
||||
assert factorrat(S(25)/14, multiple=True) == [Rational(1, 7), S.Half, 5, 5]
|
||||
assert factorrat(Rational(25, 14), multiple=True) == [Rational(1, 7), S.Half, 5, 5]
|
||||
assert factorrat(Rational(12, 1), multiple=True) == [2, 2, 3]
|
||||
assert factorrat(S(-25)/14/9, multiple=True) == \
|
||||
[-1, Rational(1, 7), Rational(1, 3), Rational(1, 3), S.Half, 5, 5]
|
||||
|
||||
|
||||
def test_visual_io():
|
||||
sm = smoothness_p
|
||||
fi = factorint
|
||||
# with smoothness_p
|
||||
n = 124
|
||||
d = fi(n)
|
||||
m = fi(d, visual=True)
|
||||
t = sm(n)
|
||||
s = sm(t)
|
||||
for th in [d, s, t, n, m]:
|
||||
assert sm(th, visual=True) == s
|
||||
assert sm(th, visual=1) == s
|
||||
for th in [d, s, t, n, m]:
|
||||
assert sm(th, visual=False) == t
|
||||
assert [sm(th, visual=None) for th in [d, s, t, n, m]] == [s, d, s, t, t]
|
||||
assert [sm(th, visual=2) for th in [d, s, t, n, m]] == [s, d, s, t, t]
|
||||
|
||||
# with factorint
|
||||
for th in [d, m, n]:
|
||||
assert fi(th, visual=True) == m
|
||||
assert fi(th, visual=1) == m
|
||||
for th in [d, m, n]:
|
||||
assert fi(th, visual=False) == d
|
||||
assert [fi(th, visual=None) for th in [d, m, n]] == [m, d, d]
|
||||
assert [fi(th, visual=0) for th in [d, m, n]] == [m, d, d]
|
||||
|
||||
# test reevaluation
|
||||
no = {"evaluate": False}
|
||||
assert sm({4: 2}, visual=False) == sm(16)
|
||||
assert sm(Mul(*[Pow(k, v, **no) for k, v in {4: 2, 2: 6}.items()], **no),
|
||||
visual=False) == sm(2**10)
|
||||
|
||||
assert fi({4: 2}, visual=False) == fi(16)
|
||||
assert fi(Mul(*[Pow(k, v, **no) for k, v in {4: 2, 2: 6}.items()], **no),
|
||||
visual=False) == fi(2**10)
|
||||
|
||||
|
||||
def test_core():
|
||||
assert core(35**13, 10) == 42875
|
||||
assert core(210**2) == 1
|
||||
assert core(7776, 3) == 36
|
||||
assert core(10**27, 22) == 10**5
|
||||
assert core(537824) == 14
|
||||
assert core(1, 6) == 1
|
||||
|
||||
|
||||
def test__divisor_sigma():
|
||||
assert _divisor_sigma(23450) == 50592
|
||||
assert _divisor_sigma(23450, 0) == 24
|
||||
assert _divisor_sigma(23450, 1) == 50592
|
||||
assert _divisor_sigma(23450, 2) == 730747500
|
||||
assert _divisor_sigma(23450, 3) == 14666785333344
|
||||
A000005 = [1, 2, 2, 3, 2, 4, 2, 4, 3, 4, 2, 6, 2, 4, 4, 5, 2, 6, 2, 6, 4,
|
||||
4, 2, 8, 3, 4, 4, 6, 2, 8, 2, 6, 4, 4, 4, 9, 2, 4, 4, 8, 2, 8]
|
||||
for n, val in enumerate(A000005, 1):
|
||||
assert _divisor_sigma(n, 0) == val
|
||||
A000203 = [1, 3, 4, 7, 6, 12, 8, 15, 13, 18, 12, 28, 14, 24, 24, 31, 18,
|
||||
39, 20, 42, 32, 36, 24, 60, 31, 42, 40, 56, 30, 72, 32, 63, 48]
|
||||
for n, val in enumerate(A000203, 1):
|
||||
assert _divisor_sigma(n, 1) == val
|
||||
A001157 = [1, 5, 10, 21, 26, 50, 50, 85, 91, 130, 122, 210, 170, 250, 260,
|
||||
341, 290, 455, 362, 546, 500, 610, 530, 850, 651, 850, 820, 1050]
|
||||
for n, val in enumerate(A001157, 1):
|
||||
assert _divisor_sigma(n, 2) == val
|
||||
|
||||
|
||||
def test_mersenne_prime_exponent():
|
||||
assert mersenne_prime_exponent(1) == 2
|
||||
assert mersenne_prime_exponent(4) == 7
|
||||
assert mersenne_prime_exponent(10) == 89
|
||||
assert mersenne_prime_exponent(25) == 21701
|
||||
raises(ValueError, lambda: mersenne_prime_exponent(52))
|
||||
raises(ValueError, lambda: mersenne_prime_exponent(0))
|
||||
|
||||
|
||||
def test_is_perfect():
|
||||
assert is_perfect(-6) is False
|
||||
assert is_perfect(6) is True
|
||||
assert is_perfect(15) is False
|
||||
assert is_perfect(28) is True
|
||||
assert is_perfect(400) is False
|
||||
assert is_perfect(496) is True
|
||||
assert is_perfect(8128) is True
|
||||
assert is_perfect(10000) is False
|
||||
|
||||
|
||||
def test_is_abundant():
|
||||
assert is_abundant(10) is False
|
||||
assert is_abundant(12) is True
|
||||
assert is_abundant(18) is True
|
||||
assert is_abundant(21) is False
|
||||
assert is_abundant(945) is True
|
||||
|
||||
|
||||
def test_is_deficient():
|
||||
assert is_deficient(10) is True
|
||||
assert is_deficient(22) is True
|
||||
assert is_deficient(56) is False
|
||||
assert is_deficient(20) is False
|
||||
assert is_deficient(36) is False
|
||||
|
||||
|
||||
def test_is_amicable():
|
||||
assert is_amicable(173, 129) is False
|
||||
assert is_amicable(220, 284) is True
|
||||
assert is_amicable(8756, 8756) is False
|
||||
|
||||
|
||||
def test_is_carmichael():
|
||||
A002997 = [561, 1105, 1729, 2465, 2821, 6601, 8911, 10585, 15841,
|
||||
29341, 41041, 46657, 52633, 62745, 63973, 75361, 101101]
|
||||
for n in range(1, 5000):
|
||||
assert is_carmichael(n) == (n in A002997)
|
||||
for n in A002997:
|
||||
assert is_carmichael(n)
|
||||
|
||||
|
||||
def test_find_carmichael_numbers_in_range():
|
||||
assert find_carmichael_numbers_in_range(0, 561) == []
|
||||
assert find_carmichael_numbers_in_range(561, 562) == [561]
|
||||
assert find_carmichael_numbers_in_range(561, 1105) == find_carmichael_numbers_in_range(561, 562)
|
||||
raises(ValueError, lambda: find_carmichael_numbers_in_range(-2, 2))
|
||||
raises(ValueError, lambda: find_carmichael_numbers_in_range(22, 2))
|
||||
|
||||
|
||||
def test_find_first_n_carmichaels():
|
||||
assert find_first_n_carmichaels(0) == []
|
||||
assert find_first_n_carmichaels(1) == [561]
|
||||
assert find_first_n_carmichaels(2) == [561, 1105]
|
||||
|
||||
|
||||
def test_dra():
|
||||
assert dra(19, 12) == 8
|
||||
assert dra(2718, 10) == 9
|
||||
assert dra(0, 22) == 0
|
||||
assert dra(23456789, 10) == 8
|
||||
raises(ValueError, lambda: dra(24, -2))
|
||||
raises(ValueError, lambda: dra(24.2, 5))
|
||||
|
||||
def test_drm():
|
||||
assert drm(19, 12) == 7
|
||||
assert drm(2718, 10) == 2
|
||||
assert drm(0, 15) == 0
|
||||
assert drm(234161, 10) == 6
|
||||
raises(ValueError, lambda: drm(24, -2))
|
||||
raises(ValueError, lambda: drm(11.6, 9))
|
||||
|
||||
|
||||
def test_deprecated_ntheory_symbolic_functions():
|
||||
from sympy.testing.pytest import warns_deprecated_sympy
|
||||
|
||||
with warns_deprecated_sympy():
|
||||
assert primenu(3) == 1
|
||||
with warns_deprecated_sympy():
|
||||
assert primeomega(3) == 1
|
||||
with warns_deprecated_sympy():
|
||||
assert totient(3) == 2
|
||||
with warns_deprecated_sympy():
|
||||
assert reduced_totient(3) == 2
|
||||
with warns_deprecated_sympy():
|
||||
assert divisor_sigma(3) == 4
|
||||
with warns_deprecated_sympy():
|
||||
assert udivisor_sigma(3) == 4
|
||||
@@ -0,0 +1,285 @@
|
||||
from bisect import bisect, bisect_left
|
||||
|
||||
from sympy.functions.combinatorial.numbers import mobius, totient
|
||||
from sympy.ntheory.generate import (sieve, Sieve)
|
||||
|
||||
from sympy.ntheory import isprime, randprime, nextprime, prevprime, \
|
||||
primerange, primepi, prime, primorial, composite, compositepi
|
||||
from sympy.ntheory.generate import cycle_length, _primepi
|
||||
from sympy.ntheory.primetest import mr
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
def test_prime():
|
||||
assert prime(1) == 2
|
||||
assert prime(2) == 3
|
||||
assert prime(5) == 11
|
||||
assert prime(11) == 31
|
||||
assert prime(57) == 269
|
||||
assert prime(296) == 1949
|
||||
assert prime(559) == 4051
|
||||
assert prime(3000) == 27449
|
||||
assert prime(4096) == 38873
|
||||
assert prime(9096) == 94321
|
||||
assert prime(25023) == 287341
|
||||
assert prime(10000000) == 179424673 # issue #20951
|
||||
assert prime(99999999) == 2038074739
|
||||
raises(ValueError, lambda: prime(0))
|
||||
sieve.extend(3000)
|
||||
assert prime(401) == 2749
|
||||
raises(ValueError, lambda: prime(-1))
|
||||
|
||||
|
||||
def test__primepi():
|
||||
assert _primepi(-1) == 0
|
||||
assert _primepi(1) == 0
|
||||
assert _primepi(2) == 1
|
||||
assert _primepi(5) == 3
|
||||
assert _primepi(11) == 5
|
||||
assert _primepi(57) == 16
|
||||
assert _primepi(296) == 62
|
||||
assert _primepi(559) == 102
|
||||
assert _primepi(3000) == 430
|
||||
assert _primepi(4096) == 564
|
||||
assert _primepi(9096) == 1128
|
||||
assert _primepi(25023) == 2763
|
||||
assert _primepi(10**8) == 5761455
|
||||
assert _primepi(253425253) == 13856396
|
||||
assert _primepi(8769575643) == 401464322
|
||||
sieve.extend(3000)
|
||||
assert _primepi(2000) == 303
|
||||
|
||||
|
||||
def test_composite():
|
||||
from sympy.ntheory.generate import sieve
|
||||
sieve._reset()
|
||||
assert composite(1) == 4
|
||||
assert composite(2) == 6
|
||||
assert composite(5) == 10
|
||||
assert composite(11) == 20
|
||||
assert composite(41) == 58
|
||||
assert composite(57) == 80
|
||||
assert composite(296) == 370
|
||||
assert composite(559) == 684
|
||||
assert composite(3000) == 3488
|
||||
assert composite(4096) == 4736
|
||||
assert composite(9096) == 10368
|
||||
assert composite(25023) == 28088
|
||||
sieve.extend(3000)
|
||||
assert composite(1957) == 2300
|
||||
assert composite(2568) == 2998
|
||||
raises(ValueError, lambda: composite(0))
|
||||
|
||||
|
||||
def test_compositepi():
|
||||
assert compositepi(1) == 0
|
||||
assert compositepi(2) == 0
|
||||
assert compositepi(5) == 1
|
||||
assert compositepi(11) == 5
|
||||
assert compositepi(57) == 40
|
||||
assert compositepi(296) == 233
|
||||
assert compositepi(559) == 456
|
||||
assert compositepi(3000) == 2569
|
||||
assert compositepi(4096) == 3531
|
||||
assert compositepi(9096) == 7967
|
||||
assert compositepi(25023) == 22259
|
||||
assert compositepi(10**8) == 94238544
|
||||
assert compositepi(253425253) == 239568856
|
||||
assert compositepi(8769575643) == 8368111320
|
||||
sieve.extend(3000)
|
||||
assert compositepi(2321) == 1976
|
||||
|
||||
|
||||
def test_generate():
|
||||
from sympy.ntheory.generate import sieve
|
||||
sieve._reset()
|
||||
assert nextprime(-4) == 2
|
||||
assert nextprime(2) == 3
|
||||
assert nextprime(5) == 7
|
||||
assert nextprime(12) == 13
|
||||
assert prevprime(3) == 2
|
||||
assert prevprime(7) == 5
|
||||
assert prevprime(13) == 11
|
||||
assert prevprime(19) == 17
|
||||
assert prevprime(20) == 19
|
||||
|
||||
sieve.extend_to_no(9)
|
||||
assert sieve._list[-1] == 23
|
||||
|
||||
assert sieve._list[-1] < 31
|
||||
assert 31 in sieve
|
||||
|
||||
assert nextprime(90) == 97
|
||||
assert nextprime(10**40) == (10**40 + 121)
|
||||
primelist = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31,
|
||||
37, 41, 43, 47, 53, 59, 61, 67, 71, 73,
|
||||
79, 83, 89, 97, 101, 103, 107, 109, 113,
|
||||
127, 131, 137, 139, 149, 151, 157, 163,
|
||||
167, 173, 179, 181, 191, 193, 197, 199,
|
||||
211, 223, 227, 229, 233, 239, 241, 251,
|
||||
257, 263, 269, 271, 277, 281, 283, 293]
|
||||
for i in range(len(primelist) - 2):
|
||||
for j in range(2, len(primelist) - i):
|
||||
assert nextprime(primelist[i], j) == primelist[i + j]
|
||||
if 3 < i:
|
||||
assert nextprime(primelist[i] - 1, j) == primelist[i + j - 1]
|
||||
raises(ValueError, lambda: nextprime(2, 0))
|
||||
raises(ValueError, lambda: nextprime(2, -1))
|
||||
assert prevprime(97) == 89
|
||||
assert prevprime(10**40) == (10**40 - 17)
|
||||
|
||||
raises(ValueError, lambda: Sieve(0))
|
||||
raises(ValueError, lambda: Sieve(-1))
|
||||
for sieve_interval in [1, 10, 11, 1_000_000]:
|
||||
s = Sieve(sieve_interval=sieve_interval)
|
||||
for head in range(s._list[-1] + 1, (s._list[-1] + 1)**2, 2):
|
||||
for tail in range(head + 1, (s._list[-1] + 1)**2):
|
||||
A = list(s._primerange(head, tail))
|
||||
B = primelist[bisect(primelist, head):bisect_left(primelist, tail)]
|
||||
assert A == B
|
||||
for k in range(s._list[-1], primelist[-1] - 1, 2):
|
||||
s = Sieve(sieve_interval=sieve_interval)
|
||||
s.extend(k)
|
||||
assert list(s._list) == primelist[:bisect(primelist, k)]
|
||||
s.extend(primelist[-1])
|
||||
assert list(s._list) == primelist
|
||||
|
||||
assert list(sieve.primerange(10, 1)) == []
|
||||
assert list(sieve.primerange(5, 9)) == [5, 7]
|
||||
sieve._reset(prime=True)
|
||||
assert list(sieve.primerange(2, 13)) == [2, 3, 5, 7, 11]
|
||||
assert list(sieve.primerange(13)) == [2, 3, 5, 7, 11]
|
||||
assert list(sieve.primerange(8)) == [2, 3, 5, 7]
|
||||
assert list(sieve.primerange(-2)) == []
|
||||
assert list(sieve.primerange(29)) == [2, 3, 5, 7, 11, 13, 17, 19, 23]
|
||||
assert list(sieve.primerange(34)) == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]
|
||||
|
||||
assert list(sieve.totientrange(5, 15)) == [4, 2, 6, 4, 6, 4, 10, 4, 12, 6]
|
||||
sieve._reset(totient=True)
|
||||
assert list(sieve.totientrange(3, 13)) == [2, 2, 4, 2, 6, 4, 6, 4, 10, 4]
|
||||
assert list(sieve.totientrange(900, 1000)) == [totient(x) for x in range(900, 1000)]
|
||||
assert list(sieve.totientrange(0, 1)) == []
|
||||
assert list(sieve.totientrange(1, 2)) == [1]
|
||||
|
||||
assert list(sieve.mobiusrange(5, 15)) == [-1, 1, -1, 0, 0, 1, -1, 0, -1, 1]
|
||||
sieve._reset(mobius=True)
|
||||
assert list(sieve.mobiusrange(3, 13)) == [-1, 0, -1, 1, -1, 0, 0, 1, -1, 0]
|
||||
assert list(sieve.mobiusrange(1050, 1100)) == [mobius(x) for x in range(1050, 1100)]
|
||||
assert list(sieve.mobiusrange(0, 1)) == []
|
||||
assert list(sieve.mobiusrange(1, 2)) == [1]
|
||||
|
||||
assert list(primerange(10, 1)) == []
|
||||
assert list(primerange(2, 7)) == [2, 3, 5]
|
||||
assert list(primerange(2, 10)) == [2, 3, 5, 7]
|
||||
assert list(primerange(1050, 1100)) == [1051, 1061,
|
||||
1063, 1069, 1087, 1091, 1093, 1097]
|
||||
s = Sieve()
|
||||
for i in range(30, 2350, 376):
|
||||
for j in range(2, 5096, 1139):
|
||||
A = list(s.primerange(i, i + j))
|
||||
B = list(primerange(i, i + j))
|
||||
assert A == B
|
||||
s = Sieve()
|
||||
sieve._reset(prime=True)
|
||||
sieve.extend(13)
|
||||
for i in range(200):
|
||||
for j in range(i, 200):
|
||||
A = list(s.primerange(i, j))
|
||||
B = list(primerange(i, j))
|
||||
assert A == B
|
||||
sieve.extend(1000)
|
||||
for a, b in [(901, 1103), # a < 1000 < b < 1000**2
|
||||
(806, 1002007), # a < 1000 < 1000**2 < b
|
||||
(2000, 30001), # 1000 < a < b < 1000**2
|
||||
(100005, 1010001), # 1000 < a < 1000**2 < b
|
||||
(1003003, 1005000), # 1000**2 < a < b
|
||||
]:
|
||||
assert list(primerange(a, b)) == list(s.primerange(a, b))
|
||||
sieve._reset(prime=True)
|
||||
sieve.extend(100000)
|
||||
assert len(sieve._list) == len(set(sieve._list))
|
||||
s = Sieve()
|
||||
assert s[10] == 29
|
||||
|
||||
assert nextprime(2, 2) == 5
|
||||
|
||||
raises(ValueError, lambda: totient(0))
|
||||
|
||||
raises(ValueError, lambda: primorial(0))
|
||||
|
||||
assert mr(1, [2]) is False
|
||||
|
||||
func = lambda i: (i**2 + 1) % 51
|
||||
assert next(cycle_length(func, 4)) == (6, 3)
|
||||
assert list(cycle_length(func, 4, values=True)) == \
|
||||
[4, 17, 35, 2, 5, 26, 14, 44, 50, 2, 5, 26, 14]
|
||||
assert next(cycle_length(func, 4, nmax=5)) == (5, None)
|
||||
assert list(cycle_length(func, 4, nmax=5, values=True)) == \
|
||||
[4, 17, 35, 2, 5]
|
||||
sieve.extend(3000)
|
||||
assert nextprime(2968) == 2969
|
||||
assert prevprime(2930) == 2927
|
||||
raises(ValueError, lambda: prevprime(1))
|
||||
raises(ValueError, lambda: prevprime(-4))
|
||||
|
||||
|
||||
def test_randprime():
|
||||
assert randprime(10, 1) is None
|
||||
assert randprime(3, -3) is None
|
||||
assert randprime(2, 3) == 2
|
||||
assert randprime(1, 3) == 2
|
||||
assert randprime(3, 5) == 3
|
||||
raises(ValueError, lambda: randprime(-12, -2))
|
||||
raises(ValueError, lambda: randprime(-10, 0))
|
||||
raises(ValueError, lambda: randprime(20, 22))
|
||||
raises(ValueError, lambda: randprime(0, 2))
|
||||
raises(ValueError, lambda: randprime(1, 2))
|
||||
for a in [100, 300, 500, 250000]:
|
||||
for b in [100, 300, 500, 250000]:
|
||||
p = randprime(a, a + b)
|
||||
assert a <= p < (a + b) and isprime(p)
|
||||
|
||||
|
||||
def test_primorial():
|
||||
assert primorial(1) == 2
|
||||
assert primorial(1, nth=0) == 1
|
||||
assert primorial(2) == 6
|
||||
assert primorial(2, nth=0) == 2
|
||||
assert primorial(4, nth=0) == 6
|
||||
|
||||
|
||||
def test_search():
|
||||
assert 2 in sieve
|
||||
assert 2.1 not in sieve
|
||||
assert 1 not in sieve
|
||||
assert 2**1000 not in sieve
|
||||
raises(ValueError, lambda: sieve.search(1))
|
||||
|
||||
|
||||
def test_sieve_slice():
|
||||
assert sieve[5] == 11
|
||||
assert list(sieve[5:10]) == [sieve[x] for x in range(5, 10)]
|
||||
assert list(sieve[5:10:2]) == [sieve[x] for x in range(5, 10, 2)]
|
||||
assert list(sieve[1:5]) == [2, 3, 5, 7]
|
||||
raises(IndexError, lambda: sieve[:5])
|
||||
raises(IndexError, lambda: sieve[0])
|
||||
raises(IndexError, lambda: sieve[0:5])
|
||||
|
||||
def test_sieve_iter():
|
||||
values = []
|
||||
for value in sieve:
|
||||
if value > 7:
|
||||
break
|
||||
values.append(value)
|
||||
assert values == list(sieve[1:5])
|
||||
|
||||
|
||||
def test_sieve_repr():
|
||||
assert "sieve" in repr(sieve)
|
||||
assert "prime" in repr(sieve)
|
||||
|
||||
|
||||
def test_deprecated_ntheory_symbolic_functions():
|
||||
from sympy.testing.pytest import warns_deprecated_sympy
|
||||
|
||||
with warns_deprecated_sympy():
|
||||
assert primepi(0) == 0
|
||||
@@ -0,0 +1,24 @@
|
||||
from hypothesis import given
|
||||
from hypothesis import strategies as st
|
||||
from sympy import divisors
|
||||
from sympy.functions.combinatorial.numbers import divisor_sigma, totient
|
||||
from sympy.ntheory.primetest import is_square
|
||||
|
||||
|
||||
@given(n=st.integers(1, 10**10))
|
||||
def test_tau_hypothesis(n):
|
||||
div = divisors(n)
|
||||
tau_n = len(div)
|
||||
assert is_square(n) == (tau_n % 2 == 1)
|
||||
sigmas = [divisor_sigma(i) for i in div]
|
||||
totients = [totient(n // i) for i in div]
|
||||
mul = [a * b for a, b in zip(sigmas, totients)]
|
||||
assert n * tau_n == sum(mul)
|
||||
|
||||
|
||||
@given(n=st.integers(1, 10**10))
|
||||
def test_totient_hypothesis(n):
|
||||
assert totient(n) <= n
|
||||
div = divisors(n)
|
||||
totients = [totient(i) for i in div]
|
||||
assert n == sum(totients)
|
||||
@@ -0,0 +1,34 @@
|
||||
from sympy.ntheory.modular import crt, crt1, crt2, solve_congruence
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_crt():
|
||||
def mcrt(m, v, r, symmetric=False):
|
||||
assert crt(m, v, symmetric)[0] == r
|
||||
mm, e, s = crt1(m)
|
||||
assert crt2(m, v, mm, e, s, symmetric) == (r, mm)
|
||||
|
||||
mcrt([2, 3, 5], [0, 0, 0], 0)
|
||||
mcrt([2, 3, 5], [1, 1, 1], 1)
|
||||
|
||||
mcrt([2, 3, 5], [-1, -1, -1], -1, True)
|
||||
mcrt([2, 3, 5], [-1, -1, -1], 2*3*5 - 1, False)
|
||||
|
||||
assert crt([656, 350], [811, 133], symmetric=True) == (-56917, 114800)
|
||||
|
||||
|
||||
def test_modular():
|
||||
assert solve_congruence(*list(zip([3, 4, 2], [12, 35, 17]))) == (1719, 7140)
|
||||
assert solve_congruence(*list(zip([3, 4, 2], [12, 6, 17]))) is None
|
||||
assert solve_congruence(*list(zip([3, 4, 2], [13, 7, 17]))) == (172, 1547)
|
||||
assert solve_congruence(*list(zip([-10, -3, -15], [13, 7, 17]))) == (172, 1547)
|
||||
assert solve_congruence(*list(zip([-10, -3, 1, -15], [13, 7, 7, 17]))) is None
|
||||
assert solve_congruence(
|
||||
*list(zip([-10, -5, 2, -15], [13, 7, 7, 17]))) == (835, 1547)
|
||||
assert solve_congruence(
|
||||
*list(zip([-10, -5, 2, -15], [13, 7, 14, 17]))) == (2382, 3094)
|
||||
assert solve_congruence(
|
||||
*list(zip([-10, 2, 2, -15], [13, 7, 14, 17]))) == (2382, 3094)
|
||||
assert solve_congruence(*list(zip((1, 1, 2), (3, 2, 4)))) is None
|
||||
raises(
|
||||
ValueError, lambda: solve_congruence(*list(zip([3, 4, 2], [12.1, 35, 17]))))
|
||||
@@ -0,0 +1,48 @@
|
||||
from sympy.ntheory.multinomial import (binomial_coefficients, binomial_coefficients_list, multinomial_coefficients)
|
||||
from sympy.ntheory.multinomial import multinomial_coefficients_iterator
|
||||
|
||||
|
||||
def test_binomial_coefficients_list():
|
||||
assert binomial_coefficients_list(0) == [1]
|
||||
assert binomial_coefficients_list(1) == [1, 1]
|
||||
assert binomial_coefficients_list(2) == [1, 2, 1]
|
||||
assert binomial_coefficients_list(3) == [1, 3, 3, 1]
|
||||
assert binomial_coefficients_list(4) == [1, 4, 6, 4, 1]
|
||||
assert binomial_coefficients_list(5) == [1, 5, 10, 10, 5, 1]
|
||||
assert binomial_coefficients_list(6) == [1, 6, 15, 20, 15, 6, 1]
|
||||
|
||||
|
||||
def test_binomial_coefficients():
|
||||
for n in range(15):
|
||||
c = binomial_coefficients(n)
|
||||
l = [c[k] for k in sorted(c)]
|
||||
assert l == binomial_coefficients_list(n)
|
||||
|
||||
|
||||
def test_multinomial_coefficients():
|
||||
assert multinomial_coefficients(1, 1) == {(1,): 1}
|
||||
assert multinomial_coefficients(1, 2) == {(2,): 1}
|
||||
assert multinomial_coefficients(1, 3) == {(3,): 1}
|
||||
assert multinomial_coefficients(2, 0) == {(0, 0): 1}
|
||||
assert multinomial_coefficients(2, 1) == {(0, 1): 1, (1, 0): 1}
|
||||
assert multinomial_coefficients(2, 2) == {(2, 0): 1, (0, 2): 1, (1, 1): 2}
|
||||
assert multinomial_coefficients(2, 3) == {(3, 0): 1, (1, 2): 3, (0, 3): 1,
|
||||
(2, 1): 3}
|
||||
assert multinomial_coefficients(3, 1) == {(1, 0, 0): 1, (0, 1, 0): 1,
|
||||
(0, 0, 1): 1}
|
||||
assert multinomial_coefficients(3, 2) == {(0, 1, 1): 2, (0, 0, 2): 1,
|
||||
(1, 1, 0): 2, (0, 2, 0): 1, (1, 0, 1): 2, (2, 0, 0): 1}
|
||||
mc = multinomial_coefficients(3, 3)
|
||||
assert mc == {(2, 1, 0): 3, (0, 3, 0): 1,
|
||||
(1, 0, 2): 3, (0, 2, 1): 3, (0, 1, 2): 3, (3, 0, 0): 1,
|
||||
(2, 0, 1): 3, (1, 2, 0): 3, (1, 1, 1): 6, (0, 0, 3): 1}
|
||||
assert dict(multinomial_coefficients_iterator(2, 0)) == {(0, 0): 1}
|
||||
assert dict(
|
||||
multinomial_coefficients_iterator(2, 1)) == {(0, 1): 1, (1, 0): 1}
|
||||
assert dict(multinomial_coefficients_iterator(2, 2)) == \
|
||||
{(2, 0): 1, (0, 2): 1, (1, 1): 2}
|
||||
assert dict(multinomial_coefficients_iterator(3, 3)) == mc
|
||||
it = multinomial_coefficients_iterator(7, 2)
|
||||
assert [next(it) for i in range(4)] == \
|
||||
[((2, 0, 0, 0, 0, 0, 0), 1), ((1, 1, 0, 0, 0, 0, 0), 2),
|
||||
((0, 2, 0, 0, 0, 0, 0), 1), ((1, 0, 1, 0, 0, 0, 0), 2)]
|
||||
@@ -0,0 +1,28 @@
|
||||
from sympy.ntheory.partitions_ import npartitions, _partition_rec, _partition
|
||||
|
||||
|
||||
def test__partition_rec():
|
||||
A000041 = [1, 1, 2, 3, 5, 7, 11, 15, 22, 30, 42, 56, 77, 101, 135,
|
||||
176, 231, 297, 385, 490, 627, 792, 1002, 1255, 1575]
|
||||
for n, val in enumerate(A000041):
|
||||
assert _partition_rec(n) == val
|
||||
|
||||
|
||||
def test__partition():
|
||||
assert [_partition(k) for k in range(13)] == \
|
||||
[1, 1, 2, 3, 5, 7, 11, 15, 22, 30, 42, 56, 77]
|
||||
assert _partition(100) == 190569292
|
||||
assert _partition(200) == 3972999029388
|
||||
assert _partition(1000) == 24061467864032622473692149727991
|
||||
assert _partition(1001) == 25032297938763929621013218349796
|
||||
assert _partition(2000) == 4720819175619413888601432406799959512200344166
|
||||
assert _partition(10000) % 10**10 == 6916435144
|
||||
assert _partition(100000) % 10**10 == 9421098519
|
||||
assert _partition(10000000) % 10**10 == 7677288980
|
||||
|
||||
|
||||
def test_deprecated_ntheory_symbolic_functions():
|
||||
from sympy.testing.pytest import warns_deprecated_sympy
|
||||
|
||||
with warns_deprecated_sympy():
|
||||
assert npartitions(0) == 1
|
||||
@@ -0,0 +1,235 @@
|
||||
from math import gcd
|
||||
|
||||
from sympy.ntheory.generate import Sieve, sieve
|
||||
from sympy.ntheory.primetest import (mr, _lucas_extrastrong_params, is_lucas_prp, is_square,
|
||||
is_strong_lucas_prp, is_extra_strong_lucas_prp,
|
||||
proth_test, isprime, is_euler_pseudoprime,
|
||||
is_gaussian_prime, is_fermat_pseudoprime, is_euler_jacobi_pseudoprime,
|
||||
MERSENNE_PRIME_EXPONENTS, _lucas_lehmer_primality_test,
|
||||
is_mersenne_prime)
|
||||
|
||||
from sympy.testing.pytest import slow, raises
|
||||
from sympy.core.numbers import I, Float
|
||||
|
||||
|
||||
def test_is_fermat_pseudoprime():
|
||||
assert is_fermat_pseudoprime(5, 1)
|
||||
assert is_fermat_pseudoprime(9, 1)
|
||||
|
||||
|
||||
def test_euler_pseudoprimes():
|
||||
assert is_euler_pseudoprime(13, 1)
|
||||
assert is_euler_pseudoprime(15, 1)
|
||||
assert is_euler_pseudoprime(17, 6)
|
||||
assert is_euler_pseudoprime(101, 7)
|
||||
assert is_euler_pseudoprime(1009, 10)
|
||||
assert is_euler_pseudoprime(11287, 41)
|
||||
|
||||
raises(ValueError, lambda: is_euler_pseudoprime(0, 4))
|
||||
raises(ValueError, lambda: is_euler_pseudoprime(3, 0))
|
||||
raises(ValueError, lambda: is_euler_pseudoprime(15, 6))
|
||||
|
||||
# A006970
|
||||
euler_prp = [341, 561, 1105, 1729, 1905, 2047, 2465, 3277,
|
||||
4033, 4681, 5461, 6601, 8321, 8481, 10261, 10585]
|
||||
for p in euler_prp:
|
||||
assert is_euler_pseudoprime(p, 2)
|
||||
|
||||
# A048950
|
||||
euler_prp = [121, 703, 1729, 1891, 2821, 3281, 7381, 8401, 8911, 10585,
|
||||
12403, 15457, 15841, 16531, 18721, 19345, 23521, 24661, 28009]
|
||||
for p in euler_prp:
|
||||
assert is_euler_pseudoprime(p, 3)
|
||||
|
||||
# A033181
|
||||
absolute_euler_prp = [1729, 2465, 15841, 41041, 46657, 75361,
|
||||
162401, 172081, 399001, 449065, 488881]
|
||||
for p in absolute_euler_prp:
|
||||
for a in range(2, p):
|
||||
if gcd(a, p) != 1:
|
||||
continue
|
||||
assert is_euler_pseudoprime(p, a)
|
||||
|
||||
|
||||
def test_is_euler_jacobi_pseudoprime():
|
||||
assert is_euler_jacobi_pseudoprime(11, 1)
|
||||
assert is_euler_jacobi_pseudoprime(15, 1)
|
||||
|
||||
|
||||
def test_lucas_extrastrong_params():
|
||||
assert _lucas_extrastrong_params(3) == (5, 3, 1)
|
||||
assert _lucas_extrastrong_params(5) == (12, 4, 1)
|
||||
assert _lucas_extrastrong_params(7) == (5, 3, 1)
|
||||
assert _lucas_extrastrong_params(9) == (0, 0, 0)
|
||||
assert _lucas_extrastrong_params(11) == (21, 5, 1)
|
||||
assert _lucas_extrastrong_params(59) == (32, 6, 1)
|
||||
assert _lucas_extrastrong_params(479) == (117, 11, 1)
|
||||
|
||||
|
||||
def test_is_extra_strong_lucas_prp():
|
||||
assert is_extra_strong_lucas_prp(4) == False
|
||||
assert is_extra_strong_lucas_prp(989) == True
|
||||
assert is_extra_strong_lucas_prp(10877) == True
|
||||
assert is_extra_strong_lucas_prp(9) == False
|
||||
assert is_extra_strong_lucas_prp(16) == False
|
||||
assert is_extra_strong_lucas_prp(169) == False
|
||||
|
||||
@slow
|
||||
def test_prps():
|
||||
oddcomposites = [n for n in range(1, 10**5) if
|
||||
n % 2 and not isprime(n)]
|
||||
# A checksum would be better.
|
||||
assert sum(oddcomposites) == 2045603465
|
||||
assert [n for n in oddcomposites if mr(n, [2])] == [
|
||||
2047, 3277, 4033, 4681, 8321, 15841, 29341, 42799, 49141,
|
||||
52633, 65281, 74665, 80581, 85489, 88357, 90751]
|
||||
assert [n for n in oddcomposites if mr(n, [3])] == [
|
||||
121, 703, 1891, 3281, 8401, 8911, 10585, 12403, 16531,
|
||||
18721, 19345, 23521, 31621, 44287, 47197, 55969, 63139,
|
||||
74593, 79003, 82513, 87913, 88573, 97567]
|
||||
assert [n for n in oddcomposites if mr(n, [325])] == [
|
||||
9, 25, 27, 49, 65, 81, 325, 341, 343, 697, 1141, 2059,
|
||||
2149, 3097, 3537, 4033, 4681, 4941, 5833, 6517, 7987, 8911,
|
||||
12403, 12913, 15043, 16021, 20017, 22261, 23221, 24649,
|
||||
24929, 31841, 35371, 38503, 43213, 44173, 47197, 50041,
|
||||
55909, 56033, 58969, 59089, 61337, 65441, 68823, 72641,
|
||||
76793, 78409, 85879]
|
||||
assert not any(mr(n, [9345883071009581737]) for n in oddcomposites)
|
||||
assert [n for n in oddcomposites if is_lucas_prp(n)] == [
|
||||
323, 377, 1159, 1829, 3827, 5459, 5777, 9071, 9179, 10877,
|
||||
11419, 11663, 13919, 14839, 16109, 16211, 18407, 18971,
|
||||
19043, 22499, 23407, 24569, 25199, 25877, 26069, 27323,
|
||||
32759, 34943, 35207, 39059, 39203, 39689, 40309, 44099,
|
||||
46979, 47879, 50183, 51983, 53663, 56279, 58519, 60377,
|
||||
63881, 69509, 72389, 73919, 75077, 77219, 79547, 79799,
|
||||
82983, 84419, 86063, 90287, 94667, 97019, 97439]
|
||||
assert [n for n in oddcomposites if is_strong_lucas_prp(n)] == [
|
||||
5459, 5777, 10877, 16109, 18971, 22499, 24569, 25199, 40309,
|
||||
58519, 75077, 97439]
|
||||
assert [n for n in oddcomposites if is_extra_strong_lucas_prp(n)
|
||||
] == [
|
||||
989, 3239, 5777, 10877, 27971, 29681, 30739, 31631, 39059,
|
||||
72389, 73919, 75077]
|
||||
|
||||
|
||||
def test_proth_test():
|
||||
# Proth number
|
||||
A080075 = [3, 5, 9, 13, 17, 25, 33, 41, 49, 57, 65,
|
||||
81, 97, 113, 129, 145, 161, 177, 193]
|
||||
# Proth prime
|
||||
A080076 = [3, 5, 13, 17, 41, 97, 113, 193]
|
||||
|
||||
for n in range(200):
|
||||
if n in A080075:
|
||||
assert proth_test(n) == (n in A080076)
|
||||
else:
|
||||
raises(ValueError, lambda: proth_test(n))
|
||||
|
||||
|
||||
def test_lucas_lehmer_primality_test():
|
||||
for p in sieve.primerange(3, 100):
|
||||
assert _lucas_lehmer_primality_test(p) == (p in MERSENNE_PRIME_EXPONENTS)
|
||||
|
||||
|
||||
def test_is_mersenne_prime():
|
||||
assert is_mersenne_prime(-3) is False
|
||||
assert is_mersenne_prime(3) is True
|
||||
assert is_mersenne_prime(10) is False
|
||||
assert is_mersenne_prime(127) is True
|
||||
assert is_mersenne_prime(511) is False
|
||||
assert is_mersenne_prime(131071) is True
|
||||
assert is_mersenne_prime(2147483647) is True
|
||||
|
||||
|
||||
def test_isprime():
|
||||
s = Sieve()
|
||||
s.extend(100000)
|
||||
ps = set(s.primerange(2, 100001))
|
||||
for n in range(100001):
|
||||
# if (n in ps) != isprime(n): print n
|
||||
assert (n in ps) == isprime(n)
|
||||
assert isprime(179424673)
|
||||
assert isprime(20678048681)
|
||||
assert isprime(1968188556461)
|
||||
assert isprime(2614941710599)
|
||||
assert isprime(65635624165761929287)
|
||||
assert isprime(1162566711635022452267983)
|
||||
assert isprime(77123077103005189615466924501)
|
||||
assert isprime(3991617775553178702574451996736229)
|
||||
assert isprime(273952953553395851092382714516720001799)
|
||||
assert isprime(int('''
|
||||
531137992816767098689588206552468627329593117727031923199444138200403\
|
||||
559860852242739162502265229285668889329486246501015346579337652707239\
|
||||
409519978766587351943831270835393219031728127'''))
|
||||
|
||||
# Some Mersenne primes
|
||||
assert isprime(2**61 - 1)
|
||||
assert isprime(2**89 - 1)
|
||||
assert isprime(2**607 - 1)
|
||||
# (but not all Mersenne's are primes
|
||||
assert not isprime(2**601 - 1)
|
||||
|
||||
# pseudoprimes
|
||||
#-------------
|
||||
# to some small bases
|
||||
assert not isprime(2152302898747)
|
||||
assert not isprime(3474749660383)
|
||||
assert not isprime(341550071728321)
|
||||
assert not isprime(3825123056546413051)
|
||||
# passes the base set [2, 3, 7, 61, 24251]
|
||||
assert not isprime(9188353522314541)
|
||||
# large examples
|
||||
assert not isprime(877777777777777777777777)
|
||||
# conjectured psi_12 given at http://mathworld.wolfram.com/StrongPseudoprime.html
|
||||
assert not isprime(318665857834031151167461)
|
||||
# conjectured psi_17 given at http://mathworld.wolfram.com/StrongPseudoprime.html
|
||||
assert not isprime(564132928021909221014087501701)
|
||||
# Arnault's 1993 number; a factor of it is
|
||||
# 400958216639499605418306452084546853005188166041132508774506\
|
||||
# 204738003217070119624271622319159721973358216316508535816696\
|
||||
# 9145233813917169287527980445796800452592031836601
|
||||
assert not isprime(int('''
|
||||
803837457453639491257079614341942108138837688287558145837488917522297\
|
||||
427376533365218650233616396004545791504202360320876656996676098728404\
|
||||
396540823292873879185086916685732826776177102938969773947016708230428\
|
||||
687109997439976544144845341155872450633409279022275296229414984230688\
|
||||
1685404326457534018329786111298960644845216191652872597534901'''))
|
||||
# Arnault's 1995 number; can be factored as
|
||||
# p1*(313*(p1 - 1) + 1)*(353*(p1 - 1) + 1) where p1 is
|
||||
# 296744956686855105501541746429053327307719917998530433509950\
|
||||
# 755312768387531717701995942385964281211880336647542183455624\
|
||||
# 93168782883
|
||||
assert not isprime(int('''
|
||||
288714823805077121267142959713039399197760945927972270092651602419743\
|
||||
230379915273311632898314463922594197780311092934965557841894944174093\
|
||||
380561511397999942154241693397290542371100275104208013496673175515285\
|
||||
922696291677532547504444585610194940420003990443211677661994962953925\
|
||||
045269871932907037356403227370127845389912612030924484149472897688540\
|
||||
6024976768122077071687938121709811322297802059565867'''))
|
||||
sieve.extend(3000)
|
||||
assert isprime(2819)
|
||||
assert not isprime(2931)
|
||||
raises(ValueError, lambda: isprime(2.0))
|
||||
raises(ValueError, lambda: isprime(Float(2)))
|
||||
|
||||
|
||||
def test_is_square():
|
||||
assert [i for i in range(25) if is_square(i)] == [0, 1, 4, 9, 16]
|
||||
|
||||
# issue #17044
|
||||
assert not is_square(60 ** 3)
|
||||
assert not is_square(60 ** 5)
|
||||
assert not is_square(84 ** 7)
|
||||
assert not is_square(105 ** 9)
|
||||
assert not is_square(120 ** 3)
|
||||
|
||||
def test_is_gaussianprime():
|
||||
assert is_gaussian_prime(7*I)
|
||||
assert is_gaussian_prime(7)
|
||||
assert is_gaussian_prime(2 + 3*I)
|
||||
assert not is_gaussian_prime(2 + 2*I)
|
||||
|
||||
|
||||
def test_issue_27145():
|
||||
#https://github.com/sympy/sympy/issues/27145
|
||||
assert [mr(i,[2,3,5,7]) for i in (1, 2, 6)] == [False, True, False]
|
||||
110
venv/lib/python3.12/site-packages/sympy/ntheory/tests/test_qs.py
Normal file
110
venv/lib/python3.12/site-packages/sympy/ntheory/tests/test_qs.py
Normal file
@@ -0,0 +1,110 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from sympy.core.random import _randint
|
||||
from sympy.ntheory import qs, qs_factor
|
||||
from sympy.ntheory.qs import SievePolynomial, _generate_factor_base, \
|
||||
_generate_polynomial, \
|
||||
_gen_sieve_array, _check_smoothness, _trial_division_stage, _find_factor
|
||||
from sympy.testing.pytest import slow
|
||||
|
||||
|
||||
@slow
|
||||
def test_qs_1():
|
||||
assert qs(10009202107, 100, 10000) == {100043, 100049}
|
||||
assert qs(211107295182713951054568361, 1000, 10000) == \
|
||||
{13791315212531, 15307263442931}
|
||||
assert qs(980835832582657*990377764891511, 2000, 10000) == \
|
||||
{980835832582657, 990377764891511}
|
||||
assert qs(18640889198609*20991129234731, 1000, 50000) == \
|
||||
{18640889198609, 20991129234731}
|
||||
|
||||
|
||||
def test_qs_2() -> None:
|
||||
n = 10009202107
|
||||
M = 50
|
||||
sieve_poly = SievePolynomial(10, 80, n)
|
||||
assert sieve_poly.eval_v(10) == sieve_poly.eval_u(10)**2 - n == -10009169707
|
||||
assert sieve_poly.eval_v(5) == sieve_poly.eval_u(5)**2 - n == -10009185207
|
||||
|
||||
idx_1000, idx_5000, factor_base = _generate_factor_base(2000, n)
|
||||
assert idx_1000 == 82
|
||||
assert [factor_base[i].prime for i in range(15)] == \
|
||||
[2, 3, 7, 11, 17, 19, 29, 31, 43, 59, 61, 67, 71, 73, 79]
|
||||
assert [factor_base[i].tmem_p for i in range(15)] == \
|
||||
[1, 1, 3, 5, 3, 6, 6, 14, 1, 16, 24, 22, 18, 22, 15]
|
||||
assert [factor_base[i].log_p for i in range(5)] == \
|
||||
[710, 1125, 1993, 2455, 2901]
|
||||
|
||||
it = _generate_polynomial(
|
||||
n, M, factor_base, idx_1000, idx_5000, _randint(0))
|
||||
g = next(it)
|
||||
assert g.a == 1133107
|
||||
assert g.b == 682543
|
||||
assert [factor_base[i].soln1 for i in range(15)] == \
|
||||
[0, 0, 3, 7, 13, 0, 8, 19, 9, 43, 27, 25, 63, 29, 19]
|
||||
assert [factor_base[i].soln2 for i in range(15)] == \
|
||||
[0, 1, 1, 3, 12, 16, 15, 6, 15, 1, 56, 55, 61, 58, 16]
|
||||
assert [factor_base[i].b_ainv for i in range(5)] == \
|
||||
[[0, 0], [0, 2], [3, 0], [3, 9], [13, 13]]
|
||||
|
||||
g_1 = next(it)
|
||||
assert g_1.a == 1133107
|
||||
assert g_1.b == 136765
|
||||
|
||||
sieve_array = _gen_sieve_array(M, factor_base)
|
||||
assert sieve_array[0:5] == [8424, 13603, 1835, 5335, 710]
|
||||
|
||||
assert _check_smoothness(9645, factor_base) == (36028797018963972, 5)
|
||||
assert _check_smoothness(210313, factor_base) == (20992, 1)
|
||||
|
||||
partial_relations: dict[int, tuple[int, int]] = {}
|
||||
smooth_relation, proper_factor = _trial_division_stage(
|
||||
n, M, factor_base, sieve_array, sieve_poly, partial_relations,
|
||||
ERROR_TERM=25*2**10)
|
||||
|
||||
assert partial_relations == {
|
||||
8699: (440, -10009008507, 75557863761098695507973),
|
||||
166741: (490, -10008962007, 524341),
|
||||
131449: (530, -10008921207, 664613997892457936451903530140172325),
|
||||
6653: (550, -10008899607, 19342813113834066795307021)
|
||||
}
|
||||
assert [smooth_relation[i][0] for i in range(5)] == [
|
||||
-250, 1064469, 72819, 231957, 44167]
|
||||
assert [smooth_relation[i][1] for i in range(5)] == [
|
||||
-10009139607, 1133094251961, 5302606761, 53804049849, 1950723889]
|
||||
assert smooth_relation[0][2] == 89213869829863962596973701078031812362502145
|
||||
assert proper_factor == set()
|
||||
|
||||
|
||||
def test_qs_3():
|
||||
N = 1817
|
||||
smooth_relations = [
|
||||
(2455024, 637, 8),
|
||||
(-27993000, 81536, 10),
|
||||
(11461840, 12544, 0),
|
||||
(149, 20384, 10),
|
||||
(-31138074, 19208, 2)
|
||||
]
|
||||
assert next(_find_factor(N, smooth_relations, 4)) == 23
|
||||
|
||||
|
||||
def test_qs_4():
|
||||
N = 10007**2 * 10009 * 10037**3 * 10039
|
||||
for factor in qs(N, 1000, 2000):
|
||||
assert N % factor == 0
|
||||
N //= factor
|
||||
|
||||
|
||||
def test_qs_factor():
|
||||
assert qs_factor(1009 * 100003, 2000, 10000) == {1009: 1, 100003: 1}
|
||||
n = 1009**2 * 2003**2*30011*400009
|
||||
factors = qs_factor(n, 2000, 10000)
|
||||
assert len(factors) > 1
|
||||
assert math.prod(p**e for p, e in factors.items()) == n
|
||||
|
||||
|
||||
def test_issue_27616():
|
||||
#https://github.com/sympy/sympy/issues/27616
|
||||
N = 9804659461513846513 + 1
|
||||
assert qs(N, 5000, 20000) is not None
|
||||
@@ -0,0 +1,349 @@
|
||||
from collections import defaultdict
|
||||
from sympy.core.containers import Tuple
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Dummy, Symbol)
|
||||
from sympy.functions.combinatorial.numbers import totient
|
||||
from sympy.ntheory import n_order, is_primitive_root, is_quad_residue, \
|
||||
legendre_symbol, jacobi_symbol, primerange, sqrt_mod, \
|
||||
primitive_root, quadratic_residues, is_nthpow_residue, nthroot_mod, \
|
||||
sqrt_mod_iter, mobius, discrete_log, quadratic_congruence, \
|
||||
polynomial_congruence, sieve
|
||||
from sympy.ntheory.residue_ntheory import _primitive_root_prime_iter, \
|
||||
_primitive_root_prime_power_iter, _primitive_root_prime_power2_iter, \
|
||||
_nthroot_mod_prime_power, _discrete_log_trial_mul, _discrete_log_shanks_steps, \
|
||||
_discrete_log_pollard_rho, _discrete_log_index_calculus, _discrete_log_pohlig_hellman, \
|
||||
_binomial_mod_prime_power, binomial_mod
|
||||
from sympy.polys.domains import ZZ
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.core.random import randint, choice
|
||||
|
||||
|
||||
def test_residue():
|
||||
assert n_order(2, 13) == 12
|
||||
assert [n_order(a, 7) for a in range(1, 7)] == \
|
||||
[1, 3, 6, 3, 6, 2]
|
||||
assert n_order(5, 17) == 16
|
||||
assert n_order(17, 11) == n_order(6, 11)
|
||||
assert n_order(101, 119) == 6
|
||||
assert n_order(11, (10**50 + 151)**2) == 10000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000022650
|
||||
raises(ValueError, lambda: n_order(6, 9))
|
||||
|
||||
assert is_primitive_root(2, 7) is False
|
||||
assert is_primitive_root(3, 8) is False
|
||||
assert is_primitive_root(11, 14) is False
|
||||
assert is_primitive_root(12, 17) == is_primitive_root(29, 17)
|
||||
raises(ValueError, lambda: is_primitive_root(3, 6))
|
||||
|
||||
for p in primerange(3, 100):
|
||||
li = list(_primitive_root_prime_iter(p))
|
||||
assert li[0] == min(li)
|
||||
for g in li:
|
||||
assert n_order(g, p) == p - 1
|
||||
assert len(li) == totient(totient(p))
|
||||
for e in range(1, 4):
|
||||
li_power = list(_primitive_root_prime_power_iter(p, e))
|
||||
li_power2 = list(_primitive_root_prime_power2_iter(p, e))
|
||||
assert len(li_power) == len(li_power2) == totient(totient(p**e))
|
||||
assert primitive_root(97) == 5
|
||||
assert n_order(primitive_root(97, False), 97) == totient(97)
|
||||
assert primitive_root(97**2) == 5
|
||||
assert n_order(primitive_root(97**2, False), 97**2) == totient(97**2)
|
||||
assert primitive_root(40487) == 5
|
||||
assert n_order(primitive_root(40487, False), 40487) == totient(40487)
|
||||
# note that primitive_root(40487) + 40487 = 40492 is a primitive root
|
||||
# of 40487**2, but it is not the smallest
|
||||
assert primitive_root(40487**2) == 10
|
||||
assert n_order(primitive_root(40487**2, False), 40487**2) == totient(40487**2)
|
||||
assert primitive_root(82) == 7
|
||||
assert n_order(primitive_root(82, False), 82) == totient(82)
|
||||
p = 10**50 + 151
|
||||
assert primitive_root(p) == 11
|
||||
assert n_order(primitive_root(p, False), p) == totient(p)
|
||||
assert primitive_root(2*p) == 11
|
||||
assert n_order(primitive_root(2*p, False), 2*p) == totient(2*p)
|
||||
assert primitive_root(p**2) == 11
|
||||
assert n_order(primitive_root(p**2, False), p**2) == totient(p**2)
|
||||
assert primitive_root(4 * 11) is None and primitive_root(4 * 11, False) is None
|
||||
assert primitive_root(15) is None and primitive_root(15, False) is None
|
||||
raises(ValueError, lambda: primitive_root(-3))
|
||||
|
||||
assert is_quad_residue(3, 7) is False
|
||||
assert is_quad_residue(10, 13) is True
|
||||
assert is_quad_residue(12364, 139) == is_quad_residue(12364 % 139, 139)
|
||||
assert is_quad_residue(207, 251) is True
|
||||
assert is_quad_residue(0, 1) is True
|
||||
assert is_quad_residue(1, 1) is True
|
||||
assert is_quad_residue(0, 2) == is_quad_residue(1, 2) is True
|
||||
assert is_quad_residue(1, 4) is True
|
||||
assert is_quad_residue(2, 27) is False
|
||||
assert is_quad_residue(13122380800, 13604889600) is True
|
||||
assert [j for j in range(14) if is_quad_residue(j, 14)] == \
|
||||
[0, 1, 2, 4, 7, 8, 9, 11]
|
||||
raises(ValueError, lambda: is_quad_residue(1.1, 2))
|
||||
raises(ValueError, lambda: is_quad_residue(2, 0))
|
||||
|
||||
assert quadratic_residues(S.One) == [0]
|
||||
assert quadratic_residues(1) == [0]
|
||||
assert quadratic_residues(12) == [0, 1, 4, 9]
|
||||
assert quadratic_residues(13) == [0, 1, 3, 4, 9, 10, 12]
|
||||
assert [len(quadratic_residues(i)) for i in range(1, 20)] == \
|
||||
[1, 2, 2, 2, 3, 4, 4, 3, 4, 6, 6, 4, 7, 8, 6, 4, 9, 8, 10]
|
||||
|
||||
assert list(sqrt_mod_iter(6, 2)) == [0]
|
||||
assert sqrt_mod(3, 13) == 4
|
||||
assert sqrt_mod(3, -13) == 4
|
||||
assert sqrt_mod(6, 23) == 11
|
||||
assert sqrt_mod(345, 690) == 345
|
||||
assert sqrt_mod(67, 101) == None
|
||||
assert sqrt_mod(1020, 104729) == None
|
||||
|
||||
for p in range(3, 100):
|
||||
d = defaultdict(list)
|
||||
for i in range(p):
|
||||
d[pow(i, 2, p)].append(i)
|
||||
for i in range(1, p):
|
||||
it = sqrt_mod_iter(i, p)
|
||||
v = sqrt_mod(i, p, True)
|
||||
if v:
|
||||
v = sorted(v)
|
||||
assert d[i] == v
|
||||
else:
|
||||
assert not d[i]
|
||||
|
||||
assert sqrt_mod(9, 27, True) == [3, 6, 12, 15, 21, 24]
|
||||
assert sqrt_mod(9, 81, True) == [3, 24, 30, 51, 57, 78]
|
||||
assert sqrt_mod(9, 3**5, True) == [3, 78, 84, 159, 165, 240]
|
||||
assert sqrt_mod(81, 3**4, True) == [0, 9, 18, 27, 36, 45, 54, 63, 72]
|
||||
assert sqrt_mod(81, 3**5, True) == [9, 18, 36, 45, 63, 72, 90, 99, 117,\
|
||||
126, 144, 153, 171, 180, 198, 207, 225, 234]
|
||||
assert sqrt_mod(81, 3**6, True) == [9, 72, 90, 153, 171, 234, 252, 315,\
|
||||
333, 396, 414, 477, 495, 558, 576, 639, 657, 720]
|
||||
assert sqrt_mod(81, 3**7, True) == [9, 234, 252, 477, 495, 720, 738, 963,\
|
||||
981, 1206, 1224, 1449, 1467, 1692, 1710, 1935, 1953, 2178]
|
||||
|
||||
for a, p in [(26214400, 32768000000), (26214400, 16384000000),
|
||||
(262144, 1048576), (87169610025, 163443018796875),
|
||||
(22315420166400, 167365651248000000)]:
|
||||
assert pow(sqrt_mod(a, p), 2, p) == a
|
||||
|
||||
n = 70
|
||||
a, p = 5**2*3**n*2**n, 5**6*3**(n+1)*2**(n+2)
|
||||
it = sqrt_mod_iter(a, p)
|
||||
for i in range(10):
|
||||
assert pow(next(it), 2, p) == a
|
||||
a, p = 5**2*3**n*2**n, 5**6*3**(n+1)*2**(n+3)
|
||||
it = sqrt_mod_iter(a, p)
|
||||
for i in range(2):
|
||||
assert pow(next(it), 2, p) == a
|
||||
n = 100
|
||||
a, p = 5**2*3**n*2**n, 5**6*3**(n+1)*2**(n+1)
|
||||
it = sqrt_mod_iter(a, p)
|
||||
for i in range(2):
|
||||
assert pow(next(it), 2, p) == a
|
||||
|
||||
assert type(next(sqrt_mod_iter(9, 27))) is int
|
||||
assert type(next(sqrt_mod_iter(9, 27, ZZ))) is type(ZZ(1))
|
||||
assert type(next(sqrt_mod_iter(1, 7, ZZ))) is type(ZZ(1))
|
||||
|
||||
assert is_nthpow_residue(2, 1, 5)
|
||||
|
||||
#issue 10816
|
||||
assert is_nthpow_residue(1, 0, 1) is False
|
||||
assert is_nthpow_residue(1, 0, 2) is True
|
||||
assert is_nthpow_residue(3, 0, 2) is True
|
||||
assert is_nthpow_residue(0, 1, 8) is True
|
||||
assert is_nthpow_residue(2, 3, 2) is True
|
||||
assert is_nthpow_residue(2, 3, 9) is False
|
||||
assert is_nthpow_residue(3, 5, 30) is True
|
||||
assert is_nthpow_residue(21, 11, 20) is True
|
||||
assert is_nthpow_residue(7, 10, 20) is False
|
||||
assert is_nthpow_residue(5, 10, 20) is True
|
||||
assert is_nthpow_residue(3, 10, 48) is False
|
||||
assert is_nthpow_residue(1, 10, 40) is True
|
||||
assert is_nthpow_residue(3, 10, 24) is False
|
||||
assert is_nthpow_residue(1, 10, 24) is True
|
||||
assert is_nthpow_residue(3, 10, 24) is False
|
||||
assert is_nthpow_residue(2, 10, 48) is False
|
||||
assert is_nthpow_residue(81, 3, 972) is False
|
||||
assert is_nthpow_residue(243, 5, 5103) is True
|
||||
assert is_nthpow_residue(243, 3, 1240029) is False
|
||||
assert is_nthpow_residue(36010, 8, 87382) is True
|
||||
assert is_nthpow_residue(28552, 6, 2218) is True
|
||||
assert is_nthpow_residue(92712, 9, 50026) is True
|
||||
x = {pow(i, 56, 1024) for i in range(1024)}
|
||||
assert {a for a in range(1024) if is_nthpow_residue(a, 56, 1024)} == x
|
||||
x = { pow(i, 256, 2048) for i in range(2048)}
|
||||
assert {a for a in range(2048) if is_nthpow_residue(a, 256, 2048)} == x
|
||||
x = { pow(i, 11, 324000) for i in range(1000)}
|
||||
assert [ is_nthpow_residue(a, 11, 324000) for a in x]
|
||||
x = { pow(i, 17, 22217575536) for i in range(1000)}
|
||||
assert [ is_nthpow_residue(a, 17, 22217575536) for a in x]
|
||||
assert is_nthpow_residue(676, 3, 5364)
|
||||
assert is_nthpow_residue(9, 12, 36)
|
||||
assert is_nthpow_residue(32, 10, 41)
|
||||
assert is_nthpow_residue(4, 2, 64)
|
||||
assert is_nthpow_residue(31, 4, 41)
|
||||
assert not is_nthpow_residue(2, 2, 5)
|
||||
assert is_nthpow_residue(8547, 12, 10007)
|
||||
assert is_nthpow_residue(Dummy(even=True) + 3, 3, 2) == True
|
||||
# _nthroot_mod_prime_power
|
||||
for p in primerange(2, 10):
|
||||
for a in range(3):
|
||||
for n in range(3, 5):
|
||||
ans = _nthroot_mod_prime_power(a, n, p, 1)
|
||||
assert isinstance(ans, list)
|
||||
if len(ans) == 0:
|
||||
for b in range(p):
|
||||
assert pow(b, n, p) != a % p
|
||||
for k in range(2, 10):
|
||||
assert _nthroot_mod_prime_power(a, n, p, k) == []
|
||||
else:
|
||||
for b in range(p):
|
||||
pred = pow(b, n, p) == a % p
|
||||
assert not(pred ^ (b in ans))
|
||||
for k in range(2, 10):
|
||||
ans = _nthroot_mod_prime_power(a, n, p, k)
|
||||
if not ans:
|
||||
break
|
||||
for b in ans:
|
||||
assert pow(b, n , p**k) == a
|
||||
|
||||
assert nthroot_mod(Dummy(odd=True), 3, 2) == 1
|
||||
assert nthroot_mod(29, 31, 74) == 45
|
||||
assert nthroot_mod(1801, 11, 2663) == 44
|
||||
for a, q, p in [(51922, 2, 203017), (43, 3, 109), (1801, 11, 2663),
|
||||
(26118163, 1303, 33333347), (1499, 7, 2663), (595, 6, 2663),
|
||||
(1714, 12, 2663), (28477, 9, 33343)]:
|
||||
r = nthroot_mod(a, q, p)
|
||||
assert pow(r, q, p) == a
|
||||
assert nthroot_mod(11, 3, 109) is None
|
||||
assert nthroot_mod(16, 5, 36, True) == [4, 22]
|
||||
assert nthroot_mod(9, 16, 36, True) == [3, 9, 15, 21, 27, 33]
|
||||
assert nthroot_mod(4, 3, 3249000) is None
|
||||
assert nthroot_mod(36010, 8, 87382, True) == [40208, 47174]
|
||||
assert nthroot_mod(0, 12, 37, True) == [0]
|
||||
assert nthroot_mod(0, 7, 100, True) == [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
|
||||
assert nthroot_mod(4, 4, 27, True) == [5, 22]
|
||||
assert nthroot_mod(4, 4, 121, True) == [19, 102]
|
||||
assert nthroot_mod(2, 3, 7, True) == []
|
||||
for p in range(1, 20):
|
||||
for a in range(p):
|
||||
for n in range(1, p):
|
||||
ans = nthroot_mod(a, n, p, True)
|
||||
assert isinstance(ans, list)
|
||||
for b in range(p):
|
||||
pred = pow(b, n, p) == a
|
||||
assert not(pred ^ (b in ans))
|
||||
ans2 = nthroot_mod(a, n, p, False)
|
||||
if ans2 is None:
|
||||
assert ans == []
|
||||
else:
|
||||
assert ans2 in ans
|
||||
|
||||
x = Symbol('x', positive=True)
|
||||
i = Symbol('i', integer=True)
|
||||
assert _discrete_log_trial_mul(587, 2**7, 2) == 7
|
||||
assert _discrete_log_trial_mul(941, 7**18, 7) == 18
|
||||
assert _discrete_log_trial_mul(389, 3**81, 3) == 81
|
||||
assert _discrete_log_trial_mul(191, 19**123, 19) == 123
|
||||
assert _discrete_log_shanks_steps(442879, 7**2, 7) == 2
|
||||
assert _discrete_log_shanks_steps(874323, 5**19, 5) == 19
|
||||
assert _discrete_log_shanks_steps(6876342, 7**71, 7) == 71
|
||||
assert _discrete_log_shanks_steps(2456747, 3**321, 3) == 321
|
||||
assert _discrete_log_pollard_rho(6013199, 2**6, 2, rseed=0) == 6
|
||||
assert _discrete_log_pollard_rho(6138719, 2**19, 2, rseed=0) == 19
|
||||
assert _discrete_log_pollard_rho(36721943, 2**40, 2, rseed=0) == 40
|
||||
assert _discrete_log_pollard_rho(24567899, 3**333, 3, rseed=0) == 333
|
||||
raises(ValueError, lambda: _discrete_log_pollard_rho(11, 7, 31, rseed=0))
|
||||
raises(ValueError, lambda: _discrete_log_pollard_rho(227, 3**7, 5, rseed=0))
|
||||
assert _discrete_log_index_calculus(983, 948, 2, 491) == 183
|
||||
assert _discrete_log_index_calculus(633383, 21794, 2, 316691) == 68048
|
||||
assert _discrete_log_index_calculus(941762639, 68822582, 2, 470881319) == 338029275
|
||||
assert _discrete_log_index_calculus(999231337607, 888188918786, 2, 499615668803) == 142811376514
|
||||
assert _discrete_log_index_calculus(47747730623, 19410045286, 43425105668, 645239603) == 590504662
|
||||
assert _discrete_log_pohlig_hellman(98376431, 11**9, 11) == 9
|
||||
assert _discrete_log_pohlig_hellman(78723213, 11**31, 11) == 31
|
||||
assert _discrete_log_pohlig_hellman(32942478, 11**98, 11) == 98
|
||||
assert _discrete_log_pohlig_hellman(14789363, 11**444, 11) == 444
|
||||
assert discrete_log(1, 0, 2) == 0
|
||||
raises(ValueError, lambda: discrete_log(-4, 1, 3))
|
||||
raises(ValueError, lambda: discrete_log(10, 3, 2))
|
||||
assert discrete_log(587, 2**9, 2) == 9
|
||||
assert discrete_log(2456747, 3**51, 3) == 51
|
||||
assert discrete_log(32942478, 11**127, 11) == 127
|
||||
assert discrete_log(432751500361, 7**324, 7) == 324
|
||||
assert discrete_log(265390227570863,184500076053622, 2) == 17835221372061
|
||||
assert discrete_log(22708823198678103974314518195029102158525052496759285596453269189798311427475159776411276642277139650833937,
|
||||
17463946429475485293747680247507700244427944625055089103624311227422110546803452417458985046168310373075327,
|
||||
123456) == 2068031853682195777930683306640554533145512201725884603914601918777510185469769997054750835368413389728895
|
||||
args = 5779, 3528, 6215
|
||||
assert discrete_log(*args) == 687
|
||||
assert discrete_log(*Tuple(*args)) == 687
|
||||
assert quadratic_congruence(400, 85, 125, 1600) == [295, 615, 935, 1255, 1575]
|
||||
assert quadratic_congruence(3, 6, 5, 25) == [3, 20]
|
||||
assert quadratic_congruence(120, 80, 175, 500) == []
|
||||
assert quadratic_congruence(15, 14, 7, 2) == [1]
|
||||
assert quadratic_congruence(8, 15, 7, 29) == [10, 28]
|
||||
assert quadratic_congruence(160, 200, 300, 461) == [144, 431]
|
||||
assert quadratic_congruence(100000, 123456, 7415263, 48112959837082048697) == [30417843635344493501, 36001135160550533083]
|
||||
assert quadratic_congruence(65, 121, 72, 277) == [249, 252]
|
||||
assert quadratic_congruence(5, 10, 14, 2) == [0]
|
||||
assert quadratic_congruence(10, 17, 19, 2) == [1]
|
||||
assert quadratic_congruence(10, 14, 20, 2) == [0, 1]
|
||||
assert quadratic_congruence(2**48-7, 2**48-1, 4, 2**48) == [8249717183797, 31960993774868]
|
||||
assert polynomial_congruence(6*x**5 + 10*x**4 + 5*x**3 + x**2 + x + 1,
|
||||
972000) == [220999, 242999, 463999, 485999, 706999, 728999, 949999, 971999]
|
||||
|
||||
assert polynomial_congruence(x**3 - 10*x**2 + 12*x - 82, 33075) == [30287]
|
||||
assert polynomial_congruence(x**2 + x + 47, 2401) == [785, 1615]
|
||||
assert polynomial_congruence(10*x**2 + 14*x + 20, 2) == [0, 1]
|
||||
assert polynomial_congruence(x**3 + 3, 16) == [5]
|
||||
assert polynomial_congruence(65*x**2 + 121*x + 72, 277) == [249, 252]
|
||||
assert polynomial_congruence(x**4 - 4, 27) == [5, 22]
|
||||
assert polynomial_congruence(35*x**3 - 6*x**2 - 567*x + 2308, 148225) == [86957,
|
||||
111157, 122531, 146731]
|
||||
assert polynomial_congruence(x**16 - 9, 36) == [3, 9, 15, 21, 27, 33]
|
||||
assert polynomial_congruence(x**6 - 2*x**5 - 35, 6125) == [3257]
|
||||
raises(ValueError, lambda: polynomial_congruence(x**x, 6125))
|
||||
raises(ValueError, lambda: polynomial_congruence(x**i, 6125))
|
||||
raises(ValueError, lambda: polynomial_congruence(0.1*x**2 + 6, 100))
|
||||
|
||||
assert binomial_mod(-1, 1, 10) == 0
|
||||
assert binomial_mod(1, -1, 10) == 0
|
||||
raises(ValueError, lambda: binomial_mod(2, 1, -1))
|
||||
assert binomial_mod(51, 10, 10) == 0
|
||||
assert binomial_mod(10**3, 500, 3**6) == 567
|
||||
assert binomial_mod(10**18 - 1, 123456789, 4) == 0
|
||||
assert binomial_mod(10**18, 10**12, (10**5 + 3)**2) == 3744312326
|
||||
|
||||
|
||||
def test_binomial_p_pow():
|
||||
n, binomials, binomial = 1000, [1], 1
|
||||
for i in range(1, n + 1):
|
||||
binomial *= n - i + 1
|
||||
binomial //= i
|
||||
binomials.append(binomial)
|
||||
|
||||
# Test powers of two, which the algorithm treats slightly differently
|
||||
trials_2 = 100
|
||||
for _ in range(trials_2):
|
||||
m, power = randint(0, n), randint(1, 20)
|
||||
assert _binomial_mod_prime_power(n, m, 2, power) == binomials[m] % 2**power
|
||||
|
||||
# Test against other prime powers
|
||||
primes = list(sieve.primerange(2*n))
|
||||
trials = 1000
|
||||
for _ in range(trials):
|
||||
m, prime, power = randint(0, n), choice(primes), randint(1, 10)
|
||||
assert _binomial_mod_prime_power(n, m, prime, power) == binomials[m] % prime**power
|
||||
|
||||
|
||||
def test_deprecated_ntheory_symbolic_functions():
|
||||
from sympy.testing.pytest import warns_deprecated_sympy
|
||||
|
||||
with warns_deprecated_sympy():
|
||||
assert mobius(3) == -1
|
||||
with warns_deprecated_sympy():
|
||||
assert legendre_symbol(2, 3) == -1
|
||||
with warns_deprecated_sympy():
|
||||
assert jacobi_symbol(2, 3) == -1
|
||||
Reference in New Issue
Block a user