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