Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sage.rings.factorint: Modularization fixes #35502

Merged
merged 6 commits into from
May 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/doc/en/reference/rings_standard/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Integers
sage/rings/bernmm
sage/rings/bernoulli_mod_p
sage/rings/factorint
sage/rings/factorint_flint
sage/rings/factorint_pari
sage/rings/fast_arith
sage/rings/sum_of_squares
sage/arith/functions
Expand Down
4 changes: 2 additions & 2 deletions src/sage/libs/flint/fmpz_factor.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ cdef fmpz_factor_to_pairlist(const fmpz_factor_t factors):
(factor, exponent) pairs. The factors are Integers, and the
exponents are Python ints. This is used and indirectly tested by
both :func:`qsieve` and
:func:`sage.rings.factorint.factor_using_flint`. The output
:func:`sage.rings.factorint_flint.factor_using_flint`. The output
format was ultimately based on that of
:func:`sage.rings.factorint.factor_using_pari`.
:func:`sage.rings.factorint_pari.factor_using_pari`.
"""
cdef list pairs = []

Expand Down
187 changes: 25 additions & 162 deletions src/sage/rings/factorint.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,19 @@ AUTHORS:
"""

#*****************************************************************************
# Copyright (C) 2010 AndrΓ© Apitzsch <[email protected]>
# Copyright (C) 2010-2011 AndrΓ© Apitzsch <[email protected]>
# 2012 Nils Bruin
# 2014 David Roe
# 2014 Travis Scrimshaw
#
# Distributed under the terms of the GNU General Public License (GPL)
# as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# http://www.gnu.org/licenses/
#*****************************************************************************

from cysignals.signals cimport sig_on, sig_off

from sage.ext.stdsage cimport PY_NEW
from sage.libs.gmp.mpz cimport *
from sage.libs.flint.fmpz cimport fmpz_t, fmpz_init, fmpz_set_mpz
from sage.libs.flint.fmpz_factor cimport *

from sage.rings.integer cimport Integer
from sage.rings.fast_arith import prime_range
Expand Down Expand Up @@ -53,23 +52,23 @@ cpdef aurifeuillian(n, m, F=None, bint check=True):
EXAMPLES::

sage: from sage.rings.factorint import aurifeuillian
sage: aurifeuillian(2,2)
sage: aurifeuillian(2, 2)
[5, 13]
sage: aurifeuillian(2,2^5)
sage: aurifeuillian(2, 2^5)
[1985, 2113]
sage: aurifeuillian(5,3)
sage: aurifeuillian(5, 3)
[1471, 2851]
sage: aurifeuillian(15,1)
sage: aurifeuillian(15, 1)
[19231, 142111]
sage: aurifeuillian(12,3)
sage: aurifeuillian(12, 3)
Traceback (most recent call last):
...
ValueError: n has to be square-free
sage: aurifeuillian(1,2)
sage: aurifeuillian(1, 2)
Traceback (most recent call last):
...
ValueError: n has to be greater than 1
sage: aurifeuillian(2,0)
sage: aurifeuillian(2, 0)
Traceback (most recent call last):
...
ValueError: m has to be positive
Expand Down Expand Up @@ -133,24 +132,24 @@ cpdef factor_aurifeuillian(n, check=True):
EXAMPLES::

sage: from sage.rings.factorint import factor_aurifeuillian as fa
sage: fa(2^6+1)
sage: fa(2^6 + 1) # optional - sage.libs.pari
[5, 13]
sage: fa(2^58+1)
sage: fa(2^58 + 1) # optional - sage.libs.pari
[536838145, 536903681]
sage: fa(3^3+1)
sage: fa(3^3 + 1) # optional - sage.libs.pari
[4, 1, 7]
sage: fa(5^5-1)
sage: fa(5^5 - 1) # optional - sage.libs.pari
[4, 11, 71]
sage: prod(_) == 5^5-1
sage: prod(_) == 5^5 - 1 # optional - sage.libs.pari
True
sage: fa(2^4+1)
sage: fa(2^4 + 1) # optional - sage.libs.pari
[17]
sage: fa((6^2*3)^3+1)
sage: fa((6^2*3)^3 + 1) # optional - sage.libs.pari
[109, 91, 127]

