I am done

This commit is contained in:
2024-10-30 22:14:35 +01:00
parent 720dc28c09
commit 40e2a747cf
36901 changed files with 5011519 additions and 0 deletions

View File

@ -0,0 +1,67 @@
"""
Number theory module (primes, etc)
"""
from .generate import nextprime, prevprime, prime, primepi, primerange, \
randprime, Sieve, sieve, primorial, cycle_length, composite, compositepi
from .primetest import isprime, is_gaussian_prime, is_mersenne_prime
from .factor_ import divisors, proper_divisors, factorint, multiplicity, \
multiplicity_in_factorial, perfect_power, 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
__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', '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',
]

View File

@ -0,0 +1,190 @@
'''
This implementation is a heavily modified fixed point implementation of
BBP_formula for calculating the nth position of pi. The original hosted
at: https://web.archive.org/web/20151116045029/http://en.literateprograms.org/Pi_with_the_BBP_formula_(Python)
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sub-license, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Modifications:
1.Once the nth digit and desired number of digits is selected, the
number of digits of working precision is calculated to ensure that
the hexadecimal digits returned are accurate. This is calculated as
int(math.log(start + prec)/math.log(16) + prec + 3)
--------------------------------------- --------
/ /
number of hex digits additional digits
This was checked by the following code which completed without
errors (and dig are the digits included in the test_bbp.py file):
for i in range(0,1000):
for j in range(1,1000):
a, b = pi_hex_digits(i, j), dig[i:i+j]
if a != b:
print('%s\n%s'%(a,b))
Deceasing the additional digits by 1 generated errors, so '3' is
the smallest additional precision needed to calculate the above
loop without errors. The following trailing 10 digits were also
checked to be accurate (and the times were slightly faster with
some of the constant modifications that were made):
>> from time import time
>> t=time();pi_hex_digits(10**2-10 + 1, 10), time()-t
('e90c6cc0ac', 0.0)
>> t=time();pi_hex_digits(10**4-10 + 1, 10), time()-t
('26aab49ec6', 0.17100000381469727)
>> t=time();pi_hex_digits(10**5-10 + 1, 10), time()-t
('a22673c1a5', 4.7109999656677246)
>> t=time();pi_hex_digits(10**6-10 + 1, 10), time()-t
('9ffd342362', 59.985999822616577)
>> t=time();pi_hex_digits(10**7-10 + 1, 10), time()-t
('c1a42e06a1', 689.51800012588501)
2. The while loop to evaluate whether the series has converged quits
when the addition amount `dt` has dropped to zero.
3. the formatting string to convert the decimal to hexadecimal is
calculated for the given precision.
4. pi_hex_digits(n) changed to have coefficient to the formula in an
array (perhaps just a matter of preference).
'''
from sympy.utilities.misc import as_int
def _series(j, n, prec=14):
# Left sum from the bbp algorithm
s = 0
D = _dn(n, prec)
D4 = 4 * D
d = j
for k in range(n + 1):
s += (pow(16, n - k, d) << D4) // d
d += 8
# Right sum iterates to infinity for full precision, but we
# stop at the point where one iteration is beyond the precision
# specified.
t = 0
k = n + 1
e = D4 - 4 # 4*(D + n - k)
d = 8 * k + j
while True:
dt = (1 << e) // d
if not dt:
break
t += dt
# k += 1
e -= 4
d += 8
total = s + t
return total
def pi_hex_digits(n, prec=14):
"""Returns a string containing ``prec`` (default 14) digits
starting at the nth digit of pi in hex. Counting of digits
starts at 0 and the decimal is not counted, so for n = 0 the
returned value starts with 3; n = 1 corresponds to the first
digit past the decimal point (which in hex is 2).
Parameters
==========
n : non-negative integer
prec : non-negative integer. default = 14
Returns
=======
str : Returns a string containing ``prec`` digits
starting at the nth digit of pi in hex.
If ``prec`` = 0, returns empty string.
Raises
======
ValueError
If ``n`` < 0 or ``prec`` < 0.
Or ``n`` or ``prec`` is not an integer.
Examples
========
>>> from sympy.ntheory.bbp_pi import pi_hex_digits
>>> pi_hex_digits(0)
'3243f6a8885a30'
>>> pi_hex_digits(0, 3)
'324'
These are consistent with the following results
>>> import math
>>> hex(int(math.pi * 2**((14-1)*4)))
'0x3243f6a8885a30'
>>> hex(int(math.pi * 2**((3-1)*4)))
'0x324'
References
==========
.. [1] http://www.numberworld.org/digits/Pi/
"""
n, prec = as_int(n), as_int(prec)
if n < 0:
raise ValueError('n cannot be negative')
if prec < 0:
raise ValueError('prec cannot be negative')
if prec == 0:
return ''
# main of implementation arrays holding formulae coefficients
n -= 1
a = [4, 2, 1, 1]
j = [1, 4, 5, 6]
#formulae
D = _dn(n, prec)
x = + (a[0]*_series(j[0], n, prec)
- a[1]*_series(j[1], n, prec)
- a[2]*_series(j[2], n, prec)
- a[3]*_series(j[3], n, prec)) & (16**D - 1)
s = ("%0" + "%ix" % prec) % (x // 16**(D - prec))
return s
def _dn(n, prec):
# controller for n dependence on precision
# n = starting digit index
# prec = the number of total digits to compute
n += 1 # because we subtract 1 for _series
# assert int(math.log(n + prec)/math.log(16)) ==\
# ((n + prec).bit_length() - 1) // 4
return ((n + prec).bit_length() - 1) // 4 + prec + 3

View File

@ -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

View File

@ -0,0 +1,150 @@
from collections import defaultdict
from sympy.utilities.iterables import multiset, is_palindromic as _palindromic
from sympy.utilities.misc import as_int
def digits(n, b=10, digits=None):
"""
Return a list of the digits of ``n`` in base ``b``. The first
element in the list is ``b`` (or ``-b`` if ``n`` is negative).
Examples
========
>>> from sympy.ntheory.digits import digits
>>> digits(35)
[10, 3, 5]
If the number is negative, the negative sign will be placed on the
base (which is the first element in the returned list):
>>> digits(-35)
[-10, 3, 5]
Bases other than 10 (and greater than 1) can be selected with ``b``:
>>> digits(27, b=2)
[2, 1, 1, 0, 1, 1]
Use the ``digits`` keyword if a certain number of digits is desired:
>>> digits(35, digits=4)
[10, 0, 0, 3, 5]
Parameters
==========
n: integer
The number whose digits are returned.
b: integer
The base in which digits are computed.
digits: integer (or None for all digits)
The number of digits to be returned (padded with zeros, if
necessary).
See Also
========
sympy.core.intfunc.num_digits, count_digits
"""
b = as_int(b)
n = as_int(n)
if b < 2:
raise ValueError("b must be greater than 1")
else:
x, y = abs(n), []
while x >= b:
x, r = divmod(x, b)
y.append(r)
y.append(x)
y.append(-b if n < 0 else b)
y.reverse()
ndig = len(y) - 1
if digits is not None:
if ndig > digits:
raise ValueError(
"For %s, at least %s digits are needed." % (n, ndig))
elif ndig < digits:
y[1:1] = [0]*(digits - ndig)
return y
def count_digits(n, b=10):
"""
Return a dictionary whose keys are the digits of ``n`` in the
given base, ``b``, with keys indicating the digits appearing in the
number and values indicating how many times that digit appeared.
Examples
========
>>> from sympy.ntheory import count_digits
>>> count_digits(1111339)
{1: 4, 3: 2, 9: 1}
The digits returned are always represented in base-10
but the number itself can be entered in any format that is
understood by Python; the base of the number can also be
given if it is different than 10:
>>> n = 0xFA; n
250
>>> count_digits(_)
{0: 1, 2: 1, 5: 1}
>>> count_digits(n, 16)
{10: 1, 15: 1}
The default dictionary will return a 0 for any digit that did
not appear in the number. For example, which digits appear 7
times in ``77!``:
>>> from sympy import factorial
>>> c77 = count_digits(factorial(77))
>>> [i for i in range(10) if c77[i] == 7]
[1, 3, 7, 9]
See Also
========
sympy.core.intfunc.num_digits, digits
"""
rv = defaultdict(int, multiset(digits(n, b)).items())
rv.pop(b) if b in rv else rv.pop(-b) # b or -b is there
return rv
def is_palindromic(n, b=10):
"""return True if ``n`` is the same when read from left to right
or right to left in the given base, ``b``.
Examples
========
>>> from sympy.ntheory import is_palindromic
>>> all(is_palindromic(i) for i in (-11, 1, 22, 121))
True
The second argument allows you to test numbers in other
bases. For example, 88 is palindromic in base-10 but not
in base-8:
>>> is_palindromic(88, 8)
False
On the other hand, a number can be palindromic in base-8 but
not in base-10:
>>> 0o121, is_palindromic(0o121)
(81, False)
Or it might be palindromic in both bases:
>>> oct(121), is_palindromic(121, 8) and is_palindromic(121)
('0o171', True)
"""
return _palindromic(digits(n, b), 1)

View File

@ -0,0 +1,345 @@
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
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 : ``n`` (if it is prime) else 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)
if isprime(n):
return n
# 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):
deltas = set()
deltas.update((abs(q - r) - 1) // 2 for q in primerange(r - 2*D, r + 2*D))
# d in deltas iff r+(2d+1) and/or r-(2d+1) is prime
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}
"""
n = as_int(n)
if B1 % 2 != 0 or B2 % 2 != 0:
raise ValueError("both bounds must be even")
_factors = set()
for prime in sieve.primerange(1, 100000):
if n % prime == 0:
_factors.add(prime)
while(n % prime == 0):
n //= prime
while(n > 1):
factor = _ecm_one_factor(n, B1, B2, max_curve, seed)
if factor is None:
raise ValueError("Increase the bounds")
_factors.add(factor)
n //= factor
factors = set()
for factor in _factors:
if isprime(factor):
factors.add(factor)
continue
factors |= ecm(factor)
return factors

View File

@ -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)

View File

@ -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

View File

@ -0,0 +1,291 @@
from math import prod
from sympy.external.gmpy import gcd, gcdext
from sympy.ntheory.primetest import isprime
from sympy.polys.domains import ZZ
from sympy.polys.galoistools import gf_crt, gf_crt1, gf_crt2
from sympy.utilities.misc import as_int
def symmetric_residue(a, m):
"""Return the residual mod m such that it is within half of the modulus.
>>> from sympy.ntheory.modular import symmetric_residue
>>> symmetric_residue(1, 6)
1
>>> symmetric_residue(4, 6)
-2
"""
if a <= m // 2:
return a
return a - m
def crt(m, v, symmetric=False, check=True):
r"""Chinese Remainder Theorem.
The moduli in m are assumed to be pairwise coprime. The output
is then an integer f, such that f = v_i mod m_i for each pair out
of v and m. If ``symmetric`` is False a positive integer will be
returned, else \|f\| will be less than or equal to the LCM of the
moduli, and thus f may be negative.
If the moduli are not co-prime the correct result will be returned
if/when the test of the result is found to be incorrect. This result
will be None if there is no solution.
The keyword ``check`` can be set to False if it is known that the moduli
are coprime.
Examples
========
As an example consider a set of residues ``U = [49, 76, 65]``
and a set of moduli ``M = [99, 97, 95]``. Then we have::
>>> from sympy.ntheory.modular import crt
>>> crt([99, 97, 95], [49, 76, 65])
(639985, 912285)
This is the correct result because::
>>> [639985 % m for m in [99, 97, 95]]
[49, 76, 65]
If the moduli are not co-prime, you may receive an incorrect result
if you use ``check=False``:
>>> crt([12, 6, 17], [3, 4, 2], check=False)
(954, 1224)
>>> [954 % m for m in [12, 6, 17]]
[6, 0, 2]
>>> crt([12, 6, 17], [3, 4, 2]) is None
True
>>> crt([3, 6], [2, 5])
(5, 6)
Note: the order of gf_crt's arguments is reversed relative to crt,
and that solve_congruence takes residue, modulus pairs.
Programmer's note: rather than checking that all pairs of moduli share
no GCD (an O(n**2) test) and rather than factoring all moduli and seeing
that there is no factor in common, a check that the result gives the
indicated residuals is performed -- an O(n) operation.
See Also
========
solve_congruence
sympy.polys.galoistools.gf_crt : low level crt routine used by this routine
"""
if check:
m = list(map(as_int, m))
v = list(map(as_int, v))
result = gf_crt(v, m, ZZ)
mm = prod(m)
if check:
if not all(v % m == result % m for v, m in zip(v, m)):
result = solve_congruence(*list(zip(v, m)),
check=False, symmetric=symmetric)
if result is None:
return result
result, mm = result
if symmetric:
return int(symmetric_residue(result, mm)), int(mm)
return int(result), int(mm)
def crt1(m):
"""First part of Chinese Remainder Theorem, for multiple application.
Examples
========
>>> from sympy.ntheory.modular import crt, crt1, crt2
>>> m = [99, 97, 95]
>>> v = [49, 76, 65]
The following two codes have the same result.
>>> crt(m, v)
(639985, 912285)
>>> mm, e, s = crt1(m)
>>> crt2(m, v, mm, e, s)
(639985, 912285)
However, it is faster when we want to fix ``m`` and
compute for multiple ``v``, i.e. the following cases:
>>> mm, e, s = crt1(m)
>>> vs = [[52, 21, 37], [19, 46, 76]]
>>> for v in vs:
... print(crt2(m, v, mm, e, s))
(397042, 912285)
(803206, 912285)
See Also
========
sympy.polys.galoistools.gf_crt1 : low level crt routine used by this routine
sympy.ntheory.modular.crt
sympy.ntheory.modular.crt2
"""
return gf_crt1(m, ZZ)
def crt2(m, v, mm, e, s, symmetric=False):
"""Second part of Chinese Remainder Theorem, for multiple application.
See ``crt1`` for usage.
Examples
========
>>> from sympy.ntheory.modular import crt1, crt2
>>> mm, e, s = crt1([18, 42, 6])
>>> crt2([18, 42, 6], [0, 0, 0], mm, e, s)
(0, 4536)
See Also
========
sympy.polys.galoistools.gf_crt2 : low level crt routine used by this routine
sympy.ntheory.modular.crt
sympy.ntheory.modular.crt1
"""
result = gf_crt2(v, m, mm, e, s, ZZ)
if symmetric:
return int(symmetric_residue(result, mm)), int(mm)
return int(result), int(mm)
def solve_congruence(*remainder_modulus_pairs, **hint):
"""Compute the integer ``n`` that has the residual ``ai`` when it is
divided by ``mi`` where the ``ai`` and ``mi`` are given as pairs to
this function: ((a1, m1), (a2, m2), ...). If there is no solution,
return None. Otherwise return ``n`` and its modulus.
The ``mi`` values need not be co-prime. If it is known that the moduli are
not co-prime then the hint ``check`` can be set to False (default=True) and
the check for a quicker solution via crt() (valid when the moduli are
co-prime) will be skipped.
If the hint ``symmetric`` is True (default is False), the value of ``n``
will be within 1/2 of the modulus, possibly negative.
Examples
========
>>> from sympy.ntheory.modular import solve_congruence
What number is 2 mod 3, 3 mod 5 and 2 mod 7?
>>> solve_congruence((2, 3), (3, 5), (2, 7))
(23, 105)
>>> [23 % m for m in [3, 5, 7]]
[2, 3, 2]
If you prefer to work with all remainder in one list and
all moduli in another, send the arguments like this:
>>> solve_congruence(*zip((2, 3, 2), (3, 5, 7)))
(23, 105)
The moduli need not be co-prime; in this case there may or
may not be a solution:
>>> solve_congruence((2, 3), (4, 6)) is None
True
>>> solve_congruence((2, 3), (5, 6))
(5, 6)
The symmetric flag will make the result be within 1/2 of the modulus:
>>> solve_congruence((2, 3), (5, 6), symmetric=True)
(-1, 6)
See Also
========
crt : high level routine implementing the Chinese Remainder Theorem
"""
def combine(c1, c2):
"""Return the tuple (a, m) which satisfies the requirement
that n = a + i*m satisfy n = a1 + j*m1 and n = a2 = k*m2.
References
==========
.. [1] https://en.wikipedia.org/wiki/Method_of_successive_substitution
"""
a1, m1 = c1
a2, m2 = c2
a, b, c = m1, a2 - a1, m2
g = gcd(a, b, c)
a, b, c = [i//g for i in [a, b, c]]
if a != 1:
g, inv_a, _ = gcdext(a, c)
if g != 1:
return None
b *= inv_a
a, m = a1 + m1*b, m1*c
return a, m
rm = remainder_modulus_pairs
symmetric = hint.get('symmetric', False)
if hint.get('check', True):
rm = [(as_int(r), as_int(m)) for r, m in rm]
# ignore redundant pairs but raise an error otherwise; also
# make sure that a unique set of bases is sent to gf_crt if
# they are all prime.
#
# The routine will work out less-trivial violations and
# return None, e.g. for the pairs (1,3) and (14,42) there
# is no answer because 14 mod 42 (having a gcd of 14) implies
# (14/2) mod (42/2), (14/7) mod (42/7) and (14/14) mod (42/14)
# which, being 0 mod 3, is inconsistent with 1 mod 3. But to
# preprocess the input beyond checking of another pair with 42
# or 3 as the modulus (for this example) is not necessary.
uniq = {}
for r, m in rm:
r %= m
if m in uniq:
if r != uniq[m]:
return None
continue
uniq[m] = r
rm = [(r, m) for m, r in uniq.items()]
del uniq
# if the moduli are co-prime, the crt will be significantly faster;
# checking all pairs for being co-prime gets to be slow but a prime
# test is a good trade-off
if all(isprime(m) for r, m in rm):
r, m = list(zip(*rm))
return crt(m, r, symmetric=symmetric, check=False)
rv = (0, 1)
for rmi in rm:
rv = combine(rv, rmi)
if rv is None:
break
n, m = rv
n = n % m
else:
if symmetric:
return symmetric_residue(n, m), m
return n, m

View File

@ -0,0 +1,188 @@
from sympy.utilities.misc import as_int
def binomial_coefficients(n):
"""Return a dictionary containing pairs :math:`{(k1,k2) : C_kn}` where
:math:`C_kn` are binomial coefficients and :math:`n=k1+k2`.
Examples
========
>>> from sympy.ntheory import binomial_coefficients
>>> binomial_coefficients(9)
{(0, 9): 1, (1, 8): 9, (2, 7): 36, (3, 6): 84,
(4, 5): 126, (5, 4): 126, (6, 3): 84, (7, 2): 36, (8, 1): 9, (9, 0): 1}
See Also
========
binomial_coefficients_list, multinomial_coefficients
"""
n = as_int(n)
d = {(0, n): 1, (n, 0): 1}
a = 1
for k in range(1, n//2 + 1):
a = (a * (n - k + 1))//k
d[k, n - k] = d[n - k, k] = a
return d
def binomial_coefficients_list(n):
""" Return a list of binomial coefficients as rows of the Pascal's
triangle.
Examples
========
>>> from sympy.ntheory import binomial_coefficients_list
>>> binomial_coefficients_list(9)
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
See Also
========
binomial_coefficients, multinomial_coefficients
"""
n = as_int(n)
d = [1] * (n + 1)
a = 1
for k in range(1, n//2 + 1):
a = (a * (n - k + 1))//k
d[k] = d[n - k] = a
return d
def multinomial_coefficients(m, n):
r"""Return a dictionary containing pairs ``{(k1,k2,..,km) : C_kn}``
where ``C_kn`` are multinomial coefficients such that
``n=k1+k2+..+km``.
Examples
========
>>> from sympy.ntheory import multinomial_coefficients
>>> multinomial_coefficients(2, 5) # indirect doctest
{(0, 5): 1, (1, 4): 5, (2, 3): 10, (3, 2): 10, (4, 1): 5, (5, 0): 1}
Notes
=====
The algorithm is based on the following result:
.. math::
\binom{n}{k_1, \ldots, k_m} =
\frac{k_1 + 1}{n - k_1} \sum_{i=2}^m \binom{n}{k_1 + 1, \ldots, k_i - 1, \ldots}
Code contributed to Sage by Yann Laigle-Chapuy, copied with permission
of the author.
See Also
========
binomial_coefficients_list, binomial_coefficients
"""
m = as_int(m)
n = as_int(n)
if not m:
if n:
return {}
return {(): 1}
if m == 2:
return binomial_coefficients(n)
if m >= 2*n and n > 1:
return dict(multinomial_coefficients_iterator(m, n))
t = [n] + [0] * (m - 1)
r = {tuple(t): 1}
if n:
j = 0 # j will be the leftmost nonzero position
else:
j = m
# enumerate tuples in co-lex order
while j < m - 1:
# compute next tuple
tj = t[j]
if j:
t[j] = 0
t[0] = tj
if tj > 1:
t[j + 1] += 1
j = 0
start = 1
v = 0
else:
j += 1
start = j + 1
v = r[tuple(t)]
t[j] += 1
# compute the value
# NB: the initialization of v was done above
for k in range(start, m):
if t[k]:
t[k] -= 1
v += r[tuple(t)]
t[k] += 1
t[0] -= 1
r[tuple(t)] = (v * tj) // (n - t[0])
return r
def multinomial_coefficients_iterator(m, n, _tuple=tuple):
"""multinomial coefficient iterator
This routine has been optimized for `m` large with respect to `n` by taking
advantage of the fact that when the monomial tuples `t` are stripped of
zeros, their coefficient is the same as that of the monomial tuples from
``multinomial_coefficients(n, n)``. Therefore, the latter coefficients are
precomputed to save memory and time.
>>> from sympy.ntheory.multinomial import multinomial_coefficients
>>> m53, m33 = multinomial_coefficients(5,3), multinomial_coefficients(3,3)
>>> m53[(0,0,0,1,2)] == m53[(0,0,1,0,2)] == m53[(1,0,2,0,0)] == m33[(0,1,2)]
True
Examples
========
>>> from sympy.ntheory.multinomial import multinomial_coefficients_iterator
>>> it = multinomial_coefficients_iterator(20,3)
>>> next(it)
((3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 1)
"""
m = as_int(m)
n = as_int(n)
if m < 2*n or n == 1:
mc = multinomial_coefficients(m, n)
yield from mc.items()
else:
mc = multinomial_coefficients(n, n)
mc1 = {}
for k, v in mc.items():
mc1[_tuple(filter(None, k))] = v
mc = mc1
t = [n] + [0] * (m - 1)
t1 = _tuple(t)
b = _tuple(filter(None, t1))
yield (t1, mc[b])
if n:
j = 0 # j will be the leftmost nonzero position
else:
j = m
# enumerate tuples in co-lex order
while j < m - 1:
# compute next tuple
tj = t[j]
if j:
t[j] = 0
t[0] = tj
if tj > 1:
t[j + 1] += 1
j = 0
else:
j += 1
t[j] += 1
t[0] -= 1
t1 = _tuple(t)
b = _tuple(filter(None, t1))
yield (t1, mc[b])

View File

@ -0,0 +1,278 @@
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 sympy.external.gmpy import gcd, legendre, jacobi
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
global _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*jacobi(m - 1, m)),
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)*legendre(m, 3)),
mpf_sqrt(from_int(k//3), prec), prec),
mpf_sin(arg, prec), prec)
v = k + v % k
if v % p == 0:
if e == 1:
return mpf_mul(
from_int(jacobi(3, k)),
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*jacobi(3, k)),
mpf_sqrt(from_int(k), prec), prec),
mpf_cos(arg, prec), prec)
if p != 2 or e >= 3:
d1, d2 = gcd(k1, 24), 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)

View File

@ -0,0 +1,793 @@
"""
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)
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:
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
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
# 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 < 885594169:
return mr(n, [725270293939359937, 3569819667048198375])
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)

