Ticket #9290: trac_9290-geometric_coxeter_groups-ts.patch

File trac_9290-geometric_coxeter_groups-ts.patch, 33.0 KB (added by tscrim, 8 years ago)
  • doc/en/reference/groups/index.rst

    # HG changeset patch
    # User Travis Scrimshaw <tscrim@ucdavis.edu>
    # Date 1378865696 25200
    # Node ID 0ea6d9729881a54f4f205fac453ba039a41845f1
    # Parent e1fa248e9d5e8b48295e6ad1395575cc32e3a7b0
    #9290: Coxeter groups implemented using their geometric representation
    
    diff --git a/doc/en/reference/groups/index.rst b/doc/en/reference/groups/index.rst
    a b Groups 
    3030   sage/groups/matrix_gps/finitely_generated
    3131   sage/groups/matrix_gps/morphism
    3232   sage/groups/matrix_gps/homset
     33   sage/groups/matrix_gps/coxeter_group
    3334   sage/groups/matrix_gps/linear
    3435   sage/groups/matrix_gps/orthogonal
    3536   sage/groups/matrix_gps/symplectic
  • sage/combinat/root_system/cartan_matrix.py

    diff --git a/sage/combinat/root_system/cartan_matrix.py b/sage/combinat/root_system/cartan_matrix.py
    a b from sage.matrix.matrix_integer_sparse i 
    3232from sage.rings.all import ZZ
    3333from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract
    3434from sage.combinat.root_system.root_system import RootSystem
     35from sage.sets.family import Family
    3536
    3637class CartanMatrix(Matrix_integer_sparse, CartanType_abstract):
    3738    r"""
    class CartanMatrix(Matrix_integer_sparse 
    327328            sage: C.reflection_group()
    328329            Weyl Group of type ['A', 3] (as a matrix group acting on the root space)
    329330        """
    330         from sage.groups.perm_gps.permgroup_named import SymmetricGroup
    331331        RS = self.root_space()
    332         G = RS.weyl_group()
     332
    333333        if type == "matrix":
    334             return G
    335         elif type == "permutation":
    336             assert G.is_finite()
     334            return RS.weyl_group()
     335
     336        if type == "permutation":
     337            if not self.is_finite():
     338                raise ValueError("only works for finite types")
    337339            Phi = RS.roots()
    338340            gens = {}
     341            from sage.groups.perm_gps.permgroup_named import SymmetricGroup
    339342            S = SymmetricGroup(len(Phi))
    340343            for i in self.index_set():
    341344                pi = S([ Phi.index( beta.simple_reflection(i) ) + 1 for beta in Phi ])
    342345                gens[i] = pi
    343346            return S.subgroup( gens[i] for i in gens )
    344         else:
    345             raise ValueError("The reflection group is only available as a matrix group or as a permutation group.")
     347
     348        raise ValueError("The reflection group is only available as a matrix group or as a permutation group.")
     349
     350    def symmetrizer(self):
     351        """
     352        Return the symmetrizer of ``self``.
     353
     354        EXAMPLES::
     355
     356            sage: C = CartanMatrix(['B',4,1])
     357            sage: cm = CartanMatrix([[2,-5],[-2,2]])
     358            sage: cm.symmetrizer()
     359            Finite family {0: 2, 1: 5}
     360
     361        TESTS:
     362
     363        Check that the symmetrizer computed from the Cartan matrix agrees
     364        with the values given by the Cartan type::
     365
     366            sage: ct = CartanType(['B',4,1])
     367            sage: ct.symmetrizer()
     368            Finite family {0: 2, 1: 2, 2: 2, 3: 2, 4: 1}
     369            sage: ct.cartan_matrix().symmetrizer()
     370            Finite family {0: 2, 1: 2, 2: 2, 3: 2, 4: 1}
     371        """
     372        sym = self.is_symmetrizable(True)
     373        if not sym:
     374            raise ValueError("the Cartan matrix is not symmetrizable")
     375        iset = self.index_set()
     376        # The result from is_symmetrizable needs to be scaled to integer coefficients
     377        from sage.rings.arith import LCM
     378        from sage.rings.all import QQ
     379        scalar = LCM(map(lambda x: QQ(x).denominator(), sym))
     380        return Family( {iset[i]: ZZ(val*scalar) for i,val in enumerate(sym)} )
    346381
    347382    ##########################################################################
    348383    # Cartan type methods
    class CartanMatrix(Matrix_integer_sparse 
    364399
    365400    def cartan_type(self):
    366401        """
    367         Return the Cartan type of ``self`` or ``None`` if unknown.
     402        Return the Cartan type of ``self`` or ``self`` if unknown.
    368403
    369404        EXAMPLES::
    370405
    class CartanMatrix(Matrix_integer_sparse 
    376411
    377412            sage: C = CartanMatrix([[2,-1,-2], [-1,2,-1], [-2,-1,2]])
    378413            sage: C.cartan_type()
     414            [ 2 -1 -2]
     415            [-1  2 -1]
     416            [-2 -1  2]
    379417        """
     418        if self._cartan_type is None:
     419            return self
    380420        return self._cartan_type
    381421
    382422    def rank(self):
    class CartanMatrix(Matrix_integer_sparse 
    451491            True
    452492            sage: M.dual().cartan_type() == ct.dual()
    453493            True
     494
     495        An example with arbitrary Cartan matrices::
     496
     497            sage: cm = CartanMatrix([[2,-5], [-2, 2]]); cm
     498            [ 2 -5]
     499            [-2  2]
     500            sage: cm.dual()
     501            [ 2 -2]
     502            [-5  2]
     503            sage: cm.dual() == CartanMatrix(cm.transpose())
     504            True
     505            sage: cm.dual().dual() == cm
     506            True
    454507        """
    455         return CartanMatrix(self._cartan_type.dual())
     508        if self._cartan_type is not None:
     509            return CartanMatrix(self._cartan_type.dual())
     510        return CartanMatrix(self.transpose())
    456511
    457512    def is_crystallographic(self):
    458513        """
  • sage/combinat/root_system/coxeter_group.py

    diff --git a/sage/combinat/root_system/coxeter_group.py b/sage/combinat/root_system/coxeter_group.py
    a b from sage.structure.parent import Parent 
    2020from sage.combinat.root_system.cartan_type import CartanType
    2121from sage.groups.perm_gps.permgroup import PermutationGroup_generic
    2222
    23 def CoxeterGroup(cartan_type, implementation = None):
     23from sage.misc.lazy_import import lazy_import
     24lazy_import('sage.groups.matrix_gps.coxeter_group', 'CoxeterMatrixGroup')
     25
     26def CoxeterGroup(data, implementation=None, base_ring=None, index_set=None):
    2427    """
     28    Return an implementation of the Coxeter group given by ``data``.
     29
    2530    INPUT:
    2631
    27      - ``cartan_type`` -- a cartan type (or coercible into; see :class:`CartanType`)
    28      - ``implementation`` -- "permutation", "matrix", "coxeter3", or None (default: None)
     32    - ``data`` -- a cartan type (or coercible into; see :class:`CartanType`)
     33      or a Coxeter matrix or graph
    2934
    30     Returns an implementation of the Coxeter group of type
    31     ``cartan_type``.
     35    - ``implementation`` -- (default: ``None``) can be one of the following:
     36
     37      * "permutation" - as a permutation representation
     38      * "matrix" - as a Weyl group (as a matrix group acting on the root space);
     39        if this is not implemented, this uses the "reflection" implementation
     40      * "coxeter3" - using the coxeter3 package
     41      * "reflection" - as elements in the reflection representation; see
     42        :class:`~sage.groups.matrix_gps.coxeter_groups.CoxeterMatrixGroup`
     43      * ``None`` - choose "permutation" representation if possible, else
     44        default to "matrix"
     45
     46    - ``base_ring`` -- (optional) the base ring for the "reflection"
     47      implementation
     48
     49    - ``index_set`` -- (optional) the index set for the "reflection"
     50      implementation
    3251
    3352    EXAMPLES:
    3453
    35     If ``implementation`` is not specified, a permutation
     54    Now assume that ``data`` represents a Cartan type. If
     55    ``implementation`` is not specified, a permutation
    3656    representation is returned whenever possible (finite irreducible
    3757    Cartan type, with the GAP3 Chevie package available)::
    3858
    def CoxeterGroup(cartan_type, implementa 
    4060        sage: W                                   # optional - chevie
    4161        Permutation Group with generators [(1,3)(2,5)(4,6), (1,4)(2,3)(5,6)]
    4262
    43     Otherwise, a Weyl group is returned::
     63    Otherwise, a matrix representation is returned::
    4464
    4565        sage: W = CoxeterGroup(["A",3,1])
    4666        sage: W
    4767        Weyl Group of type ['A', 3, 1] (as a matrix group acting on the root space)
     68        sage: W = CoxeterGroup(['H',3])
     69        sage: W
     70        Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
     71        [1 3 2]
     72        [3 1 5]
     73        [2 5 1]
    4874
    4975    We now use the ``implementation`` option::
    5076
    def CoxeterGroup(cartan_type, implementa 
    5985        Weyl Group of type ['A', 2] (as a matrix group acting on the ambient space)
    6086
    6187        sage: W = CoxeterGroup(["H",3], implementation = "matrix")
    62         Traceback (most recent call last):
    63         ...
    64         NotImplementedError: Coxeter group of type ['H', 3] as matrix group not implemented
     88        sage: W
     89        Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
     90        [1 3 2]
     91        [3 1 5]
     92        [2 5 1]
     93
     94        sage: W = CoxeterGroup(["H",3], implementation="reflection")
     95        sage: W
     96        Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
     97        [1 3 2]
     98        [3 1 5]
     99        [2 5 1]
    65100
    66101        sage: W = CoxeterGroup(["A",4,1], implementation = "permutation")
    67102        Traceback (most recent call last):
    68103        ...
    69104        NotImplementedError: Coxeter group of type ['A', 4, 1] as permutation group not implemented
    70105
     106    We use the different options for the "reflection" implementation::
     107
     108        sage: W = CoxeterGroup(["H",3], implementation="reflection", base_ring=RR)
     109        sage: W
     110        Coxeter group over Real Field with 53 bits of precision with Coxeter matrix:
     111        [1 3 2]
     112        [3 1 5]
     113        [2 5 1]
     114        sage: W = CoxeterGroup([[1,10],[10,1]], implementation="reflection", index_set=['a','b'], base_ring=SR)
     115        sage: W
     116        Coxeter group over Symbolic Ring with Coxeter matrix:
     117        [ 1 10]
     118        [10  1]
    71119    """
    72     assert implementation in ["permutation", "matrix", "coxeter3", None]
    73     cartan_type = CartanType(cartan_type)
     120    if implementation not in ["permutation", "matrix", "coxeter3", "reflection", None]:
     121        raise ValueError("invalid type implementation")
     122
     123    try:
     124        cartan_type = CartanType(data)
     125    except (TypeError, ValueError): # If it is not a Cartan type, try to see if we can represent it as a matrix group
     126        return CoxeterMatrixGroup(data, base_ring, index_set)
    74127
    75128    if implementation is None:
    76129        if cartan_type.is_finite() and cartan_type.is_irreducible() and is_chevie_available():
    def CoxeterGroup(cartan_type, implementa 
    78131        else:
    79132            implementation = "matrix"
    80133
     134    if implementation == "reflection":
     135        return CoxeterMatrixGroup(cartan_type, base_ring, index_set)
    81136    if implementation == "coxeter3":
    82137        try:
    83138            from sage.libs.coxeter3.coxeter_group import CoxeterGroup
    84139        except ImportError:
    85             raise RuntimeError, "coxeter3 must be installed"
     140            raise RuntimeError("coxeter3 must be installed")
    86141        else:
    87142            return CoxeterGroup(cartan_type)
    88143    if implementation == "permutation" and is_chevie_available() and \
    89144       cartan_type.is_finite() and cartan_type.is_irreducible():
    90145        return CoxeterGroupAsPermutationGroup(cartan_type)
    91     elif implementation == "matrix" and cartan_type.is_crystallographic():
    92         return WeylGroup(cartan_type)
    93     else:
    94         raise NotImplementedError, "Coxeter group of type %s as %s group not implemented "%(cartan_type, implementation)
     146    elif implementation == "matrix":
     147        if cartan_type.is_crystallographic():
     148            return WeylGroup(cartan_type)
     149        return CoxeterMatrixGroup(cartan_type, base_ring, index_set)
     150
     151    raise NotImplementedError("Coxeter group of type %s as %s group not implemented "%(cartan_type, implementation))
    95152
    96153@cached_function
    97154def is_chevie_available():
  • sage/combinat/root_system/dynkin_diagram.py

    diff --git a/sage/combinat/root_system/dynkin_diagram.py b/sage/combinat/root_system/dynkin_diagram.py
    a b def DynkinDiagram(*args, **kwds): 
    160160    if is_Matrix(mat):
    161161        mat = CartanMatrix(*args)
    162162    if isinstance(mat, CartanMatrix):
    163         if mat.cartan_type() is not None:
     163        if mat.cartan_type() is not mat:
    164164            try:
    165165                return mat.cartan_type().dynkin_diagram()
    166166            except AttributeError:
  • sage/combinat/root_system/weyl_group.py

    diff --git a/sage/combinat/root_system/weyl_group.py b/sage/combinat/root_system/weyl_group.py
    a b from sage.interfaces.gap import gap 
    4444from sage.misc.cachefunc import cached_method, ClearCacheOnPickle
    4545from sage.misc.superseded import deprecated_function_alias
    4646from sage.combinat.root_system.cartan_type import CartanType
     47from sage.combinat.root_system.cartan_matrix import CartanMatrix
    4748from sage.matrix.constructor import matrix, diagonal_matrix
    4849from sage.combinat.root_system.root_lattice_realizations import RootLatticeRealizations
    4950from sage.structure.unique_representation import UniqueRepresentation
    from sage.graphs.graph import DiGraph 
    5455
    5556def WeylGroup(x, prefix=None):
    5657    """
    57     Returns the Weyl group of type ct.
    58    
     58    Returns the Weyl group of the root system defined by the Cartan
     59    type (or matrix) ``ct``.
     60
    5961    INPUT:
    6062
    61     - ``ct`` - a Cartan Type.
     63    - ``x`` - a root system or a Cartan type (or matrix)
    6264   
    6365    OPTIONAL:
    6466
    65     - ``prefix`` - changes the representation of elements from matrices
     67    - ``prefix`` -- changes the representation of elements from matrices
    6668      to products of simple reflections
    6769   
    68     EXAMPLES: The following constructions yield the same result, namely
     70    EXAMPLES:
     71
     72    The following constructions yield the same result, namely
    6973    a weight lattice and its corresponding Weyl group::
    7074   
    7175        sage: G = WeylGroup(['F',4])
    def WeylGroup(x, prefix=None): 
    7579   
    7680        sage: L = RootSystem(['F',4]).ambient_space()
    7781        sage: G = L.weyl_group()
     82        sage: W = WeylGroup(L)
    7883   
    7984    Either produces a weight lattice, with access to its roots and
    8085    weights.
    def WeylGroup(x, prefix=None): 
    126131        sage: w.action(rho) # action of G on weight lattice
    127132        (5, -1, 3, 2)
    128133
     134    We can also do the same for arbitrary Cartan matrices::
     135
     136        sage: cm = CartanMatrix([[2,-5,0],[-2,2,-1],[0,-1,2]])
     137        sage: W = WeylGroup(cm)
     138        sage: W.gens()
     139        (
     140        [-1  5  0]  [ 1  0  0]  [ 1  0  0]
     141        [ 0  1  0]  [ 2 -1  1]  [ 0  1  0]
     142        [ 0  0  1], [ 0  0  1], [ 0  1 -1]
     143        )
     144        sage: s0,s1,s2 = W.gens()
     145        sage: s1*s2*s1
     146        [ 1  0  0]
     147        [ 2  0 -1]
     148        [ 2 -1  0]
     149        sage: s2*s1*s2
     150        [ 1  0  0]
     151        [ 2  0 -1]
     152        [ 2 -1  0]
     153        sage: s0*s1*s0*s2*s0
     154        [ 9  0 -5]
     155        [ 2  0 -1]
     156        [ 0  1 -1]
     157
     158    Same Cartan matrix, but with a prefix to display using simple reflections::
     159
     160        sage: W = WeylGroup(cm, prefix='s')
     161        sage: s0,s1,s2 = W.gens()
     162        sage: s0*s2*s1
     163        s2*s0*s1
     164        sage: (s1*s2)^3
     165        1
     166        sage: (s0*s1)^5
     167        s0*s1*s0*s1*s0*s1*s0*s1*s0*s1
     168        sage: s0*s1*s2*s1*s2
     169        s2*s0*s1
     170        sage: s0*s1*s2*s0*s2
     171        s0*s1*s0
     172
    129173    TESTS::
    130174
    131175        sage: TestSuite(WeylGroup(["A",3])).run()
    132         sage: TestSuite(WeylGroup(["A",3, 1])).run()
     176        sage: TestSuite(WeylGroup(["A",3,1])).run() # long time
    133177
    134         sage: W=WeylGroup(['A',3,1])
    135         sage: s=W.simple_reflections()
    136         sage: w=s[0]*s[1]*s[2]
     178        sage: W = WeylGroup(['A',3,1])
     179        sage: s = W.simple_reflections()
     180        sage: w = s[0]*s[1]*s[2]
    137181        sage: w.reduced_word()
    138182        [0, 1, 2]
    139         sage: w=s[0]*s[2]
     183        sage: w = s[0]*s[2]
    140184        sage: w.reduced_word()
    141185        [2, 0]
    142186    """
    143187    if x in RootLatticeRealizations:
    144188        return WeylGroup_gens(x, prefix=prefix)
    145189
    146     ct = CartanType(x)
    147     if ct.is_affine():
    148         return WeylGroup_gens(ct.root_system().root_space(), prefix=prefix)
    149     else:
     190    try:
     191        ct = CartanType(x)
     192    except TypeError:
     193        ct = CartanMatrix(x) # See if it's a Cartan matrix
     194    if ct.is_finite():
    150195        return WeylGroup_gens(ct.root_system().ambient_space(), prefix=prefix)
     196    return WeylGroup_gens(ct.root_system().root_space(), prefix=prefix)
    151197
    152198
    153199class WeylGroup_gens(ClearCacheOnPickle, UniqueRepresentation,
    class WeylGroup_gens(ClearCacheOnPickle, 
    163209
    164210            sage: G = WeylGroup(['B',3])
    165211            sage: TestSuite(G).run()
     212            sage: cm = CartanMatrix([[2,-5,0],[-2,2,-1],[0,-1,2]])
     213            sage: W = WeylGroup(cm)
     214            sage: TestSuite(W).run() # long time
    166215        """
    167216        self._domain = domain
    168217        if self.cartan_type().is_affine():
  • new file sage/groups/matrix_gps/coxeter_group.py

    diff --git a/sage/groups/matrix_gps/coxeter_group.py b/sage/groups/matrix_gps/coxeter_group.py
    new file mode 100644
    - +  
     1"""
     2Coxeter Groups As Matrix Groups
     3
     4This implements a general Coxeter group as a matrix group by using the
     5reflection representation.
     6
     7AUTHORS:
     8
     9- Travis Scrimshaw (2013-08-28): Initial version
     10"""
     11
     12##############################################################################
     13#       Copyright (C) 2013 Travis Scrimshaw <tscrim at ucdavis.edu>
     14#
     15#  Distributed under the terms of the GNU General Public License (GPL)
     16#
     17#  The full text of the GPL is available at:
     18#
     19#                  http://www.gnu.org/licenses/
     20##############################################################################
     21
     22from sage.structure.unique_representation import UniqueRepresentation
     23from sage.categories.coxeter_groups import CoxeterGroups
     24
     25from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract
     26from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_generic
     27from sage.groups.matrix_gps.group_element import MatrixGroupElement_generic
     28from sage.graphs.graph import Graph
     29from sage.matrix.constructor import matrix
     30from sage.matrix.matrix_space import MatrixSpace
     31from sage.rings.all import ZZ
     32from sage.rings.infinity import infinity
     33from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import UniversalCyclotomicField
     34
     35class CoxeterMatrixGroup(FinitelyGeneratedMatrixGroup_generic, UniqueRepresentation):
     36    r"""
     37    A Coxeter group represented as a matrix group.
     38
     39    Let `(W, S)` be a Coxeter system and we construct a vector space `V`
     40    over `\RR` with a basis of `\{ \alpha_s \}_{s \in S}` and inner product
     41
     42    .. MATH::
     43
     44        B(\alpha_s, \alpha_t) = -\cos\left( \frac{\pi}{m_{st}} \right)
     45
     46    where we have `B(\alpha_s, \alpha_t) = -1` if `m_{st} = \infty`. Next we
     47    define a representation `\sigma_s : V \to V` by
     48
     49    .. MATH::
     50
     51        \sigma_s \lambda = \lambda - 2 B(\alpha_s, \lambda) \alpha_s.
     52
     53    This representation is faithful so we can represent the Coxeter group `W`
     54    by the set of matrices `\sigma_s` acting on `V`.
     55
     56    INPUT:
     57
     58    - ``data`` -- a Coxeter matrix or graph or a Cartan type
     59    - ``base_ring`` -- (default: the universal cyclotomic field) the base
     60      ring which contains all values `\cos(\pi/m_{ij})` where `(m_{ij})_{ij}`
     61      is the Coxeter matrix
     62    - ``index_set`` -- (optional) an indexing set for the generators
     63
     64    For more on creating Coxeter groups, see
     65    :meth:`~sage.combinat.root_system.coxeter_group.CoxeterGroup`.
     66
     67    .. TODO::
     68
     69        Currently the label `\infty` is implemented as `-1` in the Coxeter
     70        matrix.
     71
     72    EXAMPLES:
     73
     74    We can create Coxeter groups from Coxeter matrices::
     75
     76        sage: W = CoxeterGroup([[1, 6, 3], [6, 1, 10], [3, 10, 1]])
     77        sage: W
     78        Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
     79        [ 1  6  3]
     80        [ 6  1 10]
     81        [ 3 10  1]
     82        sage: W.gens()
     83        (
     84        [                 -1 -E(12)^7 + E(12)^11                   1]
     85        [                  0                   1                   0]
     86        [                  0                   0                   1],
     87        <BLANKLINE>
     88        [                  1                   0                   0]
     89        [-E(12)^7 + E(12)^11                  -1     E(20) - E(20)^9]
     90        [                  0                   0                   1],
     91        <BLANKLINE>
     92        [              1               0               0]
     93        [              0               1               0]
     94        [              1 E(20) - E(20)^9              -1]
     95        )
     96        sage: m = matrix([[1,3,3,3], [3,1,3,2], [3,3,1,2], [3,2,2,1]])
     97        sage: W = CoxeterGroup(m)
     98        sage: W.gens()
     99        (
     100        [-1  1  1  1]  [ 1  0  0  0]  [ 1  0  0  0]  [ 1  0  0  0]
     101        [ 0  1  0  0]  [ 1 -1  1  0]  [ 0  1  0  0]  [ 0  1  0  0]
     102        [ 0  0  1  0]  [ 0  0  1  0]  [ 1  1 -1  0]  [ 0  0  1  0]
     103        [ 0  0  0  1], [ 0  0  0  1], [ 0  0  0  1], [ 1  0  0 -1]
     104        )
     105        sage: a,b,c,d = W.gens()
     106        sage: (a*b*c)^3
     107        [ 5  1 -5  7]
     108        [ 5  0 -4  5]
     109        [ 4  1 -4  4]
     110        [ 0  0  0  1]
     111        sage: (a*b)^3
     112        [1 0 0 0]
     113        [0 1 0 0]
     114        [0 0 1 0]
     115        [0 0 0 1]
     116        sage: b*d == d*b
     117        True
     118        sage: a*c*a == c*a*c
     119        True
     120
     121    We can create the matrix representation over different base rings and with
     122    different index sets. Note that the base ring must contain all
     123    `2*\cos(\pi/m_{ij})` where `(m_{ij})_{ij}` is the Coxeter matrix::
     124
     125        sage: W = CoxeterGroup(m, base_ring=RR, index_set=['a','b','c','d'])
     126        sage: W.base_ring()
     127        Real Field with 53 bits of precision
     128        sage: W.index_set()
     129        ('a', 'b', 'c', 'd')
     130
     131        sage: CoxeterGroup(m, base_ring=ZZ)
     132        Coxeter group over Integer Ring with Coxeter matrix:
     133        [1 3 3 3]
     134        [3 1 3 2]
     135        [3 3 1 2]
     136        [3 2 2 1]
     137        sage: CoxeterGroup([[1,4],[4,1]], base_ring=QQ)
     138        Traceback (most recent call last):
     139        ...
     140        TypeError: unable to convert sqrt(2) to a rational
     141
     142    Using the well-known conversion between Coxeter matrices and Coxeter
     143    graphs, we can input a Coxeter graph. Following the standard convention,
     144    edges with no label (i.e. labelled by ``None``) are treated as 3::
     145
     146        sage: G = Graph([(0,3,None), (1,3,15), (2,3,7), (0,1,3)])
     147        sage: W = CoxeterGroup(G); W
     148        Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
     149        [ 1  3  2  3]
     150        [ 3  1  2 15]
     151        [ 2  2  1  7]
     152        [ 3 15  7  1]
     153        sage: G2 = W.coxeter_graph()
     154        sage: CoxeterGroup(G2) is W
     155        True
     156
     157    Because there currently is no class for `\ZZ \cup \{ \infty \}`, labels
     158    of `\infty` are given by `-1` in the Coxeter matrix::
     159
     160        sage: G = Graph([(0,1,None), (1,2,4), (0,2,oo)])
     161        sage: W = CoxeterGroup(G)
     162        sage: W.coxeter_matrix()
     163        [ 1  3 -1]
     164        [ 3  1  4]
     165        [-1  4  1]
     166
     167    We can also create Coxeter groups from Cartan types using the
     168    ``implementation`` keyword::
     169
     170        sage: W = CoxeterGroup(['D',5], implementation="reflection")
     171        sage: W
     172        Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
     173        [1 3 2 2 2]
     174        [3 1 3 2 2]
     175        [2 3 1 3 3]
     176        [2 2 3 1 2]
     177        [2 2 3 2 1]
     178        sage: W = CoxeterGroup(['H',3], implementation="reflection")
     179        sage: W
     180        Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
     181        [1 3 2]
     182        [3 1 5]
     183        [2 5 1]
     184    """
     185    @staticmethod
     186    def __classcall_private__(cls, data, base_ring=None, index_set=None):
     187        """
     188        Normalize arguements to ensure a unique representation.
     189
     190        EXAMPLES::
     191
     192            sage: W1 = CoxeterGroup(['A',2], implementation="reflection", base_ring=UniversalCyclotomicField())
     193            sage: W2 = CoxeterGroup([[1,3],[3,1]], index_set=(1,2))
     194            sage: W1 is W2
     195            True
     196            sage: G1 = Graph([(1,2)])
     197            sage: W3 = CoxeterGroup(G1)
     198            sage: W1 is W3
     199            True
     200            sage: G2 = Graph([(1,2,3)])
     201            sage: W4 = CoxeterGroup(G2)
     202            sage: W1 is W4
     203            True
     204
     205        Check with `\infty` because of the hack of using `-1` to represent
     206        `\infty` in the Coxeter matrix::
     207
     208            sage: G = Graph([(0, 1, 3), (1, 2, oo)])
     209            sage: W1 = CoxeterGroup(matrix([[1, 3, 2], [3,1,-1], [2,-1,1]]))
     210            sage: W2 = CoxeterGroup(G)
     211            sage: W1 is W2
     212            True
     213            sage: CoxeterGroup(W1.coxeter_graph()) is W1
     214            True
     215        """
     216        if isinstance(data, CartanType_abstract):
     217            if index_set is None:
     218                index_set = data.index_set()
     219            data = data.coxeter_matrix()
     220        elif isinstance(data, Graph):
     221            G = data
     222            n = G.num_verts()
     223
     224            # Setup the basis matrix as all 2 except 1 on the diagonal
     225            data = matrix(ZZ, [[2]*n for i in range(n)])
     226            for i in range(n):
     227                data[i,i] = ZZ.one()
     228
     229            verts = G.vertices()
     230            for e in G.edges():
     231                m = e[2]
     232                if m is None:
     233                    m = 3
     234                elif m == infinity or m == -1: # FIXME: Hack because there is no ZZ\cup\{\infty\}
     235                    m = -1
     236                elif m <= 1:
     237                    raise ValueError("invalid Coxeter graph label")
     238                i = verts.index(e[0])
     239                j = verts.index(e[1])
     240                data[j,i] = data[i,j] = m
     241
     242            if index_set is None:
     243                index_set = G.vertices()
     244        else:
     245            try:
     246                data = matrix(data)
     247            except (ValueError, TypeError):
     248                data = CartanType(data).coxeter_matrix()
     249            if not data.is_symmetric():
     250                raise ValueError("the Coxeter matrix is not symmetric")
     251            if any(d != 1 for d in data.diagonal()):
     252                raise ValueError("the Coxeter matrix diagonal is not all 1")
     253            if any(val <= 1 and val != -1 for i,row in enumerate(data.rows()) for val in row[i+1:]):
     254                raise ValueError("invalid Coxeter label")
     255
     256            if index_set is None:
     257                index_set = range(data.nrows())
     258
     259        if base_ring is None:
     260            base_ring = UniversalCyclotomicField()
     261        data.set_immutable()
     262        return super(CoxeterMatrixGroup, cls).__classcall__(cls,
     263                     data, base_ring, tuple(index_set))
     264
     265    def __init__(self, coxeter_matrix, base_ring, index_set):
     266        """
     267        Initialize ``self``.
     268
     269        EXAMPLES::
     270
     271            sage: W = CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]])
     272            sage: TestSuite(W).run() # long time
     273            sage: W = CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]], base_ring=QQbar)
     274            sage: TestSuite(W).run() # long time
     275            sage: W = CoxeterGroup([[1,3,2],[3,1,6],[2,6,1]])
     276            sage: TestSuite(W).run(max_runs=30) # long time
     277            sage: W = CoxeterGroup([[1,3,2],[3,1,-1],[2,-1,1]])
     278            sage: TestSuite(W).run(max_runs=30) # long time
     279        """
     280        self._matrix = coxeter_matrix
     281        self._index_set = index_set
     282        n = ZZ(coxeter_matrix.nrows())
     283        MS = MatrixSpace(base_ring, n, sparse=True)
     284        # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty
     285        if base_ring is UniversalCyclotomicField():
     286            val = lambda x: base_ring.gen(2*x) + ~base_ring.gen(2*x) if x != -1 else base_ring(2)
     287        else:
     288            from sage.functions.trig import cos
     289            from sage.symbolic.constants import pi
     290            val = lambda x: base_ring(2*cos(pi / x)) if x != -1 else base_ring(2)
     291        gens = [MS.one() + MS({(i, j): val(coxeter_matrix[i,j]) for j in range(n)})
     292                for i in range(n)]
     293        FinitelyGeneratedMatrixGroup_generic.__init__(self, n, base_ring, gens, category=CoxeterGroups())
     294
     295    def _repr_(self):
     296        """
     297        Return a string representation of ``self``.
     298
     299        EXAMPLES::
     300
     301            sage: CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]])
     302            Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
     303            [1 3 2]
     304            [3 1 3]
     305            [2 3 1]
     306        """
     307        return "Coxeter group over {} with Coxeter matrix:\n{}".format(self.base_ring(), self._matrix)
     308
     309    def index_set(self):
     310        """
     311        Return the index set of ``self``.
     312
     313        EXAMPLES::
     314
     315            sage: W = CoxeterGroup([[1,3],[3,1]])
     316            sage: W.index_set()
     317            (0, 1)
     318            sage: W = CoxeterGroup([[1,3],[3,1]], index_set=['x', 'y'])
     319            sage: W.index_set()
     320            ('x', 'y')
     321            sage: W = CoxeterGroup(['H',3])
     322            sage: W.index_set()
     323            (1, 2, 3)
     324        """
     325        return self._index_set
     326
     327    def coxeter_matrix(self):
     328        """
     329        Return the Coxeter matrix of ``self``.
     330
     331        EXAMPLES::
     332
     333            sage: W = CoxeterGroup([[1,3],[3,1]])
     334            sage: W.coxeter_matrix()
     335            [1 3]
     336            [3 1]
     337            sage: W = CoxeterGroup(['H',3])
     338            sage: W.coxeter_matrix()
     339            [1 3 2]
     340            [3 1 5]
     341            [2 5 1]
     342        """
     343        return self._matrix
     344
     345    def coxeter_graph(self):
     346        """
     347        Return the Coxeter graph of ``self``.
     348
     349        EXAMPLES::
     350
     351            sage: W = CoxeterGroup(['H',3], implementation="reflection")
     352            sage: G = W.coxeter_graph(); G
     353            Graph on 3 vertices
     354            sage: G.edges()
     355            [(1, 2, None), (2, 3, 5)]
     356            sage: CoxeterGroup(G) is W
     357            True
     358            sage: G = Graph([(0, 1, 3), (1, 2, oo)])
     359            sage: W = CoxeterGroup(G)
     360            sage: W.coxeter_graph() == G
     361            True
     362            sage: CoxeterGroup(W.coxeter_graph()) is W
     363            True
     364        """
     365        G = Graph()
     366        G.add_vertices(self.index_set())
     367        for i, row in enumerate(self._matrix.rows()):
     368            for j, val in enumerate(row[i+1:]):
     369                if val == 3:
     370                    G.add_edge(self._index_set[i], self._index_set[i+1+j])
     371                elif val > 3:
     372                    G.add_edge(self._index_set[i], self._index_set[i+1+j], val)
     373                elif val == -1: # FIXME: Hack because there is no ZZ\cup\{\infty\}
     374                    G.add_edge(self._index_set[i], self._index_set[i+1+j], infinity)
     375        return G
     376
     377    def simple_reflection(self, i):
     378        """
     379        Return the simple reflection `s_i`.
     380
     381        INPUT:
     382
     383        - ``i`` -- an element from the index set
     384
     385        EXAMPLES::
     386
     387            sage: W = CoxeterGroup(['A',3], implementation="reflection")
     388            sage: W.simple_reflection(1)
     389            [-1  1  0]
     390            [ 0  1  0]
     391            [ 0  0  1]
     392            sage: W.simple_reflection(2)
     393            [ 1  0  0]
     394            [ 1 -1  1]
     395            [ 0  0  1]
     396            sage: W.simple_reflection(3)
     397            [ 1  0  0]
     398            [ 0  1  0]
     399            [ 0  1 -1]
     400        """
     401        if not i in self._index_set:
     402            raise ValueError("%s is not in the index set %s"%(i, self.index_set()))
     403        return self.gen(self._index_set.index(i))
     404
     405    class Element(MatrixGroupElement_generic):
     406        """
     407        A Coxeter group element.
     408        """
     409        def has_right_descent(self, i):
     410            r"""
     411            Return whether ``i`` is a right descent of ``self``.
     412
     413            A Coxeter system `(W, S)` has a root system defined as
     414            `\{ w(\alpha_s) \}_{w \in W}` and we define the positive
     415            (resp. negative) roots `\alpha = \sum_{s \in S} c_s \alpha_s`
     416            by all `c_s \geq 0` (resp.`c_s \leq 0`). In particular, we note
     417            that if `\ell(w s) > \ell(w)` then `w(\alpha_s) > 0` and if
     418            `\ell(ws) < \ell(w)` then `w(\alpha_s) < 0`.
     419            Thus `i \in I` is a right descent if `w(\alpha_{s_i}) < 0`
     420            or equivalently if the matrix representing `w` has all entries
     421            of the `i`-th column being non-positive.
     422
     423            INPUT:
     424
     425            - ``i`` -- an element in the index set
     426
     427            EXAMPLES::
     428
     429                sage: W = CoxeterGroup(['A',3], implementation="reflection")
     430                sage: a,b,c = W.gens()
     431                sage: elt = b*a*c
     432                sage: map(lambda i: elt.has_right_descent(i), [1, 2, 3])
     433                [True, False, True]
     434            """
     435            i = self.parent()._index_set.index(i)
     436            col = self.matrix().column(i)
     437            return all(x <= 0 for x in col)
     438
  • sage/groups/matrix_gps/finitely_generated.py

    diff --git a/sage/groups/matrix_gps/finitely_generated.py b/sage/groups/matrix_gps/finitely_generated.py
    a b def MatrixGroup(*gens, **kwds): 
    243243
    244244class FinitelyGeneratedMatrixGroup_generic(MatrixGroup_generic):
    245245
    246     def __init__(self, degree, base_ring, generator_matrices):
     246    def __init__(self, degree, base_ring, generator_matrices, category=None):
    247247        """
    248248        Matrix group generated by a finite number of matrices.
    249249
    class FinitelyGeneratedMatrixGroup_gener 
    266266            )
    267267        """
    268268        self._gens_matrix = generator_matrices
    269         MatrixGroup_generic.__init__(self, degree, base_ring)
     269        MatrixGroup_generic.__init__(self, degree, base_ring, category=category)
    270270       
    271271    def __cmp__(self, other):
    272272        """