Exemple #1
0
    def __init__(self, R, n, names):
        """
        The free algebra on `n` generators over a base ring.

        EXAMPLES::

            sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F # indirect doctest
            Free Algebra on 3 generators (x, y, z) over Rational Field

        TESTS:

        Note that the following is *not* the recommended way to create
        a free algebra::

            sage: from sage.algebras.free_algebra import FreeAlgebra_generic
            sage: FreeAlgebra_generic(ZZ, 3, 'abc')
            Free Algebra on 3 generators (a, b, c) over Integer Ring
        """
        if R not in Rings():
            raise TypeError("Argument R must be a ring.")
        self.__ngens = n
        indices = FreeMonoid(n, names=names)
        cat = AlgebrasWithBasis(R)
        CombinatorialFreeModule.__init__(self,
                                         R,
                                         indices,
                                         prefix='F',
                                         category=cat)
        self._assign_names(indices.variable_names())
Exemple #2
0
    def __init__(self, R, n, names):
        """
        The free algebra on `n` generators over a base ring.

        INPUT:

        -  ``R`` - ring
        -  ``n`` - an integer
        -  ``names`` - generator names

        EXAMPLES::

            sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F # indirect doctet
            Free Algebra on 3 generators (x, y, z) over Rational Field

        TEST:

        Note that the following is *not* the recommended way to create
        a free algebra.
        ::

            sage: from sage.algebras.free_algebra import FreeAlgebra_generic
            sage: FreeAlgebra_generic(ZZ,3,'abc')
            Free Algebra on 3 generators (a, b, c) over Integer Ring

        """
        if not isinstance(R, Ring):
            raise TypeError("Argument R must be a ring.")
        self.__monoid = FreeMonoid(n, names=names)
        self.__ngens = n
        #sage.structure.parent_gens.ParentWithGens.__init__(self, R, names)
        Algebra.__init__(self, R, names=names)
Exemple #3
0
    def __init__(self, R, n, names):
        """
        The free algebra on `n` generators over a base ring.

        EXAMPLES::

            sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F # indirect doctet
            Free Algebra on 3 generators (x, y, z) over Rational Field

        TEST:

        Note that the following is *not* the recommended way to create
        a free algebra::

            sage: from sage.algebras.free_algebra import FreeAlgebra_generic
            sage: FreeAlgebra_generic(ZZ, 3, 'abc')
            Free Algebra on 3 generators (a, b, c) over Integer Ring
        """
        if R not in Rings():
            raise TypeError("Argument R must be a ring.")
        self.__ngens = n
        indices = FreeMonoid(n, names=names)
        cat = AlgebrasWithBasis(R)
        CombinatorialFreeModule.__init__(self, R, indices, prefix='F',
                                         category=cat)
        self._assign_names(indices.variable_names())
Exemple #4
0
    def __init__(self, R, n, names):
        """
        The free algebra on `n` generators over a base ring.

        INPUT:

        -  ``R`` - ring
        -  ``n`` - an integer
        -  ``names`` - generator names

        EXAMPLES::

            sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F # indirect doctet
            Free Algebra on 3 generators (x, y, z) over Rational Field

        TEST:

        Note that the following is *not* the recommended way to create
        a free algebra.
        ::

            sage: from sage.algebras.free_algebra import FreeAlgebra_generic
            sage: FreeAlgebra_generic(ZZ,3,'abc')
            Free Algebra on 3 generators (a, b, c) over Integer Ring

        """
        if not isinstance(R, Ring):
            raise TypeError("Argument R must be a ring.")
        self.__ngens = n
        #sage.structure.parent_gens.ParentWithGens.__init__(self, R, names)
        self._basis_keys = FreeMonoid(n, names=names)
        Algebra.__init__(self, R, names, category=AlgebrasWithBasis(R))
Exemple #5
0
    def __classcall_private__(cls, M=None, I=frozenset(), names=None):
        """
        Normalize input to ensure a unique representation.

        TESTS::

            sage: from sage.monoids.trace_monoid import TraceMonoid
            sage: M1.<a,b,c> = TraceMonoid(I=(('a','c'), ('c','a')))
            sage: M2.<a,b,c> = TraceMonoid(I=[('a','c')])
            sage: M3 = TraceMonoid(I=[{'a','c'}], names=('a', 'b', 'c'))
            sage: M1 is M2 and M2 is M3
            True
        """
        if not M:
            if names:
                M = FreeMonoid(names=names)
            else:
                raise ValueError("names must be provided")
        elif not names:
            names = [str(g) for g in M.gens()]
        names = tuple(names)

        rels = set()
        gen_from_str = {names[i]: gen for i, gen in enumerate(M.gens())}
        for (x, y) in I:
            try:
                if isinstance(x, str):
                    x = gen_from_str[x]
                x = M(x)
                if isinstance(y, str):
                    y = gen_from_str[y]
                y = M(y)
                if x == y:
                    raise ValueError
            except (TypeError, ValueError):
                raise ValueError("invalid relation defined")
            rels.add((x, y))
            rels.add((y, x))
        I = frozenset(rels)

        return super(TraceMonoid, cls).__classcall__(cls, M, I, names)
Exemple #6
0
    def __init__(self, R, n, names):
        """
        The free algebra on `n` generators over a base ring.

        INPUT:
        
        -  ``R`` - ring
        -  ``n`` - an integer
        -  ``names`` - generator names
    
        EXAMPLES::
    
            sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F # indirect doctet
            Free Algebra on 3 generators (x, y, z) over Rational Field
        """
        if not isinstance(R, Ring):
            raise TypeError("Argument R must be a ring.")
        self.__monoid = FreeMonoid(n, names=names)
        self.__ngens = n
        #sage.structure.parent_gens.ParentWithGens.__init__(self, R, names)
        Algebra.__init__(self, R, names=names)
Exemple #7
0
    def __init__(self, R, n, names):
        """
        The free algebra on `n` generators over a base ring.

        INPUT:
        
        -  ``R`` - ring
        -  ``n`` - an integer
        -  ``names`` - generator names
    
        EXAMPLES::
    
            sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F # indirect doctet
            Free Algebra on 3 generators (x, y, z) over Rational Field
        """
        if not isinstance(R, Ring):
            raise TypeError, "Argument R must be a ring."
        self.__monoid = FreeMonoid(n, names=names)
        self.__ngens = n
        #sage.structure.parent_gens.ParentWithGens.__init__(self, R, names)
        Algebra.__init__(self, R,names=names)