TESTS::

sage: for n in [2,3,5,6,30,31,33]:
sage: for n in [2,3,5,6,30,31,33]: # optional - sage.libs.pari
....: for m in [8,96,109201283]:
....: s = -1 if n % 4 == 1 else 1
....: y = (m^2*n)^n + s
Expand Down Expand Up @@ -206,9 +205,9 @@ cpdef factor_aurifeuillian(n, check=True):

def factor_cunningham(m, proof=None):
r"""
Return factorization of self obtained using trial division
Return factorization of ``self`` obtained using trial division
for all primes in the so called Cunningham table. This is
efficient if self has some factors of type `b^n+1` or `b^n-1`,
efficient if ``self`` has some factors of type `b^n+1` or `b^n-1`,
with `b` in `\{2,3,5,6,7,10,11,12\}`.

You need to install an optional package to use this method,
Expand All @@ -226,7 +225,7 @@ def factor_cunningham(m, proof=None):
sage: from sage.rings.factorint import factor_cunningham
sage: factor_cunningham(2^257-1) # optional - cunningham_tables
535006138814359 * 1155685395246619182673033 * 374550598501810936581776630096313181393
sage: factor_cunningham((3^101+1)*(2^60).next_prime(),proof=False) # optional - cunningham_tables
sage: factor_cunningham((3^101+1)*(2^60).next_prime(), proof=False) # optional - cunningham_tables
2^2 * 379963 * 1152921504606847009 * 1017291527198723292208309354658785077827527

"""
Expand All @@ -249,12 +248,12 @@ def factor_cunningham(m, proof=None):

cpdef factor_trial_division(m, long limit=LONG_MAX):
r"""
Return partial factorization of self obtained using trial division
for all primes up to limit, where limit must fit in a C signed long.
Return partial factorization of ``self`` obtained using trial division
for all primes up to ``limit``, where ``limit`` must fit in a C ``signed long``.

INPUT:

- ``limit`` -- integer (default: ``LONG_MAX``) that fits in a C signed long
- ``limit`` -- integer (default: ``LONG_MAX``) that fits in a C ``signed long``

EXAMPLES::

Expand Down Expand Up @@ -292,139 +291,3 @@ cpdef factor_trial_division(m, long limit=LONG_MAX):

return IntegerFactorization(F, unit=unit, unsafe=True,
sort=False, simplify=False)


def factor_using_pari(n, int_=False, debug_level=0, proof=None):
r"""
Factor this integer using PARI.

This function returns a list of pairs, not a ``Factorization``
object. The first element of each pair is the factor, of type
``Integer`` if ``int_`` is ``False`` or ``int`` otherwise,
the second element is the positive exponent, of type ``int``.

INPUT:

- ``int_`` -- (default: ``False``), whether the factors are
of type ``int`` instead of ``Integer``

- ``debug_level`` -- (default: 0), debug level of the call
to PARI

- ``proof`` -- (default: ``None``), whether the factors are
required to be proven prime; if ``None``, the global default
is used

OUTPUT:

A list of pairs.

EXAMPLES::

sage: factor(-2**72 + 3, algorithm='pari') # indirect doctest
-1 * 83 * 131 * 294971519 * 1472414939

Check that PARI's debug level is properly reset (:trac:`18792`)::

sage: alarm(0.5); factor(2^1000 - 1, verbose=5)
Traceback (most recent call last):
...
AlarmInterrupt
sage: pari.get_debug_level()
0
"""
from sage.libs.pari.all import pari

if proof is None:
from sage.structure.proof.proof import get_flag
proof = get_flag(proof, "arithmetic")

prev = pari.get_debug_level()

cdef Py_ssize_t i
try:
if prev != debug_level:
pari.set_debug_level(debug_level)

p, e = n.__pari__().factor(proof=proof)
if int_:
return [(int(p[i]), int(e[i])) for i in range(len(p))]
else:
return [(Integer(p[i]), int(e[i])) for i in range(len(p))]
finally:
if prev != debug_level:
pari.set_debug_level(prev)


def factor_using_flint(Integer n):
r"""
Factor the nonzero integer ``n`` using FLINT.

