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