Exemple #8
0
class FreeAlgebra_generic(Algebra):
    """
    The free algebra on `n` generators over a base ring.

    EXAMPLES::

        sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F
        Free Algebra on 3 generators (x, y, z) over Rational Field
        sage: mul(F.gens())
        x*y*z
        sage: mul([ F.gen(i%3) for i in range(12) ])
        x*y*z*x*y*z*x*y*z*x*y*z
        sage: mul([ F.gen(i%3) for i in range(12) ]) + mul([ F.gen(i%2) for i in range(12) ])
        x*y*x*y*x*y*x*y*x*y*x*y + x*y*z*x*y*z*x*y*z*x*y*z
        sage: (2 + x*z + x^2)^2 + (x - y)^2
        4 + 5*x^2 - x*y + 4*x*z - y*x + y^2 + x^4 + x^3*z + x*z*x^2 + x*z*x*z

    TESTS:

    Free algebras commute with their base ring.
    ::

        sage: K.<a,b> = FreeAlgebra(QQ)
        sage: K.is_commutative()
        False
        sage: L.<c,d> = FreeAlgebra(K)
        sage: L.is_commutative()
        False
        sage: s = a*b^2 * c^3; s
        a*b^2*c^3
        sage: parent(s)
        Free Algebra on 2 generators (c, d) over Free Algebra on 2 generators (a, b) over Rational Field
        sage: c^3 * a * b^2
        a*b^2*c^3

    """
    Element = FreeAlgebraElement
    def __init__(self, R, n, names):
        """
        The free algebra on `n` generators over a base ring.

        INPUT:

        -  ``R`` - ring
        -  ``n`` - an integer
        -  ``names`` - generator names

        EXAMPLES::

            sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F # indirect doctet
            Free Algebra on 3 generators (x, y, z) over Rational Field

        TEST:

        Note that the following is *not* the recommended way to create
        a free algebra.
        ::

            sage: from sage.algebras.free_algebra import FreeAlgebra_generic
            sage: FreeAlgebra_generic(ZZ,3,'abc')
            Free Algebra on 3 generators (a, b, c) over Integer Ring

        """
        if not isinstance(R, Ring):
            raise TypeError("Argument R must be a ring.")
        self.__ngens = n
        #sage.structure.parent_gens.ParentWithGens.__init__(self, R, names)
        self._basis_keys = FreeMonoid(n, names=names)
        Algebra.__init__(self, R, names, category=AlgebrasWithBasis(R))

    def one_basis(self):
        """
        Return the index of the basis element `1`.

        EXAMPLES::

            sage: F = FreeAlgebra(QQ, 2, 'x,y')
            sage: F.one_basis()
            1
            sage: F.one_basis().parent()
            Free monoid on 2 generators (x, y)
        """
        return self._basis_keys.one()

    # Needed for the category AlgebrasWithBasis (but not for Algebras)
    def term(self, index, coeff=None):
        """
        Construct a term of ``self``.

        INPUT:

        - ``index`` -- the index of the basis element
        - ``coeff`` -- (default: 1) an element of the coefficient ring

        EXAMPLES::

            sage: M.<x,y> = FreeMonoid(2)
            sage: F = FreeAlgebra(QQ, 2, 'x,y')
            sage: F.term(x*x*y)
            x^2*y
            sage: F.term(y^3*x*y, 4)
            4*y^3*x*y
            sage: F.term(M.one(), 2)
            2

        TESTS:

        Check to make sure that a coefficient of 0 is properly handled::

            sage: list(F.term(M.one(), 0))
            []
        """
        if coeff is None:
            coeff = self.base_ring().one()
        if coeff == 0:
            return self.element_class(self, {})
        return self.element_class(self, {index: coeff})

    def is_field(self, proof = True):
        """
        Return True if this Free Algebra is a field, which is only if the
        base ring is a field and there are no generators

        EXAMPLES::

            sage: A=FreeAlgebra(QQ,0,'')
            sage: A.is_field()
            True
            sage: A=FreeAlgebra(QQ,1,'x')
            sage: A.is_field()
            False
        """
        if self.__ngens == 0:
            return self.base_ring().is_field(proof)
        return False

    def is_commutative(self):
        """
        Return True if this free algebra is commutative.

        EXAMPLES::

            sage: R.<x> = FreeAlgebra(QQ,1)
            sage: R.is_commutative()
            True
            sage: R.<x,y> = FreeAlgebra(QQ,2)
            sage: R.is_commutative()
            False
        """
        return self.__ngens <= 1 and self.base_ring().is_commutative()

    def __cmp__(self, other):
        """
        Two free algebras are considered the same if they have the same
        base ring, number of generators and variable names, and the same
        implementation.

        EXAMPLES::

            sage: F = FreeAlgebra(QQ,3,'x')
            sage: F ==  FreeAlgebra(QQ,3,'x')
            True
            sage: F is  FreeAlgebra(QQ,3,'x')
            True
            sage: F == FreeAlgebra(ZZ,3,'x')
            False
            sage: F == FreeAlgebra(QQ,4,'x')
            False
            sage: F == FreeAlgebra(QQ,3,'y')
            False

        Note that since :trac:`7797` there is a different
        implementation of free algebras. Two corresponding free
        algebras in different implementations are not equal, but there
        is a coercion::


        """
        if not isinstance(other, FreeAlgebra_generic):
            return -1
        c = cmp(self.base_ring(), other.base_ring())
        if c: return c
        c = cmp(self.__ngens, other.ngens())
        if c: return c
        c = cmp(self.variable_names(), other.variable_names())
        if c: return c
        return 0

    def _repr_(self):
        """
        Text representation of this free algebra.

        EXAMPLES::

            sage: F = FreeAlgebra(QQ,3,'x')
            sage: F  # indirect doctest
            Free Algebra on 3 generators (x0, x1, x2) over Rational Field
            sage: F.rename('QQ<<x0,x1,x2>>')
            sage: F #indirect doctest
            QQ<<x0,x1,x2>>
            sage: FreeAlgebra(ZZ,1,['a'])
            Free Algebra on 1 generators (a,) over Integer Ring
        """
        return "Free Algebra on %s generators %s over %s"%(
            self.__ngens, self.gens(), self.base_ring())

    def _element_constructor_(self, x):
        """
        Convert ``x`` into ``self``.

        EXAMPLES::

            sage: R.<x,y> = FreeAlgebra(QQ,2)
            sage: R(3) # indirect doctest
            3

        TESTS::

            sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
            sage: L.<x,y,z> = FreeAlgebra(ZZ,3,implementation='letterplace')
            sage: F(x)     # indirect doctest
            x
            sage: F.1*L.2
            y*z
            sage: (F.1*L.2).parent() is F
            True

       ::

            sage: K.<z> = GF(25)
            sage: F.<a,b,c> = FreeAlgebra(K,3)
            sage: L.<a,b,c> = FreeAlgebra(K,3, implementation='letterplace')
            sage: F.1+(z+1)*L.2
            b + (z+1)*c

        Check that :trac:`15169` is fixed::

            sage: A.<x> = FreeAlgebra(CC)
            sage: A(2)
            2.00000000000000
        """
        if isinstance(x, FreeAlgebraElement):
            P = x.parent()
            if P is self:
                return x
            if not (P is self.base_ring()):
                return self.element_class(self, x)
        elif hasattr(x,'letterplace_polynomial'):
            P = x.parent()
            if self.has_coerce_map_from(P): # letterplace versus generic
                ngens = P.ngens()
                M = self._basis_keys
                def exp_to_monomial(T):
                    out = []
                    for i in xrange(len(T)):
                        if T[i]:
                            out.append((i%ngens,T[i]))
                    return M(out)
                return self.element_class(self, dict([(exp_to_monomial(T),c) for T,c in x.letterplace_polynomial().dict().iteritems()]))
        # ok, not a free algebra element (or should not be viewed as one).
        if isinstance(x, basestring):
            from sage.all import sage_eval
            return sage_eval(x,locals=self.gens_dict())
        R = self.base_ring()
        # coercion from free monoid
        if isinstance(x, FreeMonoidElement) and x.parent() is self._basis_keys:
            return self.element_class(self,{x:R(1)})
        # coercion from the PBW basis
        if isinstance(x, PBWBasisOfFreeAlgebra.Element) \
                and self.has_coerce_map_from(x.parent()._alg):
            return self(x.parent().expansion(x))
        # coercion via base ring
        x = R(x)
        if x == 0:
            return self.element_class(self,{})
        return self.element_class(self,{self._basis_keys.one():x})

    def _coerce_impl(self, x):
        """
        Canonical coercion of ``x`` into ``self``.

        Here's what canonically coerces to ``self``:

        - this free algebra

        - a free algebra in letterplace implementation that has
          the same generator names and whose base ring coerces
          into ``self``'s base ring

        - the underlying monoid

        - the PBW basis of ``self``

        - anything that coerces to the base ring of this free algebra

        - any free algebra whose base ring coerces to the base ring of
          this free algebra

        EXAMPLES::

            sage: F.<x,y,z> = FreeAlgebra(GF(7),3); F
            Free Algebra on 3 generators (x, y, z) over Finite Field of size 7

        Elements of the free algebra canonically coerce in.

        ::

            sage: F._coerce_(x*y) # indirect doctest
            x*y

        Elements of the integers coerce in, since there is a coerce map
        from ZZ to GF(7).

        ::

            sage: F._coerce_(1)       # indirect doctest
            1

        There is no coerce map from QQ to GF(7).

        ::

            sage: F._coerce_(2/3)
            Traceback (most recent call last):
            ...
            TypeError: no canonical coercion from Rational Field to Free Algebra
            on 3 generators (x, y, z) over Finite Field of size 7

        Elements of the base ring coerce in.

        ::

            sage: F._coerce_(GF(7)(5))
            5

        Elements of the corresponding monoid (of monomials) coerce in::

            sage: M = F.monoid(); m = M.0*M.1^2; m
            x*y^2
            sage: F._coerce_(m)
            x*y^2

        Elements of the PBW basis::

            sage: PBW = F.pbw_basis()
            sage: px,py,pz = PBW.gens()
            sage: F(pz*px*py)
            z*x*y

        The free algebra over ZZ on x,y,z coerces in, since ZZ coerces to
        GF(7)::

            sage: G = FreeAlgebra(ZZ,3,'x,y,z')
            sage: F._coerce_(G.0^3 * G.1)
            x^3*y

        However, GF(7) doesn't coerce to ZZ, so the free algebra over GF(7)
        doesn't coerce to the one over ZZ::

            sage: G._coerce_(x^3*y)
            Traceback (most recent call last):
            ...
            TypeError: no canonical coercion from Free Algebra on 3 generators
            (x, y, z) over Finite Field of size 7 to Free Algebra on 3
            generators (x, y, z) over Integer Ring

        TESTS::

           sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
           sage: L.<x,y,z> = FreeAlgebra(GF(5),3,implementation='letterplace')
           sage: F(x)
           x
           sage: F.1*L.2     # indirect doctest
           y*z

        """
        try:
            R = x.parent()

            # monoid
            if R is self._basis_keys:
                return self(x)

            # polynomial rings in the same variable over any base that coerces in:
            if is_FreeAlgebra(R):
                if R.variable_names() == self.variable_names():
                    if self.has_coerce_map_from(R.base_ring()):
                        return self(x)
                    else:
                        raise TypeError("no natural map between bases of free algebras")

            if isinstance(R, PBWBasisOfFreeAlgebra) and self.has_coerce_map_from(R._alg):
                return self(R.expansion(x))

        except AttributeError:
            pass

        # any ring that coerces to the base ring of this free algebra.
        return self._coerce_try(x, [self.base_ring()])

    def _coerce_map_from_(self, R):
        """
        Return ``True`` if there is a coercion from ``R`` into ``self`` and
        ``False`` otherwise.  The things that coerce into ``self`` are:

        - Anything with a coercion into ``self.monoid()``.

        - Free Algebras in the same variables over a base with a coercion
          map into ``self.base_ring()``.

        - The PBW basis of ``self``.

        - Anything with a coercion into ``self.base_ring()``.

        TESTS::

            sage: F = FreeAlgebra(ZZ, 3, 'x,y,z')
            sage: G = FreeAlgebra(QQ, 3, 'x,y,z')
            sage: H = FreeAlgebra(ZZ, 1, 'y')
            sage: F._coerce_map_from_(G)
            False
            sage: G._coerce_map_from_(F)
            True
            sage: F._coerce_map_from_(H)
            False
            sage: F._coerce_map_from_(QQ)
            False
            sage: G._coerce_map_from_(QQ)
            True
            sage: F._coerce_map_from_(G.monoid())
            True
            sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z'))
            False
            sage: K.<z> = GF(25)
            sage: F.<a,b,c> = FreeAlgebra(K,3)
            sage: L.<a,b,c> = FreeAlgebra(K,3, implementation='letterplace')
            sage: F.1+(z+1)*L.2      # indirect doctest
            b + (z+1)*c

        """
        if self._basis_keys.has_coerce_map_from(R):
            return True

        # free algebras in the same variable over any base that coerces in:
        if is_FreeAlgebra(R):
            if R.variable_names() == self.variable_names():
                if self.base_ring().has_coerce_map_from(R.base_ring()):
                    return True
                else:
                    return False
        if isinstance(R, PBWBasisOfFreeAlgebra):
            return self.has_coerce_map_from(R._alg)

        return self.base_ring().has_coerce_map_from(R)

    def gen(self,i):
        """
        The i-th generator of the algebra.

        EXAMPLES::

            sage: F = FreeAlgebra(ZZ,3,'x,y,z')
            sage: F.gen(0)
            x
        """
        n = self.__ngens
        if i < 0 or not i < n:
            raise IndexError("Argument i (= %s) must be between 0 and %s."%(i, n-1))
        R = self.base_ring()
        F = self._basis_keys
        return self.element_class(self,{F.gen(i):R(1)})

    def quotient(self, mons, mats, names):
        """
        Returns a quotient algebra.

        The quotient algebra is defined via the action of a free algebra
        A on a (finitely generated) free module. The input for the quotient
        algebra is a list of monomials (in the underlying monoid for A)
        which form a free basis for the module of A, and a list of
        matrices, which give the action of the free generators of A on this
        monomial basis.

        EXAMPLE:

        Here is the quaternion algebra defined in terms of three generators::

            sage: n = 3
            sage: A = FreeAlgebra(QQ,n,'i')
            sage: F = A.monoid()
            sage: i, j, k = F.gens()
            sage: mons = [ F(1), i, j, k ]
            sage: M = MatrixSpace(QQ,4)
            sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]),  M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]),  M([0,0,0,1, 0,0,-1,0, 0,1,0,0, -1,0,0,0]) ]
            sage: H.<i,j,k> = A.quotient(mons, mats); H
            Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4 over Rational Field
        """
        import free_algebra_quotient
        return free_algebra_quotient.FreeAlgebraQuotient(self, mons, mats, names)

    quo = quotient

    def ngens(self):
        """
        The number of generators of the algebra.

        EXAMPLES::

            sage: F = FreeAlgebra(ZZ,3,'x,y,z')
            sage: F.ngens()
            3
        """
        return self.__ngens

    def monoid(self):
        """
        The free monoid of generators of the algebra.

        EXAMPLES::

            sage: F = FreeAlgebra(ZZ,3,'x,y,z')
            sage: F.monoid()
            Free monoid on 3 generators (x, y, z)
        """
        return self._basis_keys

    def g_algebra(self, relations, names=None, order='degrevlex', check = True):
        """
        The G-Algebra derived from this algebra by relations.
        By default is assumed, that two variables commute.

        TODO:

        - Coercion doesn't work yet, there is some cheating about assumptions
        - The optional argument ``check`` controls checking the degeneracy
          conditions. Furthermore, the default values interfere with
          non-degeneracy conditions.

        EXAMPLES::

            sage: A.<x,y,z>=FreeAlgebra(QQ,3)
            sage: G=A.g_algebra({y*x:-x*y})
            sage: (x,y,z)=G.gens()
            sage: x*y
            x*y
            sage: y*x
            -x*y
            sage: z*x
            x*z
            sage: (x,y,z)=A.gens()
            sage: G=A.g_algebra({y*x:-x*y+1})
            sage: (x,y,z)=G.gens()
            sage: y*x
            -x*y + 1
            sage: (x,y,z)=A.gens()
            sage: G=A.g_algebra({y*x:-x*y+z})
            sage: (x,y,z)=G.gens()
            sage: y*x
            -x*y + z
        """
        from sage.matrix.constructor  import Matrix

        base_ring=self.base_ring()
        n=self.ngens()
        cmat=Matrix(base_ring,n)
        dmat=Matrix(self,n)
        for i in xrange(n):
            for j in xrange(i+1,n):
                cmat[i,j]=1
        for (to_commute,commuted) in relations.iteritems():
            #This is dirty, coercion is broken
            assert isinstance(to_commute,FreeAlgebraElement), to_commute.__class__
            assert isinstance(commuted,FreeAlgebraElement), commuted
            ((v1,e1),(v2,e2))=list(list(to_commute)[0][1])
            assert e1==1
            assert e2==1
            assert v1>v2
            c_coef=None
            d_poly=None
            for (c,m) in commuted:
                if list(m)==[(v2,1),(v1,1)]:
                    c_coef=c
                    #buggy coercion workaround
                    d_poly=commuted-self(c)*self(m)
                    break
            assert not c_coef is None,list(m)
            v2_ind = self.gens().index(v2)
            v1_ind = self.gens().index(v1)
            cmat[v2_ind,v1_ind]=c_coef
            if d_poly:
                dmat[v2_ind,v1_ind]=d_poly
        from sage.rings.polynomial.plural import g_Algebra
        return g_Algebra(base_ring, cmat, dmat, names = names or self.variable_names(),
                         order=order, check=check)

    def poincare_birkhoff_witt_basis(self):
        """
        Return the Poincare-Birkhoff-Witt (PBW) basis of ``self``.

        EXAMPLES::

            sage: F.<x,y> = FreeAlgebra(QQ, 2)
            sage: F.poincare_birkhoff_witt_basis()
            The Poincare-Birkhoff-Witt basis of Free Algebra on 2 generators (x, y) over Rational Field
        """
        return PBWBasisOfFreeAlgebra(self)

    pbw_basis = poincare_birkhoff_witt_basis

    def pbw_element(self, elt):
        """
        Return the element ``elt`` in the Poincare-Birkhoff-Witt basis.

        EXAMPLES::

            sage: F.<x,y> = FreeAlgebra(QQ, 2)
            sage: F.pbw_element(x*y - y*x + 2)
            2*PBW[1] + PBW[x*y]
            sage: F.pbw_element(F.one())
            PBW[1]
            sage: F.pbw_element(x*y*x + x^3*y)
            PBW[x*y]*PBW[x] + PBW[y]*PBW[x]^2 + PBW[x^3*y] + PBW[x^2*y]*PBW[x]
             + PBW[x*y]*PBW[x]^2 + PBW[y]*PBW[x]^3
        """
        PBW = self.pbw_basis()
        if elt == self.zero():
            return PBW.zero()

        l = {}
        while elt: # != 0
            lst = list(elt)
            support = [i[1].to_word() for i in lst]
            min_elt = support[0]
            for word in support[1:len(support)-1]:
                if min_elt.lex_less(word):
                    min_elt = word
            coeff = lst[support.index(min_elt)][0]
            min_elt = min_elt.to_monoid_element()
            l[min_elt] = l.get(min_elt, 0) + coeff
            elt = elt - coeff * self.lie_polynomial(min_elt)
        return PBW.sum_of_terms([(k, v) for k,v in l.items() if v != 0], distinct=True)

    def lie_polynomial(self, w):
        """
        Return the Lie polynomial associated to the Lyndon word ``w``. If
        ``w`` is not Lyndon, then return the product of Lie polynomials of the
        Lyndon factorization of ``w``.

        INPUT:

        - ``w``-- a word or an element of the free monoid

        EXAMPLES::

            sage: F = FreeAlgebra(QQ, 3, 'x,y,z')
            sage: M.<x,y,z> = FreeMonoid(3)
            sage: F.lie_polynomial(x*y)
            x*y - y*x
            sage: F.lie_polynomial(y*x)
            y*x
            sage: F.lie_polynomial(x^2*y*x)
            x^2*y*x - x*y*x^2
            sage: F.lie_polynomial(y*z*x*z*x*z)
            y*z*x*z*x*z - y*z*x*z^2*x - y*z^2*x^2*z + y*z^2*x*z*x
             - z*y*x*z*x*z + z*y*x*z^2*x + z*y*z*x^2*z - z*y*z*x*z*x

        TESTS:

        We test some corner cases and alternative inputs::

            sage: F.lie_polynomial(Word('xy'))
            x*y - y*x
            sage: F.lie_polynomial('xy')
            x*y - y*x
            sage: F.lie_polynomial(M.one())
            1
            sage: F.lie_polynomial(Word([]))
            1
            sage: F.lie_polynomial('')
            1
        """
        if not w:
            return self.one()
        M = self._basis_keys

        if len(w) == 1:
            return self(M(w))

        ret = self.one()
        # We have to be careful about order here.
        # Since the Lyndon factors appear from left to right
        #   we must multiply from left to right as well.
        for factor in Word(w).lyndon_factorization():
            if len(factor) == 1:
                ret = ret * self(M(factor))
                continue
            x,y = factor.standard_factorization()
            x = M(x)
            y = M(y)
            ret = ret * (self(x * y) - self(y * x))
        return ret
