Skip to content

Avoid overflow in passing large exponents to singular #40455

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

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
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: 1 addition & 1 deletion src/sage/libs/singular/polynomial.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ cdef int singular_polynomial_rmul (poly **ret, poly *p, RingElement q, ring *r)
cdef int singular_polynomial_mul (poly **ret, poly *p, poly *q, ring *r) except -1
cdef int singular_polynomial_sub (poly **ret, poly *p, poly *q, ring *r) noexcept
cdef int singular_polynomial_div_coeff (poly **ret, poly *p, poly *q, ring *r) except -1
cdef int singular_polynomial_pow (poly **ret, poly *p, unsigned long exp, ring *r) except -1
cdef int singular_polynomial_pow (poly **ret, poly *p, int exp, ring *r) except -1
cdef int singular_polynomial_neg(poly **ret, poly *p, ring *r) noexcept

cdef object singular_polynomial_latex(poly *p, ring *r, object base, object latex_gens)
Expand Down
2 changes: 1 addition & 1 deletion src/sage/libs/singular/polynomial.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@
::

sage: R.<x,y> = Integers(10)[]
sage: l = [i*x+j*y+k for i in range(10) for j in range(10) for k in range(10)]

Check warning on line 274 in src/sage/libs/singular/polynomial.pyx

View workflow job for this annotation

GitHub Actions / Conda (macos, Python 3.11, all)

Warning: slow doctest:

slow doctest:

Check warning on line 274 in src/sage/libs/singular/polynomial.pyx

View workflow job for this annotation

GitHub Actions / Conda (macos, Python 3.12, all)

Warning: slow doctest:

slow doctest:
sage: l.sort()
sage: for i in range(len(l)):
....: for b in l[:i]:
Expand Down Expand Up @@ -374,7 +374,7 @@
sig_off()
return 0

