Skip to content

Commit

Permalink
gh-35502: sage.rings.factorint: Modularization fixes
Browse files Browse the repository at this point in the history
    
<!-- Please provide a concise, informative and self-explanatory title.
-->
<!-- Don't put issue numbers in the title. Put it in the Description
below. -->
<!-- For example, instead of "Fixes #12345", use "Add a new method to
multiply two integers" -->

### 📚 Description

<!-- Describe your changes here in detail. -->
Spliiting `sage.rings.factorint` into separate modules, per library
used.
<!-- Why is this change required? What problem does it solve? -->
<!-- If this PR resolves an open issue, please link to it here. For
example "Fixes #12345". -->
Part of:
- #29705
<!-- If your change requires a documentation PR, please link it
appropriately. -->

### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. It should be `[x]` not `[x
]`. -->

- [x] The title is concise, informative, and self-explanatory.
- [x] The description explains in detail what this PR is about.
- [x] I have linked a relevant issue or discussion.
- [ ] I have created tests covering the changes.
- [x] I have updated the documentation accordingly.

### ⌛ Dependencies

<!-- List all open PRs that this PR logically depends on
- #12345: short description why this is a dependency
- #34567: ...
-->

<!-- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
    
URL: #35502
Reported by: Matthias Köppe
Reviewer(s): Kwankyu Lee
  • Loading branch information
Release Manager committed May 21, 2023
2 parents c3ed171 + e8051b8 commit 07bd424
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 166 deletions.
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 <andre.apitzsch@st.ovgu.de>
# Copyright (C) 2010-2011 André Apitzsch <andre.apitzsch@st.ovgu.de>
# 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

0 comments on commit 07bd424

Please sign in to comment.