Exemple #9
0
class FreeAlgebra_generic(Algebra):
    """
    The free algebra on `n` generators over a base ring.

    EXAMPLES::

        sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F
        Free Algebra on 3 generators (x, y, z) over Rational Field
        sage: mul(F.gens())
        x*y*z
        sage: mul([ F.gen(i%3) for i in range(12) ])
        x*y*z*x*y*z*x*y*z*x*y*z
        sage: mul([ F.gen(i%3) for i in range(12) ]) + mul([ F.gen(i%2) for i in range(12) ])
        x*y*x*y*x*y*x*y*x*y*x*y + x*y*z*x*y*z*x*y*z*x*y*z
        sage: (2 + x*z + x^2)^2 + (x - y)^2
        4 + 5*x^2 - x*y + 4*x*z - y*x + y^2 + x^4 + x^3*z + x*z*x^2 + x*z*x*z

    TESTS:

    Free algebras commute with their base ring.
    ::

        sage: K.<a,b> = FreeAlgebra(QQ)
        sage: K.is_commutative()
        False
        sage: L.<c,d> = FreeAlgebra(K)
        sage: L.is_commutative()
        False
        sage: s = a*b^2 * c^3; s
        a*b^2*c^3
        sage: parent(s)
        Free Algebra on 2 generators (c, d) over Free Algebra on 2 generators (a, b) over Rational Field
        sage: c^3 * a * b^2
        a*b^2*c^3

    """
    Element = FreeAlgebraElement

    def __init__(self, R, n, names):
        """
        The free algebra on `n` generators over a base ring.

        INPUT:

        -  ``R`` - ring
        -  ``n`` - an integer
        -  ``names`` - generator names

        EXAMPLES::

            sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F # indirect doctet
            Free Algebra on 3 generators (x, y, z) over Rational Field

        TEST:

        Note that the following is *not* the recommended way to create
        a free algebra.
        ::

            sage: from sage.algebras.free_algebra import FreeAlgebra_generic
            sage: FreeAlgebra_generic(ZZ,3,'abc')
            Free Algebra on 3 generators (a, b, c) over Integer Ring

        """
        if not isinstance(R, Ring):
            raise TypeError("Argument R must be a ring.")
        self.__monoid = FreeMonoid(n, names=names)
        self.__ngens = n
        #sage.structure.parent_gens.ParentWithGens.__init__(self, R, names)
        Algebra.__init__(self, R, names=names)

    def is_field(self, proof=True):
        """
        Return True if this Free Algebra is a field, which is only if the
        base ring is a field and there are no generators

        EXAMPLES::

            sage: A=FreeAlgebra(QQ,0,'')
            sage: A.is_field()
            True
            sage: A=FreeAlgebra(QQ,1,'x')
            sage: A.is_field()
            False
        """
        if self.__ngens == 0:
            return self.base_ring().is_field(proof)
        return False

    def is_commutative(self):
        """
        Return True if this free algebra is commutative.

        EXAMPLES::

            sage: R.<x> = FreeAlgebra(QQ,1)
            sage: R.is_commutative()
            True
            sage: R.<x,y> = FreeAlgebra(QQ,2)
            sage: R.is_commutative()
            False
        """
        return self.__ngens <= 1 and self.base_ring().is_commutative()

    def __cmp__(self, other):
        """
        Two free algebras are considered the same if they have the same
        base ring, number of generators and variable names, and the same
        implementation.

        EXAMPLES::

            sage: F = FreeAlgebra(QQ,3,'x')
            sage: F ==  FreeAlgebra(QQ,3,'x')
            True
            sage: F is  FreeAlgebra(QQ,3,'x')
            True
            sage: F == FreeAlgebra(ZZ,3,'x')
            False
            sage: F == FreeAlgebra(QQ,4,'x')
            False
            sage: F == FreeAlgebra(QQ,3,'y')
            False

        Note that since :trac:`7797` there is a different
        implementation of free algebras. Two corresponding free
        algebras in different implementations are not equal, but there
        is a coercion::


        """
        if not isinstance(other, FreeAlgebra_generic):
            return -1
        c = cmp(self.base_ring(), other.base_ring())
        if c: return c
        c = cmp(self.__ngens, other.ngens())
        if c: return c
        c = cmp(self.variable_names(), other.variable_names())
        if c: return c
        return 0

    def _repr_(self):
        """
        Text representation of this free algebra.

        EXAMPLES::

            sage: F = FreeAlgebra(QQ,3,'x')
            sage: F  # indirect doctest
            Free Algebra on 3 generators (x0, x1, x2) over Rational Field
            sage: F.rename('QQ<<x0,x1,x2>>')
            sage: F #indirect doctest
            QQ<<x0,x1,x2>>
            sage: FreeAlgebra(ZZ,1,['a'])
            Free Algebra on 1 generators (a,) over Integer Ring
        """
        return "Free Algebra on %s generators %s over %s" % (
            self.__ngens, self.gens(), self.base_ring())

    def _element_constructor_(self, x):
        """
       Convert x into self.

       EXAMPLES::

           sage: R.<x,y> = FreeAlgebra(QQ,2)
           sage: R(3) # indirect doctest
           3

       TESTS::

           sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
           sage: L.<x,y,z> = FreeAlgebra(ZZ,3,implementation='letterplace')
           sage: F(x)     # indirect doctest
           x
           sage: F.1*L.2
           y*z
           sage: (F.1*L.2).parent() is F
           True

       ::

           sage: K.<z> = GF(25)
           sage: F.<a,b,c> = FreeAlgebra(K,3)
           sage: L.<a,b,c> = FreeAlgebra(K,3, implementation='letterplace')
           sage: F.1+(z+1)*L.2
           b + (z+1)*c

       """
        if isinstance(x, FreeAlgebraElement):
            P = x.parent()
            if P is self:
                return x
            if not (P is self.base_ring()):
                return self.element_class(self, x)
        elif hasattr(x, 'letterplace_polynomial'):
            P = x.parent()
            if self.has_coerce_map_from(P):  # letterplace versus generic
                ngens = P.ngens()
                M = self.__monoid

                def exp_to_monomial(T):
                    out = []
                    for i in xrange(len(T)):
                        if T[i]:
                            out.append((i % ngens, T[i]))
                    return M(out)

                return self.element_class(
                    self,
                    dict([(exp_to_monomial(T), c) for T, c in
                          x.letterplace_polynomial().dict().iteritems()]))
        # ok, not a free algebra element (or should not be viewed as one).
        if isinstance(x, basestring):
            from sage.all import sage_eval
            return sage_eval(x, locals=self.gens_dict())
        F = self.__monoid
        R = self.base_ring()
        # coercion from free monoid
        if isinstance(x, FreeMonoidElement) and x.parent() is F:
            return self.element_class(self, {x: R(1)})
        # coercion via base ring
        x = R(x)
        if x == 0:
            return self.element_class(self, {})
        else:
            return self.element_class(self, {F(1): x})

    def _coerce_impl(self, x):
        """
        Canonical coercion of x into self.

        Here's what canonically coerces to self:

        - this free algebra

        - a free algebra in letterplace implementation that has
          the same generator names and whose base ring coerces
          into self's base ring

        - the underlying monoid

        - anything that coerces to the base ring of this free algebra

        - any free algebra whose base ring coerces to the base ring of
          this free algebra

        EXAMPLES::

            sage: F.<x,y,z> = FreeAlgebra(GF(7),3); F
            Free Algebra on 3 generators (x, y, z) over Finite Field of size 7

        Elements of the free algebra canonically coerce in.

        ::

            sage: F._coerce_(x*y) # indirect doctest
            x*y

        Elements of the integers coerce in, since there is a coerce map
        from ZZ to GF(7).

        ::

            sage: F._coerce_(1)       # indirect doctest
            1

        There is no coerce map from QQ to GF(7).

        ::

            sage: F._coerce_(2/3)
            Traceback (most recent call last):
            ...
            TypeError: no canonical coercion from Rational Field to Free Algebra
            on 3 generators (x, y, z) over Finite Field of size 7

        Elements of the base ring coerce in.

        ::

            sage: F._coerce_(GF(7)(5))
            5

        Elements of the corresponding monoid (of monomials) coerce in::

            sage: M = F.monoid(); m = M.0*M.1^2; m
            x*y^2
            sage: F._coerce_(m)
            x*y^2

        The free algebra over ZZ on x,y,z coerces in, since ZZ coerces to
        GF(7)::

            sage: G = FreeAlgebra(ZZ,3,'x,y,z')
            sage: F._coerce_(G.0^3 * G.1)
            x^3*y

        However, GF(7) doesn't coerce to ZZ, so the free algebra over GF(7)
        doesn't coerce to the one over ZZ::

            sage: G._coerce_(x^3*y)
            Traceback (most recent call last):
            ...
            TypeError: no canonical coercion from Free Algebra on 3 generators
            (x, y, z) over Finite Field of size 7 to Free Algebra on 3
            generators (x, y, z) over Integer Ring

        TESTS::

           sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
           sage: L.<x,y,z> = FreeAlgebra(GF(5),3,implementation='letterplace')
           sage: F(x)
           x
           sage: F.1*L.2     # indirect doctest
           y*z

        """
        try:
            R = x.parent()

            # monoid
            if R is self.__monoid:
                return self(x)

            # polynomial rings in the same variable over any base that coerces in:
            if is_FreeAlgebra(R):
                if R.variable_names() == self.variable_names():
                    if self.has_coerce_map_from(R.base_ring()):
                        return self(x)
                    else:
                        raise TypeError(
                            "no natural map between bases of free algebras")

        except AttributeError:
            pass

        # any ring that coerces to the base ring of this free algebra.
        return self._coerce_try(x, [self.base_ring()])

    def _coerce_map_from_(self, R):
        """
        Returns True if there is a coercion from R into self and false
        otherwise.  The things that coerce into self are:

        - Anything with a coercion into self.monoid()

        - Free Algebras in the same variables over a base with a coercion
          map into self.base_ring()

        - Anything with a coercion into self.base_ring()

        TESTS::

            sage: F = FreeAlgebra(ZZ, 3, 'x,y,z')
            sage: G = FreeAlgebra(QQ, 3, 'x,y,z')
            sage: H = FreeAlgebra(ZZ, 1, 'y')
            sage: F._coerce_map_from_(G)
            False
            sage: G._coerce_map_from_(F)
            True
            sage: F._coerce_map_from_(H)
            False
            sage: F._coerce_map_from_(QQ)
            False
            sage: G._coerce_map_from_(QQ)
            True
            sage: F._coerce_map_from_(G.monoid())
            True
            sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z'))
            False
            sage: K.<z> = GF(25)
            sage: F.<a,b,c> = FreeAlgebra(K,3)
            sage: L.<a,b,c> = FreeAlgebra(K,3, implementation='letterplace')
            sage: F.1+(z+1)*L.2      # indirect doctest
            b + (z+1)*c

        """
        if self.__monoid.has_coerce_map_from(R):
            return True

        # free algebras in the same variable over any base that coerces in:
        if is_FreeAlgebra(R):
            if R.variable_names() == self.variable_names():
                if self.base_ring().has_coerce_map_from(R.base_ring()):
                    return True
                else:
                    return False

        return self.base_ring().has_coerce_map_from(R)

    def gen(self, i):
        """
        The i-th generator of the algebra.

        EXAMPLES::

            sage: F = FreeAlgebra(ZZ,3,'x,y,z')
            sage: F.gen(0)
            x
        """
        n = self.__ngens
        if i < 0 or not i < n:
            raise IndexError("Argument i (= %s) must be between 0 and %s." %
                             (i, n - 1))
        R = self.base_ring()
        F = self.__monoid
        return self.element_class(self, {F.gen(i): R(1)})

    def quotient(self, mons, mats, names):
        """
        Returns a quotient algebra.

        The quotient algebra is defined via the action of a free algebra
        A on a (finitely generated) free module. The input for the quotient
        algebra is a list of monomials (in the underlying monoid for A)
        which form a free basis for the module of A, and a list of
        matrices, which give the action of the free generators of A on this
        monomial basis.

        EXAMPLE:

        Here is the quaternion algebra defined in terms of three generators::

            sage: n = 3
            sage: A = FreeAlgebra(QQ,n,'i')
            sage: F = A.monoid()
            sage: i, j, k = F.gens()
            sage: mons = [ F(1), i, j, k ]
            sage: M = MatrixSpace(QQ,4)
            sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]),  M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]),  M([0,0,0,1, 0,0,-1,0, 0,1,0,0, -1,0,0,0]) ]
            sage: H.<i,j,k> = A.quotient(mons, mats); H
            Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4 over Rational Field
        """
        import free_algebra_quotient
        return free_algebra_quotient.FreeAlgebraQuotient(
            self, mons, mats, names)

    quo = quotient

    def ngens(self):
        """
        The number of generators of the algebra.

        EXAMPLES::

            sage: F = FreeAlgebra(ZZ,3,'x,y,z')
            sage: F.ngens()
            3
        """
        return self.__ngens

    def monoid(self):
        """
        The free monoid of generators of the algebra.

        EXAMPLES::

            sage: F = FreeAlgebra(ZZ,3,'x,y,z')
            sage: F.monoid()
            Free monoid on 3 generators (x, y, z)
        """
        return self.__monoid

    def g_algebra(self, relations, names=None, order='degrevlex', check=True):
        """
        The G-Algebra derived from this algebra by relations.
        By default is assumed, that two variables commute.

        TODO:

        - Coercion doesn't work yet, there is some cheating about assumptions
        - The optional argument ``check`` controls checking the degeneracy
          conditions. Furthermore, the default values interfere with
          non-degeneracy conditions.

        EXAMPLES::

            sage: A.<x,y,z>=FreeAlgebra(QQ,3)
            sage: G=A.g_algebra({y*x:-x*y})
            sage: (x,y,z)=G.gens()
            sage: x*y
            x*y
            sage: y*x
            -x*y
            sage: z*x
            x*z
            sage: (x,y,z)=A.gens()
            sage: G=A.g_algebra({y*x:-x*y+1})
            sage: (x,y,z)=G.gens()
            sage: y*x
            -x*y + 1
            sage: (x,y,z)=A.gens()
            sage: G=A.g_algebra({y*x:-x*y+z})
            sage: (x,y,z)=G.gens()
            sage: y*x
            -x*y + z
        """
        from sage.matrix.constructor import Matrix

        base_ring = self.base_ring()
        n = self.ngens()
        cmat = Matrix(base_ring, n)
        dmat = Matrix(self, n)
        for i in xrange(n):
            for j in xrange(i + 1, n):
                cmat[i, j] = 1
        for (to_commute, commuted) in relations.iteritems():
            #This is dirty, coercion is broken
            assert isinstance(to_commute,
                              FreeAlgebraElement), to_commute.__class__
            assert isinstance(commuted, FreeAlgebraElement), commuted
            ((v1, e1), (v2, e2)) = list(list(to_commute)[0][1])
            assert e1 == 1
            assert e2 == 1
            assert v1 > v2
            c_coef = None
            d_poly = None
            for (c, m) in commuted:
                if list(m) == [(v2, 1), (v1, 1)]:
                    c_coef = c
                    #buggy coercion workaround
                    d_poly = commuted - self(c) * self(m)
                    break
            assert not c_coef is None, list(m)
            v2_ind = self.gens().index(v2)
            v1_ind = self.gens().index(v1)
            cmat[v2_ind, v1_ind] = c_coef
            if d_poly:
                dmat[v2_ind, v1_ind] = d_poly
        from sage.rings.polynomial.plural import g_Algebra
        return g_Algebra(base_ring,
                         cmat,
                         dmat,
                         names=names or self.variable_names(),
                         order=order,
                         check=check)
