Ticket #10571: trac_10571.patch

File trac_10571.patch, 36.8 KB (added by malb, 11 years ago)
  • sage/interfaces/expect.py

    # HG changeset patch
    # User Martin Albrecht <martinralbrecht@googlemail.com>
    # Date 1294913836 0
    # Node ID 1ed2892e171225a58b42e834de3b0e108c697f7e
    # Parent  f43f11d9444eaaaa093257d6a83efb9d011fd1db
    print Groebner basis computation protocols for Singular and Magma (#10571)
    
    diff -r f43f11d9444e -r 1ed2892e1712 sage/interfaces/expect.py
    a b  
    3737from __future__ import with_statement
    3838
    3939import os
     40import sys
    4041import weakref
    4142import time
    4243import gc
     
    6667
    6768from sage.misc.misc import SAGE_ROOT, verbose, SAGE_TMP_INTERFACE, LOCAL_IDENTIFIER
    6869from sage.structure.element import RingElement
     70
     71from sage.misc.object_multiplexer import Multiplex
     72
    6973BAD_SESSION = -2
    7074
    7175failed_to_start = []
     
    20062010        return self._operation("^", n)
    20072011
    20082012
     2013class StdOutContext:
     2014    """
     2015    A context in which all communation between Sage and a subprocess
     2016    interfaced via pexpect is printed to stdout.
     2017    """
     2018    def __init__(self, interface, silent=False, stdout=None):
     2019        """
     2020        Construct a new context in which all communation between Sage
     2021        and a subprocess interfaced via pexpect is printed to stdout.
     2022
     2023        INPUT:
     2024
     2025        - ``interface`` - the interface whose communcation shall be dumped.
     2026
     2027        - ``silent`` - if ``True`` this context does nothing
     2028
     2029        - ``stdout`` - optional parameter for alternative stdout device (default: ``None``)
     2030
     2031        EXAMPLE::
     2032       
     2033            sage: from sage.interfaces.expect import StdOutContext
     2034            sage: with StdOutContext(gp):
     2035            ...       gp('1+1')
     2036            ...
     2037            sage[...
     2038        """
     2039        self.interface = interface
     2040        self.silent = silent
     2041        self.stdout = stdout if stdout else sys.stdout
     2042
     2043    def __enter__(self):
     2044        """
     2045        EXAMPLE::
     2046       
     2047            sage: from sage.interfaces.expect import StdOutContext
     2048            sage: with StdOutContext(singular):
     2049            ...       singular('1+1')
     2050            ...
     2051            1+...
     2052        """
     2053        if self.silent:
     2054            return
     2055        if self.interface._expect is None:
     2056            self.interface._start()
     2057        self._logfile_backup = self.interface._expect.logfile
     2058        if self.interface._expect.logfile:
     2059            self.interface._expect.logfile = Multiplex(self.interface._expect.logfile, self.stdout)
     2060        else:
     2061            self.interface._expect.logfile = Multiplex(self.stdout)
     2062           
     2063    def __exit__(self, typ, value, tb):
     2064        """
     2065        EXAMPLE::
     2066       
     2067            sage: from sage.interfaces.expect import StdOutContext
     2068            sage: with StdOutContext(gap):
     2069            ...       gap('1+1')
     2070            ...
     2071            $sage...
     2072        """
     2073        if self.silent:
     2074            return
     2075        self.interface._expect.logfile.flush()
     2076        self.stdout.write("\n")
     2077        self.interface._expect.logfile = self._logfile_backup
     2078
    20092079def reduce_load(parent, x):
    20102080    return parent(x)
    20112081
  • sage/interfaces/magma.py

    diff -r f43f11d9444e -r 1ed2892e1712 sage/interfaces/magma.py
    a b  
    26512651    """
    26522652    t = tuple([int(n) for n in magma.eval('GetVersion()').split()])
    26532653    return t, 'V%s.%s-%s'%t
     2654
     2655class MagmaGBLogPrettyPrinter:
     2656    """
     2657    A device which filters Magma Groebner basis computation logs.
     2658    """
     2659    cmd_inpt = re.compile("^>>>$")
     2660    app_inpt = re.compile("^Append\(~_sage_, 0\);$")
     2661
     2662    deg_curr = re.compile("^Basis length\: (\d+), queue length\: (\d+), step degree\: (\d+), num pairs\: (\d+)$")
     2663    pol_curr = re.compile("^Number of pair polynomials\: (\d+), at (\d+) column\(s\), .*")
     2664
     2665    def __init__(self, verbosity=1, style='magma'):
     2666        """
     2667        Construct a new Magma Groebner Basis log pretty printer.
     2668
     2669        INPUT:
     2670
     2671        - ``verbosity`` - how much information should be printed
     2672          (between 0 and 1)
     2673
     2674        - ``style`` - if "magma" the full Magma log is printed; if
     2675          'sage' only the current degree and the number of pairs in
     2676          the queue is printed (default: "magma").
     2677
     2678        EXAMPLE::
     2679
     2680            sage: P.<x,y,z> = GF(32003)[]
     2681            sage: I = sage.rings.ideal.Cyclic(P)
     2682            sage: _ = I.groebner_basis('magma',prot='sage') # indirect doctest, optional - magma, not tested
     2683           
     2684            Leading term degree:  2. Critical pairs: 2.
     2685            Leading term degree:  3. Critical pairs: 1.
     2686
     2687            Highest degree reached during computation:  3.
     2688
     2689            sage: P.<x,y,z> = GF(32003)[]
     2690            sage: I = sage.rings.ideal.Cyclic(P)
     2691            sage: _ = I.groebner_basis('magma',prot=True) # indirect doctest, optional - magma, not tested
     2692
     2693            Homogeneous weights search
     2694            Number of variables: 3, nullity: 1
     2695            Exact search time: 0.000
     2696            ********************
     2697            FAUGERE F4 ALGORITHM
     2698            ********************
     2699            Coefficient ring: GF(32003)
     2700            Rank: 3
     2701            Order: Graded Reverse Lexicographical
     2702            NEW hash table
     2703            Matrix kind: Modular FP
     2704            Datum size: 4
     2705            No queue sort
     2706            Initial length: 3
     2707            Inhomogeneous
     2708           
     2709            Initial queue setup time: 0.000
     2710            Initial queue length: 2
     2711           
     2712            *******
     2713            STEP 1
     2714            Basis length: 3, queue length: 2, step degree: 2, num pairs: 1
     2715            Basis total mons: 8, average length: 2.667
     2716            Number of pair polynomials: 1, at 4 column(s), 0.000
     2717            ...
     2718            Total Faugere F4 time: 0.000, real time: 0.000
     2719           
     2720            sage: set_random_seed(1)
     2721            sage: sr = mq.SR(1,1,2,4)
     2722            sage: F,s = sr.polynomial_system()
     2723            sage: I = F.ideal()
     2724            sage: _ = I.groebner_basis('magma',prot='sage') # indirect doctest, optional - magma, not tested
     2725            Leading term degree:  1. Critical pairs: 40.
     2726            Leading term degree:  2. Critical pairs: 40.
     2727            Leading term degree:  3. Critical pairs: 38.
     2728            Leading term degree:  2. Critical pairs: 327.
     2729            Leading term degree:  2. Critical pairs: 450.
     2730            Leading term degree:  2. Critical pairs: 416.
     2731            Leading term degree:  3. Critical pairs: 415.
     2732            Leading term degree:  4. Critical pairs: 98 (all pairs of current degree eliminated by criteria).
     2733            Leading term degree:  5. Critical pairs: 3 (all pairs of current degree eliminated by criteria).
     2734           
     2735            Highest degree reached during computation:  3.
     2736        """
     2737        self.verbosity = verbosity
     2738        self.style = style
     2739
     2740        self.curr_deg = 0 # current degree
     2741        self.curr_npairs = 0 # current number of pairs to be considered
     2742        self.max_deg = 0  # maximal degree in total
     2743
     2744        self.storage = "" # stores incomplete strings
     2745        self.sync = None # should we expect a sync integer?
     2746
     2747    def write(self, s):
     2748        """
     2749        EXAMPLE::
     2750
     2751            sage: P.<x,y,z> = GF(32003)[]
     2752            sage: I = sage.rings.ideal.Katsura(P)
     2753            sage: _ = I.groebner_basis('magma',prot=True) # indirect doctest, optional - magma
     2754           
     2755            Homogeneous weights search
     2756            Number of variables: 3, nullity: 0
     2757            Exact search time: 0.000
     2758            Found best approx weight vector: [1 1 1]
     2759            Norm: 3, count: 1
     2760            Approx search time: 0.000
     2761            ********************
     2762            FAUGERE F4 ALGORITHM
     2763            ********************
     2764            ...
     2765            Total Faugere F4 time: 0.000, real time: 0.001
     2766        """
     2767        verbosity,style = self.verbosity,self.style
     2768
     2769        if self.storage:
     2770            s = self.storage + s
     2771            self.storage = ""
     2772
     2773        for line in s.splitlines():
     2774            #print "l: '%s'"%line
     2775            # deal with the Sage <-> Magma syncing code
     2776            match = re.match(MagmaGBLogPrettyPrinter.cmd_inpt,line)
     2777            if match:
     2778                self.sync = 1
     2779                continue
     2780
     2781            if self.sync:
     2782                if self.sync == 1:
     2783                    self.sync = line
     2784                    continue
     2785                else:
     2786                    if line == '':
     2787                        continue                   
     2788                    self.sync = None
     2789                    continue
     2790           
     2791            if re.match(MagmaGBLogPrettyPrinter.app_inpt,line):
     2792                continue
     2793
     2794            if re.match(MagmaGBLogPrettyPrinter.deg_curr,line):
     2795                match = re.match(MagmaGBLogPrettyPrinter.deg_curr,line)
     2796
     2797                nbasis,npairs,deg,npairs_deg = map(int,match.groups())
     2798
     2799                self.curr_deg = deg
     2800                self.curr_npairs = npairs
     2801               
     2802            if re.match(MagmaGBLogPrettyPrinter.pol_curr,line):
     2803                match = re.match(MagmaGBLogPrettyPrinter.pol_curr,line)
     2804                pol_curr,col_curr = map(int,match.groups())
     2805
     2806                if pol_curr != 0:
     2807                    if self.max_deg < self.curr_deg:
     2808                        self.max_deg = self.curr_deg
     2809
     2810                    if style == "sage" and verbosity >= 1:
     2811                        print "Leading term degree: %2d. Critical pairs: %d."%(self.curr_deg,self.curr_npairs)
     2812                else:
     2813                    if style == "sage" and verbosity >= 1:
     2814                        print "Leading term degree: %2d. Critical pairs: %d (all pairs of current degree eliminated by criteria)."%(self.curr_deg,self.curr_npairs)
     2815
     2816            if style == "magma" and verbosity >= 1:
     2817                print line
     2818
     2819    def flush(self):
     2820        """
     2821        EXAMPLE::
     2822
     2823            sage: from sage.interfaces.magma import MagmaGBLogPrettyPrinter
     2824            sage: logs = MagmaGBLogPrettyPrinter()
     2825            sage: logs.flush()
     2826        """
     2827        import sys
     2828        sys.stdout.flush()
  • sage/interfaces/singular.py

    diff -r f43f11d9444e -r 1ed2892e1712 sage/interfaces/singular.py
    a b  
    19341934
    19351935
    19361936
     1937class SingularGBLogPrettyPrinter:
     1938    """
     1939    A device which prints Singular Groebner basis computation logs
     1940    more verbatim.
     1941    """
     1942    rng_chng = re.compile("\[\d+:\d+\]")# [m:n] internal ring change to
     1943                                        # poly representation with
     1944                                        # exponent bound m and n words in
     1945                                        # exponent vector
     1946    new_elem = re.compile("s")          # found a new element of the standard basis
     1947    red_zero = re.compile("-")          # reduced a pair/S-polynomial to 0
     1948    red_post = re.compile("\.")         # postponed a reduction of a pair/S-polynomial
     1949    cri_hilb = re.compile("h")          # used Hilbert series criterion
     1950    hig_corn = re.compile("H\(\d+\)")   # found a 'highest corner' of degree d, no need to consider higher degrees
     1951    num_crit = re.compile("\(\d+\)")    # n critical pairs are still to be reduced
     1952    red_num =  re.compile("\(S:\d+\)")  # doing complete reduction of n elements
     1953    deg_lead = re.compile("\d+")        # the degree of the leading terms is currently d
     1954
     1955    # SlimGB
     1956    red_para = re.compile("M\[(\d+),(\d+)\]") # parallel reduction of n elements with m non-zero output elements
     1957    red_betr = re.compile("b")                # exchange of a reductor by a 'better' one
     1958    non_mini = re.compile("e")                # a new reductor with non-minimal leading term
     1959
     1960    crt_lne1 = re.compile("product criterion:(\d+) chain criterion:(\d+)")
     1961    crt_lne2 = re.compile("NF:(\d+) product criterion:(\d+), ext_product criterion:(\d+)")
     1962
     1963    pat_sync = re.compile("1\+(\d+);")
     1964
     1965    global_pattern = re.compile("(\[\d+:\d+\]|s|-|\.|h|H\(\d+\)|\(\d+\)|\(S:\d+\)|\d+|M\[\d+,[b,e]*\d+\]|b|e).*")
     1966
     1967    def __init__(self, verbosity=1):
     1968        """
     1969        Construct a new Singular Groebner Basis log pretty printer.
     1970
     1971        INPUT:
     1972
     1973        - ``verbosity`` - how much information should be printed
     1974          (between 0 and 3)
     1975
     1976        EXAMPLE::
     1977
     1978            sage: from sage.interfaces.singular import SingularGBLogPrettyPrinter
     1979            sage: s0 = SingularGBLogPrettyPrinter(verbosity=0)
     1980            sage: s1 = SingularGBLogPrettyPrinter(verbosity=1)
     1981            sage: s0.write("[1:2]12")
     1982
     1983            sage: s1.write("[1:2]12")
     1984            Leading term degree: 12.
     1985        """
     1986        self.verbosity = verbosity
     1987
     1988        self.curr_deg = 0 # current degree
     1989        self.max_deg = 0  # maximal degree in total
     1990
     1991        self.nf = 0 # number of normal forms computed (SlimGB only)
     1992        self.prod = 0 # number of S-polynomials discarded using product criterion
     1993        self.ext_prod = 0 # number of S-polynomials discarded using extended product criterion
     1994        self.chain = 0 # number of S-polynomials discarded using chain criterion
     1995
     1996        self.storage = "" # stores incomplete strings
     1997        self.sync = None # should we expect a sync integer?
     1998
     1999    def write(self, s):
     2000        """
     2001        EXAMPLE::
     2002
     2003            sage: from sage.interfaces.singular import SingularGBLogPrettyPrinter
     2004            sage: s3 = SingularGBLogPrettyPrinter(verbosity=3)
     2005            sage: s3.write("(S:1337)")
     2006            Performing complete reduction of 1337 elements.
     2007            sage: s3.write("M[389,12]")
     2008            Parallel reduction of 389 elements with 12 non-zero output elements.
     2009        """
     2010        verbosity = self.verbosity
     2011
     2012        if self.storage:
     2013            s = self.storage + s
     2014            self.storage = ""
     2015
     2016        for line in s.splitlines():
     2017            # deal with the Sage <-> Singular syncing code
     2018            match = re.match(SingularGBLogPrettyPrinter.pat_sync,line)
     2019            if match:
     2020                self.sync = int(match.groups()[0])
     2021                continue
     2022
     2023            if self.sync and line == "%d"%(self.sync+1):
     2024                self.sync = None
     2025                continue
     2026
     2027            if line.endswith(";"):
     2028                continue
     2029            if line.startswith(">"):
     2030                continue
     2031
     2032            if line.startswith("std") or line.startswith("slimgb"):
     2033                continue
     2034
     2035            # collect stats returned about avoided reductions to zero
     2036            match = re.match(SingularGBLogPrettyPrinter.crt_lne1,line)
     2037            if match:
     2038                self.prod,self.chain = map(int,re.match(SingularGBLogPrettyPrinter.crt_lne1,line).groups())
     2039                self.storage = ""
     2040                continue
     2041            match = re.match(SingularGBLogPrettyPrinter.crt_lne2,line)
     2042            if match:
     2043                self.nf,self.prod,self.ext_prod = map(int,re.match(SingularGBLogPrettyPrinter.crt_lne2,line).groups())
     2044                self.storage = ""
     2045                continue
     2046
     2047            while line:
     2048                match = re.match(SingularGBLogPrettyPrinter.global_pattern, line)
     2049                if not match:
     2050                    self.storage = line
     2051                    line = None
     2052                    continue
     2053
     2054                token, = match.groups()
     2055                line = line[len(token):]
     2056
     2057                if re.match(SingularGBLogPrettyPrinter.rng_chng,token):
     2058                    continue
     2059
     2060                elif re.match(SingularGBLogPrettyPrinter.new_elem,token) and verbosity >= 3:
     2061                    print "New element found."
     2062
     2063                elif re.match(SingularGBLogPrettyPrinter.red_zero,token) and verbosity >= 2:
     2064                    print "Reduction to zero."
     2065
     2066                elif re.match(SingularGBLogPrettyPrinter.red_post, token) and verbosity >= 2:
     2067                    print "Reduction postponed."
     2068
     2069                elif re.match(SingularGBLogPrettyPrinter.cri_hilb, token) and verbosity >= 2:
     2070                    print "Hilber series criterion applied."
     2071
     2072                elif re.match(SingularGBLogPrettyPrinter.hig_corn, token) and verbosity >= 1:
     2073                    print "Maximal degree found: %s"%token
     2074
     2075                elif re.match(SingularGBLogPrettyPrinter.num_crit, token) and verbosity >= 1:
     2076                    print "Leading term degree: %2d. Critical pairs: %s."%(self.curr_deg,token[1:-1])
     2077
     2078                elif re.match(SingularGBLogPrettyPrinter.red_num, token) and verbosity >= 3:
     2079                    print "Performing complete reduction of %s elements."%token[3:-1]
     2080
     2081                elif re.match(SingularGBLogPrettyPrinter.deg_lead, token):
     2082                    if verbosity >= 1:
     2083                        print "Leading term degree: %2d."%int(token)
     2084                    self.curr_deg = int(token)
     2085                    if self.max_deg < self.curr_deg:
     2086                        self.max_deg = self.curr_deg
     2087
     2088                elif re.match(SingularGBLogPrettyPrinter.red_para, token) and verbosity >= 3:
     2089                    m,n = re.match(SingularGBLogPrettyPrinter.red_para,token).groups()
     2090                    print "Parallel reduction of %s elements with %s non-zero output elements."%(m,n)
     2091
     2092                elif re.match(SingularGBLogPrettyPrinter.red_betr, token) and verbosity >= 3:
     2093                    print "Replaced reductor by 'better' one."           
     2094
     2095                elif re.match(SingularGBLogPrettyPrinter.non_mini, token) and verbosity >= 2:
     2096                    print "New reductor with non-minimal leading term found."
     2097
     2098    def flush(self):
     2099        """
     2100        EXAMPLE::
     2101
     2102            sage: from sage.interfaces.singular import SingularGBLogPrettyPrinter
     2103            sage: s3 = SingularGBLogPrettyPrinter(verbosity=3)
     2104            sage: s3.flush()
     2105        """
     2106        import sys
     2107        sys.stdout.flush()
  • new file sage/misc/object_multiplexer.py

    diff -r f43f11d9444e -r 1ed2892e1712 sage/misc/object_multiplexer.py
    - +  
     1"""
     2Multiplex calls to one object to calls to many objects.
     3
     4AUTHORS:
     5
     6- Martin Albrecht (2011): initial version
     7"""
     8
     9#*****************************************************************************
     10#       Copyright (C) 2011 Martin Albrecht <martinralbrecht@googlemail.com>
     11#
     12#  Distributed under the terms of the GNU General Public License (GPL)
     13#
     14#    This code is distributed in the hope that it will be useful,
     15#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17#    General Public License for more details.
     18#
     19#  The full text of the GPL is available at:
     20#
     21#                  http://www.gnu.org/licenses/
     22#*****************************************************************************
     23
     24class MultiplexFunction:
     25    """
     26    A simple wrapper object for functions that are called on a list of
     27    objects.
     28    """
     29    def __init__(self, multiplexer, name):
     30        """
     31        EXAMPLE::
     32
     33            sage: from sage.misc.object_multiplexer import Multiplex, MultiplexFunction
     34            sage: m = Multiplex(1,1/2)
     35            sage: f = MultiplexFunction(m,'str')
     36            sage: f
     37            <sage.misc.object_multiplexer.MultiplexFunction instance at 0x...>
     38        """
     39        self.multiplexer = multiplexer
     40        self.name = name
     41
     42    def __call__(self, *args, **kwds):
     43        """
     44        EXAMPLE::
     45
     46            sage: from sage.misc.object_multiplexer import Multiplex, MultiplexFunction
     47            sage: m = Multiplex(1,1/2)
     48            sage: f = MultiplexFunction(m,'str')
     49            sage: f()
     50            ('1', '1/2')
     51        """
     52        l = []
     53        for child in self.multiplexer.children:
     54            l.append(getattr(child,self.name)(*args, **kwds))
     55        if all(e is None for e in l):
     56            return None
     57        else:
     58            return tuple(l)
     59
     60class Multiplex:
     61    """
     62    Obbject for a list of children such that function calls on this
     63    new objects implies that the same function is called on all
     64    children.
     65    """
     66    def __init__(self, *args):
     67        """
     68        EXAMPLE::
     69
     70            sage: from sage.misc.object_multiplexer import Multiplex
     71            sage: m = Multiplex(1,1/2)
     72            sage: m.str()     
     73            ('1', '1/2')
     74        """
     75        self.children = [arg for arg in args if arg is not None]
     76
     77    def __getattr__(self, name):
     78        """
     79        EXAMPLE::
     80
     81            sage: from sage.misc.object_multiplexer import Multiplex
     82            sage: m = Multiplex(1,1/2)
     83            sage: m.str
     84            <sage.misc.object_multiplexer.MultiplexFunction instance at 0x...>
     85            sage: m.trait_names
     86            Traceback (most recent call last):
     87            ...
     88            AttributeError: 'Multiplex' has no attribute 'trait_names'
     89        """
     90        if name.startswith("__") or name == "trait_names":
     91            raise AttributeError("'Multiplex' has no attribute '%s'"%name)
     92        return MultiplexFunction(self,name)
  • sage/rings/polynomial/multi_polynomial_ideal.py

    diff -r f43f11d9444e -r 1ed2892e1712 sage/rings/polynomial/multi_polynomial_ideal.py
    a b  
    230230                                 macaulay2 as macaulay2_default,
    231231                                 magma as magma_default)
    232232
     233from sage.interfaces.expect import StdOutContext
     234
    233235from sage.rings.ideal import Ideal_generic
    234236from sage.rings.integer import Integer
    235237from sage.structure.sequence import Sequence
    236238
    237239from sage.misc.cachefunc import cached_method
    238 from sage.misc.misc import prod, verbose
     240from sage.misc.misc import prod, verbose, get_verbose
    239241from sage.misc.sage_eval import sage_eval
    240242from sage.misc.method_decorator import MethodDecorator
    241243
     
    244246import sage.rings.polynomial.toy_variety as toy_variety
    245247import sage.rings.polynomial.toy_d_basis as toy_d_basis
    246248
     249from warnings import warn
     250
    247251class LibSingularDefaultContext:
    248252    def __init__(self, singular=singular_default):
    249253        from sage.libs.singular.option import opt_ctx
     
    471475    wrapper.__doc__ = func.__doc__
    472476    return wrapper
    473477
     478class MagmaDefaultContext:
     479    """
     480    Context to force preservation of verbosity options for Magma's
     481    Groebner basis computation.
     482    """
     483    def __init__(self, magma=magma_default):
     484        """
     485        INPUT:
     486
     487        - ``magma`` - (default: ``magma_default``)
     488
     489        EXAMPLE::
     490       
     491            sage: from sage.rings.polynomial.multi_polynomial_ideal import MagmaDefaultContext
     492            sage: magma.SetVerbose('Groebner',1) # optional - magma
     493            sage: with MagmaDefaultContext(): magma.GetVerbose('Groebner')  # optional - magma
     494            0
     495        """
     496        self.magma = magma
     497    def __enter__(self):
     498        """
     499        EXAMPLE::
     500       
     501            sage: from sage.rings.polynomial.multi_polynomial_ideal import MagmaDefaultContext
     502            sage: magma.SetVerbose('Groebner',1) # optional - magma
     503            sage: with MagmaDefaultContext(): magma.GetVerbose('Groebner')  # optional - magma
     504            0
     505        """
     506        self.groebner_basis_verbose = self.magma.GetVerbose('Groebner')
     507        self.magma.SetVerbose('Groebner',0)
     508    def __exit__(self, typ, value, tb):
     509        """
     510        EXAMPLE::
     511       
     512            sage: from sage.rings.polynomial.multi_polynomial_ideal import MagmaDefaultContext
     513            sage: magma.SetVerbose('Groebner',1) # optional - magma
     514            sage: with MagmaDefaultContext(): magma.GetVerbose('Groebner')  # optional - magma
     515            0
     516            sage: magma.GetVerbose('Groebner') # optional - magma
     517            1
     518        """
     519        self.magma.SetVerbose('Groebner',self.groebner_basis_verbose)
     520
     521def magma_standard_options(func):
     522    """
     523    Decorator to force default options for Magma.
     524
     525    EXAMPLE::
     526        sage: P.<a,b,c,d,e> = PolynomialRing(GF(127))
     527        sage: J = sage.rings.ideal.Cyclic(P).homogenize()
     528        sage: from sage.misc.sageinspect import sage_getsource
     529        sage: "mself" in sage_getsource(J._groebner_basis_magma)
     530        True
     531
     532    """
     533    def wrapper(*args, **kwds):
     534        """
     535        Execute function in ``MagmaDefaultContext``.
     536        """
     537        with MagmaDefaultContext():
     538            return func(*args, **kwds)
     539
     540    from sage.misc.sageinspect import sage_getsource
     541    wrapper._sage_src_ = lambda: sage_getsource(func)
     542    wrapper.__name__ = func.__name__
     543    wrapper.__doc__ = func.__doc__
     544    return wrapper
     545
    474546class RequireField(MethodDecorator):
    475547    """
    476548    Decorator which throws an exception if a computation over a
     
    565637        G = magma(self.gens())
    566638        return 'ideal<%s|%s>'%(P.name(), G._ref())
    567639
    568     def _groebner_basis_magma(self, magma=magma_default):
     640    @magma_standard_options
     641    def _groebner_basis_magma(self, deg_bound=None, prot=False, magma=magma_default):
    569642        """
    570643        Computes a Groebner Basis for this ideal using Magma if
    571644        available.
    572645       
    573646        INPUT:
    574647       
     648        - ``deg_bound`` - only compute to degree ``deg_bound``, that
     649          is, ignore all S-polynomials of higher degree. (default:
     650          ``None``)
     651
     652        - ``prot`` - if ``True`` Magma's protocol is printed to
     653          stdout.
     654
    575655        -  ``magma`` - Magma instance or None (default instance) (default: None)
    576656       
    577657        EXAMPLES::
     
    583663            45
    584664        """
    585665        R   = self.ring()
    586         mgb = magma(self).GroebnerBasis()
     666        if not deg_bound:
     667            mself = magma(self)
     668        else:
     669            mself = magma(self.gens())
     670
     671        if get_verbose() >= 2:
     672            prot = True
     673   
     674        from sage.interfaces.magma import MagmaGBLogPrettyPrinter
     675
     676        if prot:
     677            log_parser = MagmaGBLogPrettyPrinter(verbosity=get_verbose()+ 1, style="sage" if prot=="sage" else "magma")
     678        else:
     679            log_parser = None
     680
     681        ctx = StdOutContext(magma, silent=False if prot else True, stdout=log_parser)
     682        if prot:
     683            magma.SetVerbose('Groebner',1)
     684        with ctx:
     685            if deg_bound:
     686                mgb = mself.GroebnerBasis(deg_bound)
     687            else:
     688                mgb = mself.GroebnerBasis()
     689
     690
     691        if prot == "sage":
     692            print
     693            print "Highest degree reached during computation: %2d."%log_parser.max_deg
     694
    587695        # TODO: rewrite this to be much more sophisticated in multi-level nested cases.
    588696        mgb = [str(mgb[i+1]) for i in range(len(mgb))]
    589697        if R.base_ring().degree() > 1:
     
    12491357        r"""
    12501358        Return a Groebner basis in Singular format.
    12511359       
     1360        INPUT:
     1361
     1362        - ``algorithm`` - Singular function to call (default: ``groebner``)
     1363
     1364        - ``singular`` - Singular instance to use (default: ``singular_default``)
     1365
     1366        - ``args`` - ignored
     1367
     1368        - ``kwds`` - Singular options
     1369
    12521370        EXAMPLE::
    12531371       
    12541372            sage: R.<a,b,c,d> = PolynomialRing(QQ, 4, order='lex')
     
    12671385        from sage.libs.singular.option import _options_py_to_singular
    12681386        S = self._singular_()   # for degBound, we need to ensure
    12691387                                # that a ring is defined
     1388
     1389        if get_verbose() >= 2:
     1390            kwds['prot'] = True
     1391
    12701392        for o,v in kwds.iteritems():
    12711393            o = _options_py_to_singular.get(o,o)
    12721394            if v:
     
    12801402                else:
    12811403                    singular.option("no"+o)
    12821404
    1283         if algorithm=="groebner":
    1284             S = self._singular_().groebner()
    1285         elif algorithm=="std":
    1286             S = self._singular_().std()
    1287         elif algorithm=="slimgb":
    1288             S = self._singular_().slimgb()
    1289         elif algorithm=="stdhilb":
    1290             S = self._singular_().stdhilb()
    1291         elif algorithm=="stdfglm":
    1292             S = self._singular_().stdfglm()
     1405        obj = self._singular_()
     1406
     1407        prot = kwds.get('prot',False)
     1408
     1409        if prot == "sage":
     1410            if algorithm == 'slimgb':
     1411                warn("'slimgb' does not print sufficient information for prot='sage' to work reliably, the highest degree reached might be too low.")
     1412            from sage.interfaces.singular import SingularGBLogPrettyPrinter
     1413            log_parser = SingularGBLogPrettyPrinter(verbosity=get_verbose()+1)
    12931414        else:
    1294             raise TypeError, "algorithm '%s' unknown"%algorithm
     1415            log_parser = None
     1416
     1417        ctx = StdOutContext(singular, silent=False if prot else True, stdout=log_parser)
     1418
     1419        with ctx:
     1420            if algorithm=="groebner":
     1421                S = obj.groebner()
     1422            elif algorithm=="std":
     1423                S = obj.std()
     1424            elif algorithm=="slimgb":
     1425                S = obj.slimgb()
     1426            elif algorithm=="stdhilb":
     1427                S = obj.stdhilb()
     1428            elif algorithm=="stdfglm":
     1429                S = obj.stdfglm()
     1430            else:
     1431                raise TypeError, "algorithm '%s' unknown"%algorithm
    12951432        self.__gb_singular = S
     1433        if prot == "sage":
     1434            print
     1435            print "Highest degree reached during computation: %2d."%log_parser.max_deg
    12961436        return S
    12971437
    12981438    @libsingular_standard_options
     
    13521492
    13531493        import sage.libs.singular
    13541494        groebner = sage.libs.singular.ff.groebner
    1355         from sage.all import get_verbose
    13561495
    13571496        if get_verbose()>=2:
    13581497            opt['prot'] = True
     
    25292668                                        symmetry=symmetry, verbose=verbose)
    25302669
    25312670    @cached_method
    2532     def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, *args, **kwds):
     2671    def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=False, *args, **kwds):
    25332672        """
    25342673        Return the reduced Groebner basis of this ideal.
    25352674
    25362675        A Groebner basis `g_1,...,g_n` for an ideal `I` is a
    2537         generating set such that `<LM(g_i)> = LM(I)`, i.e.,
    2538         the leading monomial ideal of `I` is spanned by the
    2539         leading terms of `g_1,...,g_n`. Groebner bases are
    2540         the key concept in computational ideal theory in
    2541         multivariate polynomial rings which allows a variety
    2542         of problems to be solved.
     2676        generating set such that `<LM(g_i)> = LM(I)`, i.e., the
     2677        leading monomial ideal of `I` is spanned by the leading terms
     2678        of `g_1,...,g_n`. Groebner bases are the key concept in
     2679        computational ideal theory in multivariate polynomial rings
     2680        which allows a variety of problems to be solved.
    25432681
    25442682        Additionally, a *reduced* Groebner basis `G` is a unique
    2545         representation for the ideal `<G>` with respect to the
    2546         chosen monomial ordering.
     2683        representation for the ideal `<G>` with respect to the chosen
     2684        monomial ordering.
    25472685       
    25482686        INPUT:
    25492687       
    2550         -  ``algorithm`` - determines the algorithm to use, see
    2551            below for available algorithms.
    2552         -  ``*args`` - additional parameters passed to the
     2688        - ``algorithm`` - determines the algorithm to use, see below
     2689           for available algorithms.
     2690
     2691        - ``deg_bound`` - only compute to degree ``deg_bound``, that
     2692          is, ignore all S-polynomials of higher degree. (default:
     2693          ``None``)
     2694
     2695        - ``mult_bound`` - the computation is stopped if the ideal is
     2696          zero-dimensional in a ring with local ordering and its
     2697          multiplicity is lower than ``mult_bound``. Singular
     2698          only. (default: ``None``)
     2699
     2700        - ``prot`` - if set to ``True`` the computation protocol of
     2701          the underlying implementation is printed. If an algorithm
     2702          from the ``singular:`` or ``magma:`` family is used,
     2703          ``prot`` may also be ``sage`` in which case the output is
     2704          parsed and printed in a common format where the amount of
     2705          information printed can be controlled via calls to
     2706          :func:`set_verbose`.
     2707
     2708        - ``*args`` - additional parameters passed to the respective
     2709           implementations
     2710
     2711        - ``**kwds`` - additional keyword parameters passed to the
    25532712           respective implementations
    2554         -  ``**kwds`` - additional keyword parameters passed
    2555            to the respective implementations
    2556        
    2557        
     2713                         
    25582714        ALGORITHMS:
    25592715       
    25602716        ''
     
    26122768
    26132769           The Singular and libSingular versions of the respective
    26142770           algorithms are identical, but the former calls an external
    2615            Singular process while the later calls a C function, i.e. the
    2616            calling overhead is smaller.
     2771           Singular process while the later calls a C function,
     2772           i.e. the calling overhead is smaller. However, the
     2773           libSingular interface does not support pretty printing of
     2774           computation protocols.
    26172775       
    26182776        EXAMPLES:
    26192777
     
    26592817            [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c]
    26602818       
    26612819        Note that ``toy:buchberger`` does not return the reduced Groebner
    2662         basis,
    2663        
    2664         ::
     2820        basis, ::
    26652821       
    26662822            sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching
    26672823            sage: I.groebner_basis('toy:buchberger')
     
    26732829             c^6 - 79/210*c^5 - 229/2100*c^4 + 121/2520*c^3 + 1/3150*c^2 - 11/12600*c,
    26742830             c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c]
    26752831       
    2676         but that ``toy:buchberger2`` does.
    2677        
    2678         ::
     2832        but that ``toy:buchberger2`` does.::
    26792833       
    26802834            sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching
    26812835            sage: I.groebner_basis('toy:buchberger2')
     
    26942848            [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c]
    26952849       
    26962850        Singular and libSingular can compute Groebner basis with degree
    2697         restrictions::
     2851        restrictions.::
    26982852
    26992853            sage: R.<x,y> = QQ[]
    27002854            sage: I = R*[x^3+y^2,x^2*y+1]
     
    27072861            sage: I.groebner_basis(deg_bound=2)
    27082862            [x^3 + y^2, x^2*y + 1]
    27092863
    2710         In the case of libSingular, a protocol is printed, if the
    2711         verbosity level is at least 2, or if the argument ``prot``
    2712         is provided. For some reason, the protocol does not appear
    2713         during doctests, so, we skip the examples with protocol
    2714         output.
    2715         ::
     2864        A protocol is printed, if the verbosity level is at least 2,
     2865        or if the argument ``prot`` is provided. For some reason, the
     2866        protocol does not appear during doctests, so, we skip the
     2867        examples with protocol output.  ::
    27162868
    27172869            sage: set_verbose(2)
    27182870            sage: I = R*[x^3+y^2,x^2*y+1]
     
    27352887        The list of available options is provided at
    27362888        :class:`~sage.libs.singular.option.LibSingularOptions`.
    27372889
    2738         Groebner bases over `\ZZ` can be computed. ::
     2890        Note that Groebner bases over `\ZZ` can also be computed.::
    27392891       
    27402892            sage: P.<a,b,c> = PolynomialRing(ZZ,3)
    27412893            sage: I = P * (a + 2*b + 2*c - 1, a^2 - a + 2*b^2 + 2*c^2, 2*a*b + 2*b*c - b)
     
    28102962            algorithm = "magma:GroebnerBasis"
    28112963        elif algorithm.lower() == "singular":
    28122964            algorithm = "singular:groebner"
     2965        elif algorithm.lower() == "libsingular":
     2966            algorithm = "libsingular:groebner"
    28132967        elif algorithm.lower() == "macaulay2":
    28142968            algorithm = "macaulay2:gb"
    28152969        elif algorithm.lower() == "toy":
     
    28412995                            raise TypeError, "Local/unknown orderings not supported by 'toy_buchberger' implementation."
    28422996
    28432997        elif algorithm.startswith('singular:'):
    2844             gb = self._groebner_basis_singular(algorithm[9:], deg_bound=deg_bound, mult_bound=mult_bound, *args, **kwds)
     2998            gb = self._groebner_basis_singular(algorithm[9:], deg_bound=deg_bound, mult_bound=mult_bound, prot=prot, *args, **kwds)
    28452999        elif algorithm.startswith('libsingular:'):
    2846             gb = self._groebner_basis_libsingular(algorithm[len('libsingular:'):], deg_bound=deg_bound, mult_bound=mult_bound, *args, **kwds)
     3000            if prot == "sage":
     3001                warn("The libsingular interface does not support prot='sage', reverting to 'prot=True'.")
     3002            gb = self._groebner_basis_libsingular(algorithm[len('libsingular:'):], deg_bound=deg_bound, mult_bound=mult_bound, prot=prot, *args, **kwds)
    28473003        elif algorithm == 'macaulay2:gb':
    2848             gb = self._groebner_basis_macaulay2(*args, **kwds)
     3004            gb = self._groebner_basis_macaulay2(prot=prot, *args, **kwds)
    28493005        elif algorithm == 'magma:GroebnerBasis':
    2850             gb = self._groebner_basis_magma(*args, **kwds)
     3006            gb = self._groebner_basis_magma(prot=prot, deg_bound=deg_bound, *args, **kwds)
    28513007        elif algorithm == 'toy:buchberger':
    28523008            gb = toy_buchberger.buchberger(self, *args, **kwds)
    28533009        elif algorithm == 'toy:buchberger2':