Ask Your Question

Revision history [back]

Here is a function to produce the desired quotient algebra.

Given generator names, a maximum degree, and a base ring, it builds the free algebra on the generators with the requested names over the requested ring, and outputs the quotient modulo terms of degree higher than the specified maximum degree.

def my_algebra(gen_names, max_degree=2, base_ring=QQ):
    r"""
    Return the quotient of the free algebra on these generators
    by terms of degree ``max_degree + 1``.

    EXAMPLES::

        sage: G = my_algebra(['a', 'b'], max_degree=2, base_ring=QQ)
        sage: G.inject_variables()
        sage: (a * b + a) * b
        ab
        sage: gens = (G.one(),) + G.gens()
        sage: prods = [[x * y for y in gens] for x in gens]
        sage: hr = gens
        sage: hc = ('*',) + gens
        sage: table(prods, header_row=hr, header_column=hc)
          *  | 1    a    b    aa   ab   ba   bb
        +----+----+----+----+----+----+----+----+
          1  | 1    a    b    aa   ab   ba   bb
          a  | a    aa   ab   0    0    0    0
          b  | b    ba   bb   0    0    0    0
          aa | aa   0    0    0    0    0    0
          ab | ab   0    0    0    0    0    0
          ba | ba   0    0    0    0    0    0
          bb | bb   0    0    0    0    0    0
    """
    n = max_degree
    R = base_ring
    words = [w for W in [Words(gen_names, j) for j in range(n + 1)] for w in W]
    names = [str(w) for w in words[1:]]
    F = FreeAlgebra(R, names=names)
    FM = F.monoid()
    gens = FM.gens()
    mons = (FM.one(),) + gens
    r = len(mons)
    M = MatrixSpace(R, r)
    def row(m, mm):
        if len(m) + len(mm) > n:
            return [0] * r
        res = [0] * r
        res[words.index(mm * m)] = 1
        return res
    mats = [M([row(m, mm) for mm in words]) for m in words[1:]]
    return FreeAlgebraQuotient(F, mons, mats, names=names)

Here is a function to produce the desired quotient algebra.

Given generator names, a maximum degree, and a base ring, it builds the free algebra on the generators with the requested names over the requested ring, and outputs the quotient modulo terms of degree higher than the specified maximum degree.

The following function works with one-letter generators.

def my_algebra(gen_names, max_degree=2, base_ring=QQ):
    r"""
    Return the quotient of the free algebra on these generators
    by terms of degree ``max_degree + 1``.

    EXAMPLES::

        sage: G = my_algebra(['a', 'b'], max_degree=2, base_ring=QQ)
        sage: G.inject_variables()
        sage: (a * b + a) * b
        ab
        sage: gens = (G.one(),) + G.gens()
        sage: prods = [[x * y for y in gens] for x in gens]
        sage: hr = gens
        sage: hc = ('*',) + gens
        sage: table(prods, header_row=hr, header_column=hc)
          *  | 1    a    b    aa   ab   ba   bb
        +----+----+----+----+----+----+----+----+
          1  | 1    a    b    aa   ab   ba   bb
          a  | a    aa   ab   0    0    0    0
          b  | b    ba   bb   0    0    0    0
          aa | aa   0    0    0    0    0    0
          ab | ab   0    0    0    0    0    0
          ba | ba   0    0    0    0    0    0
          bb | bb   0    0    0    0    0    0
    """
    n = max_degree
    R = base_ring
    words = [w for W in [Words(gen_names, j) for j in range(n + 1)] for w in W]
    names = [str(w) for w in words[1:]]
    F = FreeAlgebra(R, names=names)
    FM = F.monoid()
    gens = FM.gens()
    mons = (FM.one(),) + gens
    r = len(mons)
    M = MatrixSpace(R, r)
    def row(m, mm):
        if len(m) + len(mm) > n:
            return [0] * r
        res = [0] * r
        res[words.index(mm * m)] = 1
        return res
    mats = [M([row(m, mm) for mm in words]) for m in words[1:]]
    return FreeAlgebraQuotient(F, mons, mats, names=names)