Exemple #10
0
class FreeAlgebra_generic(Algebra):
    """
    The free algebra on `n` generators over a base ring.

    EXAMPLES::

        sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F
        Free Algebra on 3 generators (x, y, z) over Rational Field
        sage: mul(F.gens())
        x*y*z
        sage: mul([ F.gen(i%3) for i in range(12) ])
        x*y*z*x*y*z*x*y*z*x*y*z
        sage: mul([ F.gen(i%3) for i in range(12) ]) + mul([ F.gen(i%2) for i in range(12) ])
        x*y*x*y*x*y*x*y*x*y*x*y + x*y*z*x*y*z*x*y*z*x*y*z
        sage: (2 + x*z + x^2)^2 + (x - y)^2
        4 + 5*x^2 - x*y + 4*x*z - y*x + y^2 + x^4 + x^3*z + x*z*x^2 + x*z*x*z

    TESTS:

    Free algebras commute with their base ring.
    ::

        sage: K.<a,b> = FreeAlgebra(QQ)
        sage: K.is_commutative()
        False
        sage: L.<c,d> = FreeAlgebra(K)
        sage: L.is_commutative()
        False
        sage: s = a*b^2 * c^3; s
        a*b^2*c^3
        sage: parent(s)
        Free Algebra on 2 generators (c, d) over Free Algebra on 2 generators (a, b) over Rational Field
        sage: c^3 * a * b^2
        a*b^2*c^3

    """
    Element = FreeAlgebraElement

    def __init__(self, R, n, names):
        """
        The free algebra on `n` generators over a base ring.

        INPUT:

        -  ``R`` - ring
        -  ``n`` - an integer
        -  ``names`` - generator names

        EXAMPLES::

            sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F # indirect doctet
            Free Algebra on 3 generators (x, y, z) over Rational Field

        TEST:

        Note that the following is *not* the recommended way to create
        a free algebra.
        ::

            sage: from sage.algebras.free_algebra import FreeAlgebra_generic
            sage: FreeAlgebra_generic(ZZ,3,'abc')
            Free Algebra on 3 generators (a, b, c) over Integer Ring

        """
        if not isinstance(R, Ring):
            raise TypeError("Argument R must be a ring.")
        self.__ngens = n
        #sage.structure.parent_gens.ParentWithGens.__init__(self, R, names)
        self._basis_keys = FreeMonoid(n, names=names)
        Algebra.__init__(self, R, names, category=AlgebrasWithBasis(R))

    def one_basis(self):
        """
        Return the index of the basis element `1`.

        EXAMPLES::

            sage: F = FreeAlgebra(QQ, 2, 'x,y')
            sage: F.one_basis()
            1
            sage: F.one_basis().parent()
            Free monoid on 2 generators (x, y)
        """
        return self._basis_keys.one()

    # Needed for the category AlgebrasWithBasis (but not for Algebras)
    def term(self, index, coeff=None):
        """
        Construct a term of ``self``.

        INPUT:

        - ``index`` -- the index of the basis element
        - ``coeff`` -- (default: 1) an element of the coefficient ring

        EXAMPLES::

            sage: M.<x,y> = FreeMonoid(2)
            sage: F = FreeAlgebra(QQ, 2, 'x,y')
            sage: F.term(x*x*y)
            x^2*y
            sage: F.term(y^3*x*y, 4)
            4*y^3*x*y
            sage: F.term(M.one(), 2)
            2

        TESTS:

        Check to make sure that a coefficient of 0 is properly handled::

            sage: list(F.term(M.one(), 0))
            []
        """
        if coeff is None:
            coeff = self.base_ring().one()
        if coeff == 0:
            return self.element_class(self, {})
        return self.element_class(self, {index: coeff})

    def is_field(self, proof=True):
        """
        Return True if this Free Algebra is a field, which is only if the
        base ring is a field and there are no generators

        EXAMPLES::

            sage: A=FreeAlgebra(QQ,0,'')
            sage: A.is_field()
            True
            sage: A=FreeAlgebra(QQ,1,'x')
            sage: A.is_field()
            False
        """
        if self.__ngens == 0:
            return self.base_ring().is_field(proof)
        return False

    def is_commutative(self):
        """
        Return True if this free algebra is commutative.

        EXAMPLES::

            sage: R.<x> = FreeAlgebra(QQ,1)
            sage: R.is_commutative()
            True
            sage: R.<x,y> = FreeAlgebra(QQ,2)
            sage: R.is_commutative()
            False
        """
        return self.__ngens <= 1 and self.base_ring().is_commutative()

    def __cmp__(self, other):
        """
        Two free algebras are considered the same if they have the same
        base ring, number of generators and variable names, and the same
        implementation.

        EXAMPLES::

            sage: F = FreeAlgebra(QQ,3,'x')
            sage: F ==  FreeAlgebra(QQ,3,'x')
            True
            sage: F is  FreeAlgebra(QQ,3,'x')
            True
            sage: F == FreeAlgebra(ZZ,3,'x')
            False
            sage: F == FreeAlgebra(QQ,4,'x')
            False
            sage: F == FreeAlgebra(QQ,3,'y')
            False

        Note that since :trac:`7797` there is a different
        implementation of free algebras. Two corresponding free
        algebras in different implementations are not equal, but there
        is a coercion::


        """
        if not isinstance(other, FreeAlgebra_generic):
            return -1
        c = cmp(self.base_ring(), other.base_ring())
        if c: return c
        c = cmp(self.__ngens, other.ngens())
        if c: return c
        c = cmp(self.variable_names(), other.variable_names())
        if c: return c
        return 0

    def _repr_(self):
        """
        Text representation of this free algebra.

        EXAMPLES::

            sage: F = FreeAlgebra(QQ,3,'x')
            sage: F  # indirect doctest
            Free Algebra on 3 generators (x0, x1, x2) over Rational Field
            sage: F.rename('QQ<<x0,x1,x2>>')
            sage: F #indirect doctest
            QQ<<x0,x1,x2>>
            sage: FreeAlgebra(ZZ,1,['a'])
            Free Algebra on 1 generators (a,) over Integer Ring
        """
        return "Free Algebra on %s generators %s over %s" % (
            self.__ngens, self.gens(), self.base_ring())

    def _element_constructor_(self, x):
        """
        Convert ``x`` into ``self``.

        EXAMPLES::

            sage: R.<x,y> = FreeAlgebra(QQ,2)
            sage: R(3) # indirect doctest
            3

        TESTS::

            sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
            sage: L.<x,y,z> = FreeAlgebra(ZZ,3,implementation='letterplace')
            sage: F(x)     # indirect doctest
            x
            sage: F.1*L.2
            y*z
            sage: (F.1*L.2).parent() is F
            True

       ::

            sage: K.<z> = GF(25)
            sage: F.<a,b,c> = FreeAlgebra(K,3)
            sage: L.<a,b,c> = FreeAlgebra(K,3, implementation='letterplace')
            sage: F.1+(z+1)*L.2
            b + (z+1)*c

        Check that :trac:`15169` is fixed::

            sage: A.<x> = FreeAlgebra(CC)
            sage: A(2)
            2.00000000000000
        """
        if isinstance(x, FreeAlgebraElement):
            P = x.parent()
            if P is self:
                return x
            if not (P is self.base_ring()):
                return self.element_class(self, x)
        elif hasattr(x, 'letterplace_polynomial'):
            P = x.parent()
            if self.has_coerce_map_from(P):  # letterplace versus generic
                ngens = P.ngens()
                M = self._basis_keys

                def exp_to_monomial(T):
                    out = []
                    for i in xrange(len(T)):
                        if T[i]:
                            out.append((i % ngens, T[i]))
                    return M(out)

                return self.element_class(
                    self,
                    dict([(exp_to_monomial(T), c) for T, c in
                          x.letterplace_polynomial().dict().iteritems()]))
        # ok, not a free algebra element (or should not be viewed as one).
        if isinstance(x, basestring):
            from sage.all import sage_eval
            return sage_eval(x, locals=self.gens_dict())
        R = self.base_ring()
        # coercion from free monoid
        if isinstance(x, FreeMonoidElement) and x.parent() is self._basis_keys:
            return self.element_class(self, {x: R(1)})
        # coercion from the PBW basis
        if isinstance(x, PBWBasisOfFreeAlgebra.Element) \
                and self.has_coerce_map_from(x.parent()._alg):
            return self(x.parent().expansion(x))
        # coercion via base ring
        x = R(x)
        if x == 0:
            return self.element_class(self, {})
        return self.element_class(self, {self._basis_keys.one(): x})

    def _coerce_impl(self, x):
        """
        Canonical coercion of ``x`` into ``self``.

        Here's what canonically coerces to ``self``:

        - this free algebra

        - a free algebra in letterplace implementation that has
          the same generator names and whose base ring coerces
          into ``self``'s base ring

        - the underlying monoid

        - the PBW basis of ``self``

        - anything that coerces to the base ring of this free algebra

        - any free algebra whose base ring coerces to the base ring of
          this free algebra

        EXAMPLES::

            sage: F.<x,y,z> = FreeAlgebra(GF(7),3); F
            Free Algebra on 3 generators (x, y, z) over Finite Field of size 7

        Elements of the free algebra canonically coerce in.

        ::

            sage: F._coerce_(x*y) # indirect doctest
            x*y

        Elements of the integers coerce in, since there is a coerce map
        from ZZ to GF(7).

        ::

            sage: F._coerce_(1)       # indirect doctest
            1

        There is no coerce map from QQ to GF(7).

        ::

            sage: F._coerce_(2/3)
            Traceback (most recent call last):
            ...
            TypeError: no canonical coercion from Rational Field to Free Algebra
            on 3 generators (x, y, z) over Finite Field of size 7

        Elements of the base ring coerce in.

        ::

            sage: F._coerce_(GF(7)(5))
            5

        Elements of the corresponding monoid (of monomials) coerce in::

            sage: M = F.monoid(); m = M.0*M.1^2; m
            x*y^2
            sage: F._coerce_(m)
            x*y^2

        Elements of the PBW basis::

            sage: PBW = F.pbw_basis()
            sage: px,py,pz = PBW.gens()
            sage: F(pz*px*py)
            z*x*y

        The free algebra over ZZ on x,y,z coerces in, since ZZ coerces to
        GF(7)::

            sage: G = FreeAlgebra(ZZ,3,'x,y,z')
            sage: F._coerce_(G.0^3 * G.1)
            x^3*y

        However, GF(7) doesn't coerce to ZZ, so the free algebra over GF(7)
        doesn't coerce to the one over ZZ::

            sage: G._coerce_(x^3*y)
            Traceback (most recent call last):
            ...
            TypeError: no canonical coercion from Free Algebra on 3 generators
            (x, y, z) over Finite Field of size 7 to Free Algebra on 3
            generators (x, y, z) over Integer Ring

        TESTS::

           sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
           sage: L.<x,y,z> = FreeAlgebra(GF(5),3,implementation='letterplace')
           sage: F(x)
           x
           sage: F.1*L.2     # indirect doctest
           y*z

        """
        try:
            R = x.parent()

            # monoid
            if R is self._basis_keys:
                return self(x)

            # polynomial rings in the same variable over any base that coerces in:
            if is_FreeAlgebra(R):
                if R.variable_names() == self.variable_names():
                    if self.has_coerce_map_from(R.base_ring()):
                        return self(x)
                    else:
                        raise TypeError(
                            "no natural map between bases of free algebras")

            if isinstance(R,
                          PBWBasisOfFreeAlgebra) and self.has_coerce_map_from(
                              R._alg):
                return self(R.expansion(x))

        except AttributeError:
            pass

        # any ring that coerces to the base ring of this free algebra.
        return self._coerce_try(x, [self.base_ring()])

    def _coerce_map_from_(self, R):
        """
        Return ``True`` if there is a coercion from ``R`` into ``self`` and
        ``False`` otherwise.  The things that coerce into ``self`` are:

        - Anything with a coercion into ``self.monoid()``.

        - Free Algebras in the same variables over a base with a coercion
          map into ``self.base_ring()``.

        - The PBW basis of ``self``.

        - Anything with a coercion into ``self.base_ring()``.

        TESTS::

            sage: F = FreeAlgebra(ZZ, 3, 'x,y,z')
            sage: G = FreeAlgebra(QQ, 3, 'x,y,z')
            sage: H = FreeAlgebra(ZZ, 1, 'y')
            sage: F._coerce_map_from_(G)
            False
            sage: G._coerce_map_from_(F)
            True
            sage: F._coerce_map_from_(H)
            False
            sage: F._coerce_map_from_(QQ)
            False
            sage: G._coerce_map_from_(QQ)
            True
            sage: F._coerce_map_from_(G.monoid())
            True
            sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z'))
            False
            sage: K.<z> = GF(25)
            sage: F.<a,b,c> = FreeAlgebra(K,3)
            sage: L.<a,b,c> = FreeAlgebra(K,3, implementation='letterplace')
            sage: F.1+(z+1)*L.2      # indirect doctest
            b + (z+1)*c

        """
        if self._basis_keys.has_coerce_map_from(R):
            return True

        # free algebras in the same variable over any base that coerces in:
        if is_FreeAlgebra(R):
            if R.variable_names() == self.variable_names():
                if self.base_ring().has_coerce_map_from(R.base_ring()):
                    return True
                else:
                    return False
        if isinstance(R, PBWBasisOfFreeAlgebra):
            return self.has_coerce_map_from(R._alg)

        return self.base_ring().has_coerce_map_from(R)

    def gen(self, i):
        """
        The i-th generator of the algebra.

        EXAMPLES::

            sage: F = FreeAlgebra(ZZ,3,'x,y,z')
            sage: F.gen(0)
            x
        """
        n = self.__ngens
        if i < 0 or not i < n:
            raise IndexError("Argument i (= %s) must be between 0 and %s." %
                             (i, n - 1))
        R = self.base_ring()
        F = self._basis_keys
        return self.element_class(self, {F.gen(i): R(1)})

    def quotient(self, mons, mats, names):
        """
        Returns a quotient algebra.

        The quotient algebra is defined via the action of a free algebra
        A on a (finitely generated) free module. The input for the quotient
        algebra is a list of monomials (in the underlying monoid for A)
        which form a free basis for the module of A, and a list of
        matrices, which give the action of the free generators of A on this
        monomial basis.

        EXAMPLE:

        Here is the quaternion algebra defined in terms of three generators::

            sage: n = 3
            sage: A = FreeAlgebra(QQ,n,'i')
            sage: F = A.monoid()
            sage: i, j, k = F.gens()
            sage: mons = [ F(1), i, j, k ]
            sage: M = MatrixSpace(QQ,4)
            sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]),  M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]),  M([0,0,0,1, 0,0,-1,0, 0,1,0,0, -1,0,0,0]) ]
            sage: H.<i,j,k> = A.quotient(mons, mats); H
            Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4 over Rational Field
        """
        import free_algebra_quotient
        return free_algebra_quotient.FreeAlgebraQuotient(
            self, mons, mats, names)

    quo = quotient

    def ngens(self):
        """
        The number of generators of the algebra.

        EXAMPLES::

            sage: F = FreeAlgebra(ZZ,3,'x,y,z')
            sage: F.ngens()
            3
        """
        return self.__ngens

    def monoid(self):
        """
        The free monoid of generators of the algebra.

        EXAMPLES::

            sage: F = FreeAlgebra(ZZ,3,'x,y,z')
            sage: F.monoid()
            Free monoid on 3 generators (x, y, z)
        """
        return self._basis_keys

    def g_algebra(self, relations, names=None, order='degrevlex', check=True):
        """
        The G-Algebra derived from this algebra by relations.
        By default is assumed, that two variables commute.

        TODO:

        - Coercion doesn't work yet, there is some cheating about assumptions
        - The optional argument ``check`` controls checking the degeneracy
          conditions. Furthermore, the default values interfere with
          non-degeneracy conditions.

        EXAMPLES::

            sage: A.<x,y,z>=FreeAlgebra(QQ,3)
            sage: G=A.g_algebra({y*x:-x*y})
            sage: (x,y,z)=G.gens()
            sage: x*y
            x*y
            sage: y*x
            -x*y
            sage: z*x
            x*z
            sage: (x,y,z)=A.gens()
            sage: G=A.g_algebra({y*x:-x*y+1})
            sage: (x,y,z)=G.gens()
            sage: y*x
            -x*y + 1
            sage: (x,y,z)=A.gens()
            sage: G=A.g_algebra({y*x:-x*y+z})
            sage: (x,y,z)=G.gens()
            sage: y*x
            -x*y + z
        """
        from sage.matrix.constructor import Matrix

        base_ring = self.base_ring()
        n = self.ngens()
        cmat = Matrix(base_ring, n)
        dmat = Matrix(self, n)
        for i in xrange(n):
            for j in xrange(i + 1, n):
                cmat[i, j] = 1
        for (to_commute, commuted) in relations.iteritems():
            #This is dirty, coercion is broken
            assert isinstance(to_commute,
                              FreeAlgebraElement), to_commute.__class__
            assert isinstance(commuted, FreeAlgebraElement), commuted
            ((v1, e1), (v2, e2)) = list(list(to_commute)[0][1])
            assert e1 == 1
            assert e2 == 1
            assert v1 > v2
            c_coef = None
            d_poly = None
            for (c, m) in commuted:
                if list(m) == [(v2, 1), (v1, 1)]:
                    c_coef = c
                    #buggy coercion workaround
                    d_poly = commuted - self(c) * self(m)
                    break
            assert not c_coef is None, list(m)
            v2_ind = self.gens().index(v2)
            v1_ind = self.gens().index(v1)
            cmat[v2_ind, v1_ind] = c_coef
            if d_poly:
                dmat[v2_ind, v1_ind] = d_poly
        from sage.rings.polynomial.plural import g_Algebra
        return g_Algebra(base_ring,
                         cmat,
                         dmat,
                         names=names or self.variable_names(),
                         order=order,
                         check=check)

    def poincare_birkhoff_witt_basis(self):
        """
        Return the Poincare-Birkhoff-Witt (PBW) basis of ``self``.

        EXAMPLES::

            sage: F.<x,y> = FreeAlgebra(QQ, 2)
            sage: F.poincare_birkhoff_witt_basis()
            The Poincare-Birkhoff-Witt basis of Free Algebra on 2 generators (x, y) over Rational Field
        """
        return PBWBasisOfFreeAlgebra(self)

    pbw_basis = poincare_birkhoff_witt_basis

    def pbw_element(self, elt):
        """
        Return the element ``elt`` in the Poincare-Birkhoff-Witt basis.

        EXAMPLES::

            sage: F.<x,y> = FreeAlgebra(QQ, 2)
            sage: F.pbw_element(x*y - y*x + 2)
            2*PBW[1] + PBW[x*y]
            sage: F.pbw_element(F.one())
            PBW[1]
            sage: F.pbw_element(x*y*x + x^3*y)
            PBW[x*y]*PBW[x] + PBW[y]*PBW[x]^2 + PBW[x^3*y] + PBW[x^2*y]*PBW[x]
             + PBW[x*y]*PBW[x]^2 + PBW[y]*PBW[x]^3
        """
        PBW = self.pbw_basis()
        if elt == self.zero():
            return PBW.zero()

        l = {}
        while elt:  # != 0
            lst = list(elt)
            support = [i[1].to_word() for i in lst]
            min_elt = support[0]
            for word in support[1:len(support) - 1]:
                if min_elt.lex_less(word):
                    min_elt = word
            coeff = lst[support.index(min_elt)][0]
            min_elt = min_elt.to_monoid_element()
            l[min_elt] = l.get(min_elt, 0) + coeff
            elt = elt - coeff * self.lie_polynomial(min_elt)
        return PBW.sum_of_terms([(k, v) for k, v in l.items() if v != 0],
                                distinct=True)

    def lie_polynomial(self, w):
        """
        Return the Lie polynomial associated to the Lyndon word ``w``. If
        ``w`` is not Lyndon, then return the product of Lie polynomials of the
        Lyndon factorization of ``w``.

        INPUT:

        - ``w``-- a word or an element of the free monoid

        EXAMPLES::

            sage: F = FreeAlgebra(QQ, 3, 'x,y,z')
            sage: M.<x,y,z> = FreeMonoid(3)
            sage: F.lie_polynomial(x*y)
            x*y - y*x
            sage: F.lie_polynomial(y*x)
            y*x
            sage: F.lie_polynomial(x^2*y*x)
            x^2*y*x - x*y*x^2
            sage: F.lie_polynomial(y*z*x*z*x*z)
            y*z*x*z*x*z - y*z*x*z^2*x - y*z^2*x^2*z + y*z^2*x*z*x
             - z*y*x*z*x*z + z*y*x*z^2*x + z*y*z*x^2*z - z*y*z*x*z*x

        TESTS:

        We test some corner cases and alternative inputs::

            sage: F.lie_polynomial(Word('xy'))
            x*y - y*x
            sage: F.lie_polynomial('xy')
            x*y - y*x
            sage: F.lie_polynomial(M.one())
            1
            sage: F.lie_polynomial(Word([]))
            1
            sage: F.lie_polynomial('')
            1
        """
        if not w:
            return self.one()
        M = self._basis_keys

        if len(w) == 1:
            return self(M(w))

        ret = self.one()
        # We have to be careful about order here.
        # Since the Lyndon factors appear from left to right
        #   we must multiply from left to right as well.
        for factor in Word(w).lyndon_factorization():
            if len(factor) == 1:
                ret = ret * self(M(factor))
                continue
            x, y = factor.standard_factorization()
            x = M(x)
            y = M(y)
            ret = ret * (self(x * y) - self(y * x))
        return ret