View File

@ -0,0 +1,511 @@
from sympy.core.random import _randint
from sympy.external.gmpy import gcd, invert, sqrt as isqrt
from sympy.ntheory.residue_ntheory import _sqrt_mod_prime_power
from sympy.ntheory import isprime
from math import log, sqrt
class SievePolynomial:
def __init__(self, modified_coeff=(), a=None, b=None):
"""This class denotes the seive polynomial.
If ``g(x) = (a*x + b)**2 - N``. `g(x)` can be expanded
to ``a*x**2 + 2*a*b*x + b**2 - N``, so the coefficient
is stored in the form `[a**2, 2*a*b, b**2 - N]`. This
ensures faster `eval` method because we dont have to
perform `a**2, 2*a*b, b**2` every time we call the
`eval` method. As multiplication is more expensive
than addition, by using modified_coefficient we get
a faster seiving process.
Parameters
==========
modified_coeff : modified_coefficient of sieve polynomial
a : parameter of the sieve polynomial
b : parameter of the sieve polynomial
"""
self.modified_coeff = modified_coeff
self.a = a
self.b = b
def eval(self, x):
"""
Compute the value of the sieve polynomial at point x.
Parameters
==========
x : Integer parameter for sieve polynomial
"""
ans = 0
for coeff in self.modified_coeff:
ans *= x
ans += coeff
return ans
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
self.soln1 = None
self.soln2 = None
self.a_inv = 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 _initialize_first_polynomial(N, M, factor_base, idx_1000, idx_5000, seed=None):
"""This step is the initialization of the 1st sieve polynomial.
Here `a` is selected as a product of several primes of the factor_base
such that `a` is about to ``sqrt(2*N) / M``. Other initial values of
factor_base elem are also initialized which includes a_inv, b_ainv, soln1,
soln2 which are used when the sieve polynomial is changed. The b_ainv
is required for fast polynomial change as we do not have to calculate
`2*b*invert(a, prime)` every time.
We also ensure that the `factor_base` primes which make `a` are between
1000 and 5000.
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
seed : Generate pseudoprime numbers
"""
randint = _randint(seed)
approx_val = sqrt(2*N) / M
# `a` is a parameter of the sieve polynomial and `q` is the prime factors of `a`
# randomly search for a combination of primes whose multiplication is close to approx_val
# This multiplication of primes will be `a` and the primes will be `q`
# `best_a` denotes that `a` is close to approx_val in the random search of combination
best_a, best_q, best_ratio = None, None, None
start = 0 if idx_1000 is None else idx_1000
end = len(factor_base) - 1 if idx_5000 is None else idx_5000
for _ in range(50):
a = 1
q = []
while(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 = 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
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 gamma > q_l / 2:
gamma = q_l - gamma
B.append(a//q_l*gamma)
b = sum(B)
g = SievePolynomial([a*a, 2*a*b, b*b - N], a, b)
for fb in factor_base:
if a % fb.prime == 0:
continue
fb.a_inv = invert(a, fb.prime)
fb.b_ainv = [2*b_elem*fb.a_inv % fb.prime for b_elem in B]
fb.soln1 = (fb.a_inv*(fb.tmem_p - b)) % fb.prime
fb.soln2 = (fb.a_inv*(-fb.tmem_p - b)) % fb.prime
return g, B
def _initialize_ith_poly(N, factor_base, i, g, B):
"""Initialization stage of ith poly. After we finish sieving 1`st polynomial
here we quickly change to the next polynomial from which we will again
start sieving. Suppose we generated ith sieve polynomial and now we
want to generate (i + 1)th polynomial, where ``1 <= i <= 2**(j - 1) - 1``
where `j` is the number of prime factors of the coefficient `a`
then this function can be used to go to the next polynomial. If
``i = 2**(j - 1) - 1`` then go to _initialize_first_polynomial stage.
Parameters
==========
N : number to be factored
factor_base : factor_base primes
i : integer denoting ith polynomial
g : (i - 1)th polynomial
B : array that stores a//q_l*gamma
"""
from sympy.functions.elementary.integers import ceiling
v = 1
j = i
while(j % 2 == 0):
v += 1
j //= 2
if ceiling(i / (2**v)) % 2 == 1:
neg_pow = -1
else:
neg_pow = 1
b = g.b + 2*neg_pow*B[v - 1]
a = g.a
g = SievePolynomial([a*a, 2*a*b, b*b - N], a, b)
for fb in factor_base:
if a % fb.prime == 0:
continue
fb.soln1 = (fb.soln1 - neg_pow*fb.b_ainv[v - 1]) % fb.prime
fb.soln2 = (fb.soln2 - neg_pow*fb.b_ainv[v - 1]) % fb.prime
return 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):
"""Here we check that if `num` is a smooth number or not. If `a` is a smooth
number then it returns a vector of prime exponents modulo 2. For example
if a = 2 * 5**2 * 7**3 and the factor base contains {2, 3, 5, 7} then
`a` is a smooth number and this function returns ([1, 0, 0, 1], True). If
`a` is a partial relation which means that `a` a has one prime factor
greater than the `factor_base` then it returns `(a, False)` which denotes `a`
is a partial relation.
Parameters
==========
a : integer whose smootheness is to be checked
factor_base : factor_base primes
"""
vec = []
if num < 0:
vec.append(1)
num *= -1
else:
vec.append(0)
#-1 is not included in factor_base add -1 in vector
for factor in factor_base:
if num % factor.prime != 0:
vec.append(0)
continue
factor_exp = 0
while num % factor.prime == 0:
factor_exp += 1
num //= factor.prime
vec.append(factor_exp % 2)
if num == 1:
return vec, True
if isprime(num):
return num, False
return None, None
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
"""
sqrt_n = isqrt(N)
accumulated_val = log(M * sqrt_n)*2**10 - ERROR_TERM
smooth_relations = []
proper_factor = set()
partial_relation_upper_bound = 128*factor_base[-1].prime
for idx, val in enumerate(sieve_array):
if val < accumulated_val:
continue
x = idx - M
v = sieve_poly.eval(x)
vec, is_smooth = _check_smoothness(v, factor_base)
if is_smooth is None:#Neither smooth nor partial
continue
u = sieve_poly.a*x + sieve_poly.b
# Update the partial relation
# If 2 partial relation with same large prime is found then generate smooth relation
if is_smooth is False:#partial relation found
large_prime = vec
#Consider the large_primes under 128*F
if large_prime > partial_relation_upper_bound:
continue
if large_prime not in partial_relations:
partial_relations[large_prime] = (u, v)
continue
else:
u_prev, v_prev = partial_relations[large_prime]
partial_relations.pop(large_prime)
try:
large_prime_inv = invert(large_prime, N)
except ZeroDivisionError:#if large_prime divides N
proper_factor.add(large_prime)
continue
u = u*u_prev*large_prime_inv
v = v*v_prev // (large_prime*large_prime)
vec, is_smooth = _check_smoothness(v, factor_base)
#assert u*u % N == v % N
smooth_relations.append((u, v, vec))
return smooth_relations, proper_factor
#LINEAR ALGEBRA STAGE
def _build_matrix(smooth_relations):
"""Build a 2D matrix from smooth relations.
Parameters
==========
smooth_relations : Stores smooth relations
"""
matrix = []
for s_relation in smooth_relations:
matrix.append(s_relation[2])
return matrix
def _gauss_mod_2(A):
"""Fast gaussian reduction for modulo 2 matrix.
Parameters
==========
A : Matrix
Examples
========
>>> from sympy.ntheory.qs import _gauss_mod_2
>>> _gauss_mod_2([[0, 1, 1], [1, 0, 1], [0, 1, 0], [1, 1, 1]])
([[[1, 0, 1], 3]],
[True, True, True, False],
[[0, 1, 0], [1, 0, 0], [0, 0, 1], [1, 0, 1]])
Reference
==========
.. [1] A fast algorithm for gaussian elimination over GF(2) and
its implementation on the GAPP. Cetin K.Koc, Sarath N.Arachchige"""
import copy
matrix = copy.deepcopy(A)
row = len(matrix)
col = len(matrix[0])
mark = [False]*row
for c in range(col):
for r in range(row):
if matrix[r][c] == 1:
break
mark[r] = True
for c1 in range(col):
if c1 == c:
continue
if matrix[r][c1] == 1:
for r2 in range(row):
matrix[r2][c1] = (matrix[r2][c1] + matrix[r2][c]) % 2
dependent_row = []
for idx, val in enumerate(mark):
if val == False:
dependent_row.append([matrix[idx], idx])
return dependent_row, mark, matrix
def _find_factor(dependent_rows, mark, gauss_matrix, index, smooth_relations, N):
"""Finds proper factor of N. Here, transform the dependent rows as a
combination of independent rows of the gauss_matrix to form the desired
relation of the form ``X**2 = Y**2 modN``. After obtaining the desired relation
we obtain a proper factor of N by `gcd(X - Y, N)`.
Parameters
==========
dependent_rows : denoted dependent rows in the reduced matrix form
mark : boolean array to denoted dependent and independent rows
gauss_matrix : Reduced form of the smooth relations matrix
index : denoted the index of the dependent_rows
smooth_relations : Smooth relations vectors matrix
N : Number to be factored
"""
idx_in_smooth = dependent_rows[index][1]
independent_u = [smooth_relations[idx_in_smooth][0]]
independent_v = [smooth_relations[idx_in_smooth][1]]
dept_row = dependent_rows[index][0]
for idx, val in enumerate(dept_row):
if val == 1:
for row in range(len(gauss_matrix)):
if gauss_matrix[row][idx] == 1 and mark[row] == True:
independent_u.append(smooth_relations[row][0])
independent_v.append(smooth_relations[row][1])
break
u = 1
v = 1
for i in independent_u:
u *= i
for i in independent_v:
v *= i
#assert u**2 % N == v % N
v = isqrt(v)
return gcd(u - v, N)
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
threshold : Extra smooth relations for factorization
seed : generate pseudo prime numbers
Examples
========
>>> from sympy.ntheory import qs
>>> qs(25645121643901801, 2000, 10000)
{5394769, 4753701529}
>>> qs(9804659461513846513, 2000, 10000)
{4641991, 2112166839943}
References
==========
.. [1] https://pdfs.semanticscholar.org/5c52/8a975c1405bd35c65993abf5a4edb667c1db.pdf
.. [2] https://www.rieselprime.de/ziki/Self-initializing_quadratic_sieve
"""
ERROR_TERM*=2**10
idx_1000, idx_5000, factor_base = _generate_factor_base(prime_bound, N)
smooth_relations = []
ith_poly = 0
partial_relations = {}
proper_factor = set()
threshold = 5*len(factor_base) // 100
while True:
if ith_poly == 0:
ith_sieve_poly, B_array = _initialize_first_polynomial(N, M, factor_base, idx_1000, idx_5000)
else:
ith_sieve_poly = _initialize_ith_poly(N, factor_base, ith_poly, ith_sieve_poly, B_array)
ith_poly += 1
if ith_poly >= 2**(len(B_array) - 1): # time to start with a new sieve polynomial
ith_poly = 0
sieve_array = _gen_sieve_array(M, factor_base)
s_rel, p_f = _trial_division_stage(N, M, factor_base, sieve_array, ith_sieve_poly, partial_relations, ERROR_TERM)
smooth_relations += s_rel
proper_factor |= p_f
if len(smooth_relations) >= len(factor_base) + threshold:
break
matrix = _build_matrix(smooth_relations)
dependent_row, mark, gauss_matrix = _gauss_mod_2(matrix)
N_copy = N
for index in range(len(dependent_row)):
factor = _find_factor(dependent_row, mark, gauss_matrix, index, smooth_relations, N)
if factor > 1 and factor < N:
proper_factor.add(factor)
while(N_copy % factor == 0):
N_copy //= factor
if isprime(N_copy):
proper_factor.add(N_copy)
break
if(N_copy == 1):
break
return proper_factor

File diff suppressed because it is too large Load Diff

View File

@ -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]

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -0,0 +1,627 @@
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)
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(Rational(1, 2)**3) == (S.Half, 3)
assert perfect_power(Rational(-3, 2)**3) == (-3*S.Half, 3)
@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

