Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
r""" Interface to Singular
AUTHORS:
- David Joyner and William Stein (2005): first version
- Martin Albrecht (2006-03-05): code so singular.[tab] and x = singular(...), x.[tab] includes all singular commands.
- Martin Albrecht (2006-03-06): This patch adds the equality symbol to singular. Also fix a problem in which " " as prompt means comparison will break all further communication with Singular.
- Martin Albrecht (2006-03-13): added current_ring() and current_ring_name()
- William Stein (2006-04-10): Fixed problems with ideal constructor
- Martin Albrecht (2006-05-18): added sage_poly.
- Simon King (2010-11-23): Reduce the overhead caused by waiting for the Singular prompt by doing garbage collection differently.
- Simon King (2011-06-06): Make conversion from Singular to Sage more flexible.
- Simon King (2015): Extend pickling capabilities.
Introduction ------------
This interface is extremely flexible, since it's exactly like typing into the Singular interpreter, and anything that works there should work here.
The Singular interface will only work if Singular is installed on your computer; this should be the case, since Singular is included with Sage. The interface offers three pieces of functionality:
#. ``singular_console()`` - A function that dumps you into an interactive command-line Singular session.
#. ``singular(expr, type='def')`` - Creation of a Singular object. This provides a Pythonic interface to Singular. For example, if ``f=singular(10)``, then ``f.factorize()`` returns the factorization of `10` computed using Singular.
#. ``singular.eval(expr)`` - Evaluation of arbitrary Singular expressions, with the result returned as a string.
Of course, there are polynomial rings and ideals in Sage as well (often based on a C-library interface to Singular). One can convert an object in the Singular interpreter interface to Sage by the method ``sage()``.
Tutorial --------
EXAMPLES: First we illustrate multivariate polynomial factorization::
sage: R1 = singular.ring(0, '(x,y)', 'dp') sage: R1 polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 2 // block 1 : ordering dp // : names x y // block 2 : ordering C sage: f = singular('9x16 - 18x13y2 - 9x12y3 + 9x10y4 - 18x11y2 + 36x8y4 + 18x7y5 - 18x5y6 + 9x6y4 - 18x3y6 - 9x2y7 + 9y8') sage: f 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 sage: f.parent() Singular
::
sage: F = f.factorize(); F [1]: _[1]=9 _[2]=x^6-2*x^3*y^2-x^2*y^3+y^4 _[3]=-x^5+y^2 [2]: 1,1,2
::
sage: F[1] 9, x^6-2*x^3*y^2-x^2*y^3+y^4, -x^5+y^2 sage: F[1][2] x^6-2*x^3*y^2-x^2*y^3+y^4
We can convert `f` and each exponent back to Sage objects as well.
::
sage: g = f.sage(); g 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 sage: F[1][2].sage() x^6 - 2*x^3*y^2 - x^2*y^3 + y^4 sage: g.parent() Multivariate Polynomial Ring in x, y over Rational Field
This example illustrates polynomial GCD's::
sage: R2 = singular.ring(0, '(x,y,z)', 'lp') sage: a = singular.new('3x2*(x+y)') sage: b = singular.new('9x*(y2-x2)') sage: g = a.gcd(b) sage: g x^2+x*y
This example illustrates computation of a Groebner basis::
sage: R3 = singular.ring(0, '(a,b,c,d)', 'lp') 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']) sage: I2 = I.groebner() sage: I2 c^2*d^6-c^2*d^2-d^4+1, c^3*d^2+c^2*d^3-c-d, b*d^4-b+d^5-d, b*c-b*d^5+c^2*d^4+c*d-d^6-d^2, b^2+2*b*d+d^2, a+b+c+d
The following example is the same as the one in the Singular - Gap interface documentation::
sage: R = singular.ring(0, '(x0,x1,x2)', 'lp') 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']) sage: I2 = I1.groebner() sage: I2 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 sage: I2.sage() 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
This example illustrates moving a polynomial from one ring to another. It also illustrates calling a method of an object with an argument.
::
sage: R = singular.ring(0, '(x,y,z)', 'dp') sage: f = singular('x3+y3+(x-y)*x2y2+z2') sage: f x^3*y^2-x^2*y^3+x^3+y^3+z^2 sage: R1 = singular.ring(0, '(x,y,z)', 'ds') sage: f = R.fetch(f) sage: f z^2+x^3+y^3+x^3*y^2-x^2*y^3
We can calculate the Milnor number of `f`::
sage: _=singular.LIB('sing.lib') # assign to _ to suppress printing sage: f.milnor() 4
The Jacobian applied twice yields the Hessian matrix of `f`, with which we can compute.
::
sage: H = f.jacob().jacob() sage: H 6*x+6*x*y^2-2*y^3,6*x^2*y-6*x*y^2, 0, 6*x^2*y-6*x*y^2, 6*y+2*x^3-6*x^2*y,0, 0, 0, 2 sage: H.sage() [6*x + 6*x*y^2 - 2*y^3 6*x^2*y - 6*x*y^2 0] [ 6*x^2*y - 6*x*y^2 6*y + 2*x^3 - 6*x^2*y 0] [ 0 0 2] sage: H.det() # This is a polynomial in Singular 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 sage: H.det().sage() # This is the corresponding polynomial in Sage 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
The 1x1 and 2x2 minors::
sage: H.minor(1) 2, 6*y+2*x^3-6*x^2*y, 6*x^2*y-6*x*y^2, 6*x^2*y-6*x*y^2, 6*x+6*x*y^2-2*y^3 sage: H.minor(2) 12*y+4*x^3-12*x^2*y, 12*x^2*y-12*x*y^2, 12*x^2*y-12*x*y^2, 12*x+12*x*y^2-4*y^3, -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
::
sage: _=singular.eval('option(redSB)') sage: H.minor(1).groebner() 1
Computing the Genus -------------------
We compute the projective genus of ideals that define curves over `\QQ`. It is *very important* to load the ``normal.lib`` library before calling the ``genus`` command, or you'll get an error message.
EXAMPLES::
sage: singular.lib('normal.lib') sage: R = singular.ring(0,'(x,y)','dp') sage: i2 = singular.ideal('y9 - x2*(x-1)^9 + x') sage: i2.genus() 40
Note that the genus can be much smaller than the degree::
sage: i = singular.ideal('y9 - x2*(x-1)^9') sage: i.genus() 0
An Important Concept --------------------
AUTHORS:
- Neal Harris
The following illustrates an important concept: how Sage interacts with the data being used and returned by Singular. Let's compute a Groebner basis for some ideal, using Singular through Sage.
::
sage: singular.lib('poly.lib') sage: singular.ring(32003, '(a,b,c,d,e,f)', 'lp') polynomial ring, over a field, global ordering // coefficients: ZZ/32003 // number of vars : 6 // block 1 : ordering lp // : names a b c d e f // block 2 : ordering C sage: I = singular.ideal('cyclic(6)') sage: g = singular('groebner(I)') Traceback (most recent call last): ... TypeError: Singular error: ...
We restart everything and try again, but correctly.
::
sage: singular.quit() sage: singular.lib('poly.lib'); R = singular.ring(32003, '(a,b,c,d,e,f)', 'lp') sage: I = singular.ideal('cyclic(6)') sage: I.groebner() f^48-2554*f^42-15674*f^36+12326*f^30-12326*f^18+15674*f^12+2554*f^6-1, ...
It's important to understand why the first attempt at computing a basis failed. The line where we gave singular the input 'groebner(I)' was useless because Singular has no idea what 'I' is! Although 'I' is an object that we computed with calls to Singular functions, it actually lives in Sage. As a consequence, the name 'I' means nothing to Singular. When we called ``I.groebner()``, Sage was able to call the groebner function on'I' in Singular, since 'I' actually means something to Sage.
Long Input ----------
The Singular interface reads in even very long input (using files) in a robust manner, as long as you are creating a new object.
::
sage: t = '"%s"'%10^15000 # 15 thousand character string (note that normal Singular input must be at most 10000) sage: a = singular.eval(t) sage: a = singular(t)
TESTS:
We test an automatic coercion::
sage: a = 3*singular('2'); a 6 sage: type(a) <class 'sage.interfaces.singular.SingularElement'> sage: a = singular('2')*3; a 6 sage: type(a) <class 'sage.interfaces.singular.SingularElement'>
Create a ring over GF(9) to check that ``gftables`` has been installed, see :trac:`11645`::
sage: singular.eval("ring testgf9 = (9,x),(a,b,c,d,e,f),(M((1,2,3,0)),wp(2,3),lp);") '' """
#***************************************************************************** # Copyright (C) 2005 David Joyner and William Stein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import print_function from __future__ import absolute_import from six.moves import range from six import integer_types, string_types
import os import re import sys import pexpect from time import sleep
from .expect import Expect, ExpectElement, FunctionElement, ExpectFunction
from sage.interfaces.tab_completion import ExtraTabCompletion from sage.structure.sequence import Sequence from sage.structure.element import RingElement
import sage.rings.integer
from sage.misc.misc import get_verbose from sage.misc.superseded import deprecation from sage.docs.instancedoc import instancedoc
from six import reraise as raise_
class SingularError(RuntimeError): """ Raised if Singular printed an error message """ pass
class Singular(ExtraTabCompletion, Expect): r""" Interface to the Singular interpreter.
EXAMPLES: A Groebner basis example.
::
sage: R = singular.ring(0, '(x0,x1,x2)', 'lp') 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']) sage: I.groebner() 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
AUTHORS:
- David Joyner and William Stein """ def __init__(self, maxread=None, script_subdirectory=None, logfile=None, server=None,server_tmpdir=None, seed=None): """ EXAMPLES::
sage: singular == loads(dumps(singular)) True """ terminal_echo=False, name = 'singular', prompt = prompt, # no tty, fine grained cputime() # and do not display CTRL-C prompt command = "Singular -t --ticks-per-sec 1000 --cntrlc=a", server = server, server_tmpdir = server_tmpdir, script_subdirectory = script_subdirectory, restart_on_ctrlc = True, verbose_start = False, logfile = logfile, eval_using_file_cutoff=100 if os.uname()[0]=="SunOS" else 1000)
def set_seed(self,seed=None): """ Set the seed for singular interpreter.
The seed should be an integer at least 1 and not more than 30 bits. See http://www.singular.uni-kl.de/Manual/html/sing_19.htm#SEC26 and http://www.singular.uni-kl.de/Manual/html/sing_283.htm#SEC323
EXAMPLES::
sage: s = Singular() sage: s.set_seed(1) 1 sage: [s.random(1,10) for i in range(5)] [8, 10, 4, 9, 1] """
def _start(self, alt_message=None): """ EXAMPLES::
sage: s = Singular() sage: s.is_running() False sage: s._start() sage: s.is_running() True sage: s.quit() """ # Load some standard libraries.
# these options are required by the new coefficient rings # supported by Singular 3-1-0. # set random seed
def __reduce__(self): """ EXAMPLES::
sage: singular.__reduce__() (<function reduce_load_Singular at 0x...>, ()) """
def _equality_symbol(self): """ EXAMPLES::
sage: singular._equality_symbol() '==' """
def _true_symbol(self): """ EXAMPLES::
sage: singular._true_symbol() '1' """
def _false_symbol(self): """ EXAMPLES::
sage: singular._false_symbol() '0' """
def _quit_string(self): """ EXAMPLES::
sage: singular._quit_string() 'quit' """
def _send_interrupt(self): """ Send an interrupt to Singular. If needed, additional semi-colons are sent until we get back at the prompt.
TESTS:
The following works without restarting Singular::
sage: a = singular(1) sage: _ = singular._expect.sendline('1+') # unfinished input sage: try: ....: alarm(0.5) ....: singular._expect_expr('>') # interrupt this ....: except KeyboardInterrupt: ....: pass Control-C pressed. Interrupting Singular. Please wait a few seconds...
We can still access a::
sage: 2*a 2 """ # Work around for Singular bug # http://www.singular.uni-kl.de:8002/trac/ticket/727
def _read_in_file_command(self, filename): r""" EXAMPLES::
sage: singular._read_in_file_command('test') '< "...";'
sage: filename = tmp_filename() sage: f = open(filename, 'w') sage: _ = f.write('int x = 2;\n') sage: f.close() sage: singular.read(filename) sage: singular.get('x') '2' """
def eval(self, x, allow_semicolon=True, strip=True, **kwds): r""" Send the code x to the Singular interpreter and return the output as a string.
INPUT:
- ``x`` - string (of code)
- ``allow_semicolon`` - default: False; if False then raise a TypeError if the input line contains a semicolon.
- ``strip`` - ignored
EXAMPLES::
sage: singular.eval('2 > 1') '1' sage: singular.eval('2 + 2') '4'
if the verbosity level is `> 1` comments are also printed and not only returned.
::
sage: r = singular.ring(0,'(x,y,z)','dp') sage: i = singular.ideal(['x^2','y^2','z^2']) sage: s = i.std() sage: singular.eval('hilb(%s)'%(s.name())) '// 1 t^0\n// -3 t^2\n// 3 t^4\n// -1 t^6\n\n// 1 t^0\n// 3 t^1\n// 3 t^2\n// 1 t^3\n// dimension (affine) = 0\n// degree (affine) = 8'
::
sage: set_verbose(1) sage: o = singular.eval('hilb(%s)'%(s.name())) // 1 t^0 // -3 t^2 // 3 t^4 // -1 t^6 // 1 t^0 // 3 t^1 // 3 t^2 // 1 t^3 // dimension (affine) = 0 // degree (affine) = 8
This is mainly useful if this method is called implicitly. Because then intermediate results, debugging outputs and printed statements are printed
::
sage: o = s.hilb() // 1 t^0 // -3 t^2 // 3 t^4 // -1 t^6 // 1 t^0 // 3 t^1 // 3 t^2 // 1 t^3 // dimension (affine) = 0 // degree (affine) = 8 // ** right side is not a datum, assignment ignored ...
rather than ignored
::
sage: set_verbose(0) sage: o = s.hilb() """ # Simon King: # In previous versions, the interface was first synchronised and then # unused variables were killed. This created a considerable overhead. # By trac ticket #10296, killing unused variables is now done inside # singular.set(). Moreover, it is not done by calling a separate _eval_line. # In that way, the time spent by waiting for the singular prompt is reduced.
# Before #10296, it was possible that garbage collection occured inside # of _eval_line. But collection of the garbage would launch another call # to _eval_line. The result would have been a dead lock, that could only # be avoided by synchronisation. Since garbage collection is now done # without an additional call to _eval_line, synchronisation is not # needed anymore, saving even more waiting time for the prompt.
# Uncomment the print statements below for low-level debugging of # code that involves the singular interfaces. Everything goes # through here.
raise TypeError("singular input must not contain any semicolons:\n%s"%x)
else:
def set(self, type, name, value): """ Set the variable with given name to the given value.
REMARK:
If a variable in the Singular interface was previously marked for deletion, the actual deletion is done here, before the new variable is created in Singular.
EXAMPLES::
sage: singular.set('int', 'x', '2') sage: singular.get('x') '2'
We test that an unused variable is only actually deleted if this method is called::
sage: a = singular(3) sage: n = a.name() sage: del a sage: singular.eval(n) '3' sage: singular.set('int', 'y', '5') sage: singular.eval('defined(%s)'%n) '0'
"""
def get(self, var): """ Get string representation of variable named var.
EXAMPLES::
sage: singular.set('int', 'x', '2') sage: singular.get('x') '2' """
def clear(self, var): """ Clear the variable named ``var``.
EXAMPLES::
sage: singular.set('int', 'x', '2') sage: singular.get('x') '2' sage: singular.clear('x')
"Clearing the variable" means to allow to free the memory that it uses in the Singular sub-process. However, the actual deletion of the variable is only committed when the next element in the Singular interface is created::
sage: singular.get('x') '2' sage: a = singular(3) sage: singular.get('x') '`x`'
""" # We add the variable to the list of vars to clear when we do an eval. # We queue up all the clears and do them at once to avoid synchronizing # the interface at the same time we do garbage collection, which can # lead to subtle problems. This was Willem Jan's ideas, implemented # by William Stein.
def _create(self, value, type='def'): """ Creates a new variable in the Singular session and returns the name of that variable.
EXAMPLES::
sage: singular._create('2', type='int') 'sage...' sage: singular.get(_) '2' """
def __call__(self, x, type='def'): """ Create a singular object X with given type determined by the string x. This returns var, where var is built using the Singular statement type var = ... x ... Note that the actual name of var could be anything, and can be recovered using X.name().
The object X returned can be used like any Sage object, and wraps an object in self. The standard arithmetic operators work. Moreover if foo is a function then X.foo(y,z,...) calls foo(X, y, z, ...) and returns the corresponding object.
EXAMPLES::
sage: R = singular.ring(0, '(x0,x1,x2)', 'lp') 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']) sage: I -x0^2*x2+x0*x1*x2, x0^2*x1*x2-x0*x1^2*x2-x0*x1*x2^2, x0*x1-x0*x2-x1*x2 sage: type(I) <class 'sage.interfaces.singular.SingularElement'> sage: I.parent() Singular """ return self(x.sage())
# some convenient conversions
def _coerce_map_from_(self, S): """ Return ``True`` if ``S`` admits a coercion map into the Singular interface.
EXAMPLES::
sage: singular._coerce_map_from_(ZZ) True sage: singular.coerce_map_from(ZZ) Call morphism: From: Integer Ring To: Singular sage: singular.coerce_map_from(float) """ # we want to implement this without coercing, since singular has state. try: self._coerce_(S.an_element()) return True except TypeError: pass
def cputime(self, t=None): r""" Returns the amount of CPU time that the Singular session has used. If ``t`` is not None, then it returns the difference between the current CPU time and ``t``.
EXAMPLES::
sage: t = singular.cputime() sage: R = singular.ring(0, '(x0,x1,x2)', 'lp') 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']) sage: gb = I.groebner() sage: singular.cputime(t) #random 0.02 """ else:
################################################################### # Singular libraries ################################################################### def lib(self, lib, reload=False): """ Load the Singular library named lib.
Note that if the library was already loaded during this session it is not reloaded unless the optional reload argument is True (the default is False).
EXAMPLES::
sage: singular.lib('sing.lib') sage: singular.lib('sing.lib', reload=True) """
LIB = lib load = lib
################################################################### # constructors ################################################################### def ideal(self, *gens): """ Return the ideal generated by gens.
INPUT:
- ``gens`` - list or tuple of Singular objects (or objects that can be made into Singular objects via evaluation)
OUTPUT: the Singular ideal generated by the given list of gens
EXAMPLES: A Groebner basis example done in a different way.
::
sage: _ = singular.eval("ring R=0,(x0,x1,x2),lp") 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']) sage: i1 -x0^2*x2+x0*x1*x2, x0^2*x1*x2-x0*x1^2*x2-x0*x1*x2^2, x0*x1-x0*x2-x1*x2
::
sage: i2 = singular.ideal('groebner(%s);'%i1.name()) sage: i2 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 """ gens = self(gens)
return self(gens.name(), 'ideal')
raise TypeError("gens (=%s) must be a list, tuple, string, or Singular element"%gens)
else: gens2.append(g)
def list(self, x): r""" Creates a list in Singular from a Sage list ``x``.
EXAMPLES::
sage: singular.list([1,2]) [1]: 1 [2]: 2 """
def matrix(self, nrows, ncols, entries=None): """ EXAMPLES::
sage: singular.lib("matrix") sage: R = singular.ring(0, '(x,y,z)', 'dp') sage: A = singular.matrix(3,2,'1,2,3,4,5,6') sage: A 1,2, 3,4, 5,6 sage: A.gauss_col() 2,-1, 1,0, 0,1
AUTHORS:
- Martin Albrecht (2006-01-14) """ else:
def ring(self, char=0, vars='(x)', order='lp', check=True): r""" Create a Singular ring and makes it the current ring.
INPUT:
- ``char`` - characteristic of the base ring (see examples below), which must be either 0, prime (!), or one of several special codes (see examples below).
- ``vars`` - a tuple or string that defines the variable names
- ``order`` - string - the monomial order (default: 'lp')
- ``check`` - if True, check primality of the characteristic if it is an integer.
OUTPUT: a Singular ring
.. note::
This function is *not* identical to calling the Singular ``ring`` function. In particular, it also attempts to "kill" the variable names, so they can actually be used without getting errors, and it sets printing of elements for this range to short (i.e., with \*'s and carets).
EXAMPLES: We first declare `\QQ[x,y,z]` with degree reverse lexicographic ordering.
::
sage: R = singular.ring(0, '(x,y,z)', 'dp') sage: R polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 3 // block 1 : ordering dp // : names x y z // block 2 : ordering C
::
sage: R1 = singular.ring(32003, '(x,y,z)', 'dp') sage: R2 = singular.ring(32003, '(a,b,c,d)', 'lp')
This is a ring in variables named x(1) through x(10) over the finite field of order `7`::
sage: R3 = singular.ring(7, '(x(1..10))', 'ds')
This is a polynomial ring over the transcendental extension `\QQ(a)` of `\QQ`::
sage: R4 = singular.ring('(0,a)', '(mu,nu)', 'lp')
This is a ring over the field of single-precision floats::
sage: R5 = singular.ring('real', '(a,b)', 'lp')
This is over 50-digit floats::
sage: R6 = singular.ring('(real,50)', '(a,b)', 'lp') sage: R7 = singular.ring('(complex,50,i)', '(a,b)', 'lp')
To use a ring that you've defined, use the set_ring() method on the ring. This sets the ring to be the "current ring". For example,
::
sage: R = singular.ring(7, '(a,b)', 'ds') sage: S = singular.ring('real', '(a,b)', 'lp') sage: singular.new('10*a') (1.000e+01)*a sage: R.set_ring() sage: singular.new('10*a') 3*a """ for x in vars[1:-1].split(',')])
raise ValueError("the characteristic must be 0 or prime")
def string(self, x): """ Creates a Singular string from a Sage string. Note that the Sage string has to be "double-quoted".
EXAMPLES::
sage: singular.string('"Sage"') Sage """
def set_ring(self, R): """ Sets the current Singular ring to R.
EXAMPLES::
sage: R = singular.ring(7, '(a,b)', 'ds') sage: S = singular.ring('real', '(a,b)', 'lp') sage: singular.current_ring() polynomial ring, over a field, global ordering // coefficients: float // number of vars : 2 // block 1 : ordering lp // : names a b // block 2 : ordering C sage: singular.set_ring(R) sage: singular.current_ring() polynomial ring, over a field, local ordering // coefficients: ZZ/7 // number of vars : 2 // block 1 : ordering ds // : names a b // block 2 : ordering C """ raise TypeError("R must be a singular ring")
setring = set_ring
def current_ring_name(self): """ Returns the Singular name of the currently active ring in Singular.
OUTPUT: currently active ring's name
EXAMPLES::
sage: r = PolynomialRing(GF(127),3,'xyz') sage: r._singular_().name() == singular.current_ring_name() True """ return None
def current_ring(self): """ Returns the current ring of the running Singular session.
EXAMPLES::
sage: r = PolynomialRing(GF(127),3,'xyz', order='invlex') sage: r._singular_() polynomial ring, over a field, global ordering // coefficients: ZZ/127 // number of vars : 3 // block 1 : ordering rp // : names x y z // block 2 : ordering C sage: singular.current_ring() polynomial ring, over a field, global ordering // coefficients: ZZ/127 // number of vars : 3 // block 1 : ordering rp // : names x y z // block 2 : ordering C """ else: return None
def _tab_completion(self): """ Return a list of all Singular commands.
EXAMPLES::
sage: singular._tab_completion() ['exteriorPower', ... 'flintZ'] """
def console(self): """ EXAMPLES::
sage: singular_console() #not tested SINGULAR / Development A Computer Algebra System for Polynomial Computations / version 3-0-4 0< by: G.-M. Greuel, G. Pfister, H. Schoenemann \ Nov 2007 FB Mathematik der Universitaet, D-67653 Kaiserslautern \ """ singular_console()
def version(self): """ Return the version of Singular being used.
EXAMPLES::
sage: singular.version() "Singular ... version 4.1.0 ... """
def _function_class(self): """ EXAMPLES::
sage: singular._function_class() <class 'sage.interfaces.singular.SingularFunction'> """
def _function_element_class(self): """ EXAMPLES::
sage: singular._function_element_class() <class 'sage.interfaces.singular.SingularFunctionElement'> """
def option(self, cmd=None, val=None): """ Access to Singular's options as follows:
Syntax: option() Returns a string of all defined options.
Syntax: option( 'option_name' ) Sets an option. Note to disable an option, use the prefix no.
Syntax: option( 'get' ) Returns an intvec of the state of all options.
Syntax: option( 'set', intvec_expression ) Restores the state of all options from an intvec (produced by option('get')).
EXAMPLES::
sage: singular.option() //options: redefine loadLib usage prompt sage: singular.option('get') 0, 10321 sage: old_options = _ sage: singular.option('noredefine') sage: singular.option() //options: loadLib usage prompt sage: singular.option('set', old_options) sage: singular.option('get') 0, 10321 """ #return SingularFunction(self,"option")("\"get\"") raise TypeError("singular.option('set') needs SingularElement as second parameter") #SingularFunction(self,"option")("\"set\"",val) else:
def _keyboard_interrupt(self): print("Interrupting %s..." % self) try: self._expect.sendline(chr(4)) except pexpect.ExceptionPexpect as msg: raise pexpect.ExceptionPexpect("THIS IS A BUG -- PLEASE REPORT. This should never happen.\n" + msg) self._start() raise KeyboardInterrupt("Restarting %s (WARNING: all variables defined in previous session are now invalid)" % self)
@instancedoc class SingularElement(ExtraTabCompletion, ExpectElement):
def __init__(self, parent, type, value, is_name=False): """ EXAMPLES::
sage: a = singular(2) sage: loads(dumps(a)) 2 """ # Convert SingularError to TypeError for # coercion to work properly. except BaseException: self._session_number = -1 raise else:
def _repr_(self): r""" Return string representation of ``self``.
EXAMPLES::
sage: r = singular.ring(0,'(x,y)','dp') sage: singular(0) 0 sage: singular('x') # indirect doctest x sage: singular.matrix(2,2) 0,0, 0,0 sage: singular.matrix(2,2,"(25/47*x^2*y^4 + 63/127*x + 27)^3,y,0,1") 15625/103823*x^6*y.., y, 0, 1
Note that the output is truncated, and if ``self`` has a custom name then it is used to print the items of the matrix, rather than abbreviating its contents::
sage: M = singular.matrix(2,2,"(25/47*x^2*y^4 + 63/127*x + 27)^3,y,0,1") sage: M.rename('T') sage: M T[1,1],y, 0, 1
"""
def __copy__(self): r""" Returns a copy of ``self``.
EXAMPLES::
sage: R=singular.ring(0,'(x,y)','dp') sage: M=singular.matrix(3,3,'0,0,-x, 0,y,0, x*y,0,0') sage: N=copy(M) sage: N[1,1]=singular('x+y') sage: N x+y,0,-x, 0, y,0, x*y,0,0 sage: M 0, 0,-x, 0, y,0, x*y,0,0 sage: L=R.ringlist() sage: L[4]=singular.ideal('x**2-5') sage: Q=L.ring() sage: otherR=singular.ring(5,'(x)','dp') sage: cpQ=copy(Q) sage: cpQ.set_ring() sage: cpQ polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 2 // block 1 : ordering dp // : names x y // block 2 : ordering C // quotient ring from ideal _[1]=x^2-5 sage: R.fetch(M) 0, 0,-x, 0, y,0, x*y,0,0 """ # Problem: singular has no clean method to produce # a copy of a ring/qring. We use ringlist, but this # is only possible if we make self the active ring, # use ringlist, and switch back to the previous # base ring. else:
def __len__(self): """ Returns the size of this Singular element.
EXAMPLES::
sage: R = singular.ring(0, '(x,y,z)', 'dp') sage: A = singular.matrix(2,2) sage: len(A) 4 """
def __setitem__(self, n, value): """ Set the n-th element of self to x.
INPUT:
- ``n`` - an integer *or* a 2-tuple (for setting matrix elements)
- ``value`` - anything (is coerced to a Singular object if it is not one already)
OUTPUT: Changes elements of self.
EXAMPLES::
sage: R = singular.ring(0, '(x,y,z)', 'dp') sage: A = singular.matrix(2,2) sage: A 0,0, 0,0 sage: A[1,1] = 5 sage: A 5,0, 0,0 sage: A[1,2] = '5*x + y + z3' sage: A 5,z^3+5*x+y, 0,0 """ raise ValueError("If n (=%s) is a tuple, it must be a 2-tuple"%n) else:
def __bool__(self): """ Returns ``True`` if this Singular element is not zero.
EXAMPLES::
sage: bool(singular(0)) False sage: bool(singular(1)) True """
__nonzero__ = __bool__
def sage_polystring(self): r""" If this Singular element is a polynomial, return a string representation of this polynomial that is suitable for evaluation in Python. Thus \* is used for multiplication and \*\* for exponentiation. This function is primarily used internally.
The short=0 option *must* be set for the parent ring or this function will not work as expected. This option is set by default for rings created using ``singular.ring`` or set using ``ring_name.set_ring()``.
EXAMPLES::
sage: R = singular.ring(0,'(x,y)') sage: f = singular('x^3 + 3*y^11 + 5') sage: f x^3+3*y^11+5 sage: f.sage_polystring() 'x**3+3*y**11+5' """
def sage_global_ring(self): """ Return the current basering in Singular as a polynomial ring or quotient ring.
EXAMPLES::
sage: singular.eval('ring r1 = (9,x),(a,b,c,d,e,f),(M((1,2,3,0)),wp(2,3),lp)') '' sage: R = singular('r1').sage_global_ring() sage: R Multivariate Polynomial Ring in a, b, c, d, e, f over Finite Field in x of size 3^2 sage: R.term_order() Block term order with blocks: (Matrix term order with matrix [1 2] [3 0], Weighted degree reverse lexicographic term order with weights (2, 3), Lexicographic term order of length 2)
::
sage: singular.eval('ring r2 = (0,x),(a,b,c),dp') '' sage: singular('r2').sage_global_ring() Multivariate Polynomial Ring in a, b, c over Fraction Field of Univariate Polynomial Ring in x over Rational Field
::
sage: singular.eval('ring r3 = (3,z),(a,b,c),dp') '' sage: singular.eval('minpoly = 1+z+z2+z3+z4') '' sage: singular('r3').sage_global_ring() Multivariate Polynomial Ring in a, b, c over Finite Field in z of size 3^4
Real and complex fields in both Singular and Sage are defined with a precision. The precision in Singular is given in terms of digits, but in Sage it is given in terms of bits. So, the digit precision is internally converted to a reasonable bit precision::
sage: singular.eval('ring r4 = (real,20),(a,b,c),dp') '' sage: singular('r4').sage_global_ring() Multivariate Polynomial Ring in a, b, c over Real Field with 70 bits of precision
The case of complex coefficients is not fully supported, yet, since the generator of a complex field in Sage is always called "I"::
sage: singular.eval('ring r5 = (complex,15,j),(a,b,c),dp') '' sage: R = singular('r5').sage_global_ring(); R Multivariate Polynomial Ring in a, b, c over Complex Field with 54 bits of precision sage: R.base_ring()('j') Traceback (most recent call last): ... NameError: name 'j' is not defined sage: R.base_ring()('I') 1.00000000000000*I
An example where the base ring is a polynomial ring over an extension of the rational field::
sage: singular.eval('ring r7 = (0,a), (x,y), dp') '' sage: singular.eval('minpoly = a2 + 1') '' sage: singular('r7').sage_global_ring() Multivariate Polynomial Ring in x, y over Number Field in a with defining polynomial a^2 + 1
In our last example, the base ring is a quotient ring::
sage: singular.eval('ring r6 = (9,a), (x,y,z),lp') '' sage: Q = singular('std(ideal(x^2,x+y^2+z^3))', type='qring') sage: Q.sage_global_ring() 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)
AUTHOR:
- Simon King (2011-06-06)
""" # extract the ring of coefficients else: # it ought to be a finite field else: # Singular has no extension of a non-prime field
# We have the base ring of the base ring. But is it # an extension? else: else: else:
# Now, we form the polynomial ring over BR with the given variables, # using Singular's term order # Meanwhile Singulars quotient rings are also of 'ring' type, not 'qring' as it was in the past. # To find out if a singular ring is a quotient ring or not checking for ring type does not help # and instead of that we check if the quotient ring is zero or not:
def sage_poly(self, R=None, kcache=None): """ Returns a Sage polynomial in the ring r matching the provided poly which is a singular polynomial.
INPUT:
- ``R`` - (default: None); an optional polynomial ring. If it is provided, then you have to make sure that it matches the current singular ring as, e.g., returned by singular.current_ring(). By default, the output of :meth:`sage_global_ring` is used.
- ``kcache`` - (default: None); an optional dictionary for faster finite field lookups, this is mainly useful for finite extension fields
OUTPUT: MPolynomial
EXAMPLES::
sage: R = PolynomialRing(GF(2^8,'a'), 'x,y') sage: f = R('a^20*x^2*y+a^10+x') sage: f._singular_().sage_poly(R) == f True sage: R = PolynomialRing(GF(2^8,'a'), 'x', implementation="singular") sage: f = R('a^20*x^3+x^2+a^10') sage: f._singular_().sage_poly(R) == f True
::
sage: P.<x,y> = PolynomialRing(QQ, 2) sage: f = x*y**3 - 1/9 * x + 1; f x*y^3 - 1/9*x + 1 sage: singular(f) x*y^3-1/9*x+1 sage: P(singular(f)) x*y^3 - 1/9*x + 1
TESTS::
sage: singular.eval('ring r = (3,z),(a,b,c),dp') '' sage: singular.eval('minpoly = 1+z+z2+z3+z4') '' sage: p = singular('z^4*a^3+z^2*a*b*c') sage: p.sage_poly() (-z^3 - z^2 - z - 1)*a^3 + (z^2)*a*b*c sage: singular('z^4') (-z3-z2-z-1)
AUTHORS:
- Martin Albrecht (2006-05-18) - Simon King (2011-06-06): Deal with Singular's short polynomial representation, automatic construction of a polynomial ring, if it is not explicitly given.
.. note::
For very simple polynomials ``eval(SingularElement.sage_polystring())`` is faster than SingularElement.sage_poly(R), maybe we should detect the crossover point (in dependence of the string length) and choose an appropriate conversion strategy """ # TODO: Refactor imports to move this to the top
# This returns a string which looks like a list where the first # half of the list is filled with monomials occurring in the # Singular polynomial and the second half filled with the matching # coefficients. # # Our strategy is to split the monomials at "*" to get the powers # in the single variables and then to split the result to get # actual exponent. # # So e.g. ['x^3*y^3','a'] get's split to # [[['x','3'],['y','3']],'a']. We may do this quickly, # as we know what to expect.
singular_poly_list = self.parent().eval("string(coef(%s,%s))"%(\ self.name(),variable_str)).split(",") self.parent().eval('short=%s'%is_short) else: self.name(),variable_str)).split(",")
# Directly treat constants
# Singular 4 puts parentheses around floats and sign outside them
# we need to lookup the index of a given variable represented # through a string
else:
else: elem = singular_poly_list[coeff_start+i] if elem not in kcache: kcache[elem] = k( elem ) sage_repr[ETuple(exp,ngens)]= kcache[elem]
else:
else:
else: elem = singular_poly_list[coeff_start+i] if elem not in kcache: kcache[elem] = k( elem ) sage_repr[ exp ]= kcache[elem]
else: raise TypeError("Cannot coerce %s into %s"%(self,R))
def sage_matrix(self, R, sparse=True): """ Returns Sage matrix for self
INPUT:
- ``R`` - (default: None); an optional ring, over which the resulting matrix is going to be defined. By default, the output of :meth:`sage_global_ring` is used.
- ``sparse`` - (default: True); determines whether the resulting matrix is sparse or not.
EXAMPLES::
sage: R = singular.ring(0, '(x,y,z)', 'dp') sage: A = singular.matrix(2,2) sage: A.sage_matrix(ZZ) [0 0] [0 0] sage: A.sage_matrix(RDF) [0.0 0.0] [0.0 0.0] """
#this is slow
#this is slow
def _sage_(self, R=None): r""" Convert self to Sage.
EXAMPLES::
sage: R = singular.ring(0, '(x,y,z)', 'dp') sage: A = singular.matrix(2,2) sage: A.sage(ZZ) # indirect doctest [0 0] [0 0] sage: A = random_matrix(ZZ,3,3); A [ -8 2 0] [ 0 1 -1] [ 2 1 -95] sage: As = singular(A); As -8 2 0 0 1 -1 2 1 -95 sage: As.sage() [ -8 2 0] [ 0 1 -1] [ 2 1 -95]
::
sage: singular.eval('ring R = integer, (x,y,z),lp') '// ** redefining R (ring R = integer, (x,y,z),lp;)' sage: I = singular.ideal(['x^2','y*z','z+x']) sage: I.sage() Ideal (x^2, y*z, x + z) of Multivariate Polynomial Ring in x, y, z over Integer Ring
::
sage: singular('ringlist(basering)').sage() [['integer'], ['x', 'y', 'z'], [['lp', (1, 1, 1)], ['C', (0)]], Ideal (0) of Multivariate Polynomial Ring in x, y, z over Integer Ring]
::
sage: singular.eval('ring r10 = (9,a), (x,y,z),lp') '' sage: singular.eval('setring R') '' sage: singular('r10').sage() Multivariate Polynomial Ring in x, y, z over Finite Field in a of size 3^2
Note that the current base ring has not been changed by asking for another ring::
sage: singular('basering') polynomial ring, over a domain, global ordering // coefficients: ZZ // number of vars : 3 // block 1 : ordering lp // : names x y z // block 2 : ordering C
::
sage: singular.eval('setring r10') '' sage: Q = singular('std(ideal(x^2,x+y^2+z^3))', type='qring') sage: Q.sage() 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) sage: singular('x^2+y').sage() x^2 + y sage: singular('x^2+y').sage().parent() 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)
Test that :trac:`18848` is fixed::
sage: singular(5).sage() 5 sage: type(singular(int(5)).sage()) <type 'sage.rings.integer.Integer'>
""" raise NotImplementedError("Coercion of this datatype not implemented yet")
def is_string(self): """ Tell whether this element is a string.
EXAMPLES::
sage: singular('"abc"').is_string() True sage: singular('1').is_string() False
"""
def set_ring(self): """ Sets the current ring in Singular to be self.
EXAMPLES::
sage: R = singular.ring(7, '(a,b)', 'ds') sage: S = singular.ring('real', '(a,b)', 'lp') sage: singular.current_ring() polynomial ring, over a field, global ordering // coefficients: float // number of vars : 2 // block 1 : ordering lp // : names a b // block 2 : ordering C sage: R.set_ring() sage: singular.current_ring() polynomial ring, over a field, local ordering // coefficients: ZZ/7 // number of vars : 2 // block 1 : ordering ds // : names a b // block 2 : ordering C """
def sage_flattened_str_list(self): """ EXAMPLES::
sage: R=singular.ring(0,'(x,y)','dp') sage: RL = R.ringlist() sage: RL.sage_flattened_str_list() ['0', 'x', 'y', 'dp', '1,1', 'C', '0', '_[1]=0'] """
def sage_structured_str_list(self): r""" If self is a Singular list of lists of Singular elements, returns corresponding Sage list of lists of strings.
EXAMPLES::
sage: R=singular.ring(0,'(x,y)','dp') sage: RL=R.ringlist() sage: RL [1]: 0 [2]: [1]: x [2]: y [3]: [1]: [1]: dp [2]: 1,1 [2]: [1]: C [2]: 0 [4]: _[1]=0 sage: RL.sage_structured_str_list() ['0', ['x', 'y'], [['dp', '1,\n1'], ['C', '0']], '0'] """
def _tab_completion(self): """ Returns the possible tab-completions for self. In this case, we just return all the tab completions for the Singular object.
EXAMPLES::
sage: R = singular.ring(0,'(x,y)','dp') sage: R._tab_completion() ['exteriorPower', ... 'flintZ'] """
def type(self): """ Returns the internal type of this element.
EXAMPLES::
sage: R = PolynomialRing(GF(2^8,'a'),2,'x') sage: R._singular_().type() 'ring' sage: fs = singular('x0^2','poly') sage: fs.type() 'poly' """ # singular reports // $varname $type $stuff
def __iter__(self): """ EXAMPLES::
sage: R = singular.ring(0, '(x,y,z)', 'dp') sage: A = singular.matrix(2,2) sage: list(iter(A)) [[0], [0]] sage: A[1,1] = 1; A[1,2] = 2 sage: A[2,1] = 3; A[2,2] = 4 sage: list(iter(A)) [[1,3], [2,4]] """ else:
def _singular_(self): """ EXAMPLES::
sage: R = singular.ring(0, '(x,y,z)', 'dp') sage: A = singular.matrix(2,2) sage: A._singular_() is A True """
def attrib(self, name, value=None): """ Get and set attributes for self.
INPUT:
- ``name`` - string to choose the attribute
- ``value`` - boolean value or None for reading, (default:None)
VALUES: isSB - the standard basis property is set by all commands computing a standard basis like groebner, std, stdhilb etc.; used by lift, dim, degree, mult, hilb, vdim, kbase isHomog - the weight vector for homogeneous or quasihomogeneous ideals/modules isCI - complete intersection property isCM - Cohen-Macaulay property rank - set the rank of a module (see nrows) withSB - value of type ideal, resp. module, is std withHilb - value of type intvec is hilb(_,1) (see hilb) withRes - value of type list is a free resolution withDim - value of type int is the dimension (see dim) withMult - value of type int is the multiplicity (see mult)
EXAMPLES::
sage: P.<x,y,z> = PolynomialRing(QQ) sage: I = Ideal([z^2, y*z, y^2, x*z, x*y, x^2]) sage: Ibar = I._singular_() sage: Ibar.attrib('isSB') 0 sage: singular.eval('vdim(%s)'%Ibar.name()) # sage7 name is random // ** sage7 is no standard basis 4 sage: Ibar.attrib('isSB',1) sage: singular.eval('vdim(%s)'%Ibar.name()) '4' """ else:
@instancedoc class SingularFunction(ExpectFunction): def _instancedoc_(self): """ EXAMPLES::
sage: 'groebner' in singular.groebner.__doc__ True """
""" This function is an automatically generated pexpect wrapper around the Singular function '%s'.
EXAMPLES::
sage: groebner = singular.groebner sage: P.<x, y> = PolynomialRing(QQ) sage: I = P.ideal(x^2-y, y+x) sage: groebner(singular(I)) x+y, y^2-y """%(self._name,) """
The Singular documentation for '%s' is given below. """%(self._name,)
except KeyError: return prefix
@instancedoc class SingularFunctionElement(FunctionElement): def _instancedoc_(self): r""" EXAMPLES::
sage: R = singular.ring(0, '(x,y,z)', 'dp') sage: A = singular.matrix(2,2) sage: 'matrix_expression' in A.nrows.__doc__ True """ generate_docstring_dictionary() except KeyError: return ""
def is_SingularElement(x): r""" Returns True is x is of type ``SingularElement``.
EXAMPLES::
sage: from sage.interfaces.singular import is_SingularElement sage: is_SingularElement(singular(2)) True sage: is_SingularElement(2) False """
nodes = {} node_names = {}
def generate_docstring_dictionary(): """ Generate global dictionaries which hold the docstrings for Singular functions.
EXAMPLES::
sage: from sage.interfaces.singular import generate_docstring_dictionary sage: generate_docstring_dictionary() """
global nodes global node_names
# a new node starts else:
def get_docstring(name): """ Return the docstring for the function ``name``.
INPUT:
- ``name`` - a Singular function name
EXAMPLES::
sage: from sage.interfaces.singular import get_docstring sage: 'groebner' in get_docstring('groebner') True sage: 'standard.lib' in get_docstring('groebner') True
""" except KeyError: return ""
##################################
singular = Singular()
def reduce_load_Singular(): """ EXAMPLES::
sage: from sage.interfaces.singular import reduce_load_Singular sage: reduce_load_Singular() Singular """
def singular_console(): """ Spawn a new Singular command-line session.
EXAMPLES::
sage: singular_console() #not tested SINGULAR / Development A Computer Algebra System for Polynomial Computations / version 3-0-4 0< by: G.-M. Greuel, G. Pfister, H. Schoenemann \ Nov 2007 FB Mathematik der Universitaet, D-67653 Kaiserslautern \ """ from sage.repl.rich_output.display_manager import get_display_manager if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%singular magics instead.') os.system('Singular')
def singular_version(): """ Return the version of Singular being used.
EXAMPLES::
sage: singular.version() "Singular ... version 4.1.0 ... """
class SingularGBLogPrettyPrinter: """ A device which prints Singular Groebner basis computation logs more verbatim. """ rng_chng = re.compile("\[\d+:\d+\]")# [m:n] internal ring change to # poly representation with # exponent bound m and n words in # exponent vector new_elem = re.compile("s") # found a new element of the standard basis red_zero = re.compile("-") # reduced a pair/S-polynomial to 0 red_post = re.compile("\.") # postponed a reduction of a pair/S-polynomial cri_hilb = re.compile("h") # used Hilbert series criterion hig_corn = re.compile("H\(\d+\)") # found a 'highest corner' of degree d, no need to consider higher degrees num_crit = re.compile("\(\d+\)") # n critical pairs are still to be reduced red_num = re.compile("\(S:\d+\)") # doing complete reduction of n elements deg_lead = re.compile("\d+") # the degree of the leading terms is currently d
# SlimGB red_para = re.compile("M\[(\d+),(\d+)\]") # parallel reduction of n elements with m non-zero output elements red_betr = re.compile("b") # exchange of a reductor by a 'better' one non_mini = re.compile("e") # a new reductor with non-minimal leading term
crt_lne1 = re.compile("product criterion:(\d+) chain criterion:(\d+)") crt_lne2 = re.compile("NF:(\d+) product criterion:(\d+), ext_product criterion:(\d+)")
pat_sync = re.compile("1\+(\d+);")
global_pattern = re.compile("(\[\d+:\d+\]|s|-|\.|h|H\(\d+\)|\(\d+\)|\(S:\d+\)|\d+|M\[\d+,[b,e]*\d+\]|b|e).*")
def __init__(self, verbosity=1): """ Construct a new Singular Groebner Basis log pretty printer.
INPUT:
- ``verbosity`` - how much information should be printed (between 0 and 3)
EXAMPLES::
sage: from sage.interfaces.singular import SingularGBLogPrettyPrinter sage: s0 = SingularGBLogPrettyPrinter(verbosity=0) sage: s1 = SingularGBLogPrettyPrinter(verbosity=1) sage: s0.write("[1:2]12")
sage: s1.write("[1:2]12") Leading term degree: 12. """
def write(self, s): """ EXAMPLES::
sage: from sage.interfaces.singular import SingularGBLogPrettyPrinter sage: s3 = SingularGBLogPrettyPrinter(verbosity=3) sage: s3.write("(S:1337)") Performing complete reduction of 1337 elements. sage: s3.write("M[389,12]") Parallel reduction of 389 elements with 12 non-zero output elements. """
s = self.storage + s self.storage = ""
# deal with the Sage <-> Singular syncing code self.sync = int(match.groups()[0]) continue
self.sync = None continue
continue continue
continue
# collect stats returned about avoided reductions to zero self.prod,self.chain = map(int,re.match(SingularGBLogPrettyPrinter.crt_lne1,line).groups()) self.storage = "" continue self.nf,self.prod,self.ext_prod = map(int,re.match(SingularGBLogPrettyPrinter.crt_lne2,line).groups()) self.storage = "" continue
self.storage = line line = None continue
print("New element found.")
print("Reduction to zero.")
print("Reduction postponed.")
print("Hilber series criterion applied.")
print("Maximal degree found: %s" % token)
print("Leading term degree: %2d. Critical pairs: %s."%(self.curr_deg,token[1:-1]))
elif re.match(SingularGBLogPrettyPrinter.red_betr, token) and verbosity >= 3: print("Replaced reductor by 'better' one.")
elif re.match(SingularGBLogPrettyPrinter.non_mini, token) and verbosity >= 2: print("New reductor with non-minimal leading term found.")
def flush(self): """ EXAMPLES::
sage: from sage.interfaces.singular import SingularGBLogPrettyPrinter sage: s3 = SingularGBLogPrettyPrinter(verbosity=3) sage: s3.flush() """
class SingularGBDefaultContext: """ Within this context all Singular Groebner basis calculations are reduced automatically.
AUTHORS:
- Martin Albrecht - Simon King """ def __init__(self, singular=None): """ Within this context all Singular Groebner basis calculations are reduced automatically.
INPUT:
- ``singular`` - Singular instance (default: default instance)
EXAMPLES::
sage: from sage.interfaces.singular import SingularGBDefaultContext sage: P.<a,b,c> = PolynomialRing(QQ,3, order='lex') sage: I = sage.rings.ideal.Katsura(P,3) sage: singular.option('noredTail') sage: singular.option('noredThrough') sage: Is = I._singular_() sage: gb = Is.groebner() sage: gb 84*c^4-40*c^3+c^2+c, 7*b+210*c^3-79*c^2+3*c, a+2*b+2*c-1
::
sage: with SingularGBDefaultContext(): rgb = Is.groebner() sage: rgb 84*c^4-40*c^3+c^2+c, 7*b+210*c^3-79*c^2+3*c, 7*a-420*c^3+158*c^2+8*c-7
Note that both bases are Groebner bases because they have pairwise prime leading monomials but that the monic version of the last element in ``rgb`` is smaller than the last element of ``gb`` with respect to the lexicographical term ordering. ::
sage: (7*a-420*c^3+158*c^2+8*c-7)/7 < (a+2*b+2*c-1) True
.. note::
This context is used automatically internally whenever a Groebner basis is computed so the user does not need to use it manually. """
def __enter__(self): """ EXAMPLES::
sage: from sage.interfaces.singular import SingularGBDefaultContext sage: P.<a,b,c> = PolynomialRing(QQ,3, order='lex') sage: I = sage.rings.ideal.Katsura(P,3) sage: singular.option('noredTail') sage: singular.option('noredThrough') sage: Is = I._singular_() sage: with SingularGBDefaultContext(): rgb = Is.groebner() sage: rgb 84*c^4-40*c^3+c^2+c, 7*b+210*c^3-79*c^2+3*c, 7*a-420*c^3+158*c^2+8*c-7 """
def __exit__(self, typ, value, tb): """ EXAMPLES::
sage: from sage.interfaces.singular import SingularGBDefaultContext sage: P.<a,b,c> = PolynomialRing(QQ,3, order='lex') sage: I = sage.rings.ideal.Katsura(P,3) sage: singular.option('noredTail') sage: singular.option('noredThrough') sage: Is = I._singular_() sage: with SingularGBDefaultContext(): rgb = Is.groebner() sage: rgb 84*c^4-40*c^3+c^2+c, 7*b+210*c^3-79*c^2+3*c, 7*a-420*c^3+158*c^2+8*c-7 """
def singular_gb_standard_options(func): r""" Decorator to force a reduced Singular groebner basis.
TESTS::
sage: P.<a,b,c,d,e> = PolynomialRing(GF(127)) sage: J = sage.rings.ideal.Cyclic(P).homogenize() sage: from sage.misc.sageinspect import sage_getsource sage: "basis" in sage_getsource(J.interreduced_basis) #indirect doctest True
The following tests against a bug that was fixed in :trac:`11298`::
sage: from sage.misc.sageinspect import sage_getsourcelines, sage_getargspec sage: P.<x,y> = QQ[] sage: I = P*[x,y] sage: sage_getargspec(I.interreduced_basis) ArgSpec(args=['self'], varargs=None, keywords=None, defaults=None) sage: sage_getsourcelines(I.interreduced_basis) ([' @singular_gb_standard_options\n', ' @libsingular_gb_standard_options\n', ' def interreduced_basis(self):\n', ' ... ' return self.basis.reduced()\n'], ...)
.. note::
This decorator is used automatically internally so the user does not need to use it manually. """ from sage.misc.decorators import sage_wraps @sage_wraps(func) def wrapper(*args, **kwds): return wrapper |