Exemple #11
0
class FreeAlgebra_generic(Algebra):
    """
    The free algebra on `n` generators over a base ring.

    EXAMPLES::

        sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F
        Free Algebra on 3 generators (x, y, z) over Rational Field
        sage: mul(F.gens())
        x*y*z
        sage: mul([ F.gen(i%3) for i in range(12) ])
        x*y*z*x*y*z*x*y*z*x*y*z
        sage: mul([ F.gen(i%3) for i in range(12) ]) + mul([ F.gen(i%2) for i in range(12) ])
        x*y*x*y*x*y*x*y*x*y*x*y + x*y*z*x*y*z*x*y*z*x*y*z
        sage: (2 + x*z + x^2)^2 + (x - y)^2
        4 + 5*x^2 - x*y + 4*x*z - y*x + y^2 + x^4 + x^3*z + x*z*x^2 + x*z*x*z

    TESTS:

    Free algebras commute with their base ring.
    ::

        sage: K.<a,b> = FreeAlgebra(QQ)
        sage: K.is_commutative()
        False
        sage: L.<c,d> = FreeAlgebra(K)
        sage: L.is_commutative()
        False
        sage: s = a*b^2 * c^3; s
        a*b^2*c^3
        sage: parent(s)
        Free Algebra on 2 generators (c, d) over Free Algebra on 2 generators (a, b) over Rational Field
        sage: c^3 * a * b^2
        a*b^2*c^3

    """
    Element = FreeAlgebraElement
    def __init__(self, R, n, names):
        """
        The free algebra on `n` generators over a base ring.

        INPUT:

        -  ``R`` - ring
        -  ``n`` - an integer
        -  ``names`` - generator names

        EXAMPLES::

            sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F # indirect doctet
            Free Algebra on 3 generators (x, y, z) over Rational Field

        TEST:

        Note that the following is *not* the recommended way to create
        a free algebra.
        ::

            sage: from sage.algebras.free_algebra import FreeAlgebra_generic
            sage: FreeAlgebra_generic(ZZ,3,'abc')
            Free Algebra on 3 generators (a, b, c) over Integer Ring

        """
        if not isinstance(R, Ring):
            raise TypeError("Argument R must be a ring.")
        self.__monoid = FreeMonoid(n, names=names)
        self.__ngens = n
        #sage.structure.parent_gens.ParentWithGens.__init__(self, R, names)
        Algebra.__init__(self, R,names=names)

    def is_field(self, proof = True):
        """
        Return True if this Free Algebra is a field, which is only if the
        base ring is a field and there are no generators

        EXAMPLES::

            sage: A=FreeAlgebra(QQ,0,'')
            sage: A.is_field()
            True
            sage: A=FreeAlgebra(QQ,1,'x')
            sage: A.is_field()
            False
        """
        if self.__ngens == 0:
            return self.base_ring().is_field(proof)
        return False

    def is_commutative(self):
        """
        Return True if this free algebra is commutative.

        EXAMPLES::

            sage: R.<x> = FreeAlgebra(QQ,1)
            sage: R.is_commutative()
            True
            sage: R.<x,y> = FreeAlgebra(QQ,2)
            sage: R.is_commutative()
            False
        """
        return self.__ngens <= 1 and self.base_ring().is_commutative()

    def __cmp__(self, other):
        """
        Two free algebras are considered the same if they have the same
        base ring, number of generators and variable names, and the same
        implementation.

        EXAMPLES::

            sage: F = FreeAlgebra(QQ,3,'x')
            sage: F ==  FreeAlgebra(QQ,3,'x')
            True
            sage: F is  FreeAlgebra(QQ,3,'x')
            True
            sage: F == FreeAlgebra(ZZ,3,'x')
            False
            sage: F == FreeAlgebra(QQ,4,'x')
            False
            sage: F == FreeAlgebra(QQ,3,'y')
            False

        Note that since :trac:`7797` there is a different
        implementation of free algebras. Two corresponding free
        algebras in different implementations are not equal, but there
        is a coercion::

        """
        if not isinstance(other, FreeAlgebra_generic):
            return -1
        c = cmp(self.base_ring(), other.base_ring())
        if c: return c
        c = cmp(self.__ngens, other.ngens())
        if c: return c
        c = cmp(self.variable_names(), other.variable_names())
        if c: return c
        return 0

    def _repr_(self):
        """
        Text representation of this free algebra.

        EXAMPLES::

            sage: F = FreeAlgebra(QQ,3,'x')
            sage: F  # indirect doctest
            Free Algebra on 3 generators (x0, x1, x2) over Rational Field
            sage: F.rename('QQ<<x0,x1,x2>>')
            sage: F #indirect doctest
            QQ<<x0,x1,x2>>
            sage: FreeAlgebra(ZZ,1,['a'])
            Free Algebra on 1 generators (a,) over Integer Ring
        """
        return "Free Algebra on %s generators %s over %s"%(
            self.__ngens, self.gens(), self.base_ring())

    def _element_constructor_(self, x):
        """
       Convert x into self.

       EXAMPLES::

           sage: R.<x,y> = FreeAlgebra(QQ,2)
           sage: R(3) # indirect doctest
           3

       TESTS::

           sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
           sage: L.<x,y,z> = FreeAlgebra(ZZ,3,implementation='letterplace')
           sage: F(x)     # indirect doctest
           x
           sage: F.1*L.2
           y*z
           sage: (F.1*L.2).parent() is F
           True

       ::

           sage: K.<z> = GF(25)
           sage: F.<a,b,c> = FreeAlgebra(K,3)
           sage: L.<a,b,c> = FreeAlgebra(K,3, implementation='letterplace')
           sage: F.1+(z+1)*L.2
           b + (z+1)*c

       """
        if isinstance(x, FreeAlgebraElement):
            P = x.parent()
            if P is self:
                return x
            if not (P is self.base_ring()):
                return self.element_class(self, x)
        elif hasattr(x,'letterplace_polynomial'):
            P = x.parent()
            if self.has_coerce_map_from(P): # letterplace versus generic
                ngens = P.ngens()
                M = self.__monoid
                def exp_to_monomial(T):
                    out = []
                    for i in xrange(len(T)):
                        if T[i]:
                            out.append((i%ngens,T[i]))
                    return M(out)
                return self.element_class(self, dict([(exp_to_monomial(T),c) for T,c in x.letterplace_polynomial().dict().iteritems()]))
        # ok, not a free algebra element (or should not be viewed as one).
        if isinstance(x, basestring):
            from sage.all import sage_eval
            return sage_eval(x,locals=self.gens_dict())
        F = self.__monoid
        R = self.base_ring()
        # coercion from free monoid
        if isinstance(x, FreeMonoidElement) and x.parent() is F:
            return self.element_class(self,{x:R(1)})
        # coercion via base ring
        x = R(x)
        if x == 0:
            return self.element_class(self,{})
        else:
            return self.element_class(self,{F(1):x})

    def _coerce_impl(self, x):
        """
        Canonical coercion of x into self.

        Here's what canonically coerces to self:

        - this free algebra

        - a free algebra in letterplace implementation that has
          the same generator names and whose base ring coerces
          into self's base ring

        - the underlying monoid

        - anything that coerces to the base ring of this free algebra

        - any free algebra whose base ring coerces to the base ring of
          this free algebra

        EXAMPLES::

            sage: F.<x,y,z> = FreeAlgebra(GF(7),3); F
            Free Algebra on 3 generators (x, y, z) over Finite Field of size 7

        Elements of the free algebra canonically coerce in.

        ::

            sage: F._coerce_(x*y) # indirect doctest
            x*y

        Elements of the integers coerce in, since there is a coerce map
        from ZZ to GF(7).

        ::

            sage: F._coerce_(1)       # indirect doctest
            1

        There is no coerce map from QQ to GF(7).

        ::

            sage: F._coerce_(2/3)
            Traceback (most recent call last):
            ...
            TypeError: no canonical coercion from Rational Field to Free Algebra
            on 3 generators (x, y, z) over Finite Field of size 7

        Elements of the base ring coerce in.

        ::

            sage: F._coerce_(GF(7)(5))
            5

        Elements of the corresponding monoid (of monomials) coerce in::

            sage: M = F.monoid(); m = M.0*M.1^2; m
            x*y^2
            sage: F._coerce_(m)
            x*y^2

        The free algebra over ZZ on x,y,z coerces in, since ZZ coerces to
        GF(7)::

            sage: G = FreeAlgebra(ZZ,3,'x,y,z')
            sage: F._coerce_(G.0^3 * G.1)
            x^3*y

        However, GF(7) doesn't coerce to ZZ, so the free algebra over GF(7)
        doesn't coerce to the one over ZZ::

            sage: G._coerce_(x^3*y)
            Traceback (most recent call last):
            ...
            TypeError: no canonical coercion from Free Algebra on 3 generators
            (x, y, z) over Finite Field of size 7 to Free Algebra on 3
            generators (x, y, z) over Integer Ring

        TESTS::

           sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
           sage: L.<x,y,z> = FreeAlgebra(GF(5),3,implementation='letterplace')
           sage: F(x)
           x
           sage: F.1*L.2     # indirect doctest
           y*z

        """
        try:
            R = x.parent()

            # monoid
            if R is self.__monoid:
                return self(x)

            # polynomial rings in the same variable over any base that coerces in:
            if is_FreeAlgebra(R):
                if R.variable_names() == self.variable_names():
                    if self.has_coerce_map_from(R.base_ring()):
                        return self(x)
                    else:
                        raise TypeError("no natural map between bases of free algebras")

        except AttributeError:
            pass

        # any ring that coerces to the base ring of this free algebra.
        return self._coerce_try(x, [self.base_ring()])

    def _coerce_map_from_(self, R):
        """
        Returns True if there is a coercion from R into self and false
        otherwise.  The things that coerce into self are:

        - Anything with a coercion into self.monoid()

        - Free Algebras in the same variables over a base with a coercion
          map into self.base_ring()

        - Anything with a coercion into self.base_ring()

        TESTS::

            sage: F = FreeAlgebra(ZZ, 3, 'x,y,z')
            sage: G = FreeAlgebra(QQ, 3, 'x,y,z')
            sage: H = FreeAlgebra(ZZ, 1, 'y')
            sage: F._coerce_map_from_(G)
            False
            sage: G._coerce_map_from_(F)
            True
            sage: F._coerce_map_from_(H)
            False
            sage: F._coerce_map_from_(QQ)
            False
            sage: G._coerce_map_from_(QQ)
            True
            sage: F._coerce_map_from_(G.monoid())
            True
            sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z'))
            False
            sage: K.<z> = GF(25)
            sage: F.<a,b,c> = FreeAlgebra(K,3)
            sage: L.<a,b,c> = FreeAlgebra(K,3, implementation='letterplace')
            sage: F.1+(z+1)*L.2      # indirect doctest
            b + (z+1)*c

        """
        if self.__monoid.has_coerce_map_from(R):
            return True

        # free algebras in the same variable over any base that coerces in:
        if is_FreeAlgebra(R):
            if R.variable_names() == self.variable_names():
                if self.base_ring().has_coerce_map_from(R.base_ring()):
                    return True
                else:
                    return False

        return self.base_ring().has_coerce_map_from(R)

    def gen(self,i):
        """
        The i-th generator of the algebra.

        EXAMPLES::

            sage: F = FreeAlgebra(ZZ,3,'x,y,z')
            sage: F.gen(0)
            x
        """
        n = self.__ngens
        if i < 0 or not i < n:
            raise IndexError("Argument i (= %s) must be between 0 and %s."%(i, n-1))
        R = self.base_ring()
        F = self.__monoid
        return self.element_class(self,{F.gen(i):R(1)})

    def quotient(self, mons, mats, names):
        """
        Returns a quotient algebra.

        The quotient algebra is defined via the action of a free algebra
        A on a (finitely generated) free module. The input for the quotient
        algebra is a list of monomials (in the underlying monoid for A)
        which form a free basis for the module of A, and a list of
        matrices, which give the action of the free generators of A on this
        monomial basis.

        EXAMPLE:

        Here is the quaternion algebra defined in terms of three generators::

            sage: n = 3
            sage: A = FreeAlgebra(QQ,n,'i')
            sage: F = A.monoid()
            sage: i, j, k = F.gens()
            sage: mons = [ F(1), i, j, k ]
            sage: M = MatrixSpace(QQ,4)
            sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]),  M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]),  M([0,0,0,1, 0,0,-1,0, 0,1,0,0, -1,0,0,0]) ]
            sage: H.<i,j,k> = A.quotient(mons, mats); H
            Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4 over Rational Field
        """
        import free_algebra_quotient
        return free_algebra_quotient.FreeAlgebraQuotient(self, mons, mats, names)
    quo = quotient

    def ngens(self):
        """
        The number of generators of the algebra.

        EXAMPLES::

            sage: F = FreeAlgebra(ZZ,3,'x,y,z')
            sage: F.ngens()
            3
        """
        return self.__ngens

    def monoid(self):
        """
        The free monoid of generators of the algebra.

        EXAMPLES::

            sage: F = FreeAlgebra(ZZ,3,'x,y,z')
            sage: F.monoid()
            Free monoid on 3 generators (x, y, z)
        """
        return self.__monoid

    def g_algebra(self, relations, names=None, order='degrevlex', check = True):
        """
        The G-Algebra derived from this algebra by relations.
        By default is assumed, that two variables commute.

        TODO:

        - Coercion doesn't work yet, there is some cheating about assumptions
        - The optional argument ``check`` controls checking the degeneracy
          conditions. Furthermore, the default values interfere with
          non-degeneracy conditions.

        EXAMPLES::

            sage: A.<x,y,z>=FreeAlgebra(QQ,3)
            sage: G=A.g_algebra({y*x:-x*y})
            sage: (x,y,z)=G.gens()
            sage: x*y
            x*y
            sage: y*x
            -x*y
            sage: z*x
            x*z
            sage: (x,y,z)=A.gens()
            sage: G=A.g_algebra({y*x:-x*y+1})
            sage: (x,y,z)=G.gens()
            sage: y*x
            -x*y + 1
            sage: (x,y,z)=A.gens()
            sage: G=A.g_algebra({y*x:-x*y+z})
            sage: (x,y,z)=G.gens()
            sage: y*x
            -x*y + z
        """
        from sage.matrix.constructor  import Matrix

        base_ring=self.base_ring()
        n=self.ngens()
        cmat=Matrix(base_ring,n)
        dmat=Matrix(self,n)
        for i in xrange(n):
            for j in xrange(i+1,n):
                cmat[i,j]=1
        for (to_commute,commuted) in relations.iteritems():
            #This is dirty, coercion is broken
            assert isinstance(to_commute,FreeAlgebraElement), to_commute.__class__
            assert isinstance(commuted,FreeAlgebraElement), commuted
            ((v1,e1),(v2,e2))=list(list(to_commute)[0][1])
            assert e1==1
            assert e2==1
            assert v1>v2
            c_coef=None
            d_poly=None
            for (c,m) in commuted:
                if list(m)==[(v2,1),(v1,1)]:
                    c_coef=c
                    #buggy coercion workaround
                    d_poly=commuted-self(c)*self(m)
                    break
            assert not c_coef is None,list(m)
            v2_ind = self.gens().index(v2)
            v1_ind = self.gens().index(v1)
            cmat[v2_ind,v1_ind]=c_coef
            if d_poly:
                dmat[v2_ind,v1_ind]=d_poly
        from sage.rings.polynomial.plural import g_Algebra
        return g_Algebra(base_ring, cmat, dmat, names = names or self.variable_names(),
                         order=order, check=check)