This function returns a list of (factor, exponent) pairs. The
factors will be of type ``Integer``, and the exponents will be of
type ``int``.

INPUT:

- ``n`` -- a nonzero sage Integer; the number to factor.

OUTPUT:

A list of ``(Integer, int)`` pairs representing the factors and
their exponents.

EXAMPLES::

sage: from sage.rings.factorint import factor_using_flint
sage: n = ZZ(9962572652930382)
sage: factors = factor_using_flint(n)
sage: factors
[(2, 1), (3, 1), (1660428775488397, 1)]
sage: prod( f^e for (f,e) in factors ) == n
True

Negative numbers will have a leading factor of ``(-1)^1``::

sage: n = ZZ(-1 * 2 * 3)
sage: factor_using_flint(n)
[(-1, 1), (2, 1), (3, 1)]

The factorization of unity is empty::

sage: factor_using_flint(ZZ.one())
[]

While zero has a single factor, of... zero::

sage: factor_using_flint(ZZ.zero())
[(0, 1)]

TESTS:

Check that the integers [-10,000, 10,000] are factored correctly::

sage: all(
....: prod( f^e for (f,e) in factor_using_flint(ZZ(c*k)) ) == c*k
....: for k in range(10000)
....: for c in [-1, 1]
....: )
True
"""
if n.is_zero():
return [(n, int(1))]

cdef fmpz_t p
fmpz_init(p)
fmpz_set_mpz(p, (<Integer>n).value)

cdef fmpz_factor_t factors
fmpz_factor_init(factors)

sig_on()
fmpz_factor(factors, p)
sig_off()

pairs = fmpz_factor_to_pairlist(factors)

fmpz_factor_clear(factors)
return pairs
97 changes: 97 additions & 0 deletions src/sage/rings/factorint_flint.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# sage.doctest: optional - sage.libs.flint
r"""
Integer factorization using FLINT

AUTHORS:

- Michael Orlitzky (2023)
"""

#*****************************************************************************
# Copyright (C) 2023 Michael Orlitzky
#
# Distributed under the terms of the GNU General Public License (GPL)
# as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# http://www.gnu.org/licenses/
#*****************************************************************************

from cysignals.signals cimport sig_on, sig_off

from sage.libs.flint.fmpz cimport fmpz_t, fmpz_init, fmpz_set_mpz
from sage.libs.flint.fmpz_factor cimport *
from sage.rings.integer cimport Integer


def factor_using_flint(Integer n):
r"""
Factor the nonzero integer ``n`` using FLINT.

This function returns a list of (factor, exponent) pairs. The
factors will be of type ``Integer``, and the exponents will be of
type ``int``.

INPUT:

- ``n`` -- a nonzero sage Integer; the number to factor.

OUTPUT:

A list of ``(Integer, int)`` pairs representing the factors and
their exponents.

EXAMPLES::

sage: from sage.rings.factorint_flint import factor_using_flint
sage: n = ZZ(9962572652930382)
sage: factors = factor_using_flint(n)
sage: factors
[(2, 1), (3, 1), (1660428775488397, 1)]
sage: prod( f^e for (f,e) in factors ) == n
True

Negative numbers will have a leading factor of ``(-1)^1``::

sage: n = ZZ(-1 * 2 * 3)
sage: factor_using_flint(n)
[(-1, 1), (2, 1), (3, 1)]

The factorization of unity is empty::

sage: factor_using_flint(ZZ.one())
[]

While zero has a single factor, of... zero::

sage: factor_using_flint(ZZ.zero())
[(0, 1)]

TESTS:

Check that the integers [-10,000, 10,000] are factored correctly::

sage: all(
....: prod( f^e for (f,e) in factor_using_flint(ZZ(c*k)) ) == c*k
....: for k in range(10000)
....: for c in [-1, 1]
....: )
True
"""
if n.is_zero():
return [(n, int(1))]

cdef fmpz_t p
fmpz_init(p)
fmpz_set_mpz(p, (<Integer>n).value)

cdef fmpz_factor_t factors
fmpz_factor_init(factors)

sig_on()
fmpz_factor(factors, p)
sig_off()

pairs = fmpz_factor_to_pairlist(factors)

fmpz_factor_clear(factors)
return pairs
Loading