switching to high quality piper tts and added label translations
This commit is contained in:
@@ -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',
|
||||
]
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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])
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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]
|
||||
+77
@@ -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]
|
||||
@@ -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