Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/libs/singular/ring.pyx
4056 views
1
"""
2
Wrapper for Singular's Rings
3
4
AUTHORS:
5
6
- Martin Albrecht (2009-07): initial implementation
7
8
- Kwankyu Lee (2010-06): added matrix term order support
9
"""
10
#*****************************************************************************
11
# Copyright (C) 2009 Martin Albrecht <[email protected]>
12
#
13
# Distributed under the terms of the GNU General Public License (GPL)
14
# http://www.gnu.org/licenses/
15
#*****************************************************************************
16
17
include "../../ext/stdsage.pxi"
18
19
from sage.libs.gmp.types cimport __mpz_struct
20
from sage.libs.gmp.mpz cimport mpz_init_set_ui, mpz_init_set
21
22
from sage.libs.singular.decl cimport number, lnumber, napoly, ring, currRing
23
from sage.libs.singular.decl cimport rChangeCurrRing, rCopy0, rComplete, rDelete
24
from sage.libs.singular.decl cimport omAlloc0, omStrDup, omAlloc, omAlloc0Bin, sip_sring_bin, rnumber_bin
25
from sage.libs.singular.decl cimport ringorder_dp, ringorder_Dp, ringorder_lp, ringorder_rp, ringorder_ds, ringorder_Ds, ringorder_ls, ringorder_M, ringorder_C, ringorder_wp, ringorder_Wp, ringorder_ws, ringorder_Ws
26
from sage.libs.singular.decl cimport p_Copy
27
28
from sage.rings.integer cimport Integer
29
from sage.rings.integer_ring cimport IntegerRing_class
30
from sage.rings.integer_ring import ZZ
31
from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing
32
from sage.rings.number_field.number_field_base cimport NumberField
33
from sage.rings.rational_field import RationalField
34
from sage.rings.finite_rings.finite_field_base import FiniteField as FiniteField_generic
35
36
from sage.rings.polynomial.term_order import TermOrder
37
from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomial_libsingular, MPolynomialRing_libsingular
38
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
39
40
41
from sage.misc.misc_c import is_64_bit
42
43
44
# mapping str --> SINGULAR representation
45
order_dict = {
46
"dp": ringorder_dp,
47
"Dp": ringorder_Dp,
48
"lp": ringorder_lp,
49
"rp": ringorder_rp,
50
"ds": ringorder_ds,
51
"Ds": ringorder_Ds,
52
"ls": ringorder_ls,
53
"wp": ringorder_wp,
54
"Wp": ringorder_Wp,
55
"ws": ringorder_ws,
56
"Ws": ringorder_Ws,
57
}
58
59
60
#############################################################################
61
cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL:
62
"""
63
Create a new Singular ring over the ``base_ring`` in ``n``
64
variables with the names ``names`` and the term order
65
``term_order``.
66
67
INPUT:
68
69
- ``base_ring`` - a Sage ring
70
71
- ``n`` - the number of variables (> 0)
72
73
- ``names`` - a list of names of length ``n``
74
75
- ``term_order`` - a term ordering
76
77
EXAMPLES::
78
79
sage: P.<x,y,z> = QQ[]
80
sage: P
81
Multivariate Polynomial Ring in x, y, z over Rational Field
82
83
sage: P.term_order()
84
Degree reverse lexicographic term order
85
86
sage: P = PolynomialRing(GF(127),3,names='abc', order='lex')
87
sage: P
88
Multivariate Polynomial Ring in a, b, c over Finite Field of size 127
89
90
sage: P.term_order()
91
Lexicographic term order
92
93
sage: z = QQ['z'].0
94
sage: K.<s> = NumberField(z^2 - 2)
95
sage: P.<x,y> = PolynomialRing(K, 2)
96
97
sage: P.<x,y,z> = ZZ[]; P
98
Multivariate Polynomial Ring in x, y, z over Integer Ring
99
100
sage: P.<x,y,z> = Zmod(2^10)[]; P
101
Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 1024
102
103
sage: P.<x,y,z> = Zmod(3^10)[]; P
104
Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 59049
105
106
sage: P.<x,y,z> = Zmod(2^100)[]; P
107
Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 1267650600228229401496703205376
108
109
sage: P.<x,y,z> = Zmod(2521352)[]; P
110
Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 2521352
111
112
sage: P.<x,y,z> = Zmod(25213521351515232)[]; P
113
Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 25213521351515232
114
"""
115
cdef ring* _ring
116
cdef char **_names
117
cdef char *_name
118
cdef int i,j
119
cdef int nblcks
120
cdef int offset
121
cdef int characteristic
122
cdef int ringtype = 0
123
cdef MPolynomialRing_libsingular k
124
cdef MPolynomial_libsingular minpoly
125
cdef lnumber *nmp
126
cdef int * m
127
128
cdef __mpz_struct* ringflaga
129
cdef unsigned long ringflagb
130
131
is_extension = False
132
133
n = int(n)
134
if n<1:
135
raise ArithmeticError("The number of variables must be at least 1.")
136
137
order = TermOrder(term_order, n)
138
139
_names = <char**>omAlloc0(sizeof(char*)*(len(names)))
140
for i from 0 <= i < n:
141
_name = names[i]
142
_names[i] = omStrDup(_name)
143
144
# from the SINGULAR source code documentation for the rInit function
145
## characteristic --------------------------------------------------
146
## input: 0 ch=0 : Q parameter=NULL ffChar=FALSE float_len (done)
147
## 0 1 : Q(a,...) *names FALSE (done)
148
## 0 -1 : R NULL FALSE 0
149
## 0 -1 : R NULL FALSE prec. >6
150
## 0 -1 : C *names FALSE prec. 0..?
151
## p p : Fp NULL FALSE (done)
152
## p -p : Fp(a) *names FALSE (done)
153
## q q : GF(q=p^n) *names TRUE (todo)
154
155
if base_ring.is_field() and base_ring.is_finite() and base_ring.is_prime_field():
156
if base_ring.characteristic() <= 2147483647:
157
characteristic = base_ring.characteristic()
158
else:
159
raise TypeError, "Characteristic p must be <= 2147483647."
160
161
elif PY_TYPE_CHECK(base_ring, RationalField):
162
characteristic = 0
163
164
elif PY_TYPE_CHECK(base_ring, IntegerRing_class):
165
ringflaga = <__mpz_struct*>omAlloc(sizeof(__mpz_struct))
166
mpz_init_set_ui(ringflaga, 0)
167
characteristic = 0
168
ringtype = 4 # integer ring
169
170
elif PY_TYPE_CHECK(base_ring, FiniteField_generic):
171
if base_ring.characteristic() <= 2147483647:
172
characteristic = -base_ring.characteristic() # note the negative characteristic
173
else:
174
raise TypeError, "characteristic must be <= 2147483647."
175
# TODO: This is lazy, it should only call Singular stuff not MPolynomial stuff
176
try:
177
k = PolynomialRing(base_ring.prime_subfield(), 1, [base_ring.variable_name()], 'lex')
178
except TypeError:
179
raise TypeError, "The multivariate polynomial ring in a single variable %s in lex order over %s is supposed to be of type %s"%(base_ring.variable_name(), base_ring,MPolynomialRing_libsingular)
180
minpoly = base_ring.polynomial()(k.gen())
181
is_extension = True
182
183
elif PY_TYPE_CHECK(base_ring, NumberField) and base_ring.is_absolute():
184
characteristic = 1
185
try:
186
k = PolynomialRing(RationalField(), 1, [base_ring.variable_name()], 'lex')
187
except TypeError:
188
raise TypeError, "The multivariate polynomial ring in a single variable %s in lex order over Rational Field is supposed to be of type %s"%(base_ring.variable_name(), MPolynomialRing_libsingular)
189
minpoly = base_ring.polynomial()(k.gen())
190
is_extension = True
191
192
elif is_IntegerModRing(base_ring):
193
ch = base_ring.characteristic()
194
if ch.is_power_of(2):
195
exponent = ch.nbits() -1
196
if is_64_bit:
197
# it seems Singular uses ints somewhere
198
# internally, cf. #6051 (Sage) and #138 (Singular)
199
if exponent <= 30: ringtype = 1
200
else: ringtype = 3
201
else:
202
if exponent <= 30: ringtype = 1
203
else: ringtype = 3
204
characteristic = exponent
205
ringflaga = <__mpz_struct*>omAlloc(sizeof(__mpz_struct))
206
mpz_init_set_ui(ringflaga, 2)
207
ringflagb = exponent
208
209
elif base_ring.characteristic().is_prime_power() and ch < ZZ(2)**160:
210
F = ch.factor()
211
assert(len(F)==1)
212
213
ringtype = 3
214
ringflaga = <__mpz_struct*>omAlloc(sizeof(__mpz_struct))
215
mpz_init_set(ringflaga, (<Integer>F[0][0]).value)
216
ringflagb = F[0][1]
217
characteristic = F[0][1]
218
219
else:
220
# normal modulus
221
try:
222
characteristic = ch
223
except OverflowError:
224
raise NotImplementedError("Characteristic %d too big."%ch)
225
ringtype = 2
226
ringflaga = <__mpz_struct*>omAlloc(sizeof(__mpz_struct))
227
mpz_init_set_ui(ringflaga, characteristic)
228
ringflagb = 1
229
else:
230
raise NotImplementedError("Base ring is not supported.")
231
232
_ring = <ring*>omAlloc0Bin(sip_sring_bin)
233
if (_ring is NULL):
234
raise ValueError("Failed to allocate Singular ring.")
235
_ring.ch = characteristic
236
_ring.ringtype = ringtype
237
_ring.N = n
238
_ring.names = _names
239
240
if is_extension:
241
rChangeCurrRing(k._ring)
242
_ring.algring = rCopy0(k._ring)
243
rComplete(_ring.algring, 1)
244
_ring.algring.pCompIndex = -1
245
_ring.P = _ring.algring.N
246
_ring.parameter = <char**>omAlloc0(sizeof(char*)*2)
247
_ring.parameter[0] = omStrDup(_ring.algring.names[0])
248
249
nmp = <lnumber*>omAlloc0Bin(rnumber_bin)
250
nmp.z= <napoly*>p_Copy(minpoly._poly, _ring.algring) # fragile?
251
nmp.s=2
252
253
_ring.minpoly=<number*>nmp
254
255
nblcks = len(order.blocks())
256
offset = 0
257
258
_ring.wvhdl = <int **>omAlloc0((nblcks + 2) * sizeof(int *))
259
_ring.order = <int *>omAlloc0((nblcks + 2) * sizeof(int))
260
_ring.block0 = <int *>omAlloc0((nblcks + 2) * sizeof(int))
261
_ring.block1 = <int *>omAlloc0((nblcks + 2) * sizeof(int))
262
263
if order.is_local():
264
_ring.OrdSgn = -1
265
else:
266
_ring.OrdSgn = 1
267
268
for i from 0 <= i < nblcks:
269
s = order[i].singular_str()
270
if s[0] == 'M': # matrix order
271
_ring.order[i] = ringorder_M
272
mtx = order[i].matrix().list()
273
wv = <int *>omAlloc0(len(mtx)*sizeof(int))
274
for j in range(len(mtx)):
275
wv[j] = int(mtx[j])
276
_ring.wvhdl[i] = wv
277
elif s[0] == 'w' or s[0] == 'W': # weighted degree orders
278
_ring.order[i] = order_dict.get(s[:2], ringorder_dp)
279
wts = order[i].weights()
280
wv = <int *>omAlloc0(len(wts)*sizeof(int))
281
for j in range(len(wts)):
282
wv[j] = int(wts[j])
283
_ring.wvhdl[i] = wv
284
else: # ordinary orders
285
_ring.order[i] = order_dict.get(s, ringorder_dp)
286
_ring.block0[i] = offset + 1
287
if len(order[i]) == 0: # may be zero in some cases
288
_ring.block1[i] = offset + n
289
else:
290
_ring.block1[i] = offset + len(order[i])
291
offset = _ring.block1[i]
292
293
# TODO: if we construct a free module don't hardcode! This
294
# position determines whether we break ties at monomials first or
295
# whether we break at indices first!
296
_ring.order[nblcks] = ringorder_C
297
298
if ringtype != 0:
299
_ring.ringflaga = ringflaga
300
_ring.ringflagb = ringflagb
301
302
rComplete(_ring, 1)
303
_ring.ShortOut = 0
304
305
rChangeCurrRing(_ring)
306
307
wrapped_ring = wrap_ring(_ring)
308
if wrapped_ring in ring_refcount_dict:
309
raise ValueError('newly created ring already in dictionary??')
310
ring_refcount_dict[wrapped_ring] = 1
311
return _ring
312
313
314
#############################################################################
315
ring_refcount_dict = {}
316
317
318
cdef class ring_wrapper_Py(object):
319
r"""
320
Python object wrapping the ring pointer.
321
322
This is useful to store ring pointers in Python containers.
323
324
You must not construct instances of this class yourself, use
325
:func:`wrap_ring` instead.
326
327
EXAMPLES::
328
329
sage: from sage.libs.singular.ring import ring_wrapper_Py
330
sage: ring_wrapper_Py
331
<type 'sage.libs.singular.ring.ring_wrapper_Py'>
332
"""
333
334
cdef ring* _ring
335
336
def __cinit__(self):
337
"""
338
The Cython constructor.
339
340
EXAMPLES::
341
342
sage: from sage.libs.singular.ring import ring_wrapper_Py
343
sage: t = ring_wrapper_Py(); t
344
The ring pointer 0x0
345
sage: TestSuite(t).run()
346
"""
347
self._ring = NULL
348
349
def __hash__(self):
350
"""
351
Return a hash value so that instances can be used as dictionary keys.
352
353
OUTPUT:
354
355
Integer.
356
357
EXAMPLES::
358
359
sage: from sage.libs.singular.ring import ring_wrapper_Py
360
sage: t = ring_wrapper_Py()
361
sage: t.__hash__()
362
0
363
"""
364
return <long>(self._ring)
365
366
def __repr__(self):
367
"""
368
Return a string representation.
369
370
OUTPUT:
371
372
String.
373
374
EXAMPLES::
375
376
sage: from sage.libs.singular.ring import ring_wrapper_Py
377
sage: t = ring_wrapper_Py()
378
sage: t
379
The ring pointer 0x0
380
sage: t.__repr__()
381
'The ring pointer 0x0'
382
"""
383
return 'The ring pointer '+hex(self.__hash__())
384
385
def __cmp__(ring_wrapper_Py left, ring_wrapper_Py right):
386
"""
387
Compare ``left`` and ``right`` so that instances can be used as dictionary keys.
388
389
INPUT:
390
391
- ``right`` -- a :class:`ring_wrapper_Py`
392
393
OUTPUT:
394
395
-1, 0, or +1 depending on whether ``left`` and ``right`` are
396
less than, equal, or greather than.
397
398
EXAMPLES::
399
400
sage: from sage.libs.singular.ring import ring_wrapper_Py
401
sage: t = ring_wrapper_Py()
402
sage: t.__cmp__(t)
403
0
404
"""
405
if left._ring < right._ring:
406
return -1
407
if left._ring > right._ring:
408
return +1
409
return 0
410
411
412
cdef wrap_ring(ring* R):
413
"""
414
Wrap a C ring pointer into a Python object.
415
416
INPUT:
417
418
- ``R`` -- a singular ring (a C datastructure).
419
420
OUTPUT:
421
422
A Python object :class:`ring_wrapper_Py` wrapping the C pointer.
423
"""
424
cdef ring_wrapper_Py W = ring_wrapper_Py()
425
W._ring = R
426
return W
427
428
429
cdef ring *singular_ring_reference(ring *existing_ring) except NULL:
430
"""
431
Refcount the ring ``existing_ring``.
432
433
INPUT:
434
435
- ``existing_ring`` -- an existing Singular ring.
436
437
OUTPUT:
438
439
The same ring with its refcount increased. After calling this
440
function `n` times, you need to call :func:`singular_ring_delete`
441
`n+1` times to actually deallocate the ring.
442
443
EXAMPLE::
444
445
sage: import gc
446
sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular
447
sage: from sage.libs.singular.groebner_strategy import GroebnerStrategy
448
sage: from sage.libs.singular.ring import ring_refcount_dict
449
sage: n = len(ring_refcount_dict)
450
sage: prev_rings = set(ring_refcount_dict.keys())
451
sage: P = MPolynomialRing_libsingular(GF(541), 2, ('x', 'y'), TermOrder('degrevlex', 2))
452
sage: ring_ptr = set(ring_refcount_dict.keys()).difference(prev_rings).pop()
453
sage: ring_ptr # random output
454
The ring pointer 0x7f78a646b8d0
455
sage: ring_refcount_dict[ring_ptr]
456
4
457
458
sage: strat = GroebnerStrategy(Ideal([P.gen(0) + P.gen(1)]))
459
sage: ring_refcount_dict[ring_ptr]
460
6
461
462
sage: del strat
463
sage: _ = gc.collect()
464
sage: ring_refcount_dict[ring_ptr]
465
4
466
467
sage: del P
468
sage: _ = gc.collect()
469
sage: ring_ptr in ring_refcount_dict
470
False
471
"""
472
if existing_ring==NULL:
473
raise ValueError('singular_ring_reference(ring*) called with NULL pointer.')
474
cdef object r = wrap_ring(existing_ring)
475
refcount = ring_refcount_dict.pop(r)
476
ring_refcount_dict[r] = refcount+1
477
return existing_ring
478
479
480
#############################################################################
481
cdef void singular_ring_delete(ring *doomed):
482
"""
483
Carefully deallocate the ring, without changing "currRing" (since
484
this method can be called at unpredictable times due to garbage
485
collection).
486
487
TESTS:
488
489
This example caused a segmentation fault with a previous version
490
of this method::
491
492
sage: import gc
493
sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular
494
sage: R1 = MPolynomialRing_libsingular(GF(5), 2, ('x', 'y'), TermOrder('degrevlex', 2))
495
sage: R2 = MPolynomialRing_libsingular(GF(11), 2, ('x', 'y'), TermOrder('degrevlex', 2))
496
sage: R3 = MPolynomialRing_libsingular(GF(13), 2, ('x', 'y'), TermOrder('degrevlex', 2))
497
sage: _ = gc.collect()
498
sage: foo = R1.gen(0)
499
sage: del foo
500
sage: del R1
501
sage: _ = gc.collect()
502
sage: del R2
503
sage: _ = gc.collect()
504
sage: del R3
505
sage: _ = gc.collect()
506
"""
507
if doomed==NULL:
508
print 'singular_ring_delete(ring*) called with NULL pointer.'
509
# this function is typically called in __deallocate__, so we can't raise an exception
510
import traceback
511
traceback.print_stack()
512
513
if not ring_refcount_dict: # arbitrary finalization order when we shut Sage down
514
return
515
516
cdef ring_wrapper_Py r = wrap_ring(doomed)
517
refcount = ring_refcount_dict.pop(r)
518
if refcount > 1:
519
ring_refcount_dict[r] = refcount-1
520
return
521
522
global currRing
523
cdef ring *oldRing = currRing
524
if currRing == doomed:
525
rDelete(doomed)
526
currRing = <ring*>NULL
527
else:
528
rChangeCurrRing(doomed)
529
rDelete(doomed)
530
rChangeCurrRing(oldRing)
531
532
533
534
535
#############################################################################
536
# helpers for debugging
537
538
cpdef poison_currRing(frame, event, arg):
539
"""
540
Poison the ``currRing`` pointer.
541
542
This function sets the ``currRing`` to an illegal value. By
543
setting it as the python debug hook, you can poison the currRing
544
before every evaluated Python command (but not within Cython
545
code).
546
547
INPUT:
548
549
- ``frame``, ``event``, ``arg`` -- the standard arguments for the
550
CPython debugger hook. They are not used.
551
552
OUTPUT:
553
554
Returns itself, which ensures that :func:`poison_currRing` will
555
stay in the debugger hook.
556
557
EXAMPLES::
558
559
sage: previous_trace_func = sys.gettrace() # None if no debugger running
560
sage: from sage.libs.singular.ring import poison_currRing
561
sage: sys.settrace(poison_currRing)
562
sage: sys.gettrace()
563
<built-in function poison_currRing>
564
sage: sys.settrace(previous_trace_func) # switch it off again
565
"""
566
#print "poisoning currRing"
567
global currRing
568
currRing = <ring*>NULL
569
return poison_currRing
570
571
572
cpdef print_currRing():
573
"""
574
Print the ``currRing`` pointer.
575
576
EXAMPLES::
577
578
sage: from sage.libs.singular.ring import print_currRing
579
sage: print_currRing() # random output
580
DEBUG: currRing == 0x7fc6fa6ec480
581
582
sage: from sage.libs.singular.ring import poison_currRing
583
sage: _ = poison_currRing(None, None, None)
584
sage: print_currRing()
585
DEBUG: currRing == 0x0
586
"""
587
cdef size_t addr = <size_t>currRing
588
print "DEBUG: currRing == "+str(hex(addr))
589
590