Skip to content

Commit b85e866

Browse files
author
Release Manager
committed
sagemathgh-39075: Allow more rings to be used with libsingular & rework signal detection system Somewhat related: sagemath#33319 Anyway, this allows many more rings to be used with libsingular. Previously it fallback to the expect interface. It seems weird that both Sage and Singular has different types for `GF(5)` and `Zmod(5)`, but okay. ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [x] The title is concise and informative. - [x] The description explains in detail what this PR is about. - [x] I have linked a relevant issue or discussion. - [x] I have created tests covering the changes. - [ ] I have updated the documentation and checked the documentation preview. ### ⌛ Dependencies <!-- List all open PRs that this PR logically depends on. For example, --> <!-- - sagemath#12345: short description why this is a dependency --> <!-- - sagemath#34567: ... --> URL: sagemath#39075 Reported by: user202729 Reviewer(s): Martin Rubey, user202729
2 parents 6423028 + f6c5a14 commit b85e866

File tree

8 files changed

+651
-213
lines changed

8 files changed

+651
-213
lines changed

src/sage/libs/singular/function.pyx

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence_g
9797
from sage.libs.singular.decl cimport *
9898
from sage.libs.singular.option import opt_ctx
9999
from sage.libs.singular.polynomial cimport singular_vector_maximal_component
100-
from sage.libs.singular.singular cimport sa2si, si2sa, si2sa_intvec, si2sa_bigintvec
100+
from sage.libs.singular.singular cimport sa2si, si2sa, si2sa_intvec, si2sa_bigintvec, start_catch_error, check_error
101101
from sage.libs.singular.singular import error_messages
102102

103103
from sage.interfaces.singular import get_docstring
@@ -1450,10 +1450,8 @@ EXAMPLES::
14501450

14511451
cdef inline call_function(SingularFunction self, tuple args, object R, bint signal_handler=True, attributes=None):
14521452
global currRingHdl
1453-
global errorreported
14541453
global currentVoice
14551454
global myynest
1456-
global error_messages
14571455

14581456
cdef ring *si_ring
14591457
if isinstance(R, MPolynomialRing_libsingular):
@@ -1474,29 +1472,28 @@ cdef inline call_function(SingularFunction self, tuple args, object R, bint sign
14741472

14751473
currentVoice = NULL
14761474
myynest = 0
1477-
errorreported = 0
1478-
1479-
while error_messages:
1480-
error_messages.pop()
1475+
start_catch_error()
14811476

14821477
with opt_ctx: # we are preserving the global options state here
14831478
if signal_handler:
1484-
sig_on()
1485-
_res = self.call_handler.handle_call(argument_list, si_ring)
1486-
sig_off()
1479+
try:
1480+
sig_on()
1481+
_res = self.call_handler.handle_call(argument_list, si_ring)
1482+
sig_off()
1483+
finally:
1484+
s = check_error()
14871485
else:
14881486
_res = self.call_handler.handle_call(argument_list, si_ring)
1487+
s = check_error()
14891488

1490-
if myynest:
1491-
myynest = 0
1489+
myynest = 0
14921490

14931491
if currentVoice:
14941492
currentVoice = NULL
14951493

1496-
if errorreported:
1497-
errorreported = 0
1494+
if s:
14981495
raise RuntimeError("error in Singular function call %r:\n%s" %
1499-
(self._name, "\n".join(error_messages)))
1496+
(self._name, "\n".join(s)))
15001497

15011498
res = argument_list.to_python(_res)
15021499

src/sage/libs/singular/ring.pyx

Lines changed: 164 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ AUTHORS:
1919
from sage.cpython.string cimport str_to_bytes, bytes_to_str
2020

2121
from sage.libs.gmp.types cimport __mpz_struct
22-
from sage.libs.gmp.mpz cimport mpz_init_set_ui
22+
from sage.libs.gmp.mpz cimport mpz_init_set
2323

2424
from sage.libs.singular.decl cimport ring, currRing
2525
from sage.libs.singular.decl cimport rChangeCurrRing, rComplete, rDelete, idInit
@@ -31,6 +31,7 @@ from sage.libs.singular.decl cimport n_coeffType
3131
from sage.libs.singular.decl cimport rDefault, GFInfo, ZnmInfo, nInitChar, AlgExtInfo, TransExtInfo
3232

3333

34+
from sage.rings.integer cimport Integer
3435
from sage.rings.integer_ring cimport IntegerRing_class
3536
from sage.rings.integer_ring import ZZ
3637
import sage.rings.abc
@@ -80,7 +81,7 @@ if bytes_to_str(rSimpleOrdStr(ringorder_ip)) == "rp":
8081

