Ticket #7797: trac7797-letterplace_degree_weights.patch

File trac7797-letterplace_degree_weights.patch, 30.7 KB (added by SimonKing, 8 years ago)

Positive integral degree weights for letterplace. UniqueFactory? for free algebras.

  • sage/algebras/free_algebra.py

    # HG changeset patch
    # User Simon King <simon.king@uni-jena.de>
    # Date 1306401061 -7200
    # Node ID c68f9bcba8a4f82e3756009e4c090ef381c05bb8
    # Parent  c2404702795f9be9d1ccb9bced6c76e60fd251c5
    #7797: Positive integral degree weights for letterplace algebras; UniqueFactory for free algebras.
    
    diff --git a/sage/algebras/free_algebra.py b/sage/algebras/free_algebra.py
    a b  
    99  things.
    1010
    1111- Simon King (2011-04): Put free algebras into the category framework.
    12 
    13 - Simon King (2011-03-21): reimplement free algebra constructor, using
    14   a :class:`~sage.structure.factory.UniqueFactory` for handling
    15   different implementations of free algebras.
     12  Reimplement free algebra constructor, using a
     13  :class:`~sage.structure.factory.UniqueFactory` for handling
     14  different implementations of free algebras. Allow degree weights
     15  for free algebras in letterplace implementation.
    1616
    1717EXAMPLES::
    1818
     
    2828ticket #7797, there is a different implementation
    2929:class:`~sage.algebras.letterplace.free_algebra_letterplace.FreeAlgebra_letterplace`
    3030based on Singular's letterplace rings. It is currently restricted to
    31 homogeneous elements and is therefore not the default. But the
     31weighted homogeneous elements and is therefore not the default. But the
    3232arithmetic is much faster than in the generic implementation.
    3333Moreover, we can compute Groebner bases with degree bound for its
    3434two-sided ideals, and thus provide ideal containment tests::
     
    4242    sage: y*z*y*y*z*z + 2*y*z*y*z*z*x + y*z*y*z*z*z - y*z*z*y*z*x + y*z*z*z*z*x in I
    4343    True
    4444
     45Positive integral degree weights for the letterplace implementation
     46was introduced in trac ticket #...::
     47
     48    sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3])
     49    sage: x.degree()
     50    2
     51    sage: y.degree()
     52    1
     53    sage: z.degree()
     54    3
     55    sage: I = F*[x*y-y*x, x^2+2*y*z, (x*y)^2-z^2]*F
     56    sage: Q.<a,b,c> = F.quo(I)
     57    sage: TestSuite(Q).run()
     58    sage: a^2*b^2
     59    c*c
     60
    4561TESTS::
    4662
    4763    sage: F = FreeAlgebra(GF(5),3,'x')
     
    140156        True
    141157        sage: F is FreeAlgebra(GF(5),['x','y','z'])
    142158        True
     159        sage: copy(F) is F is loads(dumps(F))
     160        True
     161        sage: TestSuite(F).run()
     162
     163    ::
     164
    143165        sage: G = FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace')
    144         sage: F is G
     166        sage: F == G
    145167        False
    146168        sage: G is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace')
    147169        True
    148         sage: copy(G) is G
     170        sage: copy(G) is G is loads(dumps(G))
    149171        True
    150         sage: copy(F) is F
     172        sage: TestSuite(G).run()
     173
     174    ::
     175
     176        sage: H = FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace', degrees=[1,2,3])
     177        sage: F != H != G
    151178        True
     179        sage: H is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace', degrees=[1,2,3])
     180        True
     181        sage: copy(H) is H is loads(dumps(H))
     182        True
     183        sage: TestSuite(H).run()
    152184
    153185    """
    154186    def create_key(self,base_ring, arg1=None, arg2=None,
    155187                                      sparse=False, order='degrevlex',
    156188                                      names=None, name=None,
    157                                       implementation=None):
     189                                      implementation=None, degrees=None):
    158190        """
    159191        Create the key under which a free algebra is stored.
    160192
     
    172204            (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
    173205            sage: FreeAlgebra.create_key(GF(5),3,'xyz', implementation='letterplace')
    174206            (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
     207            sage: FreeAlgebra.create_key(GF(5),3,'xyz', implementation='letterplace', degrees=[1,2,3])
     208            ((1, 2, 3), Multivariate Polynomial Ring in x, y, z, x_ over Finite Field of size 5)
    175209
    176210        """
    177211        if arg1 is None and arg2 is None and names is None:
    178212            # this is used for pickling
    179             return (base_ring,)
     213            if degrees is None:
     214                return (base_ring,)
     215            return tuple(degrees),base_ring
    180216        PolRing = None
    181217        # test if we can use libSingular/letterplace
    182218        if implementation is not None and implementation != 'generic':
     
    195231            except (TypeError, NotImplementedError),msg:
    196232                raise NotImplementedError, "The letterplace implementation is not available for the free algebra you requested"
    197233        if PolRing is not None:
    198             return (PolRing,)
     234            if degrees is None:
     235                return (PolRing,)
     236            from sage.all import TermOrder
     237            T = PolRing.term_order()+TermOrder('lex',1)
     238            varnames = list(PolRing.variable_names())
     239            newname = 'x'
     240            while newname in varnames:
     241                newname += '_'
     242            varnames.append(newname)
     243            return tuple(degrees),PolynomialRing(PolRing.base(), varnames,
     244                    sparse=sparse, order=T,
     245                    implementation=implementation if implementation!='letterplace'  else None)
    199246        # normalise the generator names
    200247        from sage.all import Integer
    201248        if isinstance(arg1, (int, long, Integer)):
     
    219266
    220267        TESTS::
    221268
    222             sage: FreeAlgebra.create_object('4.6.2', (QQ['x','y'],))
     269            sage: FreeAlgebra.create_object('4.7.1', (QQ['x','y'],))
    223270            Free Associative Unital Algebra on 2 generators (x, y) over Rational Field
    224             sage: FreeAlgebra.create_object('4.6.2', (QQ['x','y'],)) is FreeAlgebra(QQ,['x','y'])
     271            sage: FreeAlgebra.create_object('4.7.1', (QQ['x','y'],)) is FreeAlgebra(QQ,['x','y'])
    225272            False
    226273
    227274        """
     
    230277#                return key[0]
    231278            from sage.algebras.letterplace.free_algebra_letterplace import FreeAlgebra_letterplace
    232279            return FreeAlgebra_letterplace(key[0])
     280        if isinstance(key[0],tuple):
     281            from sage.algebras.letterplace.free_algebra_letterplace import FreeAlgebra_letterplace
     282            return FreeAlgebra_letterplace(key[1],degrees=key[0])
    233283#        if len(key[1])<=1:
    234284#            return PolynomialRing(key[0],key[1])
    235285        return FreeAlgebra_generic(key[0],len(key[1]),key[1])
     
    251301        True
    252302        sage: is_FreeAlgebra(FreeAlgebra(ZZ,10,'x',implementation='letterplace'))
    253303        True
     304        sage: is_FreeAlgebra(FreeAlgebra(ZZ,10,'x',implementation='letterplace', degrees=range(1,11)))
     305        True
    254306
    255307    """
    256308    from sage.algebras.letterplace.free_algebra_letterplace import FreeAlgebra_letterplace
  • sage/algebras/letterplace/free_algebra_element_letterplace.pyx

    diff --git a/sage/algebras/letterplace/free_algebra_element_letterplace.pyx b/sage/algebras/letterplace/free_algebra_element_letterplace.pyx
    a b  
    88###############################################################################
    99
    1010"""
    11 Homogeneous elements of free algebras, in letterplace implementation
     11Weighted homogeneous elements of free algebras, in letterplace implementation.
    1212
    1313AUTHOR:
    1414
    15 - Simon King (2011-03-23): Trac ticket #7797.
     15- Simon King (2011-03-23): Trac ticket #7797
    1616
    1717"""
    1818
     
    2929# Free algebra elements
    3030cdef class FreeAlgebraElement_letterplace(AlgebraElement):
    3131    """
    32     Homogeneous elements of a free associative unital algebra (letterplace implementation)
     32    Weighted homogeneous elements of a free associative unital algebra (letterplace implementation)
    3333
    3434    EXAMPLES::
    3535
     
    4343        y*y*y
    4444        sage: (y^3).normal_form(I)
    4545        y*y*z - y*z*y + y*z*z
     46       
     47    Here is an example with nontrivial degree weights::
     48
     49        sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3])
     50        sage: I = F*[x*y-y*x, x^2+2*y*z, (x*y)^2-z^2]*F
     51        sage: x.degree()
     52        2
     53        sage: y.degree()
     54        1
     55        sage: z.degree()
     56        3
     57        sage: (x*y)^3
     58        x*y*x*y*x*y
     59        sage: ((x*y)^3).normal_form(I)
     60        z*z*y*x
     61        sage: ((x*y)^3).degree()
     62        9
    4663
    4764    """
    4865    def __init__(self, A, x, check=True):
     
    7390        cdef FreeAlgebra_letterplace P = A
    7491        if check:
    7592            if not x.is_homogeneous():
    76                 raise ValueError, "Free algebras based on Letterplace can currently only work with homogeneous elements"
     93                raise ValueError, "Free algebras based on Letterplace can currently only work with weighted homogeneous elements"
    7794            P.set_degbound(x.degree())
    7895            x = P._current_ring(x)
    7996        AlgebraElement.__init__(self,P)
     
    133150            sage: -(a+b*(z+1)-c)^2     # indirect doctest
    134151            -a*a + (4*z + 4)*a*b + a*c + (4*z + 4)*b*a + (2*z + 1)*b*b + (z + 1)*b*c + c*a + (z + 1)*c*b - c*c
    135152
     153        It is possible to change the names temporarily::
     154
     155            sage: from sage.structure.parent_gens import localvars
     156            sage: with localvars(F, ['w', 'x','y']):
     157            ...     print a+b*(z+1)-c
     158            w + (z + 1)*x - y
     159            sage: print a+b*(z+1)-c
     160            a + (z + 1)*b - c
     161
    136162        """
    137163        cdef list L = []
    138164        cdef FreeAlgebra_letterplace P = self._parent
     
    204230
    205231        NOTE:
    206232
    207         Currently, generators can only have the degree one.
     233        Generators may have a positive integral degree weight. All
     234        elements must be weighted homogeneous.
    208235
    209236        EXAMPLE::
    210237
    211238            sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace')
    212239            sage: ((x+y+z)^3).degree()
    213240            3
     241            sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3])
     242            sage: ((x*y+z)^3).degree()
     243            9
     244           
    214245        """
    215246        return self._poly.degree()
    216247
     
    224255            sage: ((x+y-z)^2).letterplace_polynomial()
    225256            x*x_1 + x*y_1 - x*z_1 + y*x_1 + y*y_1 - y*z_1 - z*x_1 - z*y_1 + z*z_1
    226257
     258        If degree weights are used, the letterplace polynomial is
     259        homogenized by slack variables::
     260
     261            sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3])
     262            sage: ((x*y+z)^2).letterplace_polynomial()
     263            x*x__1*y_2*x_3*x__4*y_5 + x*x__1*y_2*z_3*x__4*x__5 + z*x__1*x__2*x_3*x__4*y_5 + z*x__1*x__2*z_3*x__4*x__5
     264
    227265        """
    228266        return self._poly
    229267
     
    236274            sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace')
    237275            sage: ((2*x+3*y-4*z)^2*(5*y+6*z)).lm()
    238276            x*x*y
    239            
     277            sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3])
     278            sage: ((2*x*y+z)^2).lm()
     279            x*y*x*y
     280
    240281        """
    241282        return FreeAlgebraElement_letterplace(self._parent, self._poly.lm())
    242283
     
    250291            sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace')
    251292            sage: ((2*x+3*y-4*z)^2*(5*y+6*z)).lt()
    252293            20*x*x*y
     294            sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3])
     295            sage: ((2*x*y+z)^2).lt()
     296            4*x*y*x*y
    253297
    254298        """
    255299        return FreeAlgebraElement_letterplace(self._parent, self._poly.lt())
     
    266310            20
    267311            sage: ((2*x+3*y-4*z)^2*(5*y+6*z)).lc().parent() is F.base()
    268312            True
     313            sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3])
     314            sage: ((2*x*y+z)^2).lc()
     315            4
    269316
    270317        """
    271318        return self._poly.lc()
     
    284331        return bool(self._poly)
    285332
    286333    def lm_divides(self, FreeAlgebraElement_letterplace p):
     334        """
     335        Tell whether or not the leading monomial of self devides the
     336        leading monomial of another element.
     337
     338        NOTE:
     339
     340        A free algebra element `p` divides another one `q` if there are
     341        free algebra elements `s` and `t` such that `spt = q`.
     342
     343        EXAMPLE::
     344
     345            sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3])
     346            sage: ((2*x*y+z)^2*z).lm()
     347            x*y*x*y*z
     348            sage: (y*x*y-y^4).lm()
     349            y*x*y
     350            sage: (y*x*y-y^4).lm_divides((2*x*y+z)^2*z)
     351            True
     352
     353        """
    287354        if self._parent is not p._parent:
    288355            raise TypeError, "The two arguments must be elements in the same free algebra."
    289356        cdef FreeAlgebra_letterplace A = self._parent
     
    372439            sage: x+1
    373440            Traceback (most recent call last):
    374441            ...
    375             ArithmeticError: Can only add elements of the same degree
     442            ArithmeticError: Can only add elements of the same weighted degree
    376443            sage: x+0
    377444            x
    378445            sage: 0+x
     
    385452            return other
    386453        cdef FreeAlgebraElement_letterplace right = other       
    387454        if right._poly.degree()!=self._poly.degree():
    388             raise ArithmeticError, "Can only add elements of the same degree"
     455            raise ArithmeticError, "Can only add elements of the same weighted degree"
    389456        # update the polynomials
    390457        cdef FreeAlgebra_letterplace A = self._parent
    391458        self._poly = A._current_ring(self._poly)
     
    395462    cpdef ModuleElement _sub_(self, ModuleElement other):
    396463        """
    397464        Difference, under the side condition that either one summand
    398         is zero or both have the same degree.
     465        is zero or both have the same weighted degree.
    399466
    400467        TEST::
    401468
     
    411478            sage: 0-x
    412479            -x
    413480
     481        Here is an example with non-trivial degree weights::
     482
     483            sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3])
     484            sage: x*y+z
     485            x*y + z
     486
    414487        """
    415488        if not other:
    416489            return self
     
    454527        return FreeAlgebraElement_letterplace(self._parent,self._poly._rmul_(left),check=False)
    455528
    456529    cpdef RingElement _mul_(self, RingElement other):
     530        """
     531        Product of two free algebra elements in letterplace implementation.
     532
     533        TEST::
     534
     535            sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3])
     536            sage: (x*y+z)*z   # indirect doctest
     537            x*y*z + z*z
     538
     539        """
    457540        cdef FreeAlgebraElement_letterplace left = self
    458541        cdef FreeAlgebraElement_letterplace right = other
    459542        cdef FreeAlgebra_letterplace A = left._parent
     
    498581    def reduce(self, G):
    499582        """
    500583        Reduce this element by a list of elements or by a
    501         twosided homogeneous ideal.
     584        twosided weighted homogeneous ideal.
    502585
    503586        INPUT:
    504587
    505         Either a list or tuple of homogeneous elements of the
    506         free algebra, or an ideal of the free algebra, or an
    507         ideal in the commutative polynomial ring that is
    508         currently used to implement the multiplication in the
    509         free algebra.
     588        Either a list or tuple of weighted homogeneous elements of the
     589        free algebra, or an ideal of the free algebra, or an ideal in
     590        the commutative polynomial ring that is currently used to
     591        implement the multiplication in the free algebra.
    510592
    511593        OUTPUT:
    512594
     
    574656    def normal_form(self,I):
    575657        """
    576658        Return the normal form of this element with respect to
    577         a twosided homogeneous ideal.
     659        a twosided weighted homogeneous ideal.
    578660
    579661        INPUT:
    580662
     
    608690            sage: (x^5+x*I.0*y*z-3*z^2*I.1*y).normal_form(I) == (x^5).normal_form(I)
    609691            True
    610692
     693        Here is an example with non-trivial degree weights::
     694
     695            sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[1,2,3])
     696            sage: I = F*[x*y-y*x+z, y^2+2*x*z, (x*y)^2-z^2]*F
     697            sage: ((x*y)^3).normal_form(I)
     698            z*z*y*x - z*z*z
     699            sage: (x*y)^3-((x*y)^3).normal_form(I) in I
     700            True
     701            sage: ((x*y)^3+2*z*I.0*z+y*I.1*z-x*I.2*y).normal_form(I) == ((x*y)^3).normal_form(I)
     702            True
     703
    611704        """
    612705        if self._parent != I.ring():
    613706            raise ValueError, "Can not compute normal form wrt an ideal that does not belong to %s"%self._parent
  • sage/algebras/letterplace/free_algebra_letterplace.pxd

    diff --git a/sage/algebras/letterplace/free_algebra_letterplace.pxd b/sage/algebras/letterplace/free_algebra_letterplace.pxd
    a b  
    2121    cdef MPolynomialRing_libsingular _current_ring
    2222    cdef int _degbound
    2323    cdef int __ngens
     24    cdef int _nb_slackvars
    2425    cdef object __monoid
    2526    cdef public object __custom_name
    2627    cdef str exponents_to_string(self, E)
     28    cdef tuple _degrees
  • sage/algebras/letterplace/free_algebra_letterplace.pyx

    diff --git a/sage/algebras/letterplace/free_algebra_letterplace.pyx b/sage/algebras/letterplace/free_algebra_letterplace.pyx
    a b  
    1515- Simon King (2011-03-21): Trac ticket #7797
    1616
    1717With this implementation, Groebner bases out to a degree bound and
    18 normal forms can be computed for twosided homogeneous ideals of free
    19 algebras. For now, all computations are restricted to the homogeneous
    20 case.
     18normal forms can be computed for twosided weighted homogeneous ideals
     19of free algebras. For now, all computations are restricted to weighted
     20homogeneous elements, i.e., other elements can not be created by
     21arithmetic operations.
    2122
    2223EXAMPLES::
    2324
     
    7071    sage: (b*c*b*b).normal_form(J)
    7172    1/2*b*c*c*b - 1/2*c*c*b*b
    7273
     74Here is an example with degree weights::
     75
     76    sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[1,2,3])
     77    sage: (x*y+z).degree()
     78    3
     79
    7380TEST::
    7481
    7582    sage: TestSuite(F).run()
     
    7986
    8087TODO:
    8188
    82 In this first version of a wrapper for the letterplace algebra, we can
    83 only support computations with homogeneous elements. Moreover, the
    84 computation of Groebner bases only works for global term orderings,
    85 and all generators have degree 1. These restrictions are inherited
    86 from the letterplace implementation in Singular, but it is ongoing
    87 work to lift these restrictions.
     89The computation of Groebner bases only works for global term
     90orderings, and all elements must be weighted homogeneous with respect
     91to positive integral degree weights. It is ongoing work in Singular to
     92lift these restrictions.
    8893
    8994We support coercion from the letterplace wrapper to the corresponding
    9095generic implementation of a free algebra
    9196(:class:`~sage.algebras.free_algebra.FreeAlgebra_generic`), but there
    92 is no coercion the opposite direction, since the generic
     97is no coercion in the opposite direction, since the generic
    9398implementation also comprises non-homogeneous elements.
    9499
    95100We also do not support coercion from a subalgebra, or between free
     
    169174
    170175cdef class FreeAlgebra_letterplace(Algebra):
    171176    """
    172     Finitely generated free algebra, with arithmetic restricted to homogeneous elements.
     177    Finitely generated free algebra, with arithmetic restricted to weighted homogeneous elements.
    173178
    174179    NOTE:
    175180
    176     The restriction to homogeneous elements should be lifted as soon
    177     as it is lifted in Singular's "Letterplace algebras".
     181    The restriction to weighted homogeneous elements should be lifted
     182    as soon as the restriction to homogeneous elements is lifted in
     183    Singular's "Letterplace algebras".
    178184
    179185    EXAMPLE::
    180186
     
    186192        sage: P
    187193        Multivariate Polynomial Ring in a, b, c over Finite Field in z of size 5^2
    188194
    189     We can do arithmetic as usual, as long as we stay homogeneous::
     195    We can do arithmetic as usual, as long as we stay (weighted) homogeneous::
    190196
    191197        sage: (z*a+(z+1)*b+2*c)^2
    192198        (z + 3)*a*a + (2*z + 3)*a*b + (2*z)*a*c + (2*z + 3)*b*a + (3*z + 4)*b*b + (2*z + 2)*b*c + (2*z)*c*a + (2*z + 2)*c*b - c*c
    193199        sage: a+1
    194200        Traceback (most recent call last):
    195201        ...
    196         ArithmeticError: Can only add elements of the same degree
     202        ArithmeticError: Can only add elements of the same weighted degree
    197203
    198204    """
    199205    # It is not really a free algebra over the given generators. Rather,
    200206    # it is a free algebra over the commutative monoid generated by the given generators.
    201     def __init__(self, R):
     207    def __init__(self, R, degrees=None):
    202208        """
    203209        INPUT:
    204210
     
    252258        if not isinstance(R,MPolynomialRing_libsingular):
    253259            raise TypeError, "A letterplace algebra must be provided by a polynomial ring of type %s"%MPolynomialRing_libsingular
    254260        self.__ngens = R.ngens()
     261        if degrees is None:
     262            varnames = R.variable_names()
     263            self._nb_slackvars = 0
     264        else:
     265            varnames = R.variable_names()[:-1]
     266            self._nb_slackvars = 1
    255267        base_ring = R.base_ring()
    256         Algebra.__init__(self, base_ring, R.variable_names(),
     268        Algebra.__init__(self, base_ring, varnames,
    257269                         normalize=False, category=Algebras(base_ring))
    258270        self._commutative_ring = R
    259271        self._current_ring = make_letterplace_ring(R,1)
    260272        self._degbound = 1
     273        if degrees is None:
     274            self._degrees = tuple([int(1)]*self.__ngens)
     275        else:
     276            if (not isinstance(degrees,(tuple,list))) or len(degrees)!=self.__ngens-1 or any([i<=0 for i in degrees]):
     277                raise TypeError, "The generator degrees must be given by a list or tuple of %d positive integers"%(self.__ngens-1)
     278            self._degrees = tuple([int(i) for i in degrees])
     279            self.set_degbound(max(self._degrees))
    261280        self._populate_coercion_lists_(coerce_list=[base_ring])
    262281    def __reduce__(self):
    263282        """
     
    270289
    271290        """
    272291        from sage.algebras.free_algebra import FreeAlgebra
    273         return FreeAlgebra,(self._commutative_ring,)
     292        if self._nb_slackvars==0:
     293            return FreeAlgebra,(self._commutative_ring,)
     294        return FreeAlgebra,(self._commutative_ring,None,None,None,None,None,None,None,self._degrees)
    274295    # Small methods
    275296    def ngens(self):
    276297        """
     
    283304            3
    284305
    285306        """
    286         return self.__ngens
     307        return self.__ngens-self._nb_slackvars
    287308    def gen(self,i):
    288309        """
    289310        Return the `i`-th generator.
     
    305326            c
    306327
    307328        """
    308         if i>=self.__ngens:
    309             raise ValueError, "This free algebra only has %d generators"%self.__ngens
     329        if i>=self.__ngens-self._nb_slackvars:
     330            raise ValueError, "This free algebra only has %d generators"%(self.__ngens-self._nb_slackvars)
    310331        if self._gens is not None:
    311332            return self._gens[i]
    312         return FreeAlgebraElement_letterplace(self, self._current_ring.gen(i))
     333        deg = self._degrees[i]
     334        #self.set_degbound(deg)
     335        p = self._current_ring.gen(i)
     336        cdef int n
     337        cdef int j = self.__ngens-1
     338        for n from 1<=n<deg:
     339            j += self.__ngens
     340            p *= self._current_ring.gen(j)
     341        return FreeAlgebraElement_letterplace(self, p)
    313342    def current_ring(self):
    314343        """
    315344        Return the commutative ring that is used to emulate
     
    367396        """
    368397        return self._commutative_ring.term_order()
    369398
     399    def generator_degrees(self):
     400        return self._degrees
     401
    370402    # Some basic properties of this ring
    371403    def is_commutative(self):
    372404        """
     
    381413            True
    382414
    383415        """
    384         return self.__ngens <= 1
     416        return self.__ngens-self._nb_slackvars <= 1
    385417
    386418    def is_field(self):
    387419        """
     
    399431            False
    400432
    401433        """
    402         return (not self.__ngens) and self._base.is_field()
     434        return (not (self.__ngens-self._nb_slackvars)) and self._base.is_field()
    403435
    404436    def _repr_(self):
    405437        """
     
    409441            sage: F     # indirect doctest
    410442            Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field
    411443
     444        The degree weights are not part of the string representation::
     445
     446            sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3])
     447            sage: F
     448            Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field
     449
     450
    412451        """
    413         return "Free Associative Unital Algebra on %d generators %s over %s"%(self.__ngens,self.gens(),self._base)
     452        return "Free Associative Unital Algebra on %d generators %s over %s"%(self.__ngens-self._nb_slackvars,self.gens(),self._base)
     453
    414454    def degbound(self):
    415455        """
    416456        Return the degree bound that is currently used.
     
    522562
    523563        EXAMPLE::
    524564
    525             sage: F.<x,y> = FreeAlgebra(GF(2), implementation='letterplace')
     565            sage: F.<x,y,z> = FreeAlgebra(GF(2), implementation='letterplace')
     566            sage: x*y*x*z   # indirect doctest
     567            x*y*x*z
     568
     569        It should be possible to use the letterplace algebra to implement the
     570        free algebra generated by the elements of a finitely generated free abelian
     571        monoid. However, we can not use it, yet. So, for now, we raise an error::
     572
    526573            sage: from sage.algebras.letterplace.free_algebra_element_letterplace import FreeAlgebraElement_letterplace
    527574            sage: P = F.commutative_ring()
    528             sage: FreeAlgebraElement_letterplace(F, P.0*P.1^2+P.1^3)   # indirect doctest
    529             x.y^2 + y^3
     575            sage: FreeAlgebraElement_letterplace(F, P.0*P.1^2+P.1^3) # indirect doctest
     576            Traceback (most recent call last):
     577            ...
     578            NotImplementedError:
     579              Apparently you tried to view the letterplace algebra with
     580              shift-multiplication as the free algebra over a finitely
     581              generated free abelian monoid.
     582              In principle, this is correct, but it is not implemented, yet.
    530583
    531584        """
    532585        cdef int ngens = self.__ngens
    533586        cdef int nblocks = len(E)/ngens
    534         cdef int i
     587        cdef int i,j,base, exp, var_ind
    535588        cdef list out = []
     589        cdef list tmp
    536590        for i from 0<=i<nblocks:
    537             s = '.'.join([('%s^%d'%(x,e) if e>1 else x) for x,e in zip(self._names,E[i*ngens:(i+1)*ngens]) if e])
    538             if s:
    539                 out.append(s)
     591            base = i*ngens
     592            tmp = [(j,E[base+j]) for j in xrange(ngens) if E[base+j]]
     593            if not tmp:
     594                continue
     595            var_ind, exp = tmp[0]
     596            if len(tmp)>1 or exp>1:
     597                raise NotImplementedError, "\n  Apparently you tried to view the letterplace algebra with\n  shift-multiplication as the free algebra over a finitely\n  generated free abelian monoid.\n  In principle, this is correct, but it is not implemented, yet."
     598
     599            out.append(self._names[var_ind])
     600            i += (self._degrees[var_ind]-1)
     601            ### This was the original implementation, with "monoid hack" but without generator degrees
     602            #s = '.'.join([('%s^%d'%(x,e) if e>1 else x) for x,e in zip(self._names,E[i*ngens:(i+1)*ngens]) if e])
     603            #if s:
     604            #    out.append(s)
    540605        return '*'.join(out)
    541606
    542607    def _reductor_(self, g, d):
  • sage/algebras/letterplace/letterplace_ideal.pyx

    diff --git a/sage/algebras/letterplace/letterplace_ideal.pyx b/sage/algebras/letterplace/letterplace_ideal.pyx
    a b  
    5353
    5454class LetterplaceIdeal(Ideal_nc):
    5555    """
    56     Homogeneous ideals in free algebras.
     56    Graded homogeneous ideals in free algebras.
    5757
    5858    In the two-sided case over a field, one can compute Groebner bases
    59     up to a degree bound, normal forms of homogeneous elements of the
    60     free algebra, and ideal containment.
     59    up to a degree bound, normal forms of graded homogeneous elements
     60    of the free algebra, and ideal containment.
    6161
    6262    EXAMPLES::
    6363
     
    108108        ...
    109109        TypeError: Currently, we can only compute Groebner bases if the ring of coefficients is a field
    110110
     111    The letterplace implementation of free algebras also provides integral degree weights
     112    for the generators, and we can compute Groebner bases for twosided graded homogeneous
     113    ideals::
     114
     115        sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace',degrees=[1,2,3])
     116        sage: I = F*[x*y+z-y*x,x*y*z-x^6+y^3]*F
     117        sage: I.groebner_basis(Infinity)
     118        Twosided Ideal (x*z*z - y*x*x*z - y*x*y*y + y*x*z*x + y*y*y*x + z*x*z + z*y*y - z*z*x,
     119        x*y - y*x + z,
     120        x*x*x*x*z*y*y + x*x*x*z*y*y*x - x*x*x*z*y*z - x*x*z*y*x*z + x*x*z*y*y*x*x +
     121        x*x*z*y*y*y - x*x*z*y*z*x - x*z*y*x*x*z - x*z*y*x*z*x +
     122        x*z*y*y*x*x*x + 2*x*z*y*y*y*x - 2*x*z*y*y*z - x*z*y*z*x*x -
     123        x*z*y*z*y + y*x*z*x*x*x*x*x - 4*y*x*z*x*x*z - 4*y*x*z*x*z*x +
     124        4*y*x*z*y*x*x*x + 3*y*x*z*y*y*x - 4*y*x*z*y*z + y*y*x*x*x*x*z +
     125        y*y*x*x*x*z*x - 3*y*y*x*x*z*x*x - y*y*x*x*z*y +
     126        5*y*y*x*z*x*x*x + 4*y*y*x*z*y*x - 4*y*y*y*x*x*z +
     127        4*y*y*y*x*z*x + 3*y*y*y*y*z + 4*y*y*y*z*x*x + 6*y*y*y*z*y +
     128        y*y*z*x*x*x*x + y*y*z*x*z + 7*y*y*z*y*x*x + 7*y*y*z*y*y -
     129        7*y*y*z*z*x - y*z*x*x*x*z - y*z*x*x*z*x + 3*y*z*x*z*x*x +
     130        y*z*x*z*y + y*z*y*x*x*x*x - 3*y*z*y*x*z + 7*y*z*y*y*x*x +
     131        3*y*z*y*y*y - 3*y*z*y*z*x - 5*y*z*z*x*x*x - 4*y*z*z*y*x +
     132        4*y*z*z*z - z*y*x*x*x*z - z*y*x*x*z*x - z*y*x*z*x*x -
     133        z*y*x*z*y + z*y*y*x*x*x*x - 3*z*y*y*x*z + 3*z*y*y*y*x*x +
     134        z*y*y*y*y - 3*z*y*y*z*x - z*y*z*x*x*x - 2*z*y*z*y*x +
     135        2*z*y*z*z - z*z*x*x*x*x*x + 4*z*z*x*x*z + 4*z*z*x*z*x -
     136        4*z*z*y*x*x*x - 3*z*z*y*y*x + 4*z*z*y*z + 4*z*z*z*x*x +
     137        2*z*z*z*y,
     138        x*x*x*x*x*z + x*x*x*x*z*x + x*x*x*z*x*x + x*x*z*x*x*x + x*z*x*x*x*x +
     139        y*x*z*y - y*y*x*z + y*z*z + z*x*x*x*x*x - z*z*y,
     140        x*x*x*x*x*x - y*x*z - y*y*y + z*z)
     141        of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field
     142
     143    Again, we can compute normal forms::
     144
     145        sage: (z*I.0-I.1).normal_form(I)
     146        0
     147        sage: (z*I.0-x*y*z).normal_form(I)
     148        -y*x*z + z*z
     149
    111150    """
    112151    def __init__(self, ring, gens, coerce=True, side = "twosided"):
    113152        """
     
    234273        libsingular_options['redTail'] = True
    235274        libsingular_options['redSB'] = True
    236275        A.set_degbound(degbound)
    237         P = A.current_ring()
     276        P = A._current_ring
    238277        out = [FreeAlgebraElement_letterplace(A,X,check=False) for X in
    239278               singular_system("freegb",P.ideal([x._poly for x in self.__GB.gens()]),
    240                                degbound,A.ngens(), ring = P)]
     279                               degbound,A.__ngens, ring = P)]
    241280        libsingular_options['redTail'] = bck[0]
    242281        libsingular_options['redSB'] = bck[1]
    243282        self.__GB = A.ideal(out,side='twosided',coerce=False)