Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/interfaces/singular.py
4045 views
1
r"""
2
Interface to Singular
3
4
AUTHORS:
5
6
- David Joyner and William Stein (2005): first version
7
8
- Martin Albrecht (2006-03-05): code so singular.[tab] and x =
9
singular(...), x.[tab] includes all singular commands.
10
11
- Martin Albrecht (2006-03-06): This patch adds the equality symbol to
12
13
will break all further communication with Singular.
14
15
- Martin Albrecht (2006-03-13): added current_ring() and
16
current_ring_name()
17
18
- William Stein (2006-04-10): Fixed problems with ideal constructor
19
20
- Martin Albrecht (2006-05-18): added sage_poly.
21
22
- Simon King (2010-11-23): Reduce the overhead caused by waiting for
23
the Singular prompt by doing garbage collection differently.
24
25
- Simon King (2011-06-06): Make conversion from Singular to Sage more flexible.
26
27
Introduction
28
------------
29
30
This interface is extremely flexible, since it's exactly like
31
typing into the Singular interpreter, and anything that works there
32
should work here.
33
34
The Singular interface will only work if Singular is installed on
35
your computer; this should be the case, since Singular is included
36
with Sage. The interface offers three pieces of functionality:
37
38
39
#. ``singular_console()`` - A function that dumps you
40
into an interactive command-line Singular session.
41
42
#. ``singular(expr, type='def')`` - Creation of a
43
Singular object. This provides a Pythonic interface to Singular.
44
For example, if ``f=singular(10)``, then
45
``f.factorize()`` returns the factorization of
46
`10` computed using Singular.
47
48
#. ``singular.eval(expr)`` - Evaluation of arbitrary
49
Singular expressions, with the result returned as a string.
50
51
Of course, there are polynomial rings and ideals in Sage as well
52
(often based on a C-library interface to Singular). One can convert
53
an object in the Singular interpreter interface to Sage by the
54
method ``sage()``.
55
56
57
Tutorial
58
--------
59
60
EXAMPLES: First we illustrate multivariate polynomial
61
factorization::
62
63
sage: R1 = singular.ring(0, '(x,y)', 'dp')
64
sage: R1
65
// characteristic : 0
66
// number of vars : 2
67
// block 1 : ordering dp
68
// : names x y
69
// block 2 : ordering C
70
sage: f = singular('9x16 - 18x13y2 - 9x12y3 + 9x10y4 - 18x11y2 + 36x8y4 + 18x7y5 - 18x5y6 + 9x6y4 - 18x3y6 - 9x2y7 + 9y8')
71
sage: f
72
9*x^16-18*x^13*y^2-9*x^12*y^3+9*x^10*y^4-18*x^11*y^2+36*x^8*y^4+18*x^7*y^5-18*x^5*y^6+9*x^6*y^4-18*x^3*y^6-9*x^2*y^7+9*y^8
73
sage: f.parent()
74
Singular
75
76
::
77
78
sage: F = f.factorize(); F
79
[1]:
80
_[1]=9
81
_[2]=x^6-2*x^3*y^2-x^2*y^3+y^4
82
_[3]=-x^5+y^2
83
[2]:
84
1,1,2
85
86
::
87
88
sage: F[1]
89
9,
90
x^6-2*x^3*y^2-x^2*y^3+y^4,
91
-x^5+y^2
92
sage: F[1][2]
93
x^6-2*x^3*y^2-x^2*y^3+y^4
94
95
We can convert `f` and each exponent back to Sage objects
96
as well.
97
98
::
99
100
sage: g = f.sage(); g
101
9*x^16 - 18*x^13*y^2 - 9*x^12*y^3 + 9*x^10*y^4 - 18*x^11*y^2 + 36*x^8*y^4 + 18*x^7*y^5 - 18*x^5*y^6 + 9*x^6*y^4 - 18*x^3*y^6 - 9*x^2*y^7 + 9*y^8
102
sage: F[1][2].sage()
103
x^6 - 2*x^3*y^2 - x^2*y^3 + y^4
104
sage: g.parent()
105
Multivariate Polynomial Ring in x, y over Rational Field
106
107
This example illustrates polynomial GCD's::
108
109
sage: R2 = singular.ring(0, '(x,y,z)', 'lp')
110
sage: a = singular.new('3x2*(x+y)')
111
sage: b = singular.new('9x*(y2-x2)')
112
sage: g = a.gcd(b)
113
sage: g
114
x^2+x*y
115
116
This example illustrates computation of a Groebner basis::
117
118
sage: R3 = singular.ring(0, '(a,b,c,d)', 'lp')
119
sage: I = singular.ideal(['a + b + c + d', 'a*b + a*d + b*c + c*d', 'a*b*c + a*b*d + a*c*d + b*c*d', 'a*b*c*d - 1'])
120
sage: I2 = I.groebner()
121
sage: I2
122
c^2*d^6-c^2*d^2-d^4+1,
123
c^3*d^2+c^2*d^3-c-d,
124
b*d^4-b+d^5-d,
125
b*c-b*d^5+c^2*d^4+c*d-d^6-d^2,
126
b^2+2*b*d+d^2,
127
a+b+c+d
128
129
The following example is the same as the one in the Singular - Gap
130
interface documentation::
131
132
sage: R = singular.ring(0, '(x0,x1,x2)', 'lp')
133
sage: I1 = singular.ideal(['x0*x1*x2 -x0^2*x2', 'x0^2*x1*x2-x0*x1^2*x2-x0*x1*x2^2', 'x0*x1-x0*x2-x1*x2'])
134
sage: I2 = I1.groebner()
135
sage: I2
136
x1^2*x2^2,
137
x0*x2^3-x1^2*x2^2+x1*x2^3,
138
x0*x1-x0*x2-x1*x2,
139
x0^2*x2-x0*x2^2-x1*x2^2
140
sage: I2.sage()
141
Ideal (x1^2*x2^2, x0*x2^3 - x1^2*x2^2 + x1*x2^3, x0*x1 - x0*x2 - x1*x2, x0^2*x2 - x0*x2^2 - x1*x2^2) of Multivariate Polynomial Ring in x0, x1, x2 over Rational Field
142
143
144
This example illustrates moving a polynomial from one ring to
145
another. It also illustrates calling a method of an object with an
146
argument.
147
148
::
149
150
sage: R = singular.ring(0, '(x,y,z)', 'dp')
151
sage: f = singular('x3+y3+(x-y)*x2y2+z2')
152
sage: f
153
x^3*y^2-x^2*y^3+x^3+y^3+z^2
154
sage: R1 = singular.ring(0, '(x,y,z)', 'ds')
155
sage: f = R.fetch(f)
156
sage: f
157
z^2+x^3+y^3+x^3*y^2-x^2*y^3
158
159
We can calculate the Milnor number of `f`::
160
161
sage: _=singular.LIB('sing.lib') # assign to _ to suppress printing
162
sage: f.milnor()
163
4
164
165
The Jacobian applied twice yields the Hessian matrix of
166
`f`, with which we can compute.
167
168
::
169
170
sage: H = f.jacob().jacob()
171
sage: H
172
6*x+6*x*y^2-2*y^3,6*x^2*y-6*x*y^2, 0,
173
6*x^2*y-6*x*y^2, 6*y+2*x^3-6*x^2*y,0,
174
0, 0, 2
175
sage: H.sage()
176
[6*x + 6*x*y^2 - 2*y^3 6*x^2*y - 6*x*y^2 0]
177
[ 6*x^2*y - 6*x*y^2 6*y + 2*x^3 - 6*x^2*y 0]
178
[ 0 0 2]
179
sage: H.det() # This is a polynomial in Singular
180
72*x*y+24*x^4-72*x^3*y+72*x*y^3-24*y^4-48*x^4*y^2+64*x^3*y^3-48*x^2*y^4
181
sage: H.det().sage() # This is the corresponding polynomial in Sage
182
72*x*y + 24*x^4 - 72*x^3*y + 72*x*y^3 - 24*y^4 - 48*x^4*y^2 + 64*x^3*y^3 - 48*x^2*y^4
183
184
The 1x1 and 2x2 minors::
185
186
sage: H.minor(1)
187
2,
188
6*y+2*x^3-6*x^2*y,
189
6*x^2*y-6*x*y^2,
190
6*x^2*y-6*x*y^2,
191
6*x+6*x*y^2-2*y^3
192
sage: H.minor(2)
193
12*y+4*x^3-12*x^2*y,
194
12*x^2*y-12*x*y^2,
195
12*x^2*y-12*x*y^2,
196
12*x+12*x*y^2-4*y^3,
197
-36*x*y-12*x^4+36*x^3*y-36*x*y^3+12*y^4+24*x^4*y^2-32*x^3*y^3+24*x^2*y^4
198
199
::
200
201
sage: _=singular.eval('option(redSB)')
202
sage: H.minor(1).groebner()
203
1
204
205
Computing the Genus
206
-------------------
207
208
We compute the projective genus of ideals that define curves over
209
`\QQ`. It is *very important* to load the
210
``normal.lib`` library before calling the
211
``genus`` command, or you'll get an error message.
212
213
EXAMPLE::
214
215
sage: singular.lib('normal.lib')
216
sage: R = singular.ring(0,'(x,y)','dp')
217
sage: i2 = singular.ideal('y9 - x2*(x-1)^9 + x')
218
sage: i2.genus()
219
40
220
221
Note that the genus can be much smaller than the degree::
222
223
sage: i = singular.ideal('y9 - x2*(x-1)^9')
224
sage: i.genus()
225
0
226
227
An Important Concept
228
--------------------
229
230
AUTHORS:
231
232
- Neal Harris
233
234
The following illustrates an important concept: how Sage interacts
235
with the data being used and returned by Singular. Let's compute a
236
Groebner basis for some ideal, using Singular through Sage.
237
238
::
239
240
sage: singular.lib('poly.lib')
241
sage: singular.ring(32003, '(a,b,c,d,e,f)', 'lp')
242
// characteristic : 32003
243
// number of vars : 6
244
// block 1 : ordering lp
245
// : names a b c d e f
246
// block 2 : ordering C
247
sage: I = singular.ideal('cyclic(6)')
248
sage: g = singular('groebner(I)')
249
Traceback (most recent call last):
250
...
251
TypeError: Singular error:
252
...
253
254
We restart everything and try again, but correctly.
255
256
::
257
258
sage: singular.quit()
259
sage: singular.lib('poly.lib'); R = singular.ring(32003, '(a,b,c,d,e,f)', 'lp')
260
sage: I = singular.ideal('cyclic(6)')
261
sage: I.groebner()
262
f^48-2554*f^42-15674*f^36+12326*f^30-12326*f^18+15674*f^12+2554*f^6-1,
263
...
264
265
It's important to understand why the first attempt at computing a
266
basis failed. The line where we gave singular the input
267
'groebner(I)' was useless because Singular has no idea what 'I' is!
268
Although 'I' is an object that we computed with calls to Singular
269
functions, it actually lives in Sage. As a consequence, the name
270
'I' means nothing to Singular. When we called
271
``I.groebner()``, Sage was able to call the groebner
272
function on'I' in Singular, since 'I' actually means something to
273
Sage.
274
275
Long Input
276
----------
277
278
The Singular interface reads in even very long input (using files)
279
in a robust manner, as long as you are creating a new object.
280
281
::
282
283
sage: t = '"%s"'%10^15000 # 15 thousand character string (note that normal Singular input must be at most 10000)
284
sage: a = singular.eval(t)
285
sage: a = singular(t)
286
287
TESTS:
288
289
We test an automatic coercion::
290
291
sage: a = 3*singular('2'); a
292
6
293
sage: type(a)
294
<class 'sage.interfaces.singular.SingularElement'>
295
sage: a = singular('2')*3; a
296
6
297
sage: type(a)
298
<class 'sage.interfaces.singular.SingularElement'>
299
300
Create a ring over GF(9) to check that ``gftables`` has been installed,
301
see ticket #11645::
302
303
sage: singular.eval("ring testgf9 = (9,x),(a,b,c,d,e,f),(M((1,2,3,0)),wp(2,3),lp);")
304
'ring testgf9 = (9,x),(a,b,c,d,e,f),(M((1,2,3,0)),wp(2,3),lp);'
305
"""
306
307
#We could also do these calculations without using the singular
308
#interface (behind the scenes the interface is used by Sage):
309
# sage: x, y = PolynomialRing(RationalField(), 2, names=['x','y']).gens()
310
# sage: C = ProjectivePlaneCurve(y**9 - x**2*(x-1)**9)
311
# sage: C.genus()
312
# 0
313
# sage: C = ProjectivePlaneCurve(y**9 - x**2*(x-1)**9 + x)
314
# sage: C.genus()
315
# 40
316
317
#*****************************************************************************
318
# Copyright (C) 2005 David Joyner and William Stein
319
#
320
# Distributed under the terms of the GNU General Public License (GPL)
321
#
322
# This code is distributed in the hope that it will be useful,
323
# but WITHOUT ANY WARRANTY; without even the implied warranty of
324
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
325
# General Public License for more details.
326
#
327
# The full text of the GPL is available at:
328
#
329
# http://www.gnu.org/licenses/
330
#*****************************************************************************
331
332
import os, re
333
334
from expect import Expect, ExpectElement, FunctionElement, ExpectFunction
335
336
from sage.structure.sequence import Sequence
337
338
from sage.structure.element import RingElement
339
340
import sage.rings.integer
341
342
from sage.misc.misc import get_verbose
343
344
class Singular(Expect):
345
r"""
346
Interface to the Singular interpreter.
347
348
EXAMPLES: A Groebner basis example.
349
350
::
351
352
sage: R = singular.ring(0, '(x0,x1,x2)', 'lp')
353
sage: I = singular.ideal([ 'x0*x1*x2 -x0^2*x2', 'x0^2*x1*x2-x0*x1^2*x2-x0*x1*x2^2', 'x0*x1-x0*x2-x1*x2'])
354
sage: I.groebner()
355
x1^2*x2^2,
356
x0*x2^3-x1^2*x2^2+x1*x2^3,
357
x0*x1-x0*x2-x1*x2,
358
x0^2*x2-x0*x2^2-x1*x2^2
359
360
AUTHORS:
361
362
- David Joyner and William Stein
363
"""
364
def __init__(self, maxread=1000, script_subdirectory=None,
365
logfile=None, server=None,server_tmpdir=None):
366
"""
367
EXAMPLES::
368
369
sage: singular == loads(dumps(singular))
370
True
371
"""
372
prompt = '\n> '
373
Expect.__init__(self,
374
name = 'singular',
375
prompt = prompt,
376
command = "Singular -t --ticks-per-sec 1000", #no tty and fine grained cputime()
377
maxread = maxread,
378
server = server,
379
server_tmpdir = server_tmpdir,
380
script_subdirectory = script_subdirectory,
381
restart_on_ctrlc = True,
382
verbose_start = False,
383
logfile = logfile,
384
eval_using_file_cutoff=100 if os.uname()[0]=="SunOS" else 1000)
385
self.__libs = []
386
self._prompt_wait = prompt
387
self.__to_clear = [] # list of variable names that need to be cleared.
388
389
def _start(self, alt_message=None):
390
"""
391
EXAMPLES::
392
393
sage: s = Singular()
394
sage: s.is_running()
395
False
396
sage: s._start()
397
sage: s.is_running()
398
True
399
sage: s.quit()
400
"""
401
self.__libs = []
402
Expect._start(self, alt_message)
403
# Load some standard libraries.
404
self.lib('general') # assumed loaded by misc/constants.py
405
406
# these options are required by the new coefficient rings
407
# supported by Singular 3-1-0.
408
self.option("redTail")
409
self.option("redThrough")
410
self.option("intStrategy")
411
self._saved_options = self.option('get')
412
413
def __reduce__(self):
414
"""
415
EXAMPLES::
416
417
sage: singular.__reduce__()
418
(<function reduce_load_Singular at 0x...>, ())
419
"""
420
return reduce_load_Singular, ()
421
422
def _equality_symbol(self):
423
"""
424
EXAMPLES::
425
426
sage: singular._equality_symbol()
427
'=='
428
"""
429
return '=='
430
431
def _true_symbol(self):
432
"""
433
EXAMPLES::
434
435
sage: singular._true_symbol()
436
'1'
437
"""
438
return '1'
439
440
def _false_symbol(self):
441
"""
442
EXAMPLES::
443
444
sage: singular._false_symbol()
445
'0'
446
"""
447
return '0'
448
449
def _quit_string(self):
450
"""
451
EXAMPLES::
452
453
sage: singular._quit_string()
454
'quit'
455
"""
456
return 'quit'
457
458
def _read_in_file_command(self, filename):
459
r"""
460
EXAMPLES::
461
462
sage: singular._read_in_file_command('test')
463
'< "test";'
464
465
::
466
467
sage: filename = tmp_filename()
468
sage: f = open(filename, 'w')
469
sage: f.write('int x = 2;\n')
470
sage: f.close()
471
sage: singular.read(filename)
472
sage: singular.get('x')
473
'2'
474
"""
475
return '< "%s";'%filename
476
477
478
def eval(self, x, allow_semicolon=True, strip=True, **kwds):
479
r"""
480
Send the code x to the Singular interpreter and return the output
481
as a string.
482
483
INPUT:
484
485
486
- ``x`` - string (of code)
487
488
- ``allow_semicolon`` - default: False; if False then
489
raise a TypeError if the input line contains a semicolon.
490
491
- ``strip`` - ignored
492
493
494
EXAMPLES::
495
496
sage: singular.eval('2 > 1')
497
'1'
498
sage: singular.eval('2 + 2')
499
'4'
500
501
if the verbosity level is `> 1` comments are also printed
502
and not only returned.
503
504
::
505
506
sage: r = singular.ring(0,'(x,y,z)','dp')
507
sage: i = singular.ideal(['x^2','y^2','z^2'])
508
sage: s = i.std()
509
sage: singular.eval('hilb(%s)'%(s.name()))
510
'// 1 t^0\n// -3 t^2\n// 3 t^4\n// -1 t^6\n\n// 1 t^0\n//
511
3 t^1\n// 3 t^2\n// 1 t^3\n// dimension (affine) = 0\n//
512
degree (affine) = 8'
513
514
::
515
516
sage: set_verbose(1)
517
sage: o = singular.eval('hilb(%s)'%(s.name()))
518
// 1 t^0
519
// -3 t^2
520
// 3 t^4
521
// -1 t^6
522
// 1 t^0
523
// 3 t^1
524
// 3 t^2
525
// 1 t^3
526
// dimension (affine) = 0
527
// degree (affine) = 8
528
529
This is mainly useful if this method is called implicitly. Because
530
then intermediate results, debugging outputs and printed statements
531
are printed
532
533
::
534
535
sage: o = s.hilb()
536
// 1 t^0
537
// -3 t^2
538
// 3 t^4
539
// -1 t^6
540
// 1 t^0
541
// 3 t^1
542
// 3 t^2
543
// 1 t^3
544
// dimension (affine) = 0
545
// degree (affine) = 8
546
// ** right side is not a datum, assignment ignored
547
548
rather than ignored
549
550
::
551
552
sage: set_verbose(0)
553
sage: o = s.hilb()
554
"""
555
# Simon King:
556
# In previous versions, the interface was first synchronised and then
557
# unused variables were killed. This created a considerable overhead.
558
# By trac ticket #10296, killing unused variables is now done inside
559
# singular.set(). Moreover, it is not done by calling a separate _eval_line.
560
# In that way, the time spent by waiting for the singular prompt is reduced.
561
562
# Before #10296, it was possible that garbage collection occured inside
563
# of _eval_line. But collection of the garbage would launch another call
564
# to _eval_line. The result would have been a dead lock, that could only
565
# be avoided by synchronisation. Since garbage collection is now done
566
# without an additional call to _eval_line, synchronisation is not
567
# needed anymore, saving even more waiting time for the prompt.
568
569
# Uncomment the print statements below for low-level debugging of
570
# code that involves the singular interfaces. Everything goes
571
# through here.
572
#print "input: %s"%x
573
x = str(x).rstrip().rstrip(';')
574
x = x.replace("> ",">\t") #don't send a prompt (added by Martin Albrecht)
575
if not allow_semicolon and x.find(";") != -1:
576
raise TypeError, "singular input must not contain any semicolons:\n%s"%x
577
if len(x) == 0 or x[len(x) - 1] != ';':
578
x += ';'
579
580
s = Expect.eval(self, x, **kwds)
581
582
if s.find("error") != -1 or s.find("Segment fault") != -1:
583
raise RuntimeError, 'Singular error:\n%s'%s
584
585
if get_verbose() > 0:
586
ret = []
587
for line in s.splitlines():
588
if line.startswith("//"):
589
print line
590
return s
591
else:
592
return s
593
594
def set(self, type, name, value):
595
"""
596
Set the variable with given name to the given value.
597
598
REMARK:
599
600
If a variable in the Singular interface was previously marked for
601
deletion, the actual deletion is done here, before the new variable
602
is created in Singular.
603
604
EXAMPLES::
605
606
sage: singular.set('int', 'x', '2')
607
sage: singular.get('x')
608
'2'
609
610
We test that an unused variable is only actually deleted if this method
611
is called::
612
613
sage: a = singular(3)
614
sage: n = a.name()
615
sage: del a
616
sage: singular.eval(n)
617
'3'
618
sage: singular.set('int', 'y', '5')
619
sage: singular.eval('defined(%s)'%n)
620
'0'
621
622
"""
623
cmd = ''.join('if(defined(%s)){kill %s;};'%(v,v) for v in self.__to_clear) + '%s %s=%s;'%(type, name, value)
624
self.__to_clear = []
625
try:
626
out = self.eval(cmd)
627
except RuntimeError, msg:
628
raise TypeError, msg
629
630
def get(self, var):
631
"""
632
Get string representation of variable named var.
633
634
EXAMPLES::
635
636
sage: singular.set('int', 'x', '2')
637
sage: singular.get('x')
638
'2'
639
"""
640
return self.eval('print(%s);'%var)
641
642
def clear(self, var):
643
"""
644
Clear the variable named ``var``.
645
646
EXAMPLES::
647
648
sage: singular.set('int', 'x', '2')
649
sage: singular.get('x')
650
'2'
651
sage: singular.clear('x')
652
653
"Clearing the variable" means to allow to free the memory
654
that it uses in the Singular sub-process. However, the
655
actual deletion of the variable is only committed when
656
the next element in the Singular interface is created::
657
658
sage: singular.get('x')
659
'2'
660
sage: a = singular(3)
661
sage: singular.get('x')
662
'`x`'
663
664
"""
665
# We add the variable to the list of vars to clear when we do an eval.
666
# We queue up all the clears and do them at once to avoid synchronizing
667
# the interface at the same time we do garbage collection, which can
668
# lead to subtle problems. This was Willem Jan's ideas, implemented
669
# by William Stein.
670
self.__to_clear.append(var)
671
672
def _create(self, value, type='def'):
673
"""
674
Creates a new variable in the Singular session and returns the name
675
of that variable.
676
677
EXAMPLES::
678
679
sage: singular._create('2', type='int')
680
'sage...'
681
sage: singular.get(_)
682
'2'
683
"""
684
name = self._next_var_name()
685
self.set(type, name, value)
686
return name
687
688
def __call__(self, x, type='def'):
689
"""
690
Create a singular object X with given type determined by the string
691
x. This returns var, where var is built using the Singular
692
statement type var = ... x ... Note that the actual name of var
693
could be anything, and can be recovered using X.name().
694
695
The object X returned can be used like any Sage object, and wraps
696
an object in self. The standard arithmetic operators work. Moreover
697
if foo is a function then X.foo(y,z,...) calls foo(X, y, z, ...)
698
and returns the corresponding object.
699
700
EXAMPLES::
701
702
sage: R = singular.ring(0, '(x0,x1,x2)', 'lp')
703
sage: I = singular.ideal([ 'x0*x1*x2 -x0^2*x2', 'x0^2*x1*x2-x0*x1^2*x2-x0*x1*x2^2', 'x0*x1-x0*x2-x1*x2'])
704
sage: I
705
-x0^2*x2+x0*x1*x2,
706
x0^2*x1*x2-x0*x1^2*x2-x0*x1*x2^2,
707
x0*x1-x0*x2-x1*x2
708
sage: type(I)
709
<class 'sage.interfaces.singular.SingularElement'>
710
sage: I.parent()
711
Singular
712
"""
713
if isinstance(x, SingularElement) and x.parent() is self:
714
return x
715
elif isinstance(x, ExpectElement):
716
return self(x.sage())
717
elif not isinstance(x, ExpectElement) and hasattr(x, '_singular_'):
718
return x._singular_(self)
719
720
# some convenient conversions
721
if type in ("module","list") and isinstance(x,(list,tuple,Sequence)):
722
x = str(x)[1:-1]
723
724
return SingularElement(self, type, x, False)
725
726
def has_coerce_map_from_impl(self, S):
727
# we want to implement this without coercing, since singular has state.
728
if hasattr(S, 'an_element'):
729
if hasattr(S.an_element(), '_singular_'):
730
return True
731
try:
732
self._coerce_(S.an_element())
733
except TypeError:
734
return False
735
return True
736
elif S is int or S is long:
737
return True
738
raise NotImplementedError
739
740
741
def cputime(self, t=None):
742
r"""
743
Returns the amount of CPU time that the Singular session has used.
744
If ``t`` is not None, then it returns the difference
745
between the current CPU time and ``t``.
746
747
EXAMPLES::
748
749
sage: t = singular.cputime()
750
sage: R = singular.ring(0, '(x0,x1,x2)', 'lp')
751
sage: I = singular.ideal([ 'x0*x1*x2 -x0^2*x2', 'x0^2*x1*x2-x0*x1^2*x2-x0*x1*x2^2', 'x0*x1-x0*x2-x1*x2'])
752
sage: gb = I.groebner()
753
sage: singular.cputime(t) #random
754
0.02
755
"""
756
if t:
757
return float(self.eval('timer-(%d)'%(int(1000*t))))/1000.0
758
else:
759
return float(self.eval('timer'))/1000.0
760
761
###################################################################
762
# Singular libraries
763
###################################################################
764
def lib(self, lib, reload=False):
765
"""
766
Load the Singular library named lib.
767
768
Note that if the library was already loaded during this session it
769
is not reloaded unless the optional reload argument is True (the
770
default is False).
771
772
EXAMPLES::
773
774
sage: singular.lib('sing.lib')
775
sage: singular.lib('sing.lib', reload=True)
776
"""
777
if lib[-4:] != ".lib":
778
lib += ".lib"
779
if not reload and lib in self.__libs:
780
return
781
self.eval('LIB "%s"'%lib)
782
self.__libs.append(lib)
783
784
LIB = lib
785
load = lib
786
787
###################################################################
788
# constructors
789
###################################################################
790
def ideal(self, *gens):
791
"""
792
Return the ideal generated by gens.
793
794
INPUT:
795
796
797
- ``gens`` - list or tuple of Singular objects (or
798
objects that can be made into Singular objects via evaluation)
799
800
801
OUTPUT: the Singular ideal generated by the given list of gens
802
803
EXAMPLES: A Groebner basis example done in a different way.
804
805
::
806
807
sage: _ = singular.eval("ring R=0,(x0,x1,x2),lp")
808
sage: i1 = singular.ideal([ 'x0*x1*x2 -x0^2*x2', 'x0^2*x1*x2-x0*x1^2*x2-x0*x1*x2^2', 'x0*x1-x0*x2-x1*x2'])
809
sage: i1
810
-x0^2*x2+x0*x1*x2,
811
x0^2*x1*x2-x0*x1^2*x2-x0*x1*x2^2,
812
x0*x1-x0*x2-x1*x2
813
814
::
815
816
sage: i2 = singular.ideal('groebner(%s);'%i1.name())
817
sage: i2
818
x1^2*x2^2,
819
x0*x2^3-x1^2*x2^2+x1*x2^3,
820
x0*x1-x0*x2-x1*x2,
821
x0^2*x2-x0*x2^2-x1*x2^2
822
"""
823
if isinstance(gens, str):
824
gens = self(gens)
825
826
if isinstance(gens, SingularElement):
827
return self(gens.name(), 'ideal')
828
829
if not isinstance(gens, (list, tuple)):
830
raise TypeError, "gens (=%s) must be a list, tuple, string, or Singular element"%gens
831
832
if len(gens) == 1 and isinstance(gens[0], (list, tuple)):
833
gens = gens[0]
834
gens2 = []
835
for g in gens:
836
if not isinstance(g, SingularElement):
837
gens2.append(self.new(g))
838
else:
839
gens2.append(g)
840
return self(",".join([g.name() for g in gens2]), 'ideal')
841
842
def list(self, x):
843
r"""
844
Creates a list in Singular from a Sage list ``x``.
845
846
EXAMPLES::
847
848
sage: singular.list([1,2])
849
[1]:
850
1
851
[2]:
852
2
853
"""
854
return self(x, 'list')
855
856
def matrix(self, nrows, ncols, entries=None):
857
"""
858
EXAMPLES::
859
860
sage: singular.lib("matrix")
861
sage: R = singular.ring(0, '(x,y,z)', 'dp')
862
sage: A = singular.matrix(3,2,'1,2,3,4,5,6')
863
sage: A
864
1,2,
865
3,4,
866
5,6
867
sage: A.gauss_col()
868
2,-1,
869
1,0,
870
0,1
871
872
AUTHORS:
873
874
- Martin Albrecht (2006-01-14)
875
"""
876
name = self._next_var_name()
877
if entries is None:
878
s = self.eval('matrix %s[%s][%s]'%(name, nrows, ncols))
879
else:
880
s = self.eval('matrix %s[%s][%s] = %s'%(name, nrows, ncols, entries))
881
return SingularElement(self, None, name, True)
882
883
def ring(self, char=0, vars='(x)', order='lp', check=True):
884
r"""
885
Create a Singular ring and makes it the current ring.
886
887
INPUT:
888
889
890
- ``char`` - characteristic of the base ring (see
891
examples below), which must be either 0, prime (!), or one of
892
several special codes (see examples below).
893
894
- ``vars`` - a tuple or string that defines the
895
variable names
896
897
- ``order`` - string - the monomial order (default:
898
'lp')
899
900
- ``check`` - if True, check primality of the
901
characteristic if it is an integer.
902
903
904
OUTPUT: a Singular ring
905
906
.. note::
907
908
This function is *not* identical to calling the Singular
909
``ring`` function. In particular, it also attempts to
910
"kill" the variable names, so they can actually be used
911
without getting errors, and it sets printing of elements
912
for this range to short (i.e., with \*'s and carets).
913
914
EXAMPLES: We first declare `\QQ[x,y,z]` with degree reverse
915
lexicographic ordering.
916
917
::
918
919
sage: R = singular.ring(0, '(x,y,z)', 'dp')
920
sage: R
921
// characteristic : 0
922
// number of vars : 3
923
// block 1 : ordering dp
924
// : names x y z
925
// block 2 : ordering C
926
927
::
928
929
sage: R1 = singular.ring(32003, '(x,y,z)', 'dp')
930
sage: R2 = singular.ring(32003, '(a,b,c,d)', 'lp')
931
932
This is a ring in variables named x(1) through x(10) over the
933
finite field of order `7`::
934
935
sage: R3 = singular.ring(7, '(x(1..10))', 'ds')
936
937
This is a polynomial ring over the transcendental extension
938
`\QQ(a)` of `\QQ`::
939
940
sage: R4 = singular.ring('(0,a)', '(mu,nu)', 'lp')
941
942
This is a ring over the field of single-precision floats::
943
944
sage: R5 = singular.ring('real', '(a,b)', 'lp')
945
946
This is over 50-digit floats::
947
948
sage: R6 = singular.ring('(real,50)', '(a,b)', 'lp')
949
sage: R7 = singular.ring('(complex,50,i)', '(a,b)', 'lp')
950
951
To use a ring that you've defined, use the set_ring() method on
952
the ring. This sets the ring to be the "current ring". For
953
example,
954
955
::
956
957
sage: R = singular.ring(7, '(a,b)', 'ds')
958
sage: S = singular.ring('real', '(a,b)', 'lp')
959
sage: singular.new('10*a')
960
1.000e+01*a
961
sage: R.set_ring()
962
sage: singular.new('10*a')
963
3*a
964
"""
965
if len(vars) > 2:
966
s = '; '.join(['if(defined(%s)>0){kill %s;};'%(x,x)
967
for x in vars[1:-1].split(',')])
968
self.eval(s)
969
970
if check and isinstance(char, (int, long, sage.rings.integer.Integer)):
971
if char != 0:
972
n = sage.rings.integer.Integer(char)
973
if not n.is_prime():
974
raise ValueError, "the characteristic must be 0 or prime"
975
R = self('%s,%s,%s'%(char, vars, order), 'ring')
976
self.eval('short=0') # make output include *'s for multiplication for *THIS* ring.
977
return R
978
979
def string(self, x):
980
"""
981
Creates a Singular string from a Sage string. Note that the Sage
982
string has to be "double-quoted".
983
984
EXAMPLES::
985
986
sage: singular.string('"Sage"')
987
Sage
988
"""
989
return self(x, 'string')
990
991
def set_ring(self, R):
992
"""
993
Sets the current Singular ring to R.
994
995
EXAMPLES::
996
997
sage: R = singular.ring(7, '(a,b)', 'ds')
998
sage: S = singular.ring('real', '(a,b)', 'lp')
999
sage: singular.current_ring()
1000
// characteristic : 0 (real)
1001
// number of vars : 2
1002
// block 1 : ordering lp
1003
// : names a b
1004
// block 2 : ordering C
1005
sage: singular.set_ring(R)
1006
sage: singular.current_ring()
1007
// characteristic : 7
1008
// number of vars : 2
1009
// block 1 : ordering ds
1010
// : names a b
1011
// block 2 : ordering C
1012
"""
1013
if not isinstance(R, SingularElement):
1014
raise TypeError, "R must be a singular ring"
1015
self.eval("setring %s; short=0"%R.name(), allow_semicolon=True)
1016
1017
setring = set_ring
1018
1019
def current_ring_name(self):
1020
"""
1021
Returns the Singular name of the currently active ring in
1022
Singular.
1023
1024
OUTPUT: currently active ring's name
1025
1026
EXAMPLES::
1027
1028
sage: r = PolynomialRing(GF(127),3,'xyz')
1029
sage: r._singular_().name() == singular.current_ring_name()
1030
True
1031
"""
1032
ringlist = self.eval("listvar(ring)").splitlines()
1033
p = re.compile("// ([a-zA-Z0-9_]*).*\[.*\].*\*.*") #do this in constructor?
1034
for line in ringlist:
1035
m = p.match(line)
1036
if m:
1037
return m.group(int(1))
1038
return None
1039
1040
def current_ring(self):
1041
"""
1042
Returns the current ring of the running Singular session.
1043
1044
EXAMPLES::
1045
1046
sage: r = PolynomialRing(GF(127),3,'xyz', order='invlex')
1047
sage: r._singular_()
1048
// characteristic : 127
1049
// number of vars : 3
1050
// block 1 : ordering rp
1051
// : names x y z
1052
// block 2 : ordering C
1053
sage: singular.current_ring()
1054
// characteristic : 127
1055
// number of vars : 3
1056
// block 1 : ordering rp
1057
// : names x y z
1058
// block 2 : ordering C
1059
"""
1060
name = self.current_ring_name()
1061
if name:
1062
return self(name)
1063
else:
1064
return None
1065
1066
def trait_names(self):
1067
"""
1068
Return a list of all Singular commands.
1069
1070
EXAMPLES::
1071
1072
sage: singular.trait_names()
1073
['exteriorPower',
1074
...
1075
'stdfglm']
1076
"""
1077
p = re.compile("// *([a-z0-9A-Z_]*).*") #compiles regular expression
1078
proclist = self.eval("listvar(proc)").splitlines()
1079
return [p.match(line).group(int(1)) for line in proclist]
1080
1081
def console(self):
1082
"""
1083
EXAMPLES::
1084
1085
sage: singular_console() #not tested
1086
SINGULAR / Development
1087
A Computer Algebra System for Polynomial Computations / version 3-0-4
1088
0<
1089
by: G.-M. Greuel, G. Pfister, H. Schoenemann \ Nov 2007
1090
FB Mathematik der Universitaet, D-67653 Kaiserslautern \
1091
"""
1092
singular_console()
1093
1094
def version(self):
1095
"""
1096
EXAMPLES:
1097
"""
1098
return singular_version()
1099
1100
def _function_class(self):
1101
"""
1102
EXAMPLES::
1103
1104
sage: singular._function_class()
1105
<class 'sage.interfaces.singular.SingularFunction'>
1106
"""
1107
return SingularFunction
1108
1109
def _function_element_class(self):
1110
"""
1111
EXAMPLES::
1112
1113
sage: singular._function_element_class()
1114
<class 'sage.interfaces.singular.SingularFunctionElement'>
1115
"""
1116
return SingularFunctionElement
1117
1118
def option(self, cmd=None, val=None):
1119
"""
1120
Access to Singular's options as follows:
1121
1122
Syntax: option() Returns a string of all defined options.
1123
1124
Syntax: option( 'option_name' ) Sets an option. Note to disable an
1125
option, use the prefix no.
1126
1127
Syntax: option( 'get' ) Returns an intvec of the state of all
1128
options.
1129
1130
Syntax: option( 'set', intvec_expression ) Restores the state of
1131
all options from an intvec (produced by option('get')).
1132
1133
EXAMPLES::
1134
1135
sage: singular.option()
1136
//options: redefine loadLib usage prompt
1137
sage: singular.option('get')
1138
0,
1139
10321
1140
sage: old_options = _
1141
sage: singular.option('noredefine')
1142
sage: singular.option()
1143
//options: loadLib usage prompt
1144
sage: singular.option('set', old_options)
1145
sage: singular.option('get')
1146
0,
1147
10321
1148
"""
1149
if cmd is None:
1150
return SingularFunction(self,"option")()
1151
elif cmd == "get":
1152
#return SingularFunction(self,"option")("\"get\"")
1153
return self(self.eval("option(get)"),"intvec")
1154
elif cmd == "set":
1155
if not isinstance(val,SingularElement):
1156
raise TypeError, "singular.option('set') needs SingularElement as second parameter"
1157
#SingularFunction(self,"option")("\"set\"",val)
1158
self.eval("option(set,%s)"%val.name())
1159
else:
1160
SingularFunction(self,"option")("\""+str(cmd)+"\"")
1161
1162
def _keyboard_interrupt(self):
1163
print "Interrupting %s..."%self
1164
try:
1165
self._expect.sendline(chr(4))
1166
except pexpect.ExceptionPexpect, msg:
1167
raise pexcept.ExceptionPexpect("THIS IS A BUG -- PLEASE REPORT. This should never happen.\n" + msg)
1168
self._start()
1169
raise KeyboardInterrupt, "Restarting %s (WARNING: all variables defined in previous session are now invalid)"%self
1170
1171
class SingularElement(ExpectElement):
1172
def __init__(self, parent, type, value, is_name=False):
1173
"""
1174
EXAMPLES::
1175
1176
sage: a = singular(2)
1177
sage: loads(dumps(a))
1178
(invalid object -- defined in terms of closed session)
1179
"""
1180
RingElement.__init__(self, parent)
1181
if parent is None: return
1182
if not is_name:
1183
try:
1184
self._name = parent._create( value, type)
1185
except (RuntimeError, TypeError, KeyboardInterrupt), x:
1186
self._session_number = -1
1187
raise TypeError, x
1188
else:
1189
self._name = value
1190
self._session_number = parent._session_number
1191
1192
def __repr__(self):
1193
r"""
1194
Return string representation of ``self``.
1195
1196
EXAMPLE::
1197
1198
sage: r = singular.ring(0,'(x,y)','dp')
1199
sage: singular(0)
1200
0
1201
sage: singular('x') # indirect doctest
1202
x
1203
sage: singular.matrix(2,2)
1204
0,0,
1205
0,0
1206
sage: singular.matrix(2,2,"(25/47*x^2*y^4 + 63/127*x + 27)^3,y,0,1")
1207
15625/103823*x^6*y.., y,
1208
0, 1
1209
1210
Note that the output is truncated
1211
1212
::
1213
1214
sage: M= singular.matrix(2,2,"(25/47*x^2*y^4 + 63/127*x + 27)^3,y,0,1")
1215
sage: M.rename('T')
1216
sage: M
1217
T[1,1],y,
1218
0, 1
1219
1220
if ``self`` has a custom name, it is used to print the
1221
matrix, rather than abbreviating its contents
1222
"""
1223
try:
1224
self._check_valid()
1225
except ValueError:
1226
return '(invalid object -- defined in terms of closed session)'
1227
try:
1228
if self._get_using_file:
1229
s = self.parent().get_using_file(self._name)
1230
except AttributeError:
1231
s = self.parent().get(self._name)
1232
if s.__contains__(self._name):
1233
if hasattr(self, '__custom_name'):
1234
s = s.replace(self._name, self.__dict__['__custom_name'])
1235
elif self.type() == 'matrix':
1236
s = self.parent().eval('pmat(%s,20)'%(self.name()))
1237
return s
1238
1239
def __copy__(self):
1240
r"""
1241
Returns a copy of ``self``.
1242
1243
EXAMPLES::
1244
1245
sage: R=singular.ring(0,'(x,y)','dp')
1246
sage: M=singular.matrix(3,3,'0,0,-x, 0,y,0, x*y,0,0')
1247
sage: N=copy(M)
1248
sage: N[1,1]=singular('x+y')
1249
sage: N
1250
x+y,0,-x,
1251
0, y,0,
1252
x*y,0,0
1253
sage: M
1254
0, 0,-x,
1255
0, y,0,
1256
x*y,0,0
1257
sage: L=R.ringlist()
1258
sage: L[4]=singular.ideal('x**2-5')
1259
sage: Q=L.ring()
1260
sage: otherR=singular.ring(5,'(x)','dp')
1261
sage: cpQ=copy(Q)
1262
sage: cpQ.set_ring()
1263
sage: cpQ
1264
// characteristic : 0
1265
// number of vars : 2
1266
// block 1 : ordering dp
1267
// : names x y
1268
// block 2 : ordering C
1269
// quotient ring from ideal
1270
_[1]=x^2-5
1271
sage: R.fetch(M)
1272
0, 0,-x,
1273
0, y,0,
1274
x*y,0,0
1275
"""
1276
if (self.type()=='ring') or (self.type()=='qring'):
1277
# Problem: singular has no clean method to produce
1278
# a copy of a ring/qring. We use ringlist, but this
1279
# is only possible if we make self the active ring,
1280
# use ringlist, and switch back to the previous
1281
# base ring.
1282
br=self.parent().current_ring()
1283
self.set_ring()
1284
OUT = (self.ringlist()).ring()
1285
br.set_ring()
1286
return OUT
1287
else:
1288
return self.parent()(self.name())
1289
1290
def __len__(self):
1291
"""
1292
Returns the size of this Singular element.
1293
1294
EXAMPLES::
1295
1296
sage: R = singular.ring(0, '(x,y,z)', 'dp')
1297
sage: A = singular.matrix(2,2)
1298
sage: len(A)
1299
4
1300
"""
1301
return int(self.size())
1302
1303
def __reduce__(self):
1304
"""
1305
Note that the result of the returned reduce_load is an invalid
1306
Singular object.
1307
1308
EXAMPLES::
1309
1310
sage: singular(2).__reduce__()
1311
(<function reduce_load at 0x...>, ())
1312
"""
1313
return reduce_load, () # default is an invalid object
1314
1315
def __setitem__(self, n, value):
1316
"""
1317
Set the n-th element of self to x.
1318
1319
INPUT:
1320
1321
1322
- ``n`` - an integer *or* a 2-tuple (for setting
1323
matrix elements)
1324
1325
- ``value`` - anything (is coerced to a Singular
1326
object if it is not one already)
1327
1328
1329
OUTPUT: Changes elements of self.
1330
1331
EXAMPLES::
1332
1333
sage: R = singular.ring(0, '(x,y,z)', 'dp')
1334
sage: A = singular.matrix(2,2)
1335
sage: A
1336
0,0,
1337
0,0
1338
sage: A[1,1] = 5
1339
sage: A
1340
5,0,
1341
0,0
1342
sage: A[1,2] = '5*x + y + z3'
1343
sage: A
1344
5,z^3+5*x+y,
1345
0,0
1346
"""
1347
P = self.parent()
1348
if not isinstance(value, SingularElement):
1349
value = P(value)
1350
if isinstance(n, tuple):
1351
if len(n) != 2:
1352
raise ValueError, "If n (=%s) is a tuple, it must be a 2-tuple"%n
1353
x, y = n
1354
P.eval('%s[%s,%s] = %s'%(self.name(), x, y, value.name()))
1355
else:
1356
P.eval('%s[%s] = %s'%(self.name(), n, value.name()))
1357
1358
def __nonzero__(self):
1359
"""
1360
Returns True if this Singular element is not zero.
1361
1362
EXAMPLES::
1363
1364
sage: singular(0).__nonzero__()
1365
False
1366
sage: singular(1).__nonzero__()
1367
True
1368
"""
1369
P = self.parent()
1370
return P.eval('%s == 0'%self.name()) == '0'
1371
1372
def sage_polystring(self):
1373
r"""
1374
If this Singular element is a polynomial, return a string
1375
representation of this polynomial that is suitable for evaluation
1376
in Python. Thus \* is used for multiplication and \*\* for
1377
exponentiation. This function is primarily used internally.
1378
1379
The short=0 option *must* be set for the parent ring or this
1380
function will not work as expected. This option is set by default
1381
for rings created using ``singular.ring`` or set using
1382
``ring_name.set_ring()``.
1383
1384
EXAMPLES::
1385
1386
sage: R = singular.ring(0,'(x,y)')
1387
sage: f = singular('x^3 + 3*y^11 + 5')
1388
sage: f
1389
x^3+3*y^11+5
1390
sage: f.sage_polystring()
1391
'x**3+3*y**11+5'
1392
"""
1393
return str(self).replace('^','**')
1394
1395
def sage_global_ring(self):
1396
"""
1397
Return the current basering in Singular as a polynomial ring or quotient ring.
1398
1399
EXAMPLE::
1400
1401
sage: singular.eval('ring r1 = (9,x),(a,b,c,d,e,f),(M((1,2,3,0)),wp(2,3),lp)')
1402
'ring r1 = (9,x),(a,b,c,d,e,f),(M((1,2,3,0)),wp(2,3),lp);'
1403
sage: R = singular('r1').sage_global_ring()
1404
sage: R
1405
Multivariate Polynomial Ring in a, b, c, d, e, f over Finite Field in x of size 3^2
1406
sage: R.term_order()
1407
Block term order with blocks:
1408
(Matrix term order with matrix
1409
[1 2]
1410
[3 0],
1411
Weighted degree reverse lexicographic term order with weights (2, 3),
1412
Lexicographic term order of length 2)
1413
1414
::
1415
1416
sage: singular.eval('ring r2 = (0,x),(a,b,c),dp')
1417
'ring r2 = (0,x),(a,b,c),dp;'
1418
sage: singular('r2').sage_global_ring()
1419
Multivariate Polynomial Ring in a, b, c over Fraction Field of Univariate Polynomial Ring in x over Rational Field
1420
1421
::
1422
1423
sage: singular.eval('ring r3 = (3,z),(a,b,c),dp')
1424
'ring r3 = (3,z),(a,b,c),dp;'
1425
sage: singular.eval('minpoly = 1+z+z2+z3+z4')
1426
'minpoly = 1+z+z2+z3+z4;'
1427
sage: singular('r3').sage_global_ring()
1428
Multivariate Polynomial Ring in a, b, c over Univariate Quotient Polynomial Ring in z over Finite Field of size 3 with modulus z^4 + z^3 + z^2 + z + 1
1429
1430
Real and complex fields in both Singular and Sage are defined with a precision.
1431
The precision in Singular is given in terms of digits, but in Sage it is given
1432
in terms of bits. So, the digit precision is internally converted to a reasonable
1433
bit precision::
1434
1435
sage: singular.eval('ring r4 = (real,20),(a,b,c),dp')
1436
'ring r4 = (real,20),(a,b,c),dp;'
1437
sage: singular('r4').sage_global_ring()
1438
Multivariate Polynomial Ring in a, b, c over Real Field with 70 bits of precision
1439
1440
The case of complex coefficients is not fully supported, yet, since
1441
the generator of a complex field in Sage is always called "I"::
1442
1443
sage: singular.eval('ring r5 = (complex,15,j),(a,b,c),dp')
1444
'ring r5 = (complex,15,j),(a,b,c),dp;'
1445
sage: R = singular('r5').sage_global_ring(); R
1446
Multivariate Polynomial Ring in a, b, c over Complex Field with 54 bits of precision
1447
sage: R.base_ring()('j')
1448
Traceback (most recent call last):
1449
...
1450
NameError: name 'j' is not defined
1451
sage: R.base_ring()('I')
1452
1.00000000000000*I
1453
1454
In our last example, the base ring is a quotient ring::
1455
1456
sage: singular.eval('ring r6 = (9,a), (x,y,z),lp')
1457
'ring r6 = (9,a), (x,y,z),lp;'
1458
sage: Q = singular('std(ideal(x^2,x+y^2+z^3))', type='qring')
1459
sage: Q.sage_global_ring()
1460
Quotient of Multivariate Polynomial Ring in x, y, z over Finite Field in a of size 3^2 by the ideal (y^4 - y^2*z^3 + z^6, x + y^2 + z^3)
1461
1462
AUTHOR:
1463
1464
- Simon King (2011-06-06)
1465
1466
"""
1467
# extract the ring of coefficients
1468
singular = self.parent()
1469
charstr = singular.eval('charstr(basering)').split(',',1)
1470
from sage.all import ZZ
1471
is_extension = len(charstr)==2
1472
if charstr[0]=='integer':
1473
br = ZZ
1474
is_extension = False
1475
elif charstr[0]=='0':
1476
from sage.all import QQ
1477
br = QQ
1478
elif charstr[0]=='real':
1479
from sage.all import RealField, ceil, log
1480
prec = singular.eval('ringlist(basering)[1][2][1]')
1481
br = RealField(ceil((ZZ(prec)+1)/log(2,10)))
1482
is_extension = False
1483
elif charstr[0]=='complex':
1484
from sage.all import ComplexField, ceil, log
1485
prec = singular.eval('ringlist(basering)[1][2][1]')
1486
I = singular.eval('ringlist(basering)[1][3]')
1487
br = ComplexField(ceil((ZZ(prec)+1)/log(2,10)))
1488
is_extension = False
1489
else:
1490
# it ought to be a finite field
1491
q = ZZ(charstr[0])
1492
from sage.all import GF
1493
if q.is_prime():
1494
br = GF(q)
1495
else:
1496
br = GF(q,charstr[1])
1497
# Singular has no extension of a non-prime field
1498
is_extension = False
1499
1500
# We have the base ring of the base ring. But is it
1501
# an extension?
1502
if is_extension:
1503
minpoly = singular.eval('minpoly')
1504
if minpoly == '0':
1505
from sage.all import Frac
1506
BR = Frac(br[charstr[1]])
1507
else:
1508
is_short = singular.eval('short')
1509
if is_short!='0':
1510
singular.eval('short=0')
1511
minpoly = ZZ[charstr[1]](singular.eval('minpoly'))
1512
singular.eval('short=%s'%is_short)
1513
else:
1514
minpoly = ZZ[charstr[1]](minpoly)
1515
BR = br.extension(minpoly)
1516
else:
1517
BR = br
1518
1519
# Now, we form the polynomial ring over BR with the given variables,
1520
# using Singular's term order
1521
from sage.rings.polynomial.term_order import termorder_from_singular
1522
from sage.all import PolynomialRing
1523
if singular.eval('typeof(basering)')=='ring':
1524
return PolynomialRing(BR, names=singular.eval('varstr(basering)'), order=termorder_from_singular(singular))
1525
P = PolynomialRing(BR, names=singular.eval('varstr(basering)'), order=termorder_from_singular(singular))
1526
return P.quotient(singular('ringlist(basering)[4]')._sage_(P), names=singular.eval('varstr(basering)'))
1527
1528
def sage_poly(self, R=None, kcache=None):
1529
"""
1530
Returns a Sage polynomial in the ring r matching the provided poly
1531
which is a singular polynomial.
1532
1533
INPUT:
1534
1535
1536
- ``R`` - (default: None); an optional polynomial ring.
1537
If it is provided, then you have to make sure that it
1538
matches the current singular ring as, e.g., returned by
1539
singular.current_ring(). By default, the output of
1540
:meth:`sage_global_ring` is used.
1541
1542
- ``kcache`` - (default: None); an optional dictionary
1543
for faster finite field lookups, this is mainly useful for finite
1544
extension fields
1545
1546
1547
OUTPUT: MPolynomial
1548
1549
EXAMPLES::
1550
1551
sage: R = PolynomialRing(GF(2^8,'a'),2,'xy')
1552
sage: f=R('a^20*x^2*y+a^10+x')
1553
sage: f._singular_().sage_poly(R)==f
1554
True
1555
sage: R = PolynomialRing(GF(2^8,'a'),1,'x')
1556
sage: f=R('a^20*x^3+x^2+a^10')
1557
sage: f._singular_().sage_poly(R)==f
1558
True
1559
1560
::
1561
1562
sage: P.<x,y> = PolynomialRing(QQ, 2)
1563
sage: f = x*y**3 - 1/9 * x + 1; f
1564
x*y^3 - 1/9*x + 1
1565
sage: singular(f)
1566
x*y^3-1/9*x+1
1567
sage: P(singular(f))
1568
x*y^3 - 1/9*x + 1
1569
1570
TESTS::
1571
1572
sage: singular.eval('ring r = (3,z),(a,b,c),dp')
1573
'ring r = (3,z),(a,b,c),dp;'
1574
sage: singular.eval('minpoly = 1+z+z2+z3+z4')
1575
'minpoly = 1+z+z2+z3+z4;'
1576
sage: p = singular('z^4*a^3+z^2*a*b*c')
1577
sage: p.sage_poly()
1578
(2*z^3 + 2*z^2 + 2*z + 2)*a^3 + z^2*a*b*c
1579
sage: singular('z^4')
1580
(-z3-z2-z-1)
1581
1582
AUTHORS:
1583
1584
- Martin Albrecht (2006-05-18)
1585
- Simon King (2011-06-06): Deal with Singular's short polynomial representation,
1586
automatic construction of a polynomial ring, if it is not explicitly given.
1587
1588
.. note::
1589
1590
For very simple polynomials
1591
``eval(SingularElement.sage_polystring())`` is faster than
1592
SingularElement.sage_poly(R), maybe we should detect the
1593
crossover point (in dependence of the string length) and
1594
choose an appropriate conversion strategy
1595
"""
1596
# TODO: Refactor imports to move this to the top
1597
from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict
1598
from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular
1599
from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict
1600
from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
1601
from sage.rings.polynomial.polydict import PolyDict,ETuple
1602
from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular
1603
from sage.rings.quotient_ring import QuotientRing_generic
1604
from sage.rings.quotient_ring_element import QuotientRingElement
1605
1606
ring_is_fine = False
1607
if R is None:
1608
ring_is_fine = True
1609
R = self.sage_global_ring()
1610
1611
sage_repr = {}
1612
k = R.base_ring()
1613
1614
variable_str = "*".join(R.variable_names())
1615
1616
# This returns a string which looks like a list where the first
1617
# half of the list is filled with monomials occurring in the
1618
# Singular polynomial and the second half filled with the matching
1619
# coefficients.
1620
#
1621
# Our strategy is to split the monomials at "*" to get the powers
1622
# in the single variables and then to split the result to get
1623
# actual exponent.
1624
#
1625
# So e.g. ['x^3*y^3','a'] get's split to
1626
# [[['x','3'],['y','3']],'a']. We may do this quickly,
1627
# as we know what to expect.
1628
1629
is_short = self.parent().eval('short')
1630
if is_short!='0':
1631
self.parent().eval('short=0')
1632
if isinstance(R, MPolynomialRing_libsingular):
1633
out = R(self)
1634
self.parent().eval('short=%s'%is_short)
1635
return out
1636
singular_poly_list = self.parent().eval("string(coef(%s,%s))"%(\
1637
self.name(),variable_str)).split(",")
1638
self.parent().eval('short=%s'%is_short)
1639
else:
1640
if isinstance(R, MPolynomialRing_libsingular):
1641
return R(self)
1642
singular_poly_list = self.parent().eval("string(coef(%s,%s))"%(\
1643
self.name(),variable_str)).split(",")
1644
1645
if singular_poly_list == ['1','0'] :
1646
return R(0)
1647
1648
coeff_start = int(len(singular_poly_list)/2)
1649
1650
if isinstance(R,(MPolynomialRing_polydict,QuotientRing_generic)) and (ring_is_fine or can_convert_to_singular(R)):
1651
# we need to lookup the index of a given variable represented
1652
# through a string
1653
var_dict = dict(zip(R.variable_names(),range(R.ngens())))
1654
1655
ngens = R.ngens()
1656
1657
for i in range(coeff_start):
1658
exp = dict()
1659
monomial = singular_poly_list[i]
1660
1661
if monomial!="1":
1662
variables = [var.split("^") for var in monomial.split("*") ]
1663
for e in variables:
1664
var = e[0]
1665
if len(e)==int(2):
1666
power = int(e[1])
1667
else:
1668
power=1
1669
exp[var_dict[var]]=power
1670
1671
if kcache==None:
1672
sage_repr[ETuple(exp,ngens)]=k(singular_poly_list[coeff_start+i])
1673
else:
1674
elem = singular_poly_list[coeff_start+i]
1675
if not kcache.has_key(elem):
1676
kcache[elem] = k( elem )
1677
sage_repr[ETuple(exp,ngens)]= kcache[elem]
1678
1679
p = MPolynomial_polydict(R,PolyDict(sage_repr,force_int_exponents=False,force_etuples=False))
1680
if isinstance(R, MPolynomialRing_polydict):
1681
return p
1682
else:
1683
return QuotientRingElement(R,p,reduce=False)
1684
1685
elif is_PolynomialRing(R) and (ring_is_fine or can_convert_to_singular(R)):
1686
1687
sage_repr = [0]*int(self.deg()+1)
1688
1689
for i in range(coeff_start):
1690
monomial = singular_poly_list[i]
1691
exp = int(0)
1692
1693
if monomial!="1":
1694
term = monomial.split("^")
1695
if len(term)==int(2):
1696
exp = int(term[1])
1697
else:
1698
exp = int(1)
1699
1700
if kcache==None:
1701
sage_repr[exp]=k(singular_poly_list[coeff_start+i])
1702
else:
1703
elem = singular_poly_list[coeff_start+i]
1704
if not kcache.has_key(elem):
1705
kcache[elem] = k( elem )
1706
sage_repr[ exp ]= kcache[elem]
1707
1708
return R(sage_repr)
1709
1710
else:
1711
raise TypeError, "Cannot coerce %s into %s"%(self,R)
1712
1713
def sage_matrix(self, R, sparse=True):
1714
"""
1715
Returns Sage matrix for self
1716
1717
INPUT:
1718
1719
- ``R`` - (default: None); an optional ring, over which
1720
the resulting matrix is going to be defined.
1721
By default, the output of :meth:`sage_global_ring` is used.
1722
1723
- ``sparse`` - (default: True); determines whether the
1724
resulting matrix is sparse or not.
1725
1726
EXAMPLES::
1727
1728
sage: R = singular.ring(0, '(x,y,z)', 'dp')
1729
sage: A = singular.matrix(2,2)
1730
sage: A.sage_matrix(ZZ)
1731
[0 0]
1732
[0 0]
1733
sage: A.sage_matrix(RDF)
1734
[0.0 0.0]
1735
[0.0 0.0]
1736
"""
1737
from sage.matrix.constructor import Matrix
1738
nrows, ncols = int(self.nrows()),int(self.ncols())
1739
1740
if R is None:
1741
R = self.sage_global_ring()
1742
A = Matrix(R, nrows, ncols, sparse=sparse)
1743
#this is slow
1744
for x in range(nrows):
1745
for y in range(ncols):
1746
A[x,y]=self[x+1,y+1].sage_poly(R)
1747
return A
1748
1749
A = Matrix(R, nrows, ncols, sparse=sparse)
1750
#this is slow
1751
for x in range(nrows):
1752
for y in range(ncols):
1753
A[x,y]=R(self[x+1,y+1])
1754
1755
return A
1756
1757
def _sage_(self, R=None):
1758
r"""
1759
Coerces self to Sage.
1760
1761
EXAMPLES::
1762
1763
sage: R = singular.ring(0, '(x,y,z)', 'dp')
1764
sage: A = singular.matrix(2,2)
1765
sage: A._sage_(ZZ)
1766
[0 0]
1767
[0 0]
1768
sage: A = random_matrix(ZZ,3,3); A
1769
[ -8 2 0]
1770
[ 0 1 -1]
1771
[ 2 1 -95]
1772
sage: As = singular(A); As
1773
-8 2 0
1774
0 1 -1
1775
2 1 -95
1776
sage: As._sage_()
1777
[ -8 2 0]
1778
[ 0 1 -1]
1779
[ 2 1 -95]
1780
1781
::
1782
1783
sage: singular.eval('ring R = integer, (x,y,z),lp')
1784
'// ** redefining R **'
1785
sage: I = singular.ideal(['x^2','y*z','z+x'])
1786
sage: I.sage() # indirect doctest
1787
Ideal (x^2, y*z, x + z) of Multivariate Polynomial Ring in x, y, z over Integer Ring
1788
1789
::
1790
1791
sage: singular('ringlist(basering)').sage()
1792
[['integer'], ['x', 'y', 'z'], [['lp', (1, 1, 1)], ['C', (0)]], Ideal (0) of Multivariate Polynomial Ring in x, y, z over Integer Ring]
1793
1794
::
1795
1796
sage: singular.eval('ring r10 = (9,a), (x,y,z),lp')
1797
'ring r10 = (9,a), (x,y,z),lp;'
1798
sage: singular.eval('setring R')
1799
'setring R;'
1800
sage: singular('r10').sage()
1801
Multivariate Polynomial Ring in x, y, z over Finite Field in a of size 3^2
1802
1803
Note that the current base ring has not been changed by asking for another ring::
1804
1805
sage: singular('basering')
1806
// coeff. ring is : Integers
1807
// number of vars : 3
1808
// block 1 : ordering lp
1809
// : names x y z
1810
// block 2 : ordering C
1811
1812
::
1813
1814
sage: singular.eval('setring r10')
1815
'setring r10;'
1816
sage: Q = singular('std(ideal(x^2,x+y^2+z^3))', type='qring')
1817
sage: Q.sage()
1818
Quotient of Multivariate Polynomial Ring in x, y, z over Finite Field in a of size 3^2 by the ideal (y^4 - y^2*z^3 + z^6, x + y^2 + z^3)
1819
sage: singular('x^2+y').sage()
1820
x^2 + y
1821
sage: singular('x^2+y').sage().parent()
1822
Quotient of Multivariate Polynomial Ring in x, y, z over Finite Field in a of size 3^2 by the ideal (y^4 - y^2*z^3 + z^6, x + y^2 + z^3)
1823
1824
"""
1825
typ = self.type()
1826
if typ=='poly':
1827
return self.sage_poly(R)
1828
elif typ == 'module':
1829
return self.sage_matrix(R,sparse=True)
1830
elif typ == 'matrix':
1831
return self.sage_matrix(R,sparse=False)
1832
elif typ == 'list':
1833
return [ f._sage_(R) for f in self ]
1834
elif typ == 'intvec':
1835
from sage.modules.free_module_element import vector
1836
return vector([sage.rings.integer.Integer(str(e)) for e in self])
1837
elif typ == 'intmat':
1838
from sage.matrix.constructor import matrix
1839
from sage.rings.integer_ring import ZZ
1840
A = matrix(ZZ, int(self.nrows()), int(self.ncols()))
1841
for i in xrange(A.nrows()):
1842
for j in xrange(A.ncols()):
1843
A[i,j] = sage.rings.integer.Integer(str(self[i+1,j+1]))
1844
return A
1845
elif typ == 'string':
1846
return repr(self)
1847
elif typ == 'ideal':
1848
R = R or self.sage_global_ring()
1849
return R.ideal([p.sage_poly(R) for p in self])
1850
elif typ in ['ring', 'qring']:
1851
br = singular('basering')
1852
self.set_ring()
1853
R = self.sage_global_ring()
1854
br.set_ring()
1855
return R
1856
raise NotImplementedError, "Coercion of this datatype not implemented yet"
1857
1858
def set_ring(self):
1859
"""
1860
Sets the current ring in Singular to be self.
1861
1862
EXAMPLES::
1863
1864
sage: R = singular.ring(7, '(a,b)', 'ds')
1865
sage: S = singular.ring('real', '(a,b)', 'lp')
1866
sage: singular.current_ring()
1867
// characteristic : 0 (real)
1868
// number of vars : 2
1869
// block 1 : ordering lp
1870
// : names a b
1871
// block 2 : ordering C
1872
sage: R.set_ring()
1873
sage: singular.current_ring()
1874
// characteristic : 7
1875
// number of vars : 2
1876
// block 1 : ordering ds
1877
// : names a b
1878
// block 2 : ordering C
1879
"""
1880
self.parent().set_ring(self)
1881
1882
1883
def sage_flattened_str_list(self):
1884
"""
1885
EXAMPLES::
1886
1887
sage: R=singular.ring(0,'(x,y)','dp')
1888
sage: RL = R.ringlist()
1889
sage: RL.sage_flattened_str_list()
1890
['0', 'x', 'y', 'dp', '1,1', 'C', '0', '_[1]=0']
1891
"""
1892
s = str(self)
1893
c = '\[[0-9]*\]:'
1894
r = re.compile(c)
1895
s = r.sub('',s).strip()
1896
return s.split()
1897
1898
def sage_structured_str_list(self):
1899
r"""
1900
If self is a Singular list of lists of Singular elements, returns
1901
corresponding Sage list of lists of strings.
1902
1903
EXAMPLES::
1904
1905
sage: R=singular.ring(0,'(x,y)','dp')
1906
sage: RL=R.ringlist()
1907
sage: RL
1908
[1]:
1909
0
1910
[2]:
1911
[1]:
1912
x
1913
[2]:
1914
y
1915
[3]:
1916
[1]:
1917
[1]:
1918
dp
1919
[2]:
1920
1,1
1921
[2]:
1922
[1]:
1923
C
1924
[2]:
1925
0
1926
[4]:
1927
_[1]=0
1928
sage: RL.sage_structured_str_list()
1929
['0', ['x', 'y'], [['dp', '1,\n1 '], ['C', '0 ']], '0']
1930
"""
1931
if not (self.type()=='list'):
1932
return str(self)
1933
return [X.sage_structured_str_list() for X in self]
1934
1935
def trait_names(self):
1936
"""
1937
Returns the possible tab-completions for self. In this case, we
1938
just return all the tab completions for the Singular object.
1939
1940
EXAMPLES::
1941
1942
sage: R = singular.ring(0,'(x,y)','dp')
1943
sage: R.trait_names()
1944
['exteriorPower',
1945
...
1946
'stdfglm']
1947
"""
1948
return self.parent().trait_names()
1949
1950
def type(self):
1951
"""
1952
Returns the internal type of this element.
1953
1954
EXAMPLES::
1955
1956
sage: R = PolynomialRing(GF(2^8,'a'),2,'x')
1957
sage: R._singular_().type()
1958
'ring'
1959
sage: fs = singular('x0^2','poly')
1960
sage: fs.type()
1961
'poly'
1962
"""
1963
# singular reports // $varname $type $stuff
1964
p = re.compile("// [\w]+ (\w+) [\w]*")
1965
m = p.match(self.parent().eval("type(%s)"%self.name()))
1966
return m.group(1)
1967
1968
def __iter__(self):
1969
"""
1970
EXAMPLES::
1971
1972
sage: R = singular.ring(0, '(x,y,z)', 'dp')
1973
sage: A = singular.matrix(2,2)
1974
sage: list(iter(A))
1975
[[0], [0]]
1976
sage: A[1,1] = 1; A[1,2] = 2
1977
sage: A[2,1] = 3; A[2,2] = 4
1978
sage: list(iter(A))
1979
[[1,3], [2,4]]
1980
"""
1981
if self.type()=='matrix':
1982
l = self.ncols()
1983
else:
1984
l = len(self)
1985
for i in range(1, l+1):
1986
yield self[i]
1987
1988
def _singular_(self):
1989
"""
1990
EXAMPLES::
1991
1992
sage: R = singular.ring(0, '(x,y,z)', 'dp')
1993
sage: A = singular.matrix(2,2)
1994
sage: A._singular_() is A
1995
True
1996
"""
1997
return self
1998
1999
def attrib(self, name, value=None):
2000
"""
2001
Get and set attributes for self.
2002
2003
INPUT:
2004
2005
2006
- ``name`` - string to choose the attribute
2007
2008
- ``value`` - boolean value or None for reading,
2009
(default:None)
2010
2011
2012
VALUES: isSB - the standard basis property is set by all commands
2013
computing a standard basis like groebner, std, stdhilb etc.; used
2014
by lift, dim, degree, mult, hilb, vdim, kbase isHomog - the weight
2015
vector for homogeneous or quasihomogeneous ideals/modules isCI -
2016
complete intersection property isCM - Cohen-Macaulay property rank
2017
- set the rank of a module (see nrows) withSB - value of type
2018
ideal, resp. module, is std withHilb - value of type intvec is
2019
hilb(_,1) (see hilb) withRes - value of type list is a free
2020
resolution withDim - value of type int is the dimension (see dim)
2021
withMult - value of type int is the multiplicity (see mult)
2022
2023
EXAMPLE::
2024
2025
sage: P.<x,y,z> = PolynomialRing(QQ)
2026
sage: I = Ideal([z^2, y*z, y^2, x*z, x*y, x^2])
2027
sage: Ibar = I._singular_()
2028
sage: Ibar.attrib('isSB')
2029
0
2030
sage: singular.eval('vdim(%s)'%Ibar.name()) # sage7 name is random
2031
// ** sage7 is no standard basis
2032
4
2033
sage: Ibar.attrib('isSB',1)
2034
sage: singular.eval('vdim(%s)'%Ibar.name())
2035
'4'
2036
"""
2037
if value is None:
2038
return int(self.parent().eval('attrib(%s,"%s")'%(self.name(),name)))
2039
else:
2040
self.parent().eval('attrib(%s,"%s",%d)'%(self.name(),name,value))
2041
2042
class SingularFunction(ExpectFunction):
2043
def _sage_doc_(self):
2044
"""
2045
EXAMPLES::
2046
2047
sage: 'groebner' in singular.groebner._sage_doc_()
2048
True
2049
"""
2050
if not nodes:
2051
generate_docstring_dictionary()
2052
2053
prefix = \
2054
"""
2055
This function is an automatically generated pexpect wrapper around the Singular
2056
function '%s'.
2057
2058
EXAMPLE::
2059
2060
sage: groebner = singular.groebner
2061
sage: P.<x, y> = PolynomialRing(QQ)
2062
sage: I = P.ideal(x^2-y, y+x)
2063
sage: groebner(singular(I))
2064
x+y,
2065
y^2-y
2066
"""%(self._name,)
2067
prefix2 = \
2068
"""
2069
2070
The Singular documentation for '%s' is given below.
2071
"""%(self._name,)
2072
2073
try:
2074
return prefix + prefix2 + nodes[node_names[self._name]]
2075
except KeyError:
2076
return prefix
2077
2078
class SingularFunctionElement(FunctionElement):
2079
def _sage_doc_(self):
2080
r"""
2081
EXAMPLES::
2082
2083
sage: R = singular.ring(0, '(x,y,z)', 'dp')
2084
sage: A = singular.matrix(2,2)
2085
sage: 'matrix_expression' in A.nrows._sage_doc_()
2086
True
2087
"""
2088
if not nodes:
2089
generate_docstring_dictionary()
2090
try:
2091
return nodes[node_names[self._name]]
2092
except KeyError:
2093
return ""
2094
2095
def is_SingularElement(x):
2096
r"""
2097
Returns True is x is of type ``SingularElement``.
2098
2099
EXAMPLES::
2100
2101
sage: from sage.interfaces.singular import is_SingularElement
2102
sage: is_SingularElement(singular(2))
2103
True
2104
sage: is_SingularElement(2)
2105
False
2106
"""
2107
return isinstance(x, SingularElement)
2108
2109
def reduce_load():
2110
"""
2111
Note that this returns an invalid Singular object!
2112
2113
EXAMPLES::
2114
2115
sage: from sage.interfaces.singular import reduce_load
2116
sage: reduce_load()
2117
(invalid object -- defined in terms of closed session)
2118
"""
2119
return SingularElement(None, None, None)
2120
2121
2122
2123
nodes = {}
2124
node_names = {}
2125
2126
def generate_docstring_dictionary():
2127
"""
2128
Generate global dictionaries which hold the docstrings for
2129
Singular functions.
2130
2131
EXAMPLE::
2132
2133
sage: from sage.interfaces.singular import generate_docstring_dictionary
2134
sage: generate_docstring_dictionary()
2135
"""
2136
global nodes
2137
global node_names
2138
2139
nodes.clear()
2140
node_names.clear()
2141
2142
singular_docdir = os.environ["SAGE_LOCAL"]+"/share/singular/"
2143
2144
new_node = re.compile("File: singular\.hlp, Node: ([^,]*),.*")
2145
new_lookup = re.compile("\* ([^:]*):*([^.]*)\..*")
2146
2147
L, in_node, curr_node = [], False, None
2148
2149
for line in open(singular_docdir + "singular.hlp"):
2150
m = re.match(new_node,line)
2151
if m:
2152
# a new node starts
2153
in_node = True
2154
nodes[curr_node] = "".join(L)
2155
L = []
2156
curr_node, = m.groups()
2157
elif in_node: # we are in a node
2158
L.append(line)
2159
else:
2160
m = re.match(new_lookup, line)
2161
if m:
2162
a,b = m.groups()
2163
node_names[a] = b.strip()
2164
2165
if line == "6 Index\n":
2166
in_node = False
2167
2168
nodes[curr_node] = "".join(L) # last node
2169
2170
def get_docstring(name):
2171
"""
2172
Return the docstring for the function ``name``.
2173
2174
INPUT:
2175
2176
- ``name`` - a Singular function name
2177
2178
EXAMPLE::
2179
2180
sage: from sage.interfaces.singular import get_docstring
2181
sage: 'groebner' in get_docstring('groebner')
2182
True
2183
sage: 'standard.lib' in get_docstring('groebner')
2184
True
2185
2186
"""
2187
if not nodes:
2188
generate_docstring_dictionary()
2189
try:
2190
return nodes[node_names[name]]
2191
except KeyError:
2192
return ""
2193
2194
##################################
2195
2196
singular = Singular()
2197
2198
def reduce_load_Singular():
2199
"""
2200
EXAMPLES::
2201
2202
sage: from sage.interfaces.singular import reduce_load_Singular
2203
sage: reduce_load_Singular()
2204
Singular
2205
"""
2206
return singular
2207
2208
import os
2209
def singular_console():
2210
"""
2211
Spawn a new Singular command-line session.
2212
2213
EXAMPLES::
2214
2215
sage: singular_console() #not tested
2216
SINGULAR / Development
2217
A Computer Algebra System for Polynomial Computations / version 3-0-4
2218
0<
2219
by: G.-M. Greuel, G. Pfister, H. Schoenemann \ Nov 2007
2220
FB Mathematik der Universitaet, D-67653 Kaiserslautern \
2221
"""
2222
os.system('Singular')
2223
2224
2225
def singular_version():
2226
"""
2227
Returns the version of Singular being used.
2228
2229
EXAMPLES:
2230
"""
2231
return singular.eval('system("--version");')
2232
2233
2234
2235
class SingularGBLogPrettyPrinter:
2236
"""
2237
A device which prints Singular Groebner basis computation logs
2238
more verbatim.
2239
"""
2240
rng_chng = re.compile("\[\d+:\d+\]")# [m:n] internal ring change to
2241
# poly representation with
2242
# exponent bound m and n words in
2243
# exponent vector
2244
new_elem = re.compile("s") # found a new element of the standard basis
2245
red_zero = re.compile("-") # reduced a pair/S-polynomial to 0
2246
red_post = re.compile("\.") # postponed a reduction of a pair/S-polynomial
2247
cri_hilb = re.compile("h") # used Hilbert series criterion
2248
hig_corn = re.compile("H\(\d+\)") # found a 'highest corner' of degree d, no need to consider higher degrees
2249
num_crit = re.compile("\(\d+\)") # n critical pairs are still to be reduced
2250
red_num = re.compile("\(S:\d+\)") # doing complete reduction of n elements
2251
deg_lead = re.compile("\d+") # the degree of the leading terms is currently d
2252
2253
# SlimGB
2254
red_para = re.compile("M\[(\d+),(\d+)\]") # parallel reduction of n elements with m non-zero output elements
2255
red_betr = re.compile("b") # exchange of a reductor by a 'better' one
2256
non_mini = re.compile("e") # a new reductor with non-minimal leading term
2257
2258
crt_lne1 = re.compile("product criterion:(\d+) chain criterion:(\d+)")
2259
crt_lne2 = re.compile("NF:(\d+) product criterion:(\d+), ext_product criterion:(\d+)")
2260
2261
pat_sync = re.compile("1\+(\d+);")
2262
2263
global_pattern = re.compile("(\[\d+:\d+\]|s|-|\.|h|H\(\d+\)|\(\d+\)|\(S:\d+\)|\d+|M\[\d+,[b,e]*\d+\]|b|e).*")
2264
2265
def __init__(self, verbosity=1):
2266
"""
2267
Construct a new Singular Groebner Basis log pretty printer.
2268
2269
INPUT:
2270
2271
- ``verbosity`` - how much information should be printed
2272
(between 0 and 3)
2273
2274
EXAMPLE::
2275
2276
sage: from sage.interfaces.singular import SingularGBLogPrettyPrinter
2277
sage: s0 = SingularGBLogPrettyPrinter(verbosity=0)
2278
sage: s1 = SingularGBLogPrettyPrinter(verbosity=1)
2279
sage: s0.write("[1:2]12")
2280
2281
sage: s1.write("[1:2]12")
2282
Leading term degree: 12.
2283
"""
2284
self.verbosity = verbosity
2285
2286
self.curr_deg = 0 # current degree
2287
self.max_deg = 0 # maximal degree in total
2288
2289
self.nf = 0 # number of normal forms computed (SlimGB only)
2290
self.prod = 0 # number of S-polynomials discarded using product criterion
2291
self.ext_prod = 0 # number of S-polynomials discarded using extended product criterion
2292
self.chain = 0 # number of S-polynomials discarded using chain criterion
2293
2294
self.storage = "" # stores incomplete strings
2295
self.sync = None # should we expect a sync integer?
2296
2297
def write(self, s):
2298
"""
2299
EXAMPLE::
2300
2301
sage: from sage.interfaces.singular import SingularGBLogPrettyPrinter
2302
sage: s3 = SingularGBLogPrettyPrinter(verbosity=3)
2303
sage: s3.write("(S:1337)")
2304
Performing complete reduction of 1337 elements.
2305
sage: s3.write("M[389,12]")
2306
Parallel reduction of 389 elements with 12 non-zero output elements.
2307
"""
2308
verbosity = self.verbosity
2309
2310
if self.storage:
2311
s = self.storage + s
2312
self.storage = ""
2313
2314
for line in s.splitlines():
2315
# deal with the Sage <-> Singular syncing code
2316
match = re.match(SingularGBLogPrettyPrinter.pat_sync,line)
2317
if match:
2318
self.sync = int(match.groups()[0])
2319
continue
2320
2321
if self.sync and line == "%d"%(self.sync+1):
2322
self.sync = None
2323
continue
2324
2325
if line.endswith(";"):
2326
continue
2327
if line.startswith(">"):
2328
continue
2329
2330
if line.startswith("std") or line.startswith("slimgb"):
2331
continue
2332
2333
# collect stats returned about avoided reductions to zero
2334
match = re.match(SingularGBLogPrettyPrinter.crt_lne1,line)
2335
if match:
2336
self.prod,self.chain = map(int,re.match(SingularGBLogPrettyPrinter.crt_lne1,line).groups())
2337
self.storage = ""
2338
continue
2339
match = re.match(SingularGBLogPrettyPrinter.crt_lne2,line)
2340
if match:
2341
self.nf,self.prod,self.ext_prod = map(int,re.match(SingularGBLogPrettyPrinter.crt_lne2,line).groups())
2342
self.storage = ""
2343
continue
2344
2345
while line:
2346
match = re.match(SingularGBLogPrettyPrinter.global_pattern, line)
2347
if not match:
2348
self.storage = line
2349
line = None
2350
continue
2351
2352
token, = match.groups()
2353
line = line[len(token):]
2354
2355
if re.match(SingularGBLogPrettyPrinter.rng_chng,token):
2356
continue
2357
2358
elif re.match(SingularGBLogPrettyPrinter.new_elem,token) and verbosity >= 3:
2359
print "New element found."
2360
2361
elif re.match(SingularGBLogPrettyPrinter.red_zero,token) and verbosity >= 2:
2362
print "Reduction to zero."
2363
2364
elif re.match(SingularGBLogPrettyPrinter.red_post, token) and verbosity >= 2:
2365
print "Reduction postponed."
2366
2367
elif re.match(SingularGBLogPrettyPrinter.cri_hilb, token) and verbosity >= 2:
2368
print "Hilber series criterion applied."
2369
2370
elif re.match(SingularGBLogPrettyPrinter.hig_corn, token) and verbosity >= 1:
2371
print "Maximal degree found: %s"%token
2372
2373
elif re.match(SingularGBLogPrettyPrinter.num_crit, token) and verbosity >= 1:
2374
print "Leading term degree: %2d. Critical pairs: %s."%(self.curr_deg,token[1:-1])
2375
2376
elif re.match(SingularGBLogPrettyPrinter.red_num, token) and verbosity >= 3:
2377
print "Performing complete reduction of %s elements."%token[3:-1]
2378
2379
elif re.match(SingularGBLogPrettyPrinter.deg_lead, token):
2380
if verbosity >= 1:
2381
print "Leading term degree: %2d."%int(token)
2382
self.curr_deg = int(token)
2383
if self.max_deg < self.curr_deg:
2384
self.max_deg = self.curr_deg
2385
2386
elif re.match(SingularGBLogPrettyPrinter.red_para, token) and verbosity >= 3:
2387
m,n = re.match(SingularGBLogPrettyPrinter.red_para,token).groups()
2388
print "Parallel reduction of %s elements with %s non-zero output elements."%(m,n)
2389
2390
elif re.match(SingularGBLogPrettyPrinter.red_betr, token) and verbosity >= 3:
2391
print "Replaced reductor by 'better' one."
2392
2393
elif re.match(SingularGBLogPrettyPrinter.non_mini, token) and verbosity >= 2:
2394
print "New reductor with non-minimal leading term found."
2395
2396
def flush(self):
2397
"""
2398
EXAMPLE::
2399
2400
sage: from sage.interfaces.singular import SingularGBLogPrettyPrinter
2401
sage: s3 = SingularGBLogPrettyPrinter(verbosity=3)
2402
sage: s3.flush()
2403
"""
2404
import sys
2405
sys.stdout.flush()
2406
2407