cdef int singular_polynomial_pow(poly **ret, poly *p, unsigned long exp, ring *r) except -1:
cdef int singular_polynomial_pow(poly **ret, poly *p, int exp, ring *r) except -1:
"""
``ret[0] = p**exp`` where ``p`` in ``r`` and ``exp`` > 0.

Expand Down
1 change: 0 additions & 1 deletion src/sage/libs/singular/singular.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1731,7 +1731,6 @@ cdef int overflow_check(unsigned long e, ring *_ring) except -1:
- ``_ring`` -- a pointer to some ring

Whether an overflow occurs or not partially depends

on the number of variables in the ring. See github issue
:issue:`11856`. With Singular 4, it is by default optimized
for at least 4 variables on 64-bit and 2 variables on 32-bit,
Expand Down
52 changes: 52 additions & 0 deletions src/sage/rings/polynomial/multi_polynomial_libsingular.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@

from warnings import warn

from libc.limits cimport INT_MAX

from cpython.object cimport Py_NE
from cysignals.memory cimport sig_malloc, sig_free
from cysignals.signals cimport sig_on, sig_off
Expand Down Expand Up @@ -2425,6 +2427,54 @@
Traceback (most recent call last):
...
NotImplementedError: pow() with a modulus is not implemented for this ring

Check handling of large exponents (:issue:`40442`)::

sage: P.<x> = PolynomialRing(ZZ, implementation="singular")
sage: x^(2^31-1)
x^2147483647
sage: x^(2^31)
x^2147483648
sage: x^(2^32-1)
x^4294967295
sage: x^(2^32)
x^4294967296
sage: x^(2^63-1)
x^9223372036854775807
sage: x^(2^63)
Traceback (most recent call last):
...
OverflowError: exponent overflow (9223372036854775808)
sage: x^(2^64-1)
Traceback (most recent call last):
...
OverflowError: exponent overflow (18446744056529682436)
sage: x^(2^64)
Traceback (most recent call last):
...
OverflowError: exponent overflow (18446744056529682436)
sage: P(1)^(2^64)
1

sage: P.<x,y> = ZZ[]
sage: y^(2^32-1)
y^4294967295
sage: y^(2^32)
Traceback (most recent call last):
...
OverflowError: exponent overflow (4294967296)
sage: P(1)^(2^32)
1

sage: P.<x,y,z,t> = ZZ[]
sage: y^(2^16-1)
y^65535
sage: y^(2^16)
Traceback (most recent call last):
...
OverflowError: exponent overflow (65536)
sage: P(1)^(2^16) # known bug
...UserWarning: error in Singular ignored: exponent 65536 is too large, max. is 65535...
"""
if mod is not None:
raise NotImplementedError(
Expand All @@ -2451,6 +2501,8 @@
return self._parent._one_element / (self**(-exp))
elif exp == 0:
return self._parent._one_element
elif exp > INT_MAX:
return (self ** INT_MAX) ** (exp // INT_MAX) * self ** (exp % INT_MAX)

cdef ring *_ring = self._parent_ring
cdef poly *_p
Expand Down Expand Up @@ -5738,7 +5790,7 @@

As such we test the computation is interruptible (previously it wasn't)::

sage: alarm(0.5); h = f.resultant(g, x)

Check failure on line 5793 in src/sage/rings/polynomial/multi_polynomial_libsingular.pyx

View workflow job for this annotation

GitHub Actions / Conda (ubuntu, Python 3.11, all)

Timed out (and interrupt failed)

/usr/share/miniconda/envs/sage-dev/lib/python3.11/site-packages/cysignals/signals.cpython-311-x86_64-linux-gnu.so(+0x805c)[0x7f75d501d05c] /usr/share/miniconda/envs/sage-dev/lib/python3.11/site-packages/cysignals/signals.cpython-311-x86_64-linux-gnu.so(+0x8129)[0x7f75d501d129] /usr/share/miniconda/envs/sage-dev/lib/python3.11/site-packages/cysignals/signals.cpython-311-x86_64-linux-gnu.so(+0xb156)[0x7f75d5020156] /lib/x86_64-linux-gnu/libc.so.6(+0x45330)[0x7f75d5645330] /lib/x86_64-linux-gnu/libc.so.6(__lll_lock_wait_private+0x2b)[0x7f75d5698f0b] /lib/x86_64-linux-gnu/libc.so.6(malloc+0x2d0)[0x7f75d56ad920] python3(PyObject_Malloc+0xe4)[0x5630a38a56b4] python3(PyBytes_FromStringAndSize+0x6d)[0x5630a38c7b8d] python3(+0x2baf96)[0x5630a39a1f96] python3(+0x1db40e)[0x5630a38c240e] python3(+0x28a55a)[0x5630a397155a] python3(+0x2bab2b)[0x5630a39a1b2b] python3(+0x21255f)[0x5630a38f955f] python3(PyObject_VectorcallMethod+0x86)[0x5630a38c47a6] python3(+0x2e8222)[0x5630a39cf222] python3(_PyEval_EvalFrameDefault+0x17a0)[0x5630a38cbdc0] python3(_PyFunction_Vectorcall+0x17f)[0x5630a38efa4f] python3(_PyObject_FastCallDictTstate+0xe0)[0x5630a38c2320] python3(_PyObject_Call_Prepend+0x69)[0x5630a38f74c9] python3(+0x2df799)[0x5630a39c6799] python3(_PyObject_MakeTpCall+0x29b)[0x5630a38bd6ab] python3(_PyEval_EvalFrameDefault+0x70a)[0x5630a38cad2a] python3(_PyFunction_Vectorcall+0x17f)[0x5630a38efa4f] python3(+0x20fe99)[0x5630a38f6e99] python3(_PyObject_MakeTpCall+0x2cb)[0x5630a38bd6db] python3(_PyEval_EvalFrameDefault+0x70a)[0x5630a38cad2a] python3(+0x29b0ad)[0x5630a39820ad] python3(PyEval_EvalCode+0x9f)[0x5630a39817ef] python3(+0x2b872a)[0x5630a399f72a] python3(+0x2b43b3)[0x5630a399b3b3] python3(+0x2c9780)[0x5630a39b0780] python3(_PyRun_SimpleFileObject+0x1bc)[0x5630a39b011c] python3(_PyRun_AnyFileObject+0x44)[0x5630a39afef4] python3(Py_RunMain+0x383)[0x5630a39aa643] python3(Py_BytesMain+0x37)[0x5630a3971a17] /lib/x86_64-linux-gnu/libc.so.6(+0x2a1ca)[0x7f75d562a1ca] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x8b)[0x7f75d562a28b] python3(+0x28a8ca)[0x5630a39718ca] ------------------------------------------------------------------------
Traceback (most recent call last):
...
AlarmInterrupt
Expand Down
32 changes: 29 additions & 3 deletions src/sage/rings/polynomial/plural.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ TESTS::
True
"""
from cysignals.memory cimport sig_malloc, sig_free
from libc.limits cimport INT_MAX

from sage.categories.algebras import Algebras
from sage.cpython.string cimport char_to_str
Expand Down Expand Up @@ -1618,10 +1619,12 @@ cdef class NCPolynomial_plural(RingElement):
sage: P = A.g_algebra(relations={y*x:-x*y + z}, order='lex')
sage: P.inject_variables()
Defining x, z, y
sage: (x^2^31) * x^2^31
sage: f = x^2^19; f
x^524288
sage: f*f
Traceback (most recent call last):
...
OverflowError: exponent overflow (2147483648)
OverflowError: exponent overflow (1048576)
"""
# all currently implemented rings are commutative
cdef poly *_p
Expand Down Expand Up @@ -1688,10 +1691,30 @@ cdef class NCPolynomial_plural(RingElement):
sage: P = A.g_algebra(relations={y*x:-x*y + z}, order='lex')
sage: P.inject_variables()
Defining x, z, y
sage: x^(2^20-1)
x^1048575
sage: x^2^20
Traceback (most recent call last):
....
OverflowError: exponent overflow (1048576)
sage: (x+y^2^31)^10
Traceback (most recent call last):
....
OverflowError: exponent overflow (2147483648)
OverflowError: exponent overflow (2147483647)

In the example above, the maximum exponent is `2^{20}-1`,
and in the last example, ``2147483647`` instead of ``2147483648`` appears in the
error message because of an internal implementation detail.
When there are only two variables, the maximum exponent is `2^{32}-1`,
however because of a Singular bug, raising a variable directly to the `2^{32}-1`-th
power is very slow.

sage: A.<x,y> = FreeAlgebra(QQ)
sage: B.<x,y> = A.g_algebra(relations={y*x: -x*y}, order='lex')
sage: (x^65537)^65535
x^4294967295
sage: x^(2^31) # known bug (very slow)
x^2147483648

Check that using third argument raises an error::

Expand All @@ -1714,10 +1737,13 @@ cdef class NCPolynomial_plural(RingElement):
except TypeError:
raise TypeError("non-integral exponents not supported")

# TODO duplication with multi_polynomial_libsingular and sage.structure.element
if exp < 0:
return 1/(self**(-exp))
elif exp == 0:
return (<NCPolynomialRing_plural>self._parent)._one_element
elif exp > INT_MAX:
return (self ** INT_MAX) ** (exp // INT_MAX) * self ** (exp % INT_MAX)

cdef ring *_ring = (<NCPolynomialRing_plural>self._parent)._ring
cdef poly *_p
Expand Down
Loading