This variant accepts multicharacter generator names:

def my_algebra(gen_names, max_degree=2, base_ring=QQ):
    r"""
    Return the quotient of the free algebra on these generators
    by terms of degree ``max_degree + 1``.
    """
    n = max_degree
    R = base_ring
    word_options = dict(WordOptions())
    WordOptions(letter_separator='')
    words = [w for W in [Words(gen_names, j) for j in range(n + 1)] for w in W]
    names = [str(w) for w in words[1:]]
    F = FreeAlgebra(R, names=names)
    FM = F.monoid()
    gens = FM.gens()
    mons = (FM.one(),) + gens
    r = len(mons)
    M = MatrixSpace(R, r)
    def row(m, mm):
        if len(m) + len(mm) > n:
            return [0] * r
        res = [0] * r
        res[words.index(mm * m)] = 1
        return res
    mats = [M([row(m, mm) for mm in words]) for m in words[1:]]
    WordOptions(**word_options)
    return FreeAlgebraQuotient(F, mons, mats, names=names)

This function gives the multiplication table:

def algebra_table(G):
    gens = (G.one(),) + G.gens()
    prods = [[x * y for y in gens] for x in gens]
    hr = gens
    hc = ('*',) + gens
    return table(prods, header_row=hr, header_column=hc)

Some trials in the Sage REPL:

sage: G = my_algebra(['a', 'b'], max_degree=2, base_ring=QQ)
sage: a, b = G.gen(0), G.gen(1)
sage: (a * b + a) * b
ab

sage: algebra_table(G)
  *  | 1    a    b    aa   ab   ba   bb
+----+----+----+----+----+----+----+----+
  1  | 1    a    b    aa   ab   ba   bb
  a  | a    aa   ab   0    0    0    0
  b  | b    ba   bb   0    0    0    0
  aa | aa   0    0    0    0    0    0
  ab | ab   0    0    0    0    0    0
  ba | ba   0    0    0    0    0    0
  bb | bb   0    0    0    0    0    0

sage: G = my_algebra(['x1', 'x2'], max_degree=2, base_ring=QQ)
sage: a, b = G.gen(0), G.gen(1)
sage: (a * b + a) * b
x1x2

sage: algebra_table(G)
  *    | 1      x1     x2     x1x1   x1x2   x2x1   x2x2
+------+------+------+------+------+------+------+------+
  1    | 1      x1     x2     x1x1   x1x2   x2x1   x2x2
  x1   | x1     x1x1   x1x2   0      0      0      0
  x2   | x2     x2x1   x2x2   0      0      0      0
  x1x1 | x1x1   0      0      0      0      0      0
  x1x2 | x1x2   0      0      0      0      0      0
  x2x1 | x2x1   0      0      0      0      0      0
  x2x2 | x2x2   0      0      0      0      0      0

sage: G = my_algebra(['x_1', 'x_2'], max_degree=2, base_ring=QQ)
sage: a, b = G.gen(0), G.gen(1)
sage: (a * b + a) * b
x_1x_2

sage: algebra_table(G)
  *      | 1        x_1      x_2      x_1x_1   x_1x_2   x_2x_1   x_2x_2
+--------+--------+--------+--------+--------+--------+--------+--------+
  1      | 1        x_1      x_2      x_1x_1   x_1x_2   x_2x_1   x_2x_2
  x_1    | x_1      x_1x_1   x_1x_2   0        0        0        0
  x_2    | x_2      x_2x_1   x_2x_2   0        0        0        0
  x_1x_1 | x_1x_1   0        0        0        0        0        0
  x_1x_2 | x_1x_2   0        0        0        0        0        0
  x_2x_1 | x_2x_1   0        0        0        0        0        0
  x_2x_2 | x_2x_2   0        0        0        0        0        0

In Jupyter, latexing is off for names such as x1x2 or x_1x_2. Not sure how to fix that.