Ticket #15137: trac_15137-groups-ts.patch

File trac_15137-groups-ts.patch, 14.4 KB (added by tscrim, 9 years ago)
  • doc/en/reference/groups/index.rst

    # HG changeset patch
    # User Travis Scrimshaw <tscrim@ucdavis.edu>
    # Date 1378057693 25200
    # Node ID 45a8ad32b5ca0682c029018bc439ebc4caa137fb
    # Parent 116f2adc735300c4b901d42bf27f97ce9c858f5a
    #15137: Implement right-angled Artin groups and general Coxeter groups.
    
    diff --git a/doc/en/reference/groups/index.rst b/doc/en/reference/groups/index.rst
    a b Groups 
    1111   sage/groups/free_group
    1212   sage/groups/finitely_presented
    1313   sage/groups/braid
     14   sage/groups/raag
    1415   sage/groups/abelian_gps/abelian_group
    1516   sage/groups/abelian_gps/values
    1617   sage/groups/abelian_gps/dual_abelian_group
  • sage/groups/all.py

    diff --git a/sage/groups/all.py b/sage/groups/all.py
    a b lazy_import('sage.groups.braid', 'BraidG 
    2121lazy_import('sage.groups.affine_gps.affine_group', 'AffineGroup')
    2222lazy_import('sage.groups.affine_gps.euclidean_group', 'EuclideanGroup')
    2323
     24lazy_import('sage.groups.raag', 'RightAngledArtinGroup')
     25
    2426import groups_catalog as groups
  • new file sage/groups/raag.py

    diff --git a/sage/groups/raag.py b/sage/groups/raag.py
    new file mode 100644
    - +  
     1r"""
     2Right-Angled Artin Groups
     3
     4AUTHORS:
     5
     6- Travis Scrimshaw (2013-09-01): Initial version
     7"""
     8
     9##############################################################################
     10#       Copyright (C) 2013 Travis Scrimshaw <tscrim at ucdavis.edu>
     11#
     12#  Distributed under the terms of the GNU General Public License (GPL)
     13#
     14#  The full text of the GPL is available at:
     15#
     16#                  http://www.gnu.org/licenses/
     17##############################################################################
     18
     19from sage.misc.cachefunc import cached_method
     20from sage.structure.list_clone import ClonableArray
     21from sage.structure.unique_representation import UniqueRepresentation
     22from sage.groups.group import Group
     23from sage.rings.integer import Integer
     24from sage.rings.integer_ring import IntegerRing
     25from sage.graphs.graph import Graph
     26
     27class RightAngledArtinGroup(Group, UniqueRepresentation):
     28    r"""
     29    The right-angled Artin group defined by a graph `G`.
     30
     31    Let `\Gamma = \{V(\Gamma), E(\Gamma)\}` be a simple graph.
     32    A *right-angled Artin group* (commonly abbriated as RAAG) is the group
     33
     34    .. MATH::
     35
     36        A_{\Gamma} = \langle g_v : v \in V(\Gamma)
     37        \mid [g_u, g_v] \text{ if } \{u, v\} \notin E(\Gamma) \rangle.
     38
     39    These are sometimes known as graph groups or partitally commutative groups.
     40    This RAAG's contains both free groups, given by the complete graphs,
     41    and free abelian groups, given by disjoint vertices.
     42
     43    .. NOTE::
     44
     45        This is the opposite convention of some papers.
     46
     47    EXAMPLES::
     48
     49        sage: Gamma = Graph(4)
     50        sage: G = RightAngledArtinGroup(Gamma)
     51        sage: a,b,c,d = G.gens()
     52        sage: a*c*d^4*a^-3*b
     53        v0^-2*v1*v2*v3^4
     54
     55        sage: Gamma = graphs.CompleteGraph(4)
     56        sage: G = RightAngledArtinGroup(Gamma)
     57        sage: a,b,c,d = G.gens()
     58        sage: a*c*d^4*a^-3*b
     59        v0*v2*v3^4*v0^-3*v1
     60
     61        sage: Gamma = graphs.CycleGraph(5)
     62        sage: G = RightAngledArtinGroup(Gamma)
     63        sage: G
     64        Right-angled Artin group on 5 generators
     65        sage: a,b,c,d,e = G.gens()
     66        sage: e^-1*c*b*e*b^-1*c^-4
     67        v2^-3
     68    """
     69    @staticmethod
     70    def __classcall_private__(cls, G):
     71        """
     72        Normalize input to ensure a unique representation.
     73
     74        TESTS::
     75
     76            sage: G1 = RightAngledArtinGroup(graphs.CycleGraph(5))
     77            sage: Gamma = Graph([(0,1),(1,2),(2,3),(3,4),(4,0)])
     78            sage: G2 = RightAngledArtinGroup(Gamma)
     79            sage: G3 = RightAngledArtinGroup([(0,1),(1,2),(2,3),(3,4),(4,0)])
     80            sage: G1 is G2 and G2 is G3
     81            True
     82        """
     83        if not isinstance(G, Graph):
     84            G = Graph(G)
     85        G = G.copy()
     86        G._immutable = True
     87        return super(RightAngledArtinGroup, cls).__classcall__(cls, G)
     88
     89    def __init__(self, G):
     90        """
     91        Initialize ``self``.
     92
     93        INPUT:
     94
     95        - ``G`` -- a graph
     96
     97        TESTS::
     98
     99            sage: G = RightAngledArtinGroup(graphs.CycleGraph(5))
     100            sage: TestSuite(G).run()
     101        """
     102        self._graph = G
     103        Group.__init__(self)
     104
     105    def _repr_(self):
     106        """
     107        Return a string representation of ``self``.
     108
     109        TESTS::
     110
     111            sage: RightAngledArtinGroup(graphs.CycleGraph(5))
     112            Right-angled Artin group on 5 generators
     113        """
     114        return "Right-angled Artin group on {} generators".format(self._graph.num_verts())
     115
     116    def gen(self, i):
     117        """
     118        Return the ``i``-th generator of ``self``.
     119
     120        EXAMPLES::
     121
     122            sage: Gamma = graphs.CycleGraph(5)
     123            sage: G = RightAngledArtinGroup(Gamma)
     124            sage: G.gen(2)
     125            v2
     126        """
     127        return self.element_class(self, [(i, 1)])
     128
     129    def gens(self):
     130        """
     131        Return the generators of ``self``.
     132
     133        EXAMPLES::
     134
     135            sage: Gamma = graphs.CycleGraph(5)
     136            sage: G = RightAngledArtinGroup(Gamma)
     137            sage: G.gens()
     138            (v0, v1, v2, v3, v4)
     139            sage: Gamma = Graph([('x', 'y'), ('y', 'zeta')])
     140            sage: G = RightAngledArtinGroup(Gamma)
     141            sage: G.gens()
     142            (vx, vy, vzeta)
     143        """
     144        return tuple(self.gen(i) for i in range(self._graph.num_verts()))
     145
     146    def ngens(self):
     147        """
     148        Return the number of generators of ``self``.
     149
     150        EXAMPLES::
     151
     152            sage: Gamma = graphs.CycleGraph(5)
     153            sage: G = RightAngledArtinGroup(Gamma)
     154            sage: G.ngens()
     155            5
     156        """
     157        return self._graph.num_verts()
     158
     159    def cardinality(self):
     160        """
     161        Return the number of group elements.
     162
     163        OUTPUT:
     164
     165        Infinity.
     166
     167        EXAMPLES::
     168
     169            sage: Gamma = graphs.CycleGraph(5)
     170            sage: G = RightAngledArtinGroup(Gamma)
     171            sage: G.cardinality()
     172            +Infinity
     173        """
     174        from sage.rings.infinity import Infinity
     175        return Infinity
     176
     177    order = cardinality
     178   
     179    def as_permutation_group(self):
     180        """
     181        Raises a ``ValueError`` error since right-angled Artin groups
     182        are infinite, so they have no isomorphic permutation group.
     183       
     184        EXAMPLES::
     185
     186            sage: Gamma = graphs.CycleGraph(5)
     187            sage: G = RightAngledArtinGroup(Gamma)
     188            sage: G.as_permutation_group()
     189            Traceback (most recent call last):
     190            ...
     191            ValueError: the group is infinite
     192        """
     193        raise ValueError("the group is infinite")
     194
     195    def graph(self):
     196        """
     197        Return the defining graph of ``self``.
     198
     199        EXAMPLES::
     200
     201            sage: Gamma = graphs.CycleGraph(5)
     202            sage: G = RightAngledArtinGroup(Gamma)
     203            sage: G.graph()
     204            Cycle graph: Graph on 5 vertices
     205        """
     206        return self._graph.copy()
     207
     208    @cached_method
     209    def one(self):
     210        """
     211        Return the identity element `1`.
     212
     213        EXAMPLES::
     214
     215            sage: Gamma = graphs.CycleGraph(5)
     216            sage: G = RightAngledArtinGroup(Gamma)
     217            sage: G.one()
     218            1
     219        """
     220        return self.element_class(self, [])
     221
     222    one_element = one
     223
     224    def _element_constructor_(self, x):
     225        """
     226        Construct an element of ``self`` from ``x``.
     227
     228        TESTS::
     229
     230            sage: Gamma = graphs.CycleGraph(5)
     231            sage: G = RightAngledArtinGroup(Gamma)
     232            sage: elt = G([[0,3], [3,1], [2,1], [1,1], [3,1]]); elt
     233            v0^3*v3*v2*v1*v3
     234            sage: G(elt)
     235            v0^3*v3*v2*v1*v3
     236            sage: G(1)
     237            1
     238        """
     239        if isinstance(x, RightAngledArtinGroup.Element):
     240            if x.parent() is self:
     241                return x
     242            raise ValueError("there is no coercion from {} into {}".format(x.parent(), self))
     243        if x == 1:
     244            return self.one()
     245        verts = self._graph.vertices()
     246        x = map(lambda s: [verts.index(s[0]), s[1]], x)
     247        return self.element_class(self, self._normal_form(x))
     248
     249    def _normal_form(self, word):
     250        """
     251        Return the normal form of the word ``word``. Helper function for
     252        creaing elements.
     253
     254        EXAMPLES::
     255
     256            sage: Gamma = graphs.CycleGraph(5)
     257            sage: G = RightAngledArtinGroup(Gamma)
     258            sage: G._normal_form([[0,2], [3,1], [2,1], [0,1], [1,1], [3,1]])
     259            [[0, 3], [3, 1], [2, 1], [1, 1], [3, 1]]
     260            sage: a,b,c,d,e = G.gens()
     261            sage: a^2 * d * c * a * b * d
     262            v0^3*v3*v2*v1*v3
     263            sage: a*b*d == d*a*b and a*b*d == a*d*b
     264            True
     265            sage: a*c*a^-1*c^-1
     266            1
     267            sage: (a*b*c*d*e)^2 * (a*b*c*d*e)^-2
     268            1
     269        """
     270        pos = 0
     271        G = self._graph
     272        w = map(list, word) # Make a (2 level) deep copy
     273        while pos < len(w):
     274            comm_set = [w[pos][0]] # The current set of totally commuting elements
     275            i = pos + 1
     276
     277            while i < len(w):
     278                letter = w[i][0] # The current letter
     279                # Check if this could fit in the commuting set
     280                if letter in comm_set:
     281                    # Try to move it in
     282                    if any(G.has_edge(w[j][0], letter) for j in range(pos + len(comm_set), i)):
     283                        # We can't, so go onto the next letter
     284                        i += 1
     285                        continue
     286                    j = comm_set.index(letter)
     287                    w[pos+j][1] += w[i][1]
     288                    w.pop(i)
     289                    i -= 1 # Since we removed a syllable
     290                    # Check cancellations
     291                    if w[pos+j][1] == 0:
     292                        w.pop(pos+j)
     293                        comm_set.pop(j)
     294                        i -= 1
     295                        if len(comm_set) == 0:
     296                            pos = 0 # Start again since cancellation can be pronounced effects
     297                            break
     298                elif all( not G.has_edge(w[j][0], letter) for j in range(pos, i)):
     299                    j = 0
     300                    for x in comm_set:
     301                        if x > letter:
     302                            break
     303                        j += 1
     304                    w.insert(pos+j, w.pop(i))
     305                    comm_set.insert(j, letter)
     306
     307                i += 1
     308            pos += len(comm_set)
     309        return w
     310
     311    class Element(ClonableArray):
     312        """
     313        An element of a right-angled Artin group (RAAG).
     314
     315        Elements of RAAGs are modeled as lists of pairs ``[i, p]`` where
     316        ``i`` is the index of a vertex in the defining graph (with some
     317        fixed order of the vertices) and ``p`` is the power.
     318        """
     319        def check(self):
     320            """
     321            Check if ``self`` is a valid element. Nothing to check.
     322
     323            TESTS::
     324
     325                sage: Gamma = graphs.CycleGraph(5)
     326                sage: G = RightAngledArtinGroup(Gamma)
     327                sage: elt = G.gen(2)
     328                sage: elt.check()
     329            """
     330            pass
     331
     332        def _repr_(self):
     333            """
     334            Return a string representation of ``self``.
     335
     336            TESTS::
     337
     338                sage: Gamma = graphs.CycleGraph(5)
     339                sage: G = RightAngledArtinGroup(Gamma)
     340                sage: a,b,c,d,e = G.gens()
     341                sage: a * b^2 * e^-3
     342                v0*v1^2*v4^-3
     343                sage: Gamma = Graph([('x', 'y'), ('y', 'zeta')])
     344                sage: G = RightAngledArtinGroup(Gamma)
     345                sage: x,y,z = G.gens()
     346                sage: z * y^-2 * x^3
     347                vx^3*vy^-2*vzeta
     348            """
     349            if len(self) == 0:
     350                return '1'
     351            v = self.parent()._graph.vertices()
     352            to_str = lambda i,p: "v{}".format(i) if p == 1 else "v{}^{}".format(i, p)
     353            return '*'.join(to_str(v[i], p) for i,p in self)
     354
     355        def _latex_(self):
     356            r"""
     357            Return a LaTeX representation of ``self``.
     358
     359            TESTS::
     360
     361                sage: Gamma = graphs.CycleGraph(5)
     362                sage: G = RightAngledArtinGroup(Gamma)
     363                sage: a,b,c,d,e = G.gens()
     364                sage: latex(a*b*e^-4*d^3)
     365                \sigma_{0}\sigma_{1}\sigma_{4}^{-4}\sigma_{3}^{3}
     366                sage: latex(G.one())
     367                1
     368                sage: Gamma = Graph([('x', 'y'), ('y', 'zeta')])
     369                sage: G = RightAngledArtinGroup(Gamma)
     370                sage: x,y,z = G.gens()
     371                sage: latex(x^-5*y*z^3)
     372                \sigma_{\text{\texttt{x}}}^{-5}\sigma_{\text{\texttt{y}}}\sigma_{\text{\texttt{zeta}}}^{3}
     373            """
     374            if len(self) == 0:
     375                return '1'
     376
     377            from sage.misc.latex import latex
     378            latexrepr = ''
     379            v = self.parent()._graph.vertices()
     380            for i,p in self:
     381                latexrepr += "\\sigma_{{{}}}".format(latex(v[i]))
     382                if p != 1:
     383                    latexrepr += "^{{{}}}".format(p)
     384            return latexrepr
     385
     386        def _mul_(self, y):
     387            """
     388            Return ``self`` multiplied by ``y``.
     389
     390            TESTS::
     391
     392                sage: Gamma = graphs.CycleGraph(5)
     393                sage: G = RightAngledArtinGroup(Gamma)
     394                sage: a,b,c,d,e = G.gens()
     395                sage: a * b
     396                v0*v1
     397                sage: b * a
     398                v1*v0
     399                sage: a*b*c*d*e
     400                v0*v1*v2*v3*v4
     401                sage: a^2*d*c*a*b*d
     402                v0^3*v3*v2*v1*v3
     403                sage: e^-1*a*b*d*c*a^-2*e*d*b^2*e*b^-3
     404                v4^-1*v0*v3*v1*v0^-2*v2*v1^-1*v4*v3*v4
     405            """
     406            P = self.parent()
     407            lst = list(self) + list(y)
     408            return self.__class__(self.parent(), P._normal_form(lst))
     409
     410        def __invert__(self):
     411            """
     412            Return the inverse of ``self``.
     413
     414            TESTS::
     415
     416                sage: Gamma = graphs.CycleGraph(5)
     417                sage: G = RightAngledArtinGroup(Gamma)
     418                sage: a,b,c,d,e = G.gens()
     419                sage: (a * b)^-2
     420                v1^-1*v0^-1*v1^-1*v0^-1
     421            """
     422            return self.__class__(self.parent(), map(lambda x: [x[0], -x[1]], reversed(self)))
     423