View File

@ -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

View File

@ -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)

View File

@ -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]))))

View File

@ -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)]

View File

@ -0,0 +1,27 @@
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
def test_deprecated_ntheory_symbolic_functions():
from sympy.testing.pytest import warns_deprecated_sympy
with warns_deprecated_sympy():
assert npartitions(0) == 1

View File

@ -0,0 +1,230 @@
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)

View File

@ -0,0 +1,124 @@
from __future__ import annotations
from sympy.ntheory import qs
from sympy.ntheory.qs import SievePolynomial, _generate_factor_base, \
_initialize_first_polynomial, _initialize_ith_poly, \
_gen_sieve_array, _check_smoothness, _trial_division_stage, _gauss_mod_2, \
_build_matrix, _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, 3000, 50000) == \
{980835832582657, 990377764891511}
assert qs(18640889198609*20991129234731, 1000, 50000) == \
{18640889198609, 20991129234731}
def test_qs_2() -> None:
n = 10009202107
M = 50
# a = 10, b = 15, modified_coeff = [a**2, 2*a*b, b**2 - N]
sieve_poly = SievePolynomial([100, 1600, -10009195707], 10, 80)
assert sieve_poly.eval(10) == -10009169707
assert sieve_poly.eval(5) == -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]
g, B = _initialize_first_polynomial(
n, M, factor_base, idx_1000, idx_5000, seed=0)
assert g.a == 1133107
assert g.b == 682543
assert B == [272889, 409654]
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].a_inv for i in range(15)] == \
[1, 1, 5, 7, 3, 5, 26, 6, 40, 5, 21, 45, 4, 1, 8]
assert [factor_base[i].b_ainv for i in range(5)] == \
[[0, 0], [0, 2], [3, 0], [3, 9], [13, 13]]
g_1 = _initialize_ith_poly(n, factor_base, 1, g, B)
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) == (5, False)
assert _check_smoothness(210313, factor_base)[0][0:15] == \
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1]
assert _check_smoothness(210313, factor_base)[1]
partial_relations: dict[int, tuple[int, int]] = {}
smooth_relation, partial_relation = _trial_division_stage(
n, M, factor_base, sieve_array, sieve_poly, partial_relations,
ERROR_TERM=25*2**10)
assert partial_relations == {
8699: (440, -10009008507),
166741: (490, -10008962007),
131449: (530, -10008921207),
6653: (550, -10008899607)
}
assert [smooth_relation[i][0] for i in range(5)] == [
-250, -670615476700, -45211565844500, -231723037747200, -1811665537200]
assert [smooth_relation[i][1] for i in range(5)] == [
-10009139607, 1133094251961, 5302606761, 53804049849, 1950723889]
assert smooth_relation[0][2][0:15] == [
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
assert _gauss_mod_2(
[[0, 0, 1], [1, 0, 1], [0, 1, 0], [0, 1, 1], [0, 1, 1]]
) == (
[[[0, 1, 1], 3], [[0, 1, 1], 4]],
[True, True, True, False, False],
[[0, 0, 1], [1, 0, 0], [0, 1, 0], [0, 1, 1], [0, 1, 1]]
)
def test_qs_3():
N = 1817
smooth_relations = [
(2455024, 637, [0, 0, 0, 1]),
(-27993000, 81536, [0, 1, 0, 1]),
(11461840, 12544, [0, 0, 0, 0]),
(149, 20384, [0, 1, 0, 1]),
(-31138074, 19208, [0, 1, 0, 0])
]
matrix = _build_matrix(smooth_relations)
assert matrix == [
[0, 0, 0, 1],
[0, 1, 0, 1],
[0, 0, 0, 0],
[0, 1, 0, 1],
[0, 1, 0, 0]
]
dependent_row, mark, gauss_matrix = _gauss_mod_2(matrix)
assert dependent_row == [[[0, 0, 0, 0], 2], [[0, 1, 0, 0], 3]]
assert mark == [True, True, False, False, True]
assert gauss_matrix == [
[0, 0, 0, 1],
[0, 1, 0, 0],
[0, 0, 0, 0],
[0, 1, 0, 0],
[0, 1, 0, 1]
]
factor = _find_factor(
dependent_row, mark, gauss_matrix, 0, smooth_relations, N)
assert factor == 23

View File

@ -0,0 +1,345 @@
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(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 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