8182
#############################################################################
8283
cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL:
83-
"""
84+
r"""
8485
Create a new Singular ring over the ``base_ring`` in ``n``
8586
variables with the names ``names`` and the term order
8687
``term_order``.
@@ -159,17 +160,136 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL:
159160
sage: R.<x,y,z> = F[]
160161
sage: from sage.libs.singular.function import singular_function
161162
sage: sing_print = singular_function('print')
162-
sage: sing_print(R)
163-
'polynomial ring, over a field, global ordering\n// coefficients: ZZ/7(a, b)\n// number of vars : 3\n// block 1 : ordering dp\n// : names x y z\n// block 2 : ordering C'
163+
sage: print(sing_print(R))
164+
polynomial ring, over a field, global ordering
165+
// coefficients: ZZ/7(a, b)
166+
// number of vars : 3
167+
// block 1 : ordering dp
168+
// : names x y z
169+
// block 2 : ordering C
164170
165171
::
166172
167173
sage: F = PolynomialRing(QQ, 's,t').fraction_field()
168174
sage: R.<x,y,z> = F[]
169175
sage: from sage.libs.singular.function import singular_function
170-
sage: sing_print = singular_function('print')
171-
sage: sing_print(R)
172-
'polynomial ring, over a field, global ordering\n// coefficients: QQ(s, t)\n// number of vars : 3\n// block 1 : ordering dp\n// : names x y z\n// block 2 : ordering C'
176+
sage: print(sing_print(R))
177+
polynomial ring, over a field, global ordering
178+
// coefficients: QQ(s, t)
179+
// number of vars : 3
180+
// block 1 : ordering dp
181+
// : names x y z
182+
// block 2 : ordering C
183+
184+
Small primes::
185+
186+
sage: R = PolynomialRing(GF(2), ("a", "b"), implementation="singular"); print(sing_print(R))
187+
polynomial ring, over a field, global ordering
188+
// coefficients: ZZ/2
189+
// number of vars : 2
190+
// block 1 : ordering dp
191+
// : names a b
192+
// block 2 : ordering C
193+
sage: R = PolynomialRing(GF(3), ("a", "b"), implementation="singular"); print(sing_print(R))
194+
polynomial ring, over a field, global ordering
195+
// coefficients: ZZ/3
196+
// number of vars : 2
197+
// block 1 : ordering dp
198+
// : names a b
199+
// block 2 : ordering C
200+
sage: R = PolynomialRing(GF(1000000007), ("a", "b"), implementation="singular"); print(sing_print(R))
201+
polynomial ring, over a field, global ordering
202+
// coefficients: ZZ/1000000007
203+
// number of vars : 2
204+
// block 1 : ordering dp
205+
// : names a b
206+
// block 2 : ordering C
207+
208+
When ``Zmod`` is used, use a different Singular type
209+
(note that the print is wrong, the field in fact doesn't have zero-divisors)::
210+
211+
sage: R = PolynomialRing(Zmod(2), ("a", "b"), implementation="singular"); print(sing_print(R))
212+
polynomial ring, over a ring (with zero-divisors), global ordering
213+
// coefficients: ZZ/(2)
214+
// number of vars : 2
215+
// block 1 : ordering dp
216+
// : names a b
217+
// block 2 : ordering C
218+
sage: R = PolynomialRing(Zmod(3), ("a", "b"), implementation="singular"); print(sing_print(R))
219+
polynomial ring, over a ring (with zero-divisors), global ordering
220+
// coefficients: ZZ/(3)
221+
// number of vars : 2
222+
// block 1 : ordering dp
223+
// : names a b
224+
// block 2 : ordering C
225+
226+
Large prime (note that the print is wrong, the field in fact doesn't have zero-divisors)::
227+
228+
sage: R = PolynomialRing(GF(2^128+51), ("a", "b"), implementation="singular"); print(sing_print(R))
229+
polynomial ring, over a ring (with zero-divisors), global ordering
230+
// coefficients: ZZ/bigint(340282366920938463463374607431768211507)
231+
// number of vars : 2
232+
// block 1 : ordering dp
233+
// : names a b
234+
// block 2 : ordering C
235+
236+
Finite field with large degree (note that if stack size is too small and the exponent is too large
237+
a stack overflow may happen inside libsingular)::
238+
239+
sage: R = PolynomialRing(GF(2^160), ("a", "b"), implementation="singular"); print(sing_print(R))
240+
polynomial ring, over a field, global ordering
241+
// coefficients: ZZ/2[z160]/(z160^160+z160^159+z160^155+z160^154+z160^153+z160^152+z160^151+z160^149+z160^148+z160^147+z160^146+z160^145+z160^144+z160^143+z160^141+z160^139+z160^137+z160^131+z160^129+z160^128+z160^127+z160^126+z160^123+z160^122+z160^121+z160^117+z160^116+z160^115+z160^113+z160^111+z160^110+z160^108+z160^106+z160^102+z160^100+z160^99+z160^97+z160^96+z160^95+z160^94+z160^93+z160^92+z160^91+z160^87+z160^86+z160^82+z160^80+z160^79+z160^78+z160^74+z160^73+z160^72+z160^71+z160^70+z160^67+z160^66+z160^65+z160^62+z160^59+z160^58+z160^57+z160^55+z160^54+z160^53+z160^52+z160^51+z160^49+z160^47+z160^44+z160^40+z160^35+z160^32+z160^30+z160^28+z160^27+z160^26+z160^24+z160^23+z160^21+z160^20+z160^18+z160^16+z160^11+z160^10+z160^8+z160^7+1)
242+
// number of vars : 2
243+
// block 1 : ordering dp
244+
// : names a b
245+
// block 2 : ordering C
246+
247+
Integer modulo small power of 2::
248+
249+
sage: R = PolynomialRing(Zmod(2^32), ("a", "b"), implementation="singular"); print(sing_print(R))
250+
polynomial ring, over a ring (with zero-divisors), global ordering
251+
// coefficients: ZZ/(2^32)
252+
// number of vars : 2
253+
// block 1 : ordering dp
254+
// : names a b
255+
// block 2 : ordering C
256+
257+
Integer modulo large power of 2::
258+
259+
sage: R = PolynomialRing(Zmod(2^1000), ("a", "b"), implementation="singular"); print(sing_print(R))
260+
polynomial ring, over a ring (with zero-divisors), global ordering
261+
// coefficients: ZZ/(bigint(2)^1000)
262+
// number of vars : 2
263+
// block 1 : ordering dp
264+
// : names a b
265+
// block 2 : ordering C
266+
267+
Integer modulo large power of odd prime::
268+
269+
sage: R = PolynomialRing(Zmod(3^300), ("a", "b"), implementation="singular"); print(sing_print(R))
270+
polynomial ring, over a ring (with zero-divisors), global ordering
271+
// coefficients: ZZ/(bigint(3)^300)
272+
// number of vars : 2
273+
// block 1 : ordering dp
274+
// : names a b
275+
// block 2 : ordering C
276+
277+
Integer modulo non-prime::
278+
279+
sage: R = PolynomialRing(Zmod(15^20), ("a", "b"), implementation="singular"); print(sing_print(R))
280+
polynomial ring, over a ring (with zero-divisors), global ordering
281+
// coefficients: ZZ/bigint(332525673007965087890625)
282+
// number of vars : 2
283+
// block 1 : ordering dp
284+
// : names a b
285+
// block 2 : ordering C
286+
287+
Non-prime finite field with large characteristic (not supported, see :issue:`33319`)::
288+
289+
sage: PolynomialRing(GF((2^31+11)^2), ("a", "b"), implementation="singular")
290+
Traceback (most recent call last):
291+
...
292+
TypeError: characteristic must be <= 2147483647.
173293
"""
174294
cdef long cexponent
175295
cdef GFInfo* _param
@@ -182,7 +302,7 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL:
182302
cdef int offset
183303
cdef int nvars
184304
cdef int characteristic
185-
cdef int modbase
305+
cdef Integer ch, modbase
186306
cdef int ringorder_column_pos
187307
cdef int ringorder_column_asc
188308

@@ -377,39 +497,57 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL:
377497
_cf = nInitChar( n_Z, NULL) # integer coefficient ring
378498
_ring = rDefault (_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl)
379499

380-
elif (isinstance(base_ring, FiniteField_generic) and base_ring.is_prime_field()):
381-
if base_ring.characteristic() <= 2147483647:
500+
elif isinstance(base_ring, sage.rings.abc.IntegerModRing):
501+
502+
ch = base_ring.characteristic()
503+
if ch < 2:
504+
raise NotImplementedError(f"polynomials over {base_ring} are not supported in Singular")
505+
506+
isprime = ch.is_prime()
507+
508+
if isprime and ch <= 2147483647 and isinstance(base_ring, FiniteField_generic):
509+
# don't use this branch for e.g. Zmod(5)
382510
characteristic = base_ring.characteristic()
511+
512+
# example for simpler ring creation interface without monomial orderings:
513+
#_ring = rDefault(characteristic, nvars, _names)
514+
515+
_ring = rDefault(characteristic, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl)
516+
383517
else:
384-
raise TypeError("Characteristic p must be <= 2147483647.")
518+
modbase, cexponent = ch.perfect_power()
385519

386-
# example for simpler ring creation interface without monomial orderings:
387-
#_ring = rDefault(characteristic, nvars, _names)
520+
if modbase == 2 and cexponent > 1:
521+
_cf = nInitChar(n_Z2m, <void *>cexponent)
388522

389-
_ring = rDefault(characteristic, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl)
523+
elif modbase.is_prime() and cexponent > 1:
524+
_info.base = <__mpz_struct *>omAlloc(sizeof(__mpz_struct))
525+
mpz_init_set(_info.base, modbase.value)
526+
_info.exp = cexponent
527+
_cf = nInitChar(n_Znm, <void *>&_info)
528+
529+
else:
530+
_info.base = <__mpz_struct *>omAlloc(sizeof(__mpz_struct))
531+
mpz_init_set(_info.base, ch.value)
532+
_info.exp = 1
533+
_cf = nInitChar(n_Zn, <void *>&_info)
534+
_ring = rDefault(_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl)
390535

391536
elif isinstance(base_ring, FiniteField_generic):
392-
if base_ring.characteristic() <= 2147483647:
393-
characteristic = -base_ring.characteristic() # note the negative characteristic
394-
else:
537+
assert not base_ring.is_prime_field() # would have been handled above
538+
if base_ring.characteristic() > 2147483647:
395539
raise TypeError("characteristic must be <= 2147483647.")
396540

397541
# TODO: This is lazy, it should only call Singular stuff not PolynomialRing()
398542
k = PolynomialRing(base_ring.prime_subfield(),
399-
name=base_ring.variable_name(), order='lex', implementation='singular')
543+
name=base_ring.variable_name(), order='lex',
544+
implementation='singular')
400545
minpoly = base_ring.polynomial()(k.gen())
401546

402-
ch = base_ring.characteristic()
403-
F = ch.factor()
404-
assert(len(F)==1)
405-
406-
modbase = F[0][0]
407-
cexponent = F[0][1]
408-
409547
_ext_names = <char**>omAlloc0(sizeof(char*))
410548
_name = str_to_bytes(k._names[0])
411549
_ext_names[0] = omStrDup(_name)
412-
_cfr = rDefault( modbase, 1, _ext_names )
550+
_cfr = rDefault(<int>base_ring.characteristic(), 1, _ext_names)
413551

414552
_cfr.qideal = idInit(1,1)
415553
rComplete(_cfr, 1)
@@ -422,60 +560,6 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL:
422560

423561
_ring = rDefault (_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl)
424562

425-
elif isinstance(base_ring, sage.rings.abc.IntegerModRing):
426-
427-
ch = base_ring.characteristic()
428-
if ch < 2:
429-
raise NotImplementedError(f"polynomials over {base_ring} are not supported in Singular")
430-
431-
isprime = ch.is_prime()
432-
433-
if not isprime and ch.is_power_of(2):
434-
exponent = ch.nbits() -1
435-
cexponent = exponent
436-
437-
if exponent <= 30:
438-
ringtype = n_Z2m
439-
else:
440-
ringtype = n_Znm
441-
442-
if ringtype == n_Znm:
443-
F = ch.factor()
444-
445-
modbase = F[0][0]
446-
cexponent = F[0][1]
447-
448-
_info.base = <__mpz_struct*>omAlloc(sizeof(__mpz_struct))
449-
mpz_init_set_ui(_info.base, modbase)
450-
_info.exp = cexponent
451-
_cf = nInitChar(ringtype, <void *>&_info)
452-
else: # ringtype == n_Z2m
453-
_cf = nInitChar(ringtype, <void *>cexponent)
454-
455-
elif not isprime and ch.is_prime_power() and ch < ZZ(2)**160:
456-
F = ch.factor()
457-
assert(len(F)==1)
458-
459-
modbase = F[0][0]
460-
cexponent = F[0][1]
461-
462-
_info.base = <__mpz_struct*>omAlloc(sizeof(__mpz_struct))
463-
mpz_init_set_ui(_info.base, modbase)
464-
_info.exp = cexponent
465-
_cf = nInitChar( n_Znm, <void *>&_info )
466-
467-
else:
468-
try:
469-
characteristic = ch
470-
except OverflowError:
471-
raise NotImplementedError("Characteristic %d too big." % ch)
472-
473-
_info.base = <__mpz_struct*>omAlloc(sizeof(__mpz_struct))
474-
mpz_init_set_ui(_info.base, characteristic)
475-
_info.exp = 1
476-
_cf = nInitChar( n_Zn, <void *>&_info )
477-
_ring = rDefault(_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl)
478-
479563
else:
480564
raise NotImplementedError(f"polynomials over {base_ring} are not supported in Singular")
481565

src/sage/libs/singular/singular.pxd

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ cdef number *sa2si_NF(object element, ring *_ring) noexcept
5555
# dispatches to all the above.
5656
cdef number *sa2si(Element elem, ring * _ring) noexcept
5757

58+
# ==============
59+
# Error handling
60+
# ==============
61+
62+
cdef int start_catch_error() except -1
63+
cdef object check_error()
64+
5865
# ==============
5966
# Initialisation
6067
# ==============

0 commit comments

Comments
 (0)