Ask Your Question

Revision history [back]

This has to do with rewriting systems for groups given by presentations.

When a group G is defined as a quotient of the free group by some relations, as in the question, elements in G are stored as words in the generators.

Deciding whether elements given by different words are equal in the group is undecidable in general, although of course for some groups it is decidable.

Technically speaking, a rewriting system is associated with the group presentation.

A rewriting system is called confluent if it provides a canonical representative for each group element.

The rewriting system associated with the group G as defined in the question is not confluent.

sage: F.<x> = FreeGroup('x')
sage: G = F / [x^3]

sage: r = G.rewriting_system()
sage: r
Rewriting system of Finitely presented group < x | x^3 >
with rules:
    x^3    --->    1

sage: s = G.rewriting_system()
sage: s.make_confluent()
sage: s
Rewriting system of Finitely presented group < x | x^3 >
with rules:
    x^-2    --->    x
    x^2    --->    x^-1

To compare the initial rewriting system and the confluent one:

sage: r.is_confluent()
False
sage: s.is_confluent()
True

The initial one can only simplify positive multiples of 3 in the exponent, while the confluent one gives a unique form with exponents between -1 and 1.

sage: a = "  n    x^n   G(x^n)   r(x^n)   s(x^n)"
sage: b = "-------------------------------------"
sage: c = [(n, x^n, G(x^n), r.reduce(x^n), s.reduce(x^n)) for n in range(-5, 8)]
sage: print('\n'.join(['', a, b] + ["%3s %6s %8s %8s %8s" % t for t in c]))

  n    x^n   G(x^n)   r(x^n)   s(x^n)
-------------------------------------
 -5   x^-5     x^-5     x^-5        x
 -4   x^-4     x^-4     x^-4     x^-1
 -3   x^-3     x^-3     x^-3        1
 -2   x^-2     x^-2     x^-2        x
 -1   x^-1     x^-1     x^-1     x^-1
  0      1        1        1        1
  1      x        x        x        x
  2    x^2      x^2      x^2     x^-1
  3    x^3      x^3        1        1
  4    x^4      x^4        x        x
  5    x^5      x^5      x^2     x^-1
  6    x^6      x^6        1        1
  7    x^7      x^7        x        x

For some groups, attempting to make the rewriting system confluent will not terminate. This is why it is not done systematically.

The function my_cayley_graph below has an option to try and make the rewriting system confluent.

When this succeeds, this guarantees a correct Cayley graph.

def my_cayley_graph(self, side="right", simple=False, elements=None,
                    generators=None, connecting_set=None,
                    make_rewriting_system_confluent=False):
    r"""
    Return the Cayley graph for this finite semigroup.

    INPUT:

    - ``side`` -- "left", "right", or "twosided":
      the side on which the generators act (default:"right")
    - ``simple`` -- boolean (default:False):
      if True, returns a simple graph (no loops, no labels,
      no multiple edges)
    - ``generators`` -- a list, tuple, or family of elements
      of ``self`` (default: ``self.semigroup_generators()``)
    - ``connecting_set`` -- alias for ``generators``; deprecated
    - ``elements`` -- a list (or iterable) of elements of ``self``
    - ``make_rewriting_system_confluent`` -- whether to attempt
      to make ``self``'s rewriting system confluent to compute
      the Cayley graph (warning: this might not terminate)

    Adapted from the `cayley_graph` method of semigroups, see Sage source code at
    https://github.com/sagemath/sage/blob/9.8/src/sage/categories/semigroups.py#L174

    OUTPUT:

    - :class:`DiGraph`

    EXAMPLES:

    We illustrate the ``make_rewriting_system_confluent`` option::

        sage: F.<x> = FreeGroup('x')
        sage: G = F / [x^3]
        sage: C = my_cayley_graph(G, make_rewriting_system_confluent=True)
        sage: C.vertices(sort=False), C.edges(sort=False)
        ([1, x, x^-1],
         [(1, x, 0), (1, x^-1, 1), (x, 1, 1), (x, x^-1, 0), (x^-1, 1, 0), (x^-1, x, 1)])

    AUTHORS:

    - Bobby Moretti (2007-08-10)
    - Robert Miller (2008-05-01): editing
    - Nicolas M. Thiery (2008-12): extension to semigroups,
      ``side``, ``simple``, and ``elements`` options, ...
    - Samuel Lelièvre (2023-05-19): add option to make rewriting system confluent
    """
    from sage.graphs.digraph import DiGraph
    from sage.categories.monoids import Monoids
    from sage.categories.groups import Groups
    if side not in ["left", "right", "twosided"]:
        raise ValueError("option 'side' must be 'left', 'right' or 'twosided'")
    if elements is None:
        assert self.is_finite(), "elements should be specified for infinite semigroups"
        elements = self
    else:
        elements = set(elements)
    if simple or self in Groups():
        result = DiGraph()
    else:
        result = DiGraph(multiedges=True, loops=True)
    result.add_vertices(elements)

    if connecting_set is not None:
        generators = connecting_set
    if generators is None:
        if self in Monoids and hasattr(self, "monoid_generators"):
            generators = self.monoid_generators()
        else:
            generators = self.semigroup_generators()
    if isinstance(generators, (list, tuple)):
        generators = dict((self(g), self(g)) for g in generators)
    left  = (side == "left"  or side == "twosided")
    right = (side == "right" or side == "twosided")
    k = self.rewriting_system()
    if make_rewriting_system_confluent:
        k.make_confluent()
    def add_edge(source, target, label, side_label):
        r"""
        Add an appropriate edge to ``result`` given the options.

        Skips edges whose targets are not in ``elements``.
        """
        source = k.reduce(source)
        target = k.reduce(target)
        if (elements is not self and target not in elements):
            return
        if simple:
            if source != target:
                result.add_edge([source, target])
        elif side == "twosided":
            result.add_edge([source, target, (label, side_label)])
        else:
            result.add_edge([source, target, label])
    for x in elements:
        for i in generators.keys():
            if left:
                add_edge(x, generators[i] * x, i, "left" )
            if right:
                add_edge(x, x * generators[i], i, "right")
    return result

Example.

sage: F.<x> = FreeGroup('x')
sage: G = F / [x^3]

sage: C = my_cayley_graph(G, make_rewriting_system_confluent=True)

sage: C.vertices(sort=False), C.edges(sort=False)
([1, x, x^-1],
 [(1, x, 0), (1, x^-1, 1), (x, 1, 1), (x, x^-1, 0), (x^-1, 1, 0), (x^-1, x, 1)])

sage: C
Digraph on 3 vertices

sage: C.plot()
Launched png viewer for Graphics object consisting of 12 graphics primitives

Cayley graph for cyclic group of order 3