Skip to content

Commit e3567f5

Browse files
committed
Implement partial integer factorization using flint
1 parent 665a3fa commit e3567f5

File tree

3 files changed

+45
-18
lines changed

3 files changed

+45
-18
lines changed

src/sage/matrix/matrix_integer_dense.pyx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2936,6 +2936,10 @@ cdef class Matrix_integer_dense(Matrix_dense):
29362936
precision=precision)
29372937

29382938
R = A.to_matrix(self.new_matrix())
2939+
2940+
else:
2941+
raise ValueError("unknown algorithm")
2942+
29392943
return R
29402944

29412945
def LLL(self, delta=None, eta=None, algorithm='fpLLL:wrapper', fp=None, prec=0, early_red=False, use_givens=False, use_siegel=False, transformation=False, **kwds):

src/sage/rings/factorint_flint.pyx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ from sage.libs.flint.fmpz_factor_sage cimport *
2424
from sage.rings.integer cimport Integer
2525

2626

27-
def factor_using_flint(Integer n):
27+
def factor_using_flint(Integer n, unsigned bits = 0):
2828
r"""
2929
Factor the nonzero integer ``n`` using FLINT.
3030
@@ -35,6 +35,7 @@ def factor_using_flint(Integer n):
3535
INPUT:
3636
3737
- ``n`` -- a nonzero sage Integer; the number to factor
38+
- ``bits`` -- if nonzero, passed to ``fmpz_factor_smooth``
3839
3940
OUTPUT:
4041
@@ -89,7 +90,10 @@ def factor_using_flint(Integer n):
8990
fmpz_factor_init(factors)
9091

9192
sig_on()
92-
fmpz_factor(factors, p)
93+
if bits:
94+
fmpz_factor_smooth(factors, p, bits, 0) # TODO make proved=* customizable
95+
else:
96+
fmpz_factor(factors, p)
9397
sig_off()
9498

9599
pairs = fmpz_factor_to_pairlist(factors)

src/sage/rings/integer.pyx

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3876,8 +3876,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement):
38763876
sig_off()
38773877
return x
38783878

3879-
def factor(self, algorithm='pari', proof=None, limit=None, int_=False,
3880-
verbose=0):
3879+
def factor(self, algorithm=None, proof=None, limit=None, int_=False,
3880+
verbose=0, flint_bits=None):
38813881
"""
38823882
Return the prime factorization of this integer as a
38833883
formal Factorization object.
@@ -3896,7 +3896,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement):
38963896
- ``'magma'`` -- use the MAGMA computer algebra system (requires
38973897
an installation of MAGMA)
38983898
3899-
- ``'qsieve'`` -- use Bill Hart's quadratic sieve code;
3899+
- ``'qsieve'`` -- use ``qsieve_factor`` in the FLINT library;
39003900
WARNING: this may not work as expected, see qsieve? for
39013901
more information
39023902
@@ -3910,6 +3910,10 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement):
39103910
given it must fit in a ``signed int``, and the factorization is done
39113911
using trial division and primes up to limit
39123912
3913+
- ``flint_bits`` -- integer or ``None`` (default: ``None``); if specified,
3914+
perform only a partial factorization, primes at most ``2^flint_bits``
3915+
have a high probability of being detected
3916+
39133917
OUTPUT: a Factorization object containing the prime factors and
39143918
their multiplicities
39153919
@@ -3958,6 +3962,13 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement):
39583962
sage: n.factor(algorithm='flint') # needs sage.libs.flint
39593963
2 * 3 * 11 * 13 * 41 * 73 * 22650083 * 1424602265462161
39603964
3965+
Example with ``flint_bits``. The small prime factor is found since it is
3966+
much smaller than `2^{50}`, but not the large ones::
3967+
3968+
sage: n = next_prime(2^256) * next_prime(2^257) * next_prime(2^40)
3969+
sage: n.factor(algorithm='flint', flint_bits=50) # needs sage.libs.flint
3970+
1099511627791 * 2681...6291
3971+
39613972
We factor using a quadratic sieve algorithm::
39623973
39633974
sage: # needs sage.libs.pari
@@ -3985,14 +3996,11 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement):
39853996
sage: n.factor(algorithm='foobar')
39863997
Traceback (most recent call last):
39873998
...
3988-
ValueError: Algorithm is not known
3999+
ValueError: algorithm is not known
39894000
"""
39904001
from sage.structure.factorization import Factorization
39914002
from sage.structure.factorization_integer import IntegerFactorization
39924003

3993-
if algorithm not in ['pari', 'flint', 'kash', 'magma', 'qsieve', 'ecm']:
3994-
raise ValueError("Algorithm is not known")
3995-
39964004
cdef Integer n, p, unit
39974005

39984006
if mpz_sgn(self.value) == 0:
@@ -4003,18 +4011,27 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement):
40034011
unit = one
40044012
else:
40054013
n = PY_NEW(Integer)
4006-
unit = PY_NEW(Integer)
40074014
mpz_neg(n.value, self.value)
4008-
mpz_set_si(unit.value, -1)
4009-
4010-
if mpz_cmpabs_ui(n.value, 1) == 0:
4011-
return IntegerFactorization([], unit=unit, unsafe=True,
4012-
sort=False, simplify=False)
4015+
unit = smallInteger(-1)
40134016

40144017
if limit is not None:
4018+
if algorithm is not None:
4019+
raise ValueError('trial division will always be used when when limit is provided')
40154020
from sage.rings.factorint import factor_trial_division
40164021
return factor_trial_division(self, limit)
40174022

4023+
if algorithm is None:
4024+
algorithm = 'pari'
4025+
elif algorithm not in ['pari', 'flint', 'kash', 'magma', 'qsieve', 'ecm']:
4026+
raise ValueError("algorithm is not known")
4027+
4028+
if algorithm != 'flint' and flint_bits is not None:
4029+
raise ValueError("cannot specify flint_bits when algorithm is not flint")
4030+
4031+
if n.is_one():
4032+
return IntegerFactorization([], unit=unit, unsafe=True,
4033+
sort=False, simplify=False)
4034+
40184035
if mpz_fits_slong_p(n.value):
40194036
global n_factor_to_list
40204037
if n_factor_to_list is None:
@@ -4044,7 +4061,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement):
40444061
sort=False, simplify=False)
40454062
elif algorithm == 'flint':
40464063
from sage.rings.factorint_flint import factor_using_flint
4047-
F = factor_using_flint(n)
4064+
if flint_bits is not None and flint_bits <= 0:
4065+
raise ValueError('flint_bits must be positive or None')
4066+
F = factor_using_flint(n, flint_bits or 0)
40484067
F.sort()
40494068
return IntegerFactorization(F, unit=unit, unsafe=True,
40504069
sort=False, simplify=False)
@@ -6662,13 +6681,13 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement):
66626681
if not mpz_sgn(n.value):
66636682
mpz_set_ui(t.value, 0)
66646683
mpz_abs(g.value, self.value)
6665-
mpz_set_si(s.value, 1 if mpz_sgn(self.value) >= 0 else -1)
6684+
s = smallInteger(1 if mpz_sgn(self.value) >= 0 else -1)
66666685
return g, s, t
66676686

66686687
if not mpz_sgn(self.value):
66696688
mpz_set_ui(s.value, 0)
66706689
mpz_abs(g.value, n.value)
6671-
mpz_set_si(t.value, 1 if mpz_sgn(n.value) >= 0 else -1)
6690+
t = smallInteger(1 if mpz_sgn(n.value) >= 0 else -1)
66726691
return g, s, t
66736692

66746693
# both n and self are nonzero, so we need to do a division and

0 commit comments

Comments
 (0)