Ticket #11187: trac_11187-finite_reflection_groups-cs.patch

File trac_11187-finite_reflection_groups-cs.patch, 199.3 KB (added by stumpc5, 7 years ago)
  • sage/categories/all.py

    # HG changeset patch
    # User Christian Stump <christian.stump at gmail.com>
    # Date 1359029540 0
    # Node ID 89ad099889ef9e2f92cd85a81ce48eb4bab3d9d5
    # Parent  d8e146847bc7bb1381310a84e1f961575f66f608
    #11187 Implementation of finite reflection groups using the GAP3 package chevie
    
    diff --git a/sage/categories/all.py b/sage/categories/all.py
    a b from graded_coalgebras_with_basis imp 
    117117from graded_bialgebras_with_basis    import GradedBialgebrasWithBasis
    118118from graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis
    119119
     120# reflection groups
     121from complex_reflection_groups import ComplexReflectionGroups, WellGeneratedComplexReflectionGroups
    120122
    121123# coxeter groups
    122124from coxeter_groups import CoxeterGroups
  • new file sage/categories/complex_reflection_groups.py

    diff --git a/sage/categories/complex_reflection_groups.py b/sage/categories/complex_reflection_groups.py
    new file mode 100644
    - +  
     1r"""
     2Finite (complex) reflection groups
     3"""
     4#*****************************************************************************
     5#  Copyright (C) 2011    Christian Stump <christian.stump at lacim.ca>
     6#
     7#  Distributed under the terms of the GNU General Public License (GPL)
     8#                  http://www.gnu.org/licenses/
     9#******************************************************************************
     10
     11from sage.misc.abstract_method import abstract_method
     12from sage.misc.all import prod
     13from sage.misc.cachefunc import cached_method
     14from sage.categories.category_singleton import Category_singleton
     15from sage.categories.adjective_category import AdjectiveCategory
     16from sage.categories.groups import Groups
     17
     18class ComplexReflectionGroups(Category_singleton):
     19    r"""
     20    The category of finite dimensional complex reflection groups.
     21    This is the base category for subgroups of the special linear group which are generated by reflections.
     22
     23    A *reflection group* is a group `W` generated by (complex) reflections
     24    `t \in \operatorname{O}(V)` acting on a complex vector space `V` such that
     25    `t` fixes a hyperplane pointwise and acts by a root of unity on its orthogonal complement.
     26
     27    The (finite) dimension of `V` is the *rank* of `W`.
     28
     29    See http://en.wikipedia.org/wiki/Reflection_group for details.
     30
     31    EXAMPLES::
     32
     33        sage: ComplexReflectionGroups()
     34        Category of complex reflection groups
     35        sage: ComplexReflectionGroups().super_categories()
     36        [Category of groups]
     37        sage: ComplexReflectionGroups().all_super_categories()
     38        [Category of complex reflection groups, Category of groups,
     39         Category of monoids, Category of semigroups,
     40         Category of magmas, Category of sets,
     41         Category of sets with partial maps, Category of objects]
     42
     43    Let us consider an example of a reflection group::
     44
     45        sage: W = ComplexReflectionGroups().example(); W
     46        Irreducible finite complex reflection group of rank 3 and type (3,1,3)
     47
     48    P is in the category of sets::
     49
     50        sage: W in ComplexReflectionGroups()
     51        True
     52
     53    TESTS::
     54
     55        sage: TestSuite(W).run()
     56        sage: TestSuite(ComplexReflectionGroups()).run()
     57
     58    .. seealso:: :class:`ComplexReflectionGroups`, :class:`CoxeterGroups`, :mod:`sage.combinat.root_system` for finite real reflection groups.
     59    """
     60
     61    @cached_method
     62    def super_categories(self):
     63        r"""
     64        EXAMPLES::
     65
     66            sage: ComplexReflectionGroups().super_categories()
     67            [Category of groups]
     68        """
     69        return [Groups()]
     70
     71    def example(self):
     72        r"""
     73        Returns an example of a complex reflection group.
     74
     75        EXAMPLES::
     76
     77            sage: ComplexReflectionGroups().example()
     78            Irreducible finite complex reflection group of rank 3 and type (3,1,3)
     79        """
     80        from sage.combinat.root_system.complex_reflection_group import ComplexReflectionGroup
     81        return ComplexReflectionGroup((3,1,3))
     82
     83    class ParentMethods:
     84
     85        @abstract_method
     86        def index_set(self):
     87            r"""
     88            Returns the index set of the simple reflections of ``self``.
     89            """
     90
     91        def simple_reflection(self, i):
     92            r"""
     93            Returns the `i`-th simple reflection of ``self``.
     94
     95            For `i` in `1,\dots,\ell`, this gives the `i`-th simple reflection of ``self``.
     96            """
     97            return self.one().apply_simple_reflection(i)
     98
     99        @abstract_method(optional=True)
     100        def hyperplane_index_set(self):
     101            r"""
     102            Returns the index set of the reflection hyperplanes of ``self``.
     103            """
     104
     105        @abstract_method(optional=True)
     106        def distinguished_reflection(self, i):
     107            r"""
     108            Returns the `i`-th distinguished reflection of ``self``. For a definition of
     109            destinguished reflections, see :meth:`distinguished_reflections`.
     110
     111            For `i` in `1,\dots,N^*`, this gives the `i`-th distinguished reflection of ``self``.
     112            """
     113
     114        @abstract_method(optional=True)
     115        def reflection_index_set(self):
     116            r"""
     117            Returns the index set of the reflections of ``self``.
     118            """
     119
     120        @abstract_method(optional=True)
     121        def reflection(self, i):
     122            r"""
     123            Returns the `i`-th reflection of ``self``.
     124
     125            For `i` in `1,\dots,N`, this gives the `i`-th reflection of ``self``.
     126            """
     127
     128        @cached_method
     129        def simple_reflections(self):
     130            r"""
     131            Returning the simple reflections of ``self`` as a family indexed by ``self.index_set()``.
     132
     133            EXAMPLES::
     134
     135                sage: W = ComplexReflectionGroup((1,1,3))
     136                sage: W.simple_reflections()
     137                Finite family {0: (1,4)(2,3)(5,6), 1: (1,3)(2,5)(4,6)}
     138
     139                sage: W = ComplexReflectionGroup((1,1,3),index_set=['a','b'])
     140                sage: W.simple_reflections()
     141                Finite family {'a': (1,4)(2,3)(5,6), 'b': (1,3)(2,5)(4,6)}
     142            """
     143            from sage.sets.family import Family
     144            return Family(self.index_set(), self.simple_reflection)
     145
     146        @cached_method
     147        def distinguished_reflections(self):
     148            r"""
     149            Returns a finite family containing the distinguished reflections of ``self``,
     150            indexed by ``self.hyperplane_index_set()``.
     151            These are the reflections in ``self`` acting on the complement
     152            of the fixed hyperplane `H` as `\operatorname{exp}(2 \pi i / n)`, where `n`
     153            is the order of the reflection subgroup fixing `H`.
     154
     155           EXAMPLES::
     156
     157                sage: W = ComplexReflectionGroup((1,1,3))
     158                sage: W.distinguished_reflections()
     159                Finite family {0: (1,4)(2,3)(5,6), 1: (1,3)(2,5)(4,6), 2: (1,5)(2,4)(3,6)}
     160
     161                sage: W = ComplexReflectionGroup((1,1,3),hyperplane_index_set=['a','b','c'])
     162                sage: W.distinguished_reflections()
     163                Finite family {'a': (1,4)(2,3)(5,6), 'c': (1,5)(2,4)(3,6), 'b': (1,3)(2,5)(4,6)}
     164
     165                sage: W = ComplexReflectionGroup((3,1,1))
     166                sage: W.distinguished_reflections()
     167                Finite family {0: (1,2,3)}
     168
     169                sage: W = ComplexReflectionGroup((1,1,3),(3,1,2))
     170                sage: W.distinguished_reflections()
     171                Finite family {0: (1,6)(2,5)(7,8), 1: (1,5)(2,7)(6,8), 2: (3,9,15)(4,10,16)(12,17,23)(14,18,24)(20,25,29)(21,22,26)(27,28,30), 3: (3,11)(4,12)(9,13)(10,14)(15,19)(16,20)(17,21)(18,22)(23,27)(24,28)(25,26)(29,30), 4: (4,21,27)(10,22,28)(11,13,19)(12,14,20)(16,26,30)(17,18,25)(23,24,29), 5: (3,13)(4,24)(9,19)(10,29)(11,15)(12,26)(14,21)(16,23)(17,30)(18,27)(20,22)(25,28), 6: (3,19)(4,25)(9,11)(10,17)(12,28)(13,15)(14,30)(16,18)(20,27)(21,29)(22,23)(24,26), 7: (1,7)(2,6)(5,8)}
     172            """
     173            from sage.sets.family import Family
     174            return Family(self.hyperplane_index_set(), self.distinguished_reflection)
     175
     176        @cached_method
     177        def reflections(self):
     178            r"""
     179            Returns a finite family containing the reflections of ``self``,
     180            indexed by ``self.reflection_index_set()``.
     181
     182           EXAMPLES::
     183
     184                sage: W = ComplexReflectionGroup((1,1,3))
     185                sage: W.reflections()
     186                Finite family {0: (1,4)(2,3)(5,6), 1: (1,3)(2,5)(4,6), 2: (1,5)(2,4)(3,6)}
     187
     188                sage: W = ComplexReflectionGroup((1,1,3),reflection_index_set=['a','b','c'])
     189                sage: W.reflections()
     190                Finite family {'a': (1,4)(2,3)(5,6), 'c': (1,5)(2,4)(3,6), 'b': (1,3)(2,5)(4,6)}
     191
     192                sage: W = ComplexReflectionGroup((3,1,1))
     193                sage: W.reflections()
     194                Finite family {0: (1,2,3), 1: (1,3,2)}
     195
     196                sage: W = ComplexReflectionGroup((1,1,3),(3,1,2))
     197                sage: W.reflections()
     198                Finite family {0: (1,6)(2,5)(7,8), 1: (1,5)(2,7)(6,8), 2: (3,9,15)(4,10,16)(12,17,23)(14,18,24)(20,25,29)(21,22,26)(27,28,30), 3: (3,11)(4,12)(9,13)(10,14)(15,19)(16,20)(17,21)(18,22)(23,27)(24,28)(25,26)(29,30), 4: (4,21,27)(10,22,28)(11,13,19)(12,14,20)(16,26,30)(17,18,25)(23,24,29), 5: (3,13)(4,24)(9,19)(10,29)(11,15)(12,26)(14,21)(16,23)(17,30)(18,27)(20,22)(25,28), 6: (3,19)(4,25)(9,11)(10,17)(12,28)(13,15)(14,30)(16,18)(20,27)(21,29)(22,23)(24,26), 7: (1,7)(2,6)(5,8), 8: (3,15,9)(4,16,10)(12,23,17)(14,24,18)(20,29,25)(21,26,22)(27,30,28), 9: (4,27,21)(10,28,22)(11,19,13)(12,20,14)(16,30,26)(17,25,18)(23,29,24)}
     199            """
     200            from sage.sets.family import Family
     201            return Family(self.reflection_index_set(), self.reflection)
     202
     203        @abstract_method(optional=True)
     204        def irreducible_components(self):
     205            r"""
     206            Returns a list containing all irreducible components of ``self`` as finite reflection groups.
     207            """
     208
     209        def an_element(self):
     210            r"""
     211            Implements: :meth:`Sets.ParentMethods.an_element` by
     212            returning the product of the simple reflections (which is *not*
     213            necessarily a Coxeter element).
     214
     215            EXAMPLES::
     216
     217                sage: W=ComplexReflectionGroups().example()
     218                sage: W
     219                Irreducible finite complex reflection group of rank 3 and type (3,1,3)
     220                sage: W.an_element() # random
     221                (1,3)(2,5)(4,6)
     222            """
     223            return self.prod(self.reflection(i) for i in self.index_set())
     224
     225        an_element_force = an_element
     226
     227        def some_elements(self):
     228            r"""
     229            Implements :meth:`Sets.ParentMethods.some_elements` by
     230            returning some typical element of `self`.
     231
     232            EXAMPLES::
     233
     234                sage: W=ComplexReflectionGroup((1,1,4))
     235                sage: W.some_elements()
     236                [(1,7)(2,4)(5,6)(8,10)(11,12), (1,4)(2,8)(3,5)(7,10)(9,11), (2,5)(3,9)(4,6)(8,11)(10,12), (), (1,7)(2,4)(5,6)(8,10)(11,12)]
     237                sage: W.order()   
     238                24
     239            """
     240            return [self.simple_reflection(i) for i in self.index_set() ] + [ self.one(), self.an_element_force() ]
     241
     242        def from_word(self, word, word_type='simple'):
     243            r"""
     244            INPUT:
     245
     246             - ``word`` - a list (or iterable) of elements of the appropriate index set
     247 
     248            Returns the group element corresponding to the given
     249            word. Namely, if ``word`` is `[i_1,i_2,\ldots,i_k]`, then
     250            this returns the corresponding product of
     251            (simple/distinguished/all) reflections `t_{i_1} t_{i_2} \cdots t_{i_k}`.
     252
     253            EXAMPLES::
     254
     255                sage: W = ComplexReflectionGroup((1,1,4)); W
     256                Irreducible finite complex reflection group of rank 3 and type (1,1,4)
     257                sage: W.from_word([0,1,0,1,0,1])
     258                ()
     259
     260                sage: W.from_word([0,1,2]).reduced_word()
     261                word: 012
     262
     263                sage: W.from_word([0,1,2], word_type='all').reduced_word()
     264                word: 012
     265
     266                sage: W.from_word([0,1,2], word_type='all').reduced_word_in_reflections()
     267                word: 420
     268
     269                sage: W.from_word([0,1,2]).reduced_word_in_reflections()
     270                word: 420
     271            """
     272            if word_type == 'simple':
     273                f = self.one().apply_simple_reflections
     274            elif word_type == 'distinguished':
     275                f = self.one().apply_distinguished_reflections
     276            elif word_type == 'all':
     277                f = self.one().apply_reflections
     278            return f(word, side = 'right')
     279
     280        def group_generators(self):
     281            r"""
     282            Implements :meth:`Groups.ParentMethods.group_generators`
     283            by returning the simple reflections of ``self``.
     284            """
     285            return self.simple_reflections()
     286
     287        semigroup_generators = group_generators
     288
     289    class ElementMethods:
     290
     291        # at least one of the two methods must be reimplemented
     292        # it is recommended to reimplement both, as computing
     293        # the inverse might not be very efficient...
     294
     295        def apply_simple_reflection_left(self, i):
     296            """
     297            Returns ``self`` multiplied by the simple reflection ``s[i]`` on the left
     298
     299            This low level method is used intensively. Coxeter groups
     300            are encouraged to override this straightforward
     301            implementation whenever a faster approach exists.
     302
     303            EXAMPLES::
     304
     305                sage: W=CoxeterGroups().example()
     306                sage: w = W.an_element(); w
     307                (1, 2, 3, 0)
     308                sage: w.apply_simple_reflection_left(0)
     309                (0, 2, 3, 1)
     310                sage: w.apply_simple_reflection_left(1)
     311                (2, 1, 3, 0)
     312                sage: w.apply_simple_reflection_left(2)
     313                (1, 3, 2, 0)
     314
     315            TESTS::
     316
     317                sage: w.apply_simple_reflection_left.__module__
     318                'sage.categories.coxeter_groups'
     319            """
     320            s = self.parent().simple_reflections()
     321            return s[i] * self
     322
     323        def apply_simple_reflection_right(self, i):
     324            """
     325            Returns ``self`` multiplied by the simple reflection ``s[i]`` on the right
     326
     327            This low level method is used intensively. Coxeter groups
     328            are encouraged to override this straightforward
     329            implementation whenever a faster approach exists.
     330
     331            EXAMPLES::
     332
     333                sage: W=CoxeterGroups().example()
     334                sage: w = W.an_element(); w
     335                (1, 2, 3, 0)
     336                sage: w.apply_simple_reflection_right(0)
     337                (2, 1, 3, 0)
     338                sage: w.apply_simple_reflection_right(1)
     339                (1, 3, 2, 0)
     340                sage: w.apply_simple_reflection_right(2)
     341                (1, 2, 0, 3)
     342
     343            TESTS::
     344
     345                sage: w.apply_simple_reflection_right.__module__
     346                'sage.categories.coxeter_groups'
     347            """
     348            s = self.parent().simple_reflections()
     349            return self * s[i]
     350
     351        def apply_simple_reflection(self, i, side = 'right'):
     352            """
     353            Returns ``self`` multiplied by the simple reflection ``s[i]``
     354
     355            INPUT:
     356
     357            - ``i`` -- an element of the index set
     358            - ``side`` -- "left" or "right" (default: "right")
     359
     360            This default implementation simply calls
     361            :meth:`apply_simple_reflection_left` or
     362            :meth:`apply_simple_reflection_right`.
     363
     364            EXAMPLES::
     365
     366                sage: W=CoxeterGroups().example()
     367                sage: w = W.an_element(); w
     368                (1, 2, 3, 0)
     369                sage: w.apply_simple_reflection(0, side = "left")
     370                (0, 2, 3, 1)
     371                sage: w.apply_simple_reflection(1, side = "left")
     372                (2, 1, 3, 0)
     373                sage: w.apply_simple_reflection(2, side = "left")
     374                (1, 3, 2, 0)
     375
     376                sage: w.apply_simple_reflection(0, side = "right")
     377                (2, 1, 3, 0)
     378                sage: w.apply_simple_reflection(1, side = "right")
     379                (1, 3, 2, 0)
     380                sage: w.apply_simple_reflection(2, side = "right")
     381                (1, 2, 0, 3)
     382
     383            By default, ``side`` is "right"::
     384
     385                sage: w.apply_simple_reflection(0)
     386                (2, 1, 3, 0)
     387
     388            TESTS::
     389
     390                sage: w.apply_simple_reflection_right.__module__
     391                'sage.categories.coxeter_groups'
     392            """
     393            if side == 'right':
     394                return self.apply_simple_reflection_right(i)
     395            else:
     396                return self.apply_simple_reflection_left(i)
     397
     398        @abstract_method(optional=True)
     399        def reflection_length(self):
     400            r"""
     401            Returns the reflection length of ``self``, that is the
     402            minimal length of a product of reflections giving ``self``.
     403
     404            EXAMPLES::
     405
     406                sage: W = ComplexReflectionGroup((1,1,2))
     407                sage: sorted([ t.reflection_length() for t in W ])
     408                [0, 1]
     409
     410                sage: W = ComplexReflectionGroup((2,1,2))
     411                sage: sorted([ t.reflection_length() for t in W ])
     412                [0, 1, 1, 1, 1, 2, 2, 2]
     413
     414                sage: W = ComplexReflectionGroup((3,1,2))
     415                sage: sorted([ t.reflection_length() for t in W ])
     416                [0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
     417
     418                sage: W = ComplexReflectionGroup((2,2,2))
     419                sage: sorted([ t.reflection_length() for t in W ])
     420                [0, 1, 1, 2]
     421            """
     422
     423        def is_reflection(self):
     424            r"""
     425            Returns True if ``self`` is a reflection, i.e., if ``self`` fixes a hyperplane pointwise.
     426
     427            EXAMPLES::
     428
     429                sage: W = ComplexReflectionGroup((1,1,4)); W
     430                Irreducible finite complex reflection group of rank 3 and type (1,1,4)
     431                sage: [ t.is_reflection() for t in W.reflections() ]
     432                [True, True, True, True, True, True]
     433                sage: len( [ t for t in W.reflections() if t.is_reflection() ] )
     434                6
     435
     436                sage: W = ComplexReflectionGroup((2,1,3)); W
     437                Irreducible finite complex reflection group of rank 3 and type (2,1,3)
     438                sage: [ t.is_reflection() for t in W.reflections() ]
     439                [True, True, True, True, True, True, True, True, True]
     440                sage: len( [t for t in W.reflections() if t.is_reflection() ] )
     441                9
     442            """
     443            return self.reflection_length() == 1
     444
     445        def apply_simple_reflections(self, word, side = 'right'):
     446            r"""
     447            ... multiplies all simple reflections in ``word`` to ``self``...
     448
     449            INPUT:
     450
     451             - word -- A sequence of indices of reflections
     452             - side -- (defaut:'right') Indicates multiplying from left or right
     453
     454            Returns the result of the (left/right) multiplication of   
     455            word to self.  self is not changed.
     456
     457            EXAMPLES::
     458
     459                sage: W = ComplexReflectionGroup((1,1,3)); W
     460                Irreducible finite complex reflection group of rank 2 and type (1,1,3)
     461                sage: W.one().apply_simple_reflections([0])
     462                (1,4)(2,3)(5,6)
     463                sage: W.one().apply_simple_reflections([1])
     464                (1,3)(2,5)(4,6)
     465                sage: W.one().apply_simple_reflections([1,0])
     466                (1,2,6)(3,4,5)
     467                sage: W.one().apply_simple_reflections([0,1])
     468                (1,6,2)(3,5,4)
     469                sage: W.one().apply_simple_reflections([0,1,0])
     470                (1,5)(2,4)(3,6)
     471                sage: W.one().apply_simple_reflections([0,1,0,1])
     472                (1,2,6)(3,4,5)
     473                sage: W.one().apply_simple_reflections([0,1,0,1,0])
     474                (1,3)(2,5)(4,6)
     475                sage: W.one().apply_simple_reflections([0,1,0,1,0,1])
     476                ()
     477            """
     478            for i in word:
     479                self = self.apply_simple_reflection(i, side=side)
     480            return self
     481
     482        def apply_distinguished_reflection(self, i, side = 'right'):
     483            r"""
     484            ... multiplies the ``i``-th distinguished reflection to ``self``...
     485            """
     486            G = self.parent()
     487            assert i in G.hyperplane_index_set()
     488            if side == 'right':
     489                return self * G.distinguished_reflection(i)
     490            else:
     491                return self.parent().reflection(i) * self
     492
     493        def apply_distinguished_reflections(self, word, side = 'right'):
     494            r"""
     495            ... multiplies all reflections in ``word`` to ``self``...
     496
     497            INPUT:
     498
     499             - word -- A sequence of indices of reflections
     500             - side -- (defaut:'right') Indicates multiplying from left or right
     501
     502            Returns the result of the (left/right) multiplication of   
     503            word to self.  self is not changed.
     504
     505            EXAMPLES::
     506
     507                sage: W = ComplexReflectionGroup((1,1,3)); W
     508                Irreducible finite complex reflection group of rank 2 and type (1,1,3)
     509                sage: W.one().apply_distinguished_reflections([0])
     510                (1,4)(2,3)(5,6)
     511                sage: W.one().apply_distinguished_reflections([1])
     512                (1,3)(2,5)(4,6)
     513                sage: W.one().apply_distinguished_reflections([1,0])
     514                (1,2,6)(3,4,5)
     515                sage: W.one().apply_distinguished_reflections([0,1])
     516                (1,6,2)(3,5,4)
     517                sage: W.one().apply_distinguished_reflections([0,1,0])
     518                (1,5)(2,4)(3,6)
     519                sage: W.one().apply_distinguished_reflections([0,1,0,1])
     520                (1,2,6)(3,4,5)
     521                sage: W.one().apply_distinguished_reflections([0,1,0,1,0])
     522                (1,3)(2,5)(4,6)
     523                sage: W.one().apply_distinguished_reflections([0,1,0,1,0,1])
     524                ()
     525            """
     526            for i in word:
     527                self = self.apply_distinguished_reflection(i, side=side)
     528            return self
     529
     530        def apply_reflection(self, i, side = 'right'):
     531            r"""
     532            ... multiplies the ``i``-th reflection to ``self``...
     533            """
     534            G = self.parent()
     535            assert i in G.reflection_index_set()
     536            if side == 'right':
     537                return self * G.reflection(i)
     538            else:
     539                return self.parent().reflection(i) * self
     540
     541        def apply_reflections(self, word, side = 'right'):
     542            r"""
     543            ... multiplies all reflections in ``word`` to ``self``...
     544
     545            INPUT:
     546
     547             - word -- A sequence of indices of reflections
     548             - side -- (defaut:'right') Indicates multiplying from left or right
     549
     550            Returns the result of the (left/right) multiplication of   
     551            word to self.  self is not changed.
     552
     553            EXAMPLES::
     554
     555                sage: W = ComplexReflectionGroup((1,1,3)); W
     556                Irreducible finite complex reflection group of rank 2 and type (1,1,3)
     557                sage: W.one().apply_reflections([0])
     558                (1,4)(2,3)(5,6)
     559                sage: W.one().apply_reflections([1])
     560                (1,3)(2,5)(4,6)
     561                sage: W.one().apply_reflections([1,0])
     562                (1,2,6)(3,4,5)
     563                sage: W.one().apply_reflections([0,1])
     564                (1,6,2)(3,5,4)
     565                sage: W.one().apply_reflections([0,1,0])
     566                (1,5)(2,4)(3,6)
     567                sage: W.one().apply_reflections([0,1,0,1])
     568                (1,2,6)(3,4,5)
     569                sage: W.one().apply_reflections([0,1,0,1,0])
     570                (1,3)(2,5)(4,6)
     571                sage: W.one().apply_reflections([0,1,0,1,0,1])
     572                ()
     573            """
     574            for i in word:
     575                self = self.apply_reflection(i, side=side)
     576            return self
     577
     578    class Finite(AdjectiveCategory):
     579        r"""
     580        The category of finite complex reflection groups.
     581        This is the base category for finite subgroups of the special linear group which are generated by reflections.
     582
     583        EXAMPLES::
     584
     585            sage: ComplexReflectionGroups().Finite()
     586            Category of finite complex reflection groups
     587            sage: ComplexReflectionGroups().Finite().super_categories()
     588            [Category of complex reflection groups, Category of finite groups]
     589            sage: ComplexReflectionGroups().Finite().all_super_categories()
     590            [Category of finite complex reflection groups, Category of complex reflection groups,
     591            Category of finite groups, Category of groups, Category of finite monoids,
     592            Category of monoids, Category of finite semigroups, Category of semigroups,
     593            Category of magmas, Category of finite enumerated sets, Category of enumerated sets,
     594            Category of finite sets, Category of sets,
     595            Category of sets with partial maps, Category of objects]
     596           
     597
     598        Let us consider an example of a finite reflection group::
     599
     600            sage: W = ComplexReflectionGroups().Finite().example(); W
     601            Finite complex reflection group of rank 4 and type (1,1,3) x (2,1,2)
     602
     603            sage: W.reflections()
     604            Finite family {0: (1,8)(2,5)(9,12), 1: (1,5)(2,9)(8,12), 2: (3,10)(4,7)(11,14), 3: (3,6)(4,11)(10,13), 4: (4,14)(6,13)(7,11), 5: (3,13)(6,10)(7,14), 6: (1,9)(2,8)(5,12)}
     605
     606        P is in the category of sets::
     607
     608            sage: W in ComplexReflectionGroups().Finite()
     609            True
     610
     611        .. seealso:: :class:`ComplexReflectionGroups`, :class:`CoxeterGroups`, :mod:`sage.combinat.root_system` for finite real reflection groups.
     612        """
     613
     614        def example(self):
     615            r"""
     616            Returns an example of a finite complex reflection group.
     617
     618            EXAMPLES::
     619
     620                sage: ComplexReflectionGroups().Finite().example()
     621                Finite complex reflection group of rank 4 and type (1,1,3) x (2,1,2)
     622            """
     623            from sage.combinat.root_system.complex_reflection_group import ComplexReflectionGroup
     624            return ComplexReflectionGroup((1,1,3),(2,1,2))
     625
     626        class ParentMethods:
     627
     628            def is_finite(self):
     629                r"""
     630                Returns ``True`` since ``self`` is finite.
     631
     632                EXAMPLES::
     633
     634                    sage: C = ComplexReflectionGroups().Finite().example()
     635                    sage: C.is_finite()
     636                    True
     637                """
     638                return True
     639
     640            @abstract_method(optional=True)
     641            def degrees(self):
     642                r"""
     643                Returns the degrees of ``self``, as a list.
     644                """
     645
     646            @abstract_method(optional=True)
     647            def codegrees(self):
     648                r"""
     649                Returns the codegrees of ``self``, as a list.
     650                """
     651
     652            def nr_simple_reflections(self):
     653                r"""
     654                Returns the number of reflections simple of ``self``.
     655
     656                EXAMPLES::
     657
     658                    sage: W = ComplexReflectionGroup((1,1,3))
     659                    sage: W.nr_simple_reflections()
     660                    2
     661                    sage: W = ComplexReflectionGroup((2,1,3))
     662                    sage: W.nr_simple_reflections()
     663                    3
     664                    sage: W = ComplexReflectionGroup((4,1,3))
     665                    sage: W.nr_simple_reflections()
     666                    3
     667                    sage: W = ComplexReflectionGroup((4,2,3))
     668                    sage: W.nr_simple_reflections()
     669                    4
     670                """
     671                return len(self.simple_reflections())
     672
     673            def nr_reflecting_hyperplanes(self):
     674                r"""
     675                Returns the number of reflecting hyperplanes of ``self``. It is given by the sum of the codegrees of self plus its rank.
     676                For real groups, this coincides with the number of reflections.
     677
     678                EXAMPLES::
     679
     680                    sage: W = ComplexReflectionGroup((1,1,3))
     681                    sage: W.nr_reflecting_hyperplanes()
     682                    3
     683                    sage: W = ComplexReflectionGroup((2,1,3))
     684                    sage: W.nr_reflecting_hyperplanes()
     685                    9
     686                    sage: W = ComplexReflectionGroup((4,1,3))
     687                    sage: W.nr_reflecting_hyperplanes()
     688                    15
     689                    sage: W = ComplexReflectionGroup((4,2,3))
     690                    sage: W.nr_reflecting_hyperplanes()
     691                    15
     692                """
     693                return sum(self.codegrees())+self.rank()
     694
     695            def nr_reflections(self):
     696                r"""
     697                Returns the number of reflections of ``self``. It is given by the sum of the degrees of self minus its rank.
     698                For real groups, this coincides with the number of reflecting hyperplanes.
     699
     700                EXAMPLES::
     701
     702                    sage: W = ComplexReflectionGroup((1,1,3))
     703                    sage: W.nr_reflections()
     704                    3
     705                    sage: W = ComplexReflectionGroup((2,1,3))
     706                    sage: W.nr_reflections()
     707                    9
     708                    sage: W = ComplexReflectionGroup((4,1,3))
     709                    sage: W.nr_reflections()
     710                    21
     711                    sage: W = ComplexReflectionGroup((4,2,3))
     712                    sage: W.nr_reflections()
     713                    15
     714                """
     715                return sum(self.degrees()) - self.rank()
     716
     717            def rank(self):
     718                r"""
     719                Returns the rank of ``self``. This is the dimension of the underlying vector space.
     720
     721                EXAMPLES::
     722
     723                    sage: W = ComplexReflectionGroup((1,1,3))
     724                    sage: W.rank()
     725                    2
     726                    sage: W = ComplexReflectionGroup((2,1,3))
     727                    sage: W.rank()
     728                    3
     729                    sage: W = ComplexReflectionGroup((4,1,3))
     730                    sage: W.rank()
     731                    3
     732                    sage: W = ComplexReflectionGroup((4,2,3))
     733                    sage: W.rank()
     734                    3
     735                """
     736                return len(self.degrees())
     737
     738            def nr_irreducible_components(self):
     739                r"""
     740                Returns the number of irreducible components of ``self``.
     741
     742                EXAMPLES::
     743
     744                    sage: W = ComplexReflectionGroup((1,1,3))
     745                    sage: W.nr_irreducible_components()
     746                    1
     747
     748                    sage: W = ComplexReflectionGroup((1,1,3),(2,1,3))
     749                    sage: W.nr_irreducible_components()
     750                    2
     751                """
     752                return len(self.irreducible_components())
     753
     754            def cardinality(self):
     755                r"""
     756                Returns the cardinality of ``self``. It is given by the product of the degrees of ``self``.
     757
     758                EXAMPLES::
     759
     760                    sage: W = ComplexReflectionGroup((1,1,3))
     761                    sage: W.cardinality()
     762                    6
     763                    sage: W = ComplexReflectionGroup((2,1,3))
     764                    sage: W.cardinality()
     765                    48
     766                    sage: W = ComplexReflectionGroup((4,1,3))
     767                    sage: W.cardinality()
     768                    384
     769                    sage: W = ComplexReflectionGroup((4,2,3))
     770                    sage: W.cardinality()
     771                    192
     772                """
     773                return prod(self.degrees())
     774
     775            def is_irreducible(self):
     776                r"""
     777                Returns True if ``self`` is irreducible.
     778
     779                EXAMPLES::
     780
     781                    sage: W = ComplexReflectionGroup((1,1,3)); W
     782                    Irreducible finite complex reflection group of rank 2 and type (1,1,3)
     783                    sage: W.is_irreducible()
     784                    True
     785
     786                    sage: W = ComplexReflectionGroup((1,1,3),(2,1,3)); W
     787                    Finite complex reflection group of rank 5 and type (1,1,3) x (2,1,3)
     788                    sage: W.is_irreducible()
     789                    False
     790                """
     791                return self.nr_irreducible_components() == 1
     792
     793            def is_reducible(self):
     794                r"""
     795                Returns True if ``self`` is not irreducible.
     796
     797                EXAMPLES::
     798
     799                    sage: W = ComplexReflectionGroup((1,1,3)); W
     800                    Irreducible finite complex reflection group of rank 2 and type (1,1,3)
     801                    sage: W.is_reducible()
     802                    False
     803
     804                    sage: W = ComplexReflectionGroup((1,1,3),(2,1,3)); W
     805                    Finite complex reflection group of rank 5 and type (1,1,3) x (2,1,3)
     806                    sage: W.is_reducible()
     807                    True
     808                """
     809                return not self.is_irreducible()
     810
     811            def is_well_generated(self):
     812                r"""
     813                Returns True if ``self`` is well generated. This is, if ``self`` is generated by `\ell` many reflections where `\ell` is the rank of ``self``.
     814
     815                REMARK:
     816
     817                - all finite real reflection groups are well generated,
     818                - the finite complex reflection groups of type `G(r,1,n)` and of type `G(r,r,n` are well generated,
     819                - the finite complex reflection groups of type `G(r,p,n)` with `1 < p < r` are *not* well generated.
     820
     821                EXAMPLES::
     822
     823                    sage: W = ComplexReflectionGroup((1,1,3))
     824                    sage: W.is_well_generated()
     825                    True
     826
     827                    sage: W = ComplexReflectionGroup((4,1,3))
     828                    sage: W.is_well_generated()
     829                    True
     830
     831                    sage: W = ComplexReflectionGroup((4,2,3))
     832                    sage: W.is_well_generated()
     833                    False
     834
     835                    sage: W = ComplexReflectionGroup((4,4,3))
     836                    sage: W.is_well_generated()
     837                    True
     838                """
     839                if self in WellGeneratedComplexReflectionGroups():
     840                    return True
     841                else:
     842                    return self.nr_simple_reflections() == self.rank()
     843
     844            def is_real(self):
     845                r"""
     846                Returns True if ``self`` is real. For irreducible reflection groups, this is equivalent to `2` is a degree of ``self``.
     847
     848                EXAMPLES::
     849
     850                    sage: W = ComplexReflectionGroup((1,1,3))
     851                    sage: W.is_real()
     852                    True
     853
     854                    sage: W = ComplexReflectionGroup((4,1,3))
     855                    sage: W.is_real()
     856                    False
     857                """
     858                return self.degrees().count(2) == self.nr_irreducible_components()
     859
     860            @cached_method
     861            def reflecting_hyperplanes(self):
     862                r"""
     863                Returns the list of all reflecting hyperplanes of ``self``.
     864
     865                REMARK:
     866
     867                - the method does not yet work for non-crystallographic types
     868
     869                EXAMPLES::
     870
     871                    sage: W = ComplexReflectionGroup((1,1,3))
     872                    sage: for H in W.reflecting_hyperplanes(): print H
     873                    Vector space of degree 2 and dimension 1 over Rational Field
     874                    Basis matrix:
     875                    [0 1]
     876                    Vector space of degree 2 and dimension 1 over Rational Field
     877                    Basis matrix:
     878                    [1 0]
     879                    Vector space of degree 2 and dimension 1 over Rational Field
     880                    Basis matrix:
     881                    [ 1 -1]
     882
     883                    sage: W = ComplexReflectionGroup((2,1,2))
     884                    sage: for H in W.reflecting_hyperplanes():
     885                    ...       print H
     886                    Vector space of degree 2 and dimension 1 over Rational Field
     887                    Basis matrix:
     888                    [0 1]
     889                    Vector space of degree 2 and dimension 1 over Rational Field
     890                    Basis matrix:
     891                    [1 0]
     892                    Vector space of degree 2 and dimension 1 over Rational Field
     893                    Basis matrix:
     894                    [ 1 -1]
     895                    Vector space of degree 2 and dimension 1 over Rational Field
     896                    Basis matrix:
     897                    [ 1 -2]
     898                """
     899                from sage.matrix.all import identity_matrix
     900                Hs = []
     901                for r in self.distinguished_reflections():
     902                    mat = r.as_matrix()
     903                    mat = mat - identity_matrix(mat.base_ring(),self.rank())
     904                    Hs.append( mat.right_kernel() )
     905                return Hs
     906
     907        class ElementMethods:
     908
     909            @abstract_method(optional=True)
     910            def as_matrix(self):
     911                r"""
     912                Returns the matrix presentation of ``self`` acting on the vector space V.
     913
     914                EXAMPLES::
     915
     916                sage: W = ComplexReflectionGroup((1,1,3))
     917                sage: [ t.as_matrix() for t in W ]
     918                [
     919                [1 0]  [-1  0]  [ 1  1]  [-1 -1]  [ 0  1]  [ 0 -1]
     920                [0 1], [ 1  1], [ 0 -1], [ 1  0], [-1 -1], [-1  0]
     921                ]
     922
     923                sage: W = ComplexReflectionGroup((3,1,1))
     924                sage: [ t.as_matrix() for t in W ]
     925                [[1], [E(3)], [E(3)^2]]
     926                """
     927
     928            def character_value(self):
     929                r"""
     930                Returns the value at ``self`` of the character of the reflection representation `V` of ``self.parent()``.
     931
     932                EXAMPLES::
     933
     934                    sage: W = ComplexReflectionGroup((1,1,3)); W
     935                    Irreducible finite complex reflection group of rank 2 and type (1,1,3)
     936                    sage: [ t.character_value() for t in W ]
     937                    [2, 0, 0, -1, -1, 0]
     938
     939                    sage: W = ComplexReflectionGroup((2,1,2)); W
     940                    Irreducible finite complex reflection group of rank 2 and type (2,1,2)
     941                    sage: [ t.character_value() for t in W ]
     942                    [2, 0, 0, 0, 0, 0, 0, -2]
     943
     944                    sage: W = ComplexReflectionGroup((3,1,2)); W
     945                    Irreducible finite complex reflection group of rank 2 and type (3,1,2)
     946                    sage: [ t.character_value() for t in W ]
     947                    [2, -E(3)^2, 0, -E(3), 0, 0, 0, 0, 0, -E(3)^2, 0, 0, 2*E(3), -E(3), 0, -1, -1, 2*E(3)^2]
     948                """
     949                return self.as_matrix().trace()
     950
     951        class Irreducible(AdjectiveCategory):
     952           
     953            def example(self):
     954                r"""
     955                Returns an example of an irreducible finite complex reflection group.
     956
     957                EXAMPLES::
     958
     959                    sage: ComplexReflectionGroups().Finite().Irreducible().example()
     960                    Irreducible finite complex reflection group of rank 3 and type (4,2,3)
     961                """
     962                from sage.combinat.root_system.complex_reflection_group import ComplexReflectionGroup
     963                return ComplexReflectionGroup((4,2,3))
     964
     965class WellGeneratedComplexReflectionGroups(Category_singleton):
     966
     967    def super_categories(self):
     968        return [ComplexReflectionGroups()]
     969
     970    def example(self):
     971        r"""
     972        Returns an example of a well-generated complex reflection group.
     973
     974        EXAMPLES::
     975
     976            sage: WellGeneratedComplexReflectionGroups().example()
     977            Finite complex reflection group of rank 4 and type (1,1,3) x (2,1,2)
     978        """
     979        from sage.combinat.root_system.complex_reflection_group import ComplexReflectionGroup
     980        return ComplexReflectionGroup((1,1,3),(2,1,2))
     981
     982    class Finite(AdjectiveCategory):
     983        r"""
     984        Let us consider an example of a finite complex reflection group::
     985
     986            sage: W = WellGeneratedComplexReflectionGroups().Finite().example(); W
     987            Finite complex reflection group of rank 4 and type (1,1,3) x (3,1,2)
     988
     989        P is in the category of finite complex reflection groups::
     990
     991            sage: W in WellGeneratedComplexReflectionGroups().Finite()
     992            True
     993
     994        TESTS::
     995
     996            sage: TestSuite(W).run()
     997            sage: TestSuite(WellGeneratedComplexReflectionGroups().Finite()).run()
     998
     999        """
     1000        def example(self):
     1001            r"""
     1002            Returns an example of a well-generated finite complex reflection group.
     1003
     1004            EXAMPLES::
     1005
     1006                sage: WellGeneratedComplexReflectionGroups().Finite().example()
     1007                Finite complex reflection group of rank 4 and type (1,1,3) x (3,1,2)
     1008            """
     1009            from sage.combinat.root_system.complex_reflection_group import ComplexReflectionGroup
     1010            return ComplexReflectionGroup((1,1,3),(3,1,2))
     1011
     1012        class Irreducible(AdjectiveCategory):
     1013
     1014            def example(self):
     1015                r"""
     1016                Returns an example of an irreducible well-generated finite complex reflection group.
     1017
     1018                EXAMPLES::
     1019
     1020                    sage: WellGeneratedComplexReflectionGroups().Finite().Irreducible().example()
     1021                    Irreducible finite complex reflection group of rank 3 and type (4,1,3)
     1022                """
     1023                from sage.combinat.root_system.complex_reflection_group import ComplexReflectionGroup
     1024                return ComplexReflectionGroup((4,1,3))
     1025
     1026            class ParentMethods:
     1027
     1028                def coxeter_number(self):
     1029                    r"""
     1030                    Returns the Coxeter number of a well-generated, irreducible reflection group. This is defined to be the
     1031                    order of a regular element in ``self``, and is equal to the highest degree of self.
     1032
     1033                    EXAMPLES::
     1034
     1035                        sage: W = ComplexReflectionGroup((1,1,3))
     1036                        sage: W.coxeter_number()
     1037                        3
     1038
     1039                        sage: W = ComplexReflectionGroup((4,1,3))
     1040                        sage: W.coxeter_number()
     1041                        12
     1042
     1043                        sage: W = ComplexReflectionGroup((4,4,3))
     1044                        sage: W.coxeter_number()
     1045                        8
     1046                    """
     1047                    return max(self.degrees())
     1048
     1049                def number_of_reflections_of_full_support(self):
     1050                    n = self.rank()
     1051                    h = self.coxeter_number()
     1052                    l = self.cardinality()
     1053                    codegrees = self.codegrees()[1:]
     1054                    return n*h/l * prod( codeg for codeg in codegrees )
     1055
     1056                @cached_method
     1057                def fuss_catalan_number(self,m,positive=False,polynomial=False):
     1058                    r"""
     1059                    Returns the m-th Fuss-Catalan number associated to ``self``. It is given by the product
     1060                    of the m-th Fuss-Catalan numbers of the irreducible components of ``self``. For an
     1061                    irreducible finite reflection group, it is defined by `\prod_{i = 1}^\ell \frac{d_i + mh}{d_i}`
     1062                    where `d_1,\ldots,d_\ell` are the degrees and where `h` is the Coxeter number.
     1063
     1064                    REMARKS:
     1065
     1066                    - For the symmetric group `S_n`, it reduces to the Fuss-Catalan number `\frac{1}{mn+1}\binom{(m+1)n}{n}`.
     1067                    - The Fuss-Catalan numbers for `G(r,1,n)` all coincide for `r > 1`.
     1068
     1069                    EXAMPLES::
     1070
     1071                        sage: W = ComplexReflectionGroup((1,1,3))
     1072                        sage: [ W.fuss_catalan_number(i) for i in [1,2,3] ]
     1073                        [5, 12, 22]
     1074
     1075                        sage: W = ComplexReflectionGroup((1,1,4))
     1076                        sage: [ W.fuss_catalan_number(i) for i in [1,2,3] ]
     1077                        [14, 55, 140]
     1078
     1079                        sage: W = ComplexReflectionGroup((1,1,5))
     1080                        sage: [ W.fuss_catalan_number(i) for i in [1,2,3] ]
     1081                        [42, 273, 969]
     1082
     1083                        sage: W = ComplexReflectionGroup((2,1,2))
     1084                        sage: [ W.fuss_catalan_number(i) for i in [1,2,3] ]
     1085                        [6, 15, 28]
     1086
     1087                        sage: W = ComplexReflectionGroup((2,1,3))
     1088                        sage: [ W.fuss_catalan_number(i) for i in [1,2,3] ]
     1089                        [20, 84, 220]
     1090
     1091                        sage: W = ComplexReflectionGroup((2,1,4))
     1092                        sage: [ W.fuss_catalan_number(i) for i in [1,2,3] ]
     1093                        [70, 495, 1820]
     1094                    """
     1095                    from sage.rings.all import ZZ
     1096                    from sage.combinat.q_analogues import q_int
     1097                    assert m in ZZ and m > 0, "%s is not a positive integer."%m
     1098                    h = self.coxeter_number()
     1099                    if polynomial:
     1100                        f = lambda n: q_int(n)
     1101                    else:
     1102                        f = lambda n: n
     1103                    if positive:
     1104                        num = prod( f(codeg + m*h) for codeg in self.codegrees() if m > 0 or codeg > 0 )
     1105                    else:
     1106                        num = prod( f(deg + m*h) for deg in self.degrees() )
     1107                    den = prod( f(deg) for deg in self.degrees() )
     1108                    ret = num / den
     1109                    if ret in ZZ:
     1110                        ret = ZZ(ret)
     1111                    return ret
     1112
     1113                def catalan_number(self,positive=False):
     1114                    return self.fuss_catalan_number(1,positive=positive)
     1115
     1116        # needs to be moved to cartesian product: class CartesianProduct(AdjectiveCategory):
     1117        class ParentMethods:
     1118
     1119            def fuss_catalan_number(self,m):
     1120                return prod( W.fuss_catalan_number(m) for W in self.irreducible_components() )
     1121
     1122            def catalan_number(self):
     1123                r"""
     1124                Returns the Catalan number associated to ``self``. It is given by the product
     1125                of the Catalan numbers of the irreducible components of ``self``. For an
     1126                irreducible finite reflection group, it is defined by `\prod_{i = 1}^\ell \frac{d_i + h}{d_i}`
     1127                where `d_1,\ldots,d_\ell` are the degrees and where `h` is the Coxeter number.
     1128
     1129                REMARKS:
     1130
     1131                - For the symmetric group `S_n`, it reduces to the Catalan number `\frac{1}{n+1}\binom{2n}{n}`.
     1132                - The Catalan numbers for `G(r,1,n)` all coincide for `r > 1`.
     1133
     1134                EXAMPLES::
     1135
     1136                    sage: [ ComplexReflectionGroup((1,1,n)).catalan_number() for n in [2,3,4,5] ]
     1137                    [2, 5, 14, 42]
     1138
     1139                    sage: [ ComplexReflectionGroup((2,1,n)).catalan_number() for n in [2,3,4,5] ]
     1140                    [6, 20, 70, 252]
     1141
     1142                    sage: [ ComplexReflectionGroup((2,2,n)).catalan_number() for n in [2,3,4,5] ]
     1143                    [4, 14, 50, 182]
     1144                """
     1145                return self.fuss_catalan_number(1)
     1146
  • sage/categories/coxeter_groups.py

    diff --git a/sage/categories/coxeter_groups.py b/sage/categories/coxeter_groups.py
    a b Coxeter Groups 
    33"""
    44#*****************************************************************************
    55#  Copyright (C) 2009    Nicolas M. Thiery <nthiery at users.sf.net>
     6#                        Christian Stump <christian.stump at gmail.com
    67#
    78#  Distributed under the terms of the GNU General Public License (GPL)
    89#                  http://www.gnu.org/licenses/
    from sage.misc.constant_function import  
    1617from sage.misc.misc import attrcall, uniq
    1718from sage.misc.superseded import deprecation
    1819from sage.categories.category_singleton import Category_singleton
    19 from sage.categories.groups import Groups
     20from sage.categories.complex_reflection_groups import WellGeneratedComplexReflectionGroups
    2021from sage.categories.enumerated_sets import EnumeratedSets
    2122from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
    2223from sage.structure.sage_object import have_same_parent
    class CoxeterGroups(Category_singleton): 
    4142        sage: C                            # todo: uppercase for Coxeter
    4243        Category of coxeter groups
    4344        sage: C.super_categories()
    44         [Category of groups, Category of enumerated sets]
     45        [Category of well generated complex reflection groups, Category of enumerated sets]
    4546
    4647        sage: W = C.example(); W
    4748        The symmetric group on {0, ..., 3}
    class CoxeterGroups(Category_singleton): 
    5152
    5253    Here are some further examples::
    5354
    54         sage: FiniteCoxeterGroups().example()
     55        sage: CoxeterGroups().Finite().example()
    5556        The 5-th dihedral group of order 10
    5657        sage: FiniteWeylGroups().example()
    5758        The symmetric group on {0, ..., 3}
    class CoxeterGroups(Category_singleton): 
    103104        EXAMPLES::
    104105
    105106            sage: CoxeterGroups().super_categories()
    106             [Category of groups, Category of enumerated sets]
     107            [Category of well generated complex reflection groups, Category of enumerated sets]
    107108        """
    108         return [Groups(), EnumeratedSets()]
    109 
    110     Finite = LazyImport('sage.categories.finite_coxeter_groups', 'FiniteCoxeterGroups')
     109        return [WellGeneratedComplexReflectionGroups(), EnumeratedSets()]
    111110
    112111    class ParentMethods:
    113112
    class CoxeterGroups(Category_singleton): 
    124123                sage: W.index_set()
    125124                [1, 2]
    126125            """
    127             # return self.simple_reflections().keys()
     126
     127        def simple_reflection(self,i):
     128            """
     129            INPUT:
     130            - ``i`` - an element from ``self.index set()``.
     131
     132            Returns the simple reflection `s_i`
     133
     134            EXAMPLES::
     135
     136                sage: W = CoxeterGroups().example()
     137                sage: W
     138                The symmetric group on {0, ..., 3}
     139                sage: W.simple_reflection(1)
     140                (0, 2, 1, 3)
     141                sage: s = W.simple_reflections()
     142                sage: s[1]
     143                (0, 2, 1, 3)
     144            """
     145            return self.one().apply_simple_reflection(i)
    128146
    129147        def _an_element_(self):
    130148            """
    class CoxeterGroups(Category_singleton): 
    151169            EXAMPLES::
    152170
    153171                sage: W=WeylGroup(['A',3])
    154                 sage: W.some_elements()   
     172                sage: W.some_elements()
    155173                [[0 1 0 0]
    156174                [1 0 0 0]
    157175                [0 0 1 0]
    class CoxeterGroups(Category_singleton): 
    172190                [1 0 0 0]
    173191                [0 1 0 0]
    174192                [0 0 1 0]]
    175                 sage: W.order()   
     193                sage: W.order()
    176194                24
    177195            """
    178196            return list(self.simple_reflections()) + [ self.one(), self.an_element() ]
    class CoxeterGroups(Category_singleton): 
    183201
    184202            EXAMPLES::
    185203
    186                 sage: D5 = FiniteCoxeterGroups().example(5)
     204                sage: D5 = CoxeterGroups().Finite().example(5)
    187205                sage: sorted(list(D5)) # indirect doctest (but see :meth:`._test_enumerated_set_iter_list`)
    188206                [(),
    189207                 (1,),
    class CoxeterGroups(Category_singleton): 
    207225                [ 0  1  0]
    208226                [ 0  0  1]
    209227                sage: g.next()
    210                 [ 0 -1  2]
    211                 [ 1 -1  1]
     228                [-1  1  1]
     229                [-1  0  2]
    212230                [ 0  0  1]
    213231            """
    214             return iter(self.weak_order_ideal(predicate = ConstantFunction(True)))
     232            return iter(self.weak_order_ideal())
    215233
    216         def weak_order_ideal(self, predicate, side ="right", category = None):
     234        def weak_order_ideal(self, predicate=lambda x:True, side ="left", category = None):
    217235            """
    218236            Returns a weak order ideal defined by a predicate
    219237
    class CoxeterGroups(Category_singleton): 
    227245
    228246            EXAMPLES::
    229247
    230                 sage: D6 = FiniteCoxeterGroups().example(5)
     248                sage: D6 = CoxeterGroups().Finite().example(5)
    231249                sage: I = D6.weak_order_ideal(predicate = lambda w: w.length() <= 3)
    232250                sage: I.cardinality()
    233251                7
    234252                sage: list(I)
    235                 [(), (1,), (1, 2), (1, 2, 1), (2,), (2, 1), (2, 1, 2)]
     253                [(), (1,), (2, 1), (1, 2, 1), (2,), (1, 2), (2, 1, 2)]
    236254
    237255            We now consider an infinite Coxeter group::
    238256
    class CoxeterGroups(Category_singleton): 
    243261                 [0 1],
    244262                 [-1  2]
    245263                 [ 0  1],
    246                  [ 3 -2]
    247                  [ 2 -1],
     264                 [-1  2]
     265                 [-2  3],
    248266                 [ 1  0]
    249267                 [ 2 -1],
    250                  [-1  2]
    251                  [-2  3]]
     268                 [ 3 -2]
     269                 [ 2 -1]]
    252270
    253271            Even when the result is finite, some features of
    254272            :class:`FiniteEnumeratedSets` are not available::
    class CoxeterGroups(Category_singleton): 
    268286                 [0 1],
    269287                 [-1  2]
    270288                 [ 0  1],
    271                  [ 3 -2]
    272                  [ 2 -1],
     289                 [-1  2]
     290                 [-2  3],
    273291                 [ 1  0]
    274292                 [ 2 -1],
    275                  [-1  2]
    276                  [-2  3]]
     293                 [ 3 -2]
     294                 [ 2 -1]]
    277295
    278296            .. rubric:: Background
    279297
    class CoxeterGroups(Category_singleton): 
    291309            def succ(u):
    292310                for i in u.descents(positive = True, side = side):
    293311                    u1 = u.apply_simple_reflection(i, side)
    294                     if i == u1.first_descent(side = side) and predicate(u1):
     312                    if u1.is_first_descent(i, side = side) and predicate(u1):
    295313                        yield u1
    296314                return
    297             from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups
    298             default_category = FiniteEnumeratedSets() if self in FiniteCoxeterGroups() else EnumeratedSets()
     315            default_category = FiniteEnumeratedSets() if self in CoxeterGroups().Finite() else EnumeratedSets()
    299316            return SearchForest((self.one(),), succ, category = default_category.or_subcategory(category))
    300317
    301318        def grassmannian_elements(self, side = "right"):
    class CoxeterGroups(Category_singleton): 
    330347            INPUT:
    331348
    332349            - ``word`` - a list (or iterable) of elements of ``self.index_set()``
    333  
     350
    334351            Returns the group element corresponding to the given
    335352            word. Namely, if ``word`` is `[i_1,i_2,\ldots,i_k]`, then
    336353            this returns the corresponding product of simple
    class CoxeterGroups(Category_singleton): 
    342359
    343360            EXAMPLES::
    344361
    345                 sage: W = CoxeterGroups().example()                     
     362                sage: W = CoxeterGroups().example()
    346363                sage: W
    347364                The symmetric group on {0, ..., 3}
    348365                sage: s = W.simple_reflections()
    class CoxeterGroups(Category_singleton): 
    391408                tester.assertEquals(self.from_reduced_word(red), x)
    392409                tester.assertEquals(self.prod((s[i] for i in red)), x)
    393410
    394         def simple_reflection(self, i):
    395             """
    396             INPUT:
    397 
    398             - ``i`` - an element from the index set.
    399  
    400             Returns the simple reflection `s_i`
    401 
    402             EXAMPLES::
    403 
    404                 sage: W = CoxeterGroups().example()                     
    405                 sage: W
    406                 The symmetric group on {0, ..., 3}
    407                 sage: W.simple_reflection(1)
    408                 (0, 2, 1, 3)
    409                 sage: s = W.simple_reflections()
    410                 sage: s[1]
    411                 (0, 2, 1, 3)
    412 
    413             """
    414             assert(i in self.index_set())
    415             return self.one().apply_simple_reflection(i) # don't care about left/right
    416411
    417412        @cached_method
    418413        def simple_reflections(self):
    class CoxeterGroups(Category_singleton): 
    421416
    422417            EXAMPLES::
    423418
    424                 sage: W = CoxeterGroups().example()                     
     419                sage: W = CoxeterGroups().example()
    425420                sage: W
    426421                The symmetric group on {0, ..., 3}
    427422                sage: s = W.simple_reflections()
    class CoxeterGroups(Category_singleton): 
    448443
    449444            EXAMPLES::
    450445
    451                 sage: D10 = FiniteCoxeterGroups().example(10)
     446                sage: D10 = CoxeterGroups().Finite().example(10)
    452447                sage: D10.group_generators()
    453448                Finite family {1: (1,), 2: (2,)}
    454449                sage: SymmetricGroup(5).group_generators()
    class CoxeterGroups(Category_singleton): 
    470465            """
    471466            return self.simple_reflections()
    472467
     468        def coxeter_matrix(self):
     469            from sage.rings.integer_ring import ZZ
     470            from sage.matrix.all import MatrixSpace
     471
     472            S = self.simple_reflections()
     473            I = self.index_set()
     474            I_inv = self._index_set
     475            n = self.rank()
     476            MS = MatrixSpace(ZZ, n)
     477            m = MS(0)
     478            for i in I:
     479                for j in I:
     480                    m[I_inv[i],I_inv[j]] = (S[i]*S[j]).order()
     481            return m
     482
     483        def cartan_matrix(self):
     484            from sage.rings.integer_ring import ZZ
     485            from sage.rings.universal_cyclotomic_field.all import UCF
     486            from sage.symbolic.constants import pi
     487            from sage.functions.trig import cos
     488
     489            if self.is_crystallographic():
     490                R = ZZ
     491            else:
     492                R = UCF
     493                print "not yet working properly for not crystallographic groups!"
     494            m = self.coxeter_matrix()
     495            m = m.base_extend(R)
     496            for i in range(m.ncols()):
     497                for j in range(m.ncols()):
     498                    m[i,j] = -2*cos(pi/m[i,j])
     499            return m
     500
    473501        semigroup_generators = group_generators
    474502
    475503        def simple_projection(self, i, side = 'right', length_increasing = True, toward_max = None):
    class CoxeterGroups(Category_singleton): 
    501529                4
    502530                sage: u0(sigma)
    503531                (2, 1, 3, 0)
    504                 sage: pi   
     532                sage: pi
    505533                (2, 1, 3, 0)
    506534                sage: u0(pi)
    507535                (2, 1, 3, 0)
    class CoxeterGroups(Category_singleton): 
    553581
    554582            EXAMPLES::
    555583
    556                 sage: W = CoxeterGroups().example()                     
     584                sage: W = CoxeterGroups().example()
    557585                sage: W
    558586                The symmetric group on {0, ..., 3}
    559587                sage: s = W.simple_reflections()
    class CoxeterGroups(Category_singleton): 
    607635        def bruhat_interval(self, x, y):
    608636            """
    609637            Returns the list of t such that x <= t <= y.
    610    
     638
    611639            EXAMPLES::
    612    
     640
    613641                sage: W = WeylGroup("A3", prefix="s")
    614642                sage: [s1,s2,s3]=W.simple_reflections()
    615643                sage: W.bruhat_interval(s2,s1*s3*s2*s1*s3)
    class CoxeterGroups(Category_singleton): 
    668696                        tester.assert_(not opi[i](w).has_descent(i, side = side))
    669697                        tester.assertEquals(set([pi[i](w), opi[i](w)]),
    670698                                            set([w, w.apply_simple_reflection(i, side = side)]))
    671                        
    672699
    673700        def _test_has_descent(self, **options):
    674701            """
    class CoxeterGroups(Category_singleton): 
    707734                    tester.assertEquals((s[i]*s[j]).has_descent(i, side = 'right'), u == v)
    708735
    709736    class ElementMethods:
     737
    710738        def has_descent(self, i, side = 'right', positive=False):
    711739            """
    712740            Returns whether i is a (left/right) descent of self.
    class CoxeterGroups(Category_singleton): 
    812840                    return i
    813841            return None
    814842
     843        def is_first_descent(self, i, side = 'right', index_set=None, positive=False):
     844            if index_set is None:
     845                index_set = self.parent().index_set()
     846            for j in index_set:
     847                if self.has_descent(j, side = side, positive = positive):
     848                    return j == i
     849                elif j == i:
     850                    return False
     851            return False
    815852
    816853        def descents(self, side = 'right', index_set=None, positive=False):
    817854            """
    class CoxeterGroups(Category_singleton): 
    947984        #def lex_min_reduced_word(w):
    948985        #    return list(reversed((w.inverse()).reduced_word()))
    949986
     987        def support(self):
     988            return set(self.reduced_word())
     989
     990        def has_full_support(self):
     991            return self.support() == set(self.parent().index_set())
     992
    950993        def reduced_words(self):
    951994            r"""
    952995            Returns all reduced words for self.
    class CoxeterGroups(Category_singleton): 
    11821225                self = self.apply_simple_reflection(i, side)
    11831226            return self
    11841227
    1185 
    1186         def apply_simple_reflection_left(self, i):
    1187             """
    1188             Returns ``self`` multiplied by the simple reflection ``s[i]`` on the left
    1189 
    1190             This low level method is used intensively. Coxeter groups
    1191             are encouraged to override this straightforward
    1192             implementation whenever a faster approach exists.
    1193 
    1194             EXAMPLES::
    1195 
    1196                 sage: W=CoxeterGroups().example()
    1197                 sage: w = W.an_element(); w
    1198                 (1, 2, 3, 0)
    1199                 sage: w.apply_simple_reflection_left(0)
    1200                 (0, 2, 3, 1)
    1201                 sage: w.apply_simple_reflection_left(1)
    1202                 (2, 1, 3, 0)
    1203                 sage: w.apply_simple_reflection_left(2)
    1204                 (1, 3, 2, 0)
    1205 
    1206             TESTS::
    1207 
    1208                 sage: w.apply_simple_reflection_left.__module__
    1209                 'sage.categories.coxeter_groups'
    1210             """
    1211             s = self.parent().simple_reflections()
    1212             return s[i] * self
    1213 
    1214         def apply_simple_reflection_right(self, i):
    1215             """
    1216             Returns ``self`` multiplied by the simple reflection ``s[i]`` on the right
    1217 
    1218             This low level method is used intensively. Coxeter groups
    1219             are encouraged to override this straightforward
    1220             implementation whenever a faster approach exists.
    1221 
    1222             EXAMPLES::
    1223 
    1224                 sage: W=CoxeterGroups().example()
    1225                 sage: w = W.an_element(); w
    1226                 (1, 2, 3, 0)
    1227                 sage: w.apply_simple_reflection_right(0)
    1228                 (2, 1, 3, 0)
    1229                 sage: w.apply_simple_reflection_right(1)
    1230                 (1, 3, 2, 0)
    1231                 sage: w.apply_simple_reflection_right(2)
    1232                 (1, 2, 0, 3)
    1233 
    1234             TESTS::
    1235 
    1236                 sage: w.apply_simple_reflection_right.__module__
    1237                 'sage.categories.coxeter_groups'
    1238             """
    1239             s = self.parent().simple_reflections()
    1240             return self * s[i]
    1241 
    1242         def apply_simple_reflection(self, i, side = 'right'):
    1243             """
    1244             Returns ``self`` multiplied by the simple reflection ``s[i]``
    1245 
    1246             INPUT:
    1247 
    1248             - ``i`` -- an element of the index set
    1249             - ``side`` -- "left" or "right" (default: "right")
    1250 
    1251             This default implementation simply calls
    1252             :meth:`apply_simple_reflection_left` or
    1253             :meth:`apply_simple_reflection_right`.
    1254 
    1255             EXAMPLES::
    1256 
    1257                 sage: W=CoxeterGroups().example()
    1258                 sage: w = W.an_element(); w
    1259                 (1, 2, 3, 0)
    1260                 sage: w.apply_simple_reflection(0, side = "left")
    1261                 (0, 2, 3, 1)
    1262                 sage: w.apply_simple_reflection(1, side = "left")
    1263                 (2, 1, 3, 0)
    1264                 sage: w.apply_simple_reflection(2, side = "left")
    1265                 (1, 3, 2, 0)
    1266 
    1267                 sage: w.apply_simple_reflection(0, side = "right")
    1268                 (2, 1, 3, 0)
    1269                 sage: w.apply_simple_reflection(1, side = "right")
    1270                 (1, 3, 2, 0)
    1271                 sage: w.apply_simple_reflection(2, side = "right")
    1272                 (1, 2, 0, 3)
    1273 
    1274             By default, ``side`` is "right"::
    1275 
    1276                 sage: w.apply_simple_reflection(0)
    1277                 (2, 1, 3, 0)
    1278 
    1279             TESTS::
    1280 
    1281                 sage: w.apply_simple_reflection_right.__module__
    1282                 'sage.categories.coxeter_groups'
    1283             """
    1284             if side == 'right':
    1285                 return self.apply_simple_reflection_right(i)
    1286             else:
    1287                 return self.apply_simple_reflection_left(i)
    1288 
    12891228        def _mul_(self, other):
    12901229            r"""
    12911230            Returns the product of ``self`` and ``other``
    class CoxeterGroups(Category_singleton): 
    13251264
    13261265            EXAMPLES::
    13271266
    1328                 sage: W=WeylGroup(['B',7])         
     1267                sage: W=WeylGroup(['B',7])
    13291268                sage: w=W.an_element()
    13301269                sage: u=w.inverse()
    13311270                sage: u==~w
    class CoxeterGroups(Category_singleton): 
    14021341            The algorithm works recursively, using the 'inverse' of the method described for
    14031342            lower covers :meth:`bruhat_lower_covers`. Namely, it runs through all `i` in the
    14041343            index set: if `w`=``self`` has no right descent `i`, then `w s_i` is a cover;
    1405             if `w` has a decent at `i`, then `u_j s_i` is a cover of `w` where `u_j` is a cover 
     1344            if `w` has a decent at `i`, then `u_j s_i` is a cover of `w` where `u_j` is a cover
    14061345            of `w s_i`.
    14071346
    14081347            EXAMPLES::
    class CoxeterGroups(Category_singleton): 
    14271366            Covers = []
    14281367            for i in self.parent().index_set():
    14291368                if i in self.descents():
    1430                     Covers += [ x.apply_simple_reflection(i) for x in self.apply_simple_reflection(i).bruhat_upper_covers() 
     1369                    Covers += [ x.apply_simple_reflection(i) for x in self.apply_simple_reflection(i).bruhat_upper_covers()
    14311370                                if i not in x.descents() ]
    14321371                else:
    14331372                    Covers += [ self.apply_simple_reflection(i) ]
    class CoxeterGroups(Category_singleton): 
    17061645            return [ self.apply_simple_reflection(i, side=side)
    17071646                     for i in self.descents(side=side, index_set = index_set, positive = positive) ]
    17081647
     1648        def coxeter_sorting_word(self,c):
     1649            if hasattr(c,"reduced_word"):
     1650                c = c.reduced_word()
     1651            elif not isinstance(c,list):
     1652                c = list(c)
     1653            n = self.parent().rank()
     1654            pi = self
     1655            l = pi.length()
     1656            i = 0
     1657            sorting_word = []
     1658            while l > 0:
     1659                s = c[i]
     1660                if pi.has_left_descent(s):
     1661                    pi = pi.apply_simple_reflection_left(s)
     1662                    l -= 1
     1663                    sorting_word.append(s)
     1664                i += 1
     1665                if i == n:
     1666                    i = 0
     1667            return sorting_word
     1668
     1669        def is_coxeter_sortable(self,c,sorting_word=None):
     1670            if hasattr(c,"reduced_word"):
     1671                c = c.reduced_word()
     1672            elif not isinstance(c,list):
     1673                c = list(c)
     1674            if sorting_word is None:
     1675                sorting_word = self.coxeter_sorting_word(c)
     1676            n = len(c)
     1677            containment_list = [ True ]*n
     1678            l = 0
     1679            i = 0
     1680            while l < len(sorting_word):
     1681                s = c[i]
     1682                t = sorting_word[l]
     1683                if s == t:
     1684                    l += 1
     1685                    if not containment_list[s]:
     1686                        return False
     1687                else:
     1688                    containment_list[s] = False
     1689                i += 1
     1690                if i == n:
     1691                    i = 0
     1692            return True
    17091693
    17101694        def apply_demazure_product(self, element, side = 'right', length_increasing = True):
    17111695            r"""
    class CoxeterGroups(Category_singleton): 
    20362020                [[1, 2, 3]]
    20372021            """
    20382022            return self.weak_covers(side = side, index_set = index_set, positive = True)
     2023
     2024    Finite = LazyImport('sage.categories.finite_coxeter_groups', 'FiniteCoxeterGroups')
  • sage/categories/examples/finite_coxeter_groups.py

    diff --git a/sage/categories/examples/finite_coxeter_groups.py b/sage/categories/examples/finite_coxeter_groups.py
    a b Examples of finite Coxeter groups 
    1212from sage.misc.cachefunc import cached_method
    1313from sage.structure.parent import Parent
    1414from sage.structure.element_wrapper import ElementWrapper
    15 from sage.categories.all import CoxeterGroups, FiniteCoxeterGroups
     15from sage.categories.all import CoxeterGroups, CoxeterGroups
    1616from sage.structure.unique_representation import UniqueRepresentation
    1717from sage.misc.functional import is_odd, is_even
    1818
    class DihedralGroup(UniqueRepresentation 
    4949        sage: list(G)
    5050        [(),
    5151        (1,),
    52         (1, 2),
     52        (2, 1),
    5353        (1, 2, 1),
    54         (1, 2, 1, 2),
     54        (2, 1, 2, 1),
    5555        (1, 2, 1, 2, 1),
    5656        (2,),
    57         (2, 1),
     57        (1, 2),
    5858        (2, 1, 2),
    59         (2, 1, 2, 1)]
     59        (1, 2, 1, 2)]
    6060
    6161    This reduced word is unique, except for the longest element where
    6262    the choosen reduced word is `(1,2,1,2\dots)`::
    class DihedralGroup(UniqueRepresentation 
    123123
    124124        """
    125125        assert n >= 2
    126         Parent.__init__(self, category = FiniteCoxeterGroups())
     126        Parent.__init__(self, category = CoxeterGroups().Finite().Irreducible())
    127127        self.n = n
    128128
    129129    def _repr_(self):
    class DihedralGroup(UniqueRepresentation 
    177177            [1, 2]
    178178        """
    179179        return [1,2]
    180    
     180
    181181    class Element(ElementWrapper):
    182182        wrapped_class = tuple
    183183        __lt__ = ElementWrapper._lt_by_value
    class DihedralGroup(UniqueRepresentation 
    225225
    226226                sage: D5 = FiniteCoxeterGroups().example(5)
    227227                sage: [i^2 for i in D5]                   
    228                 [(), (), (1, 2, 1, 2), (), (2, 1), (), (), (2, 1, 2, 1), (), (1, 2)]
     228                [(), (), (2, 1, 2, 1), (), (1, 2), (), (), (1, 2, 1, 2), (), (2, 1)]
    229229                sage: [i^5 for i in D5]                   
    230230                [(), (1,), (), (1, 2, 1), (), (1, 2, 1, 2, 1), (2,), (), (2, 1, 2), ()]
    231231            """
  • sage/categories/examples/finite_weyl_groups.py

    diff --git a/sage/categories/examples/finite_weyl_groups.py b/sage/categories/examples/finite_weyl_groups.py
    a b class SymmetricGroup(UniqueRepresentatio 
    138138        """
    139139        return range(self.n-1)
    140140
     141    def cartan_type(self):
     142        r"""
     143        Returns the Cartan type `['A',n-1]` of ``self``.
     144
     145        EXAMPLES::
     146
     147            sage: S = FiniteWeylGroups().example()
     148            sage: S.cartan_type()
     149            ['A', 4]
     150        """
     151        from sage.combinat.root_system.cartan_type import CartanType
     152        return CartanType(['A',self.n])
     153
    141154    def simple_reflection(self, i):
    142155        """
    143156        Implements :meth:`CoxeterGroups.ParentMethods.simple_reflection`
    class SymmetricGroup(UniqueRepresentatio 
    167180   
    168181    class Element(ElementWrapper):
    169182
     183        def apply_simple_reflection_right(self, i):
     184            """
     185            Implements :meth:`CoxeterGroups.ParentMethods.simple_reflection`
     186            by returning the transposition `(i, i+1)`.
     187
     188            EXAMPLES::
     189
     190                sage: FiniteWeylGroups().example().simple_reflection(2)
     191                (0, 1, 3, 2)
     192            """
     193            return self*self.parent().simple_reflection(i)
     194
    170195        def has_right_descent(self, i):
    171196            """
    172197            Implements :meth:`CoxeterGroups.ElementMethods.has_right_descent`.
  • sage/categories/finite_coxeter_groups.py

    diff --git a/sage/categories/finite_coxeter_groups.py b/sage/categories/finite_coxeter_groups.py
    a b class FiniteCoxeterGroups(AdjectiveCateg 
    2222        sage: FiniteCoxeterGroups()
    2323        Category of finite coxeter groups
    2424        sage: FiniteCoxeterGroups().super_categories()
    25         [Category of coxeter groups, Category of finite groups]
     25        [Category of coxeter groups, Category of finite well generated complex reflection groups]
    2626
    2727        sage: G = FiniteCoxeterGroups().example()
    2828        sage: G.cayley_graph(side = "right").plot()
    class FiniteCoxeterGroups(AdjectiveCateg 
    249249
    250250        weak_lattice = weak_poset
    251251
     252        @cached_method
     253        def cambrian_lattice(self, c, side = "right", facade = False):
     254            """
     255            INPUT:
     256
     257            - ``c`` -- a standard Coxeter element in ``self``
     258            - ``side`` -- "left", "right", or "twosided" (default: "right")
     259            - ``facade`` -- a boolean (default: False)
     260
     261            Returns the left (resp. right) Cambrian lattice, which is the
     262            sublattice of the weak lattice containing all
     263            ``c``-sortable elements.
     264
     265            EXAMPLES::
     266
     267                tba
     268            """
     269            from sage.combinat.posets.lattices import LatticePoset
     270            return LatticePoset(self.weak_lattice(side=side,facade=facade).subposet( [ w for w in self if w.is_coxeter_sortable(c) ] ))
     271
    252272    class ElementMethods:
    253273
    254274        @cached_in_parent_method
  • sage/categories/finite_weyl_groups.py

    diff --git a/sage/categories/finite_weyl_groups.py b/sage/categories/finite_weyl_groups.py
    a b Finite Weyl Groups 
    77#  Distributed under the terms of the GNU General Public License (GPL)
    88#                  http://www.gnu.org/licenses/
    99#******************************************************************************
    10 
     10from sage.misc.cachefunc import cached_method
    1111from sage.categories.adjective_category import AdjectiveCategory
    1212
    1313class FiniteWeylGroups(AdjectiveCategory):
    class FiniteWeylGroups(AdjectiveCategory 
    2727    TESTS::
    2828
    2929        sage: W = FiniteWeylGroups().example()
    30         sage: TestSuite(W).run(verbose = "True")
    31         running ._test_an_element() . . . pass
    32         running ._test_associativity() . . . pass
    33         running ._test_category() . . . pass
    34         running ._test_elements() . . .
    35           Running the test suite of self.an_element()
    36           running ._test_category() . . . pass
    37           running ._test_eq() . . . pass
    38           running ._test_not_implemented_methods() . . . pass
    39           running ._test_pickling() . . . pass
    40           pass
    41         running ._test_elements_eq() . . . pass
    42         running ._test_enumerated_set_contains() . . . pass
    43         running ._test_enumerated_set_iter_cardinality() . . . pass
    44         running ._test_enumerated_set_iter_list() . . . pass
    45         running ._test_eq() . . . pass
    46         running ._test_has_descent() . . . pass
    47         running ._test_inverse() . . . pass
    48         running ._test_not_implemented_methods() . . . pass
    49         running ._test_one() . . . pass
    50         running ._test_pickling() . . . pass
    51         running ._test_prod() . . . pass
    52         running ._test_reduced_word() . . . pass
    53         running ._test_simple_projections() . . . pass
    54         running ._test_some_elements() . . . pass
     30        sage: TestSuite(W).run()
    5531    """
    5632
    5733    class ParentMethods:
    58         pass
     34
     35        @cached_method
     36        def root_poset(self):
     37            return self.cartan_type().root_system().root_poset()
     38
     39        @cached_method
     40        def degrees(self):
     41            from sage.combinat.partition import Partition
     42            deg_conj = [ x.rank() for x in self.root_poset() ]
     43            return [ i+1 for i in reversed( Partition( [deg_conj.count(i) for i in range(max(deg_conj)+1)] ).conjugate() ) ]
     44
     45        @cached_method
     46        def codegrees(self):
     47            return [ i-2 for i in self.degrees() ]
    5948
    6049    class ElementMethods:
    6150        pass
  • sage/categories/magmas.py

    diff --git a/sage/categories/magmas.py b/sage/categories/magmas.py
    a b class Magmas(Category_singleton): 
    305305            import operator
    306306            return OperationTable(self, operation=operator.mul, names=names, elements=elements)
    307307
     308        def magma_closure_iter(self, I, predicate=lambda x:True, return_word=False):
     309            index_list = range(len(I))
     310            if hasattr(self,'one'):
     311                elements = [ (self.one(),[]) ]
     312            else:
     313                elements = [ (I[i],[i]) for i in index_list if predicate(I[i]) ]
     314            elements_set = set( x[0] for x in elements )
     315            done = 0
     316
     317            for x,word in elements:
     318                if return_word:
     319                    yield x, word
     320                else:
     321                    yield x
     322            while done < len(elements):
     323                x,word = elements[done]
     324                for i in index_list:
     325                    y = self.product(x,I[i])
     326                    if predicate(y) and y not in elements_set:
     327                        elements.append((y,word+[i]))
     328                        elements_set.add(y)
     329                        if return_word:
     330                            yield elements[-1]
     331                        else:
     332                            yield y
     333                done+=1
     334            return
     335
    308336    class ElementMethods:
    309337
    310338        def __mul__(self, right):
  • sage/categories/weyl_groups.py

    diff --git a/sage/categories/weyl_groups.py b/sage/categories/weyl_groups.py
    a b Weyl Groups 
    99#******************************************************************************
    1010
    1111from sage.misc.cachefunc import cached_method, cached_in_parent_method
     12from sage.misc.abstract_method import abstract_method
    1213from sage.misc.lazy_import import LazyImport
    1314from sage.categories.category_singleton import Category_singleton
    1415from sage.categories.coxeter_groups import CoxeterGroups
    class WeylGroups(Category_singleton): 
    6263
    6364    class ParentMethods:
    6465
     66        @abstract_method(optional=True)
     67        def cartan_type(self):
     68            r"""
     69            Returns the Cartan type of self.
     70
     71            EXAMPLES::
     72
     73                tba
     74            """
     75
    6576        def pieri_factors(self, *args, **keywords):
    6677            r"""
    6778            Returns the set of Pieri factors in this Weyl group.
    class WeylGroups(Category_singleton): 
    89100                sage: W = WeylGroup(['B',3])
    90101                sage: PF = W.pieri_factors()
    91102                sage: [w.reduced_word() for w in PF]
    92                 [[1, 2, 3, 2, 1], [1, 2, 3, 2], [2, 3, 2], [2, 3], [3, 1, 2, 1], [1, 2, 1], [2], [1, 2], [1], [], [2, 1], [3, 2, 1], [3, 1], [2, 3, 2, 1], [3], [3, 2], [1, 2, 3], [1, 2, 3, 1], [3, 1, 2], [2, 3, 1]]
     103                [[1, 2, 3, 2, 1], [1, 2, 3, 2], [2, 3, 2], [2, 3, 2, 1], [3, 1, 2, 1], [3, 2], [3, 1, 2], [1, 2], [3, 1], [2], [2, 3], [3, 2, 1], [2, 3, 1], [1], [1, 2, 3, 1], [1, 2, 3], [3], [1, 2, 1], [], [2, 1]]
    93104
    94105                sage: W = WeylGroup(['C',4,1])
    95106                sage: PF = W.pieri_factors()
    class WeylGroups(Category_singleton): 
    165176
    166177            return self in self.parent().pieri_factors()
    167178
    168 
    169179        def left_pieri_factorizations(self, max_length = infinity):
    170180            r"""
    171181            Returns all factorizations of ``self`` as `uv`, where `u`
    class WeylGroups(Category_singleton): 
    301311                           for (u,v) in self.left_pieri_factorizations(max_length)
    302312                           if u != W.unit()))
    303313
    304 
    305314        def stanley_symmetric_function(self):
    306315            r"""
    307316            INPUT:
  • sage/combinat/root_system/all.py

    diff --git a/sage/combinat/root_system/all.py b/sage/combinat/root_system/all.py
    a b lazy_import('sage.combinat.root_system.a 
    44from cartan_type import CartanType
    55from virtual_cartan_type import VirtualCartanType
    66from dynkin_diagram import DynkinDiagram, dynkin_diagram
    7 from cartan_matrix import cartan_matrix
     7from cartan_matrix import CartanMatrix, cartan_matrix
    88from coxeter_matrix import coxeter_matrix
    99from root_system import RootSystem, WeylDim
    1010from weyl_group import WeylGroup, WeylGroupElement
    1111from coxeter_group import CoxeterGroup
     12from complex_reflection_group import ComplexReflectionGroup
    1213from weyl_characters import WeylCharacterRing, branch_weyl_character, branching_rule_from_plethysm, get_branching_rule, WeightRing
    1314
  • sage/combinat/root_system/ambient_space.py

    diff --git a/sage/combinat/root_system/ambient_space.py b/sage/combinat/root_system/ambient_space.py
    a b Ambient lattices and ambient spaces 
    1111from sage.misc.cachefunc import cached_method
    1212from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement
    1313from weight_lattice_realizations import WeightLatticeRealizations
    14 from sage.rings.all import ZZ, QQ
     14from sage.rings.all import ZZ, QQ, UCF
    1515from sage.misc.cachefunc import ClearCacheOnPickle
    1616
    1717class AmbientSpace(ClearCacheOnPickle, CombinatorialFreeModule):
    class AmbientSpace(ClearCacheOnPickle, C 
    5454
    5555        """
    5656        self.root_system = root_system
     57        if base_ring is None:
     58            if root_system.cartan_type().is_crystalographic():
     59                base_ring = QQ
     60            else:
     61                base_ring = UCF
    5762        CombinatorialFreeModule.__init__(self, base_ring,
    5863                                         range(0,self.dimension()),
    5964                                         element_class = AmbientSpaceElement,
  • 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 AUTHORS: 
    77    :class:`CartanType` to prepare cartan_matrix() for deprecation.
    88"""
    99#*****************************************************************************
    10 #       Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>,
     10#       Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>,
     11#                     2012 Christian Stump <christian.stump@gmail.com>
    1112#
    1213#  Distributed under the terms of the GNU General Public License (GPL)
    1314#
    AUTHORS: 
    2021#
    2122#                  http://www.gnu.org/licenses/
    2223#*****************************************************************************
     24from sage.misc.cachefunc import cached_method
    2325from cartan_type import CartanType
     26from dynkin_diagram import DynkinDiagram
     27from sage.matrix.constructor import Matrix
     28from sage.matrix.matrix import is_Matrix
     29
     30class CartanMatrix(object):
     31    def __init__(self, *args):
     32        if len(args) == 0:
     33            M = Matrix()
     34            n = 0
     35            index_set = tuple()
     36            cartan_type = None
     37        elif not is_Matrix(args[0]):
     38            ct = CartanType(*args)
     39            if not hasattr(ct, "cartan_matrix"):
     40                raise ValueError, "Cartan matrix data not yet hardcoded for type %s"%ct
     41            M = ct.cartan_matrix()
     42            n = M.ncols()
     43            index_set = ct.index_set()
     44            cartan_type = ct
     45        else:
     46            M = args[0]
     47            n = M.ncols()
     48            cartan_type = None
     49            assert is_generalized_cartan_matrix(M), "The input matrix is not a generalized Cartan matrix."
     50            M.set_immutable()
     51            if len(args) == 1:
     52                index_set = tuple(range(n))
     53            elif len(args) == 2:
     54                index_set = tuple( x for x in args[1] )
     55                assert len(set(index_set)) == n, "The given index set is not valid."
     56            else:
     57                raise ValueError, "You have given a symmetrizable matrix, but too many additional arguments."
     58
     59        self._M = M
     60        self._rank = n
     61        self._index_set = index_set
     62        self._cartan_type = cartan_type
     63
     64    def __repr__(self):
     65        return self._M.__repr__()
     66
     67    def index_set(self):
     68        return self._index_set
     69
     70    def dynkin_diagram(self):
     71        if self._cartan_type is not None:
     72            return DynkinDiagram(self._cartan_type)
     73        else:
     74            return DynkinDiagram(self._M)
     75
     76    def cartan_type(self):
     77        return self._cartan_type
     78
     79    def root_system(self):
     80        return self.dynkin_diagram().root_system()
     81
     82    def root_space(self):
     83        return self.root_system().root_space()
     84
     85    def reflection_group(self, type="matrix"):
     86        from sage.groups.perm_gps.permgroup_named import SymmetricGroup
     87        RS = self.root_space()
     88        G = RS.weyl_group()
     89        if type == "matrix":
     90            return G
     91        elif type == "permutation":
     92            assert G.is_finite()
     93            Phi = RS.roots()
     94            gens = {}
     95            S = SymmetricGroup(len(Phi))
     96            for i in self.index_set():
     97                pi = S([ Phi.index( beta.simple_reflection(i) ) + 1 for beta in Phi ])
     98                gens[i] = pi
     99            return S.subgroup( gens[i] for i in gens )
     100        else:
     101            raise ValueError, "The reflection group is only available as a matrix group or as a permutation group."
     102
     103def is_generalized_cartan_matrix(M):
     104        n = M.ncols()
     105        return M.is_square() and \
     106               all( M[i,i] == 2 for i in xrange(n) ) and \
     107               all( M[i,j] <= 0 for i in range(n) for j in range(n) if i != j ) and \
     108               all( M[j,i] == 0 for i in range(n) for j in range(i+1,n) if M[i,j] == 0 ) and \
     109               M.is_symmetrizable()
    24110
    25111def cartan_matrix(t):
    26112    """
    def cartan_matrix(t): 
    158244        ``CartanType(...).cartan_matrix()``, to avoid polluting the
    159245        global namespace.
    160246    """
    161     return CartanType(t).cartan_matrix()
     247    from sage.misc.misc import deprecation
     248    from cartan_type import CartanType
     249    deprecation("cartan_type is deprecated, use CartanType instead!")
     250    return CartanMatrix(t)
  • sage/combinat/root_system/cartan_type.py

    diff --git a/sage/combinat/root_system/cartan_type.py b/sage/combinat/root_system/cartan_type.py
    a b class CartanTypeFactory(SageObject): 
    442442                        import type_H
    443443                        return type_H.CartanType(n)
    444444                if letter == "I":
    445                     if n == 1:
     445                    if n == 2:
    446446                        return CartanType([["A", 1], ["A", 1]])
    447                     if n == 3:
     447                    elif n == 3:
    448448                        return CartanType(["A", 2])
    449                     if n == 4:
     449                    elif n == 4:
    450450                        return CartanType(["C", 2])
    451                     if n == 6:
     451                    elif n == 6:
    452452                        return CartanType(["G", 2])
    453                     if n >= 1:
     453                    elif n >= 2:
    454454                        import type_I
    455455                        return type_I.CartanType(n)
     456                    else:
     457                        raise ValueError, "The Cartan type ['I', %s] does not exist."%n
    456458            if len(t) == 3:
    457459                if t[2] == 1: # Untwisted affind
    458460                    if letter == "A":
    class CartanType_abstract(object): 
    776778        m.set_immutable()
    777779        return m
    778780
     781    @cached_method
     782    def cartan_matrix(self):
     783        """
     784        Returns the Cartan matrix associated with self.
     785       
     786        EXAMPLES::
     787       
     788            sage: CartanType(['A',4]).cartan_matrix()
     789            [ 2 -1  0  0]
     790            [-1  2 -1  0]
     791            [ 0 -1  2 -1]
     792            [ 0  0 -1  2]
     793        """
     794        return self.dynkin_diagram().cartan_matrix()
     795
    779796    def dual(self):
    780797        """
    781798        Returns the dual cartan type, possibly just as a formal dual.
    class CartanType_crystalographic(CartanT 
    10321049        """
    10331050
    10341051    @cached_method
    1035     def cartan_matrix(self):
    1036         """
    1037         Returns the Cartan matrix associated with self.
    1038        
    1039         EXAMPLES::
    1040        
    1041             sage: CartanType(['A',4]).cartan_matrix()
    1042             [ 2 -1  0  0]
    1043             [-1  2 -1  0]
    1044             [ 0 -1  2 -1]
    1045             [ 0  0 -1  2]
    1046         """
    1047         return self.dynkin_diagram().cartan_matrix()
    1048 
    1049     @cached_method
    10501052    def coxeter_diagram(self):
    10511053        """
    10521054        Returns the Coxeter diagram for ``self``
  • new file sage/combinat/root_system/complex_reflection_group.py

    diff --git a/sage/combinat/root_system/complex_reflection_group.py b/sage/combinat/root_system/complex_reflection_group.py
    new file mode 100644
    - +  
     1r"""
     2Finite (complex) reflection groups
     3
     4AUTHORS:
     5
     6- Christian Stump
     7
     8.. note::
     9
     10    - For definitions and classification types of finite complex reflection groups, see http://en.wikipedia.org/wiki/Complex_reflection_group.
     11    - Uses the GAP3 package *chevie*.
     12
     13Version: 2011-04-26
     14
     15TODO:
     16
     17- Element class should be unique to be able to work with large groups without creating elements multiple times
     18"""
     19#*****************************************************************************
     20#       Copyright (C) 2011 Christian Stump <christian.stump at lacim.ca>
     21#
     22#  Distributed under the terms of the GNU General Public License (GPL)
     23#
     24#                  http://www.gnu.org/licenses/
     25#*****************************************************************************
     26
     27from sage.misc.all import prod, add
     28from sage.misc.cachefunc import cached_function, cached_method, cached_in_parent_method
     29from sage.categories.category import Category
     30from sage.categories.permutation_groups import PermutationGroups
     31from sage.categories.complex_reflection_groups import ComplexReflectionGroups, WellGeneratedComplexReflectionGroups
     32from sage.categories.coxeter_groups import CoxeterGroups
     33from sage.groups.perm_gps.permgroup_element import PermutationGroupElement
     34from sage.structure.unique_representation import UniqueRepresentation
     35from sage.structure.parent import Parent
     36from sage.combinat.root_system.cartan_type import CartanType
     37from sage.groups.perm_gps.permgroup import PermutationGroup_generic
     38from sage.rings.all import ZZ, QQ
     39from sage.matrix.all import Matrix, identity_matrix
     40from sage.matrix.matrix import is_Matrix
     41from sage.interfaces.gap3 import GAP3Record, gap3
     42from sage.interfaces.gap import gap
     43from sage.combinat.words.word import Word
     44from sage.rings.universal_cyclotomic_field.all import UniversalCyclotomicField, E
     45UCF = UniversalCyclotomicField()
     46from sage.rings.arith import gcd, lcm
     47from sage.modules.free_module_element import vector
     48from sage.combinat.root_system.cartan_matrix import CartanMatrix
     49
     50class FiniteComplexReflectionGroup(UniqueRepresentation, PermutationGroup_generic):
     51
     52    def __init__(self, W_types, index_set=None, hyperplane_index_set=None, reflection_index_set=None, is_coxeter_group=False):
     53        r"""
     54        TESTS::
     55
     56            sage: from sage.categories.complex_reflection_groups import ComplexReflectionGroups
     57            sage: W = ComplexReflectionGroups().example()
     58            sage: TestSuite(W).run()
     59        """
     60        W_components = []
     61        reflection_type = []
     62        for W_type in W_types:
     63            if W_type == (1,1,1):
     64                raise ValueError, "The one element group is not considered a reflection group."
     65            elif W_type in ZZ:
     66                call_str = 'ComplexReflectionGroup(%s)'%W_type
     67            elif isinstance(W_type,CartanMatrix):
     68                call_str = 'PermRootGroup(IdentityMat(%s),%s)'%(W_type._rank,str(W_type._M._gap_()))
     69            elif is_Matrix(W_type):
     70                call_str = 'PermRootGroup(IdentityMat(%s),%s)'%(W_type._rank,str(W_type._gap_()))
     71            elif is_coxeter_group:
     72                if W_type[0] == "I":
     73                    call_str = 'CoxeterGroup("I",2,%s)'%W_type[1]
     74                else:
     75                    call_str = 'CoxeterGroup("%s",%s)'%W_type
     76            else:
     77                call_str = 'ComplexReflectionGroup%s'%str(W_type)
     78            W_components.append(gap3(call_str))
     79            X = list(W_components[-1].ReflectionType())
     80            if len(X) > 1:
     81                raise ValueError, "Your input data %s is not valid."%W_type
     82            X = X[0]
     83            type_dict = dict()
     84            type_dict["series"] = X.series.sage()
     85            type_dict["rank"] = X.rank.sage()
     86            type_dict["indices"] = X.indices.sage()
     87            if hasattr(X.ST,"sage"):
     88                type_dict["ST"] = X.ST.sage()
     89            elif hasattr(X.p,"sage") and hasattr(X.q,"sage"):
     90                type_dict["ST"] = ( X.p.sage(), X.q.sage(), X.rank.sage() )
     91            elif hasattr(X.bond,"sage"):
     92                type_dict["bond"] = X.bond.sage()
     93            if type_dict["series"] == "B" and X.cartanType.sage() == 1:
     94                type_dict["series"] = "C"
     95            reflection_type.append( type_dict )
     96
     97        self._type = reflection_type
     98        self._gap_group = prod(W_components)
     99        generators = [str(x) for x in self._gap_group.generators]
     100        self._index_set = index_set
     101        self._hyperplane_index_set = hyperplane_index_set
     102        self._reflection_index_set = reflection_index_set
     103
     104        self._elements = None
     105        self._conjugacy_classes = {}
     106        self._conjugacy_classes_representatives = None
     107        self._reflection_representation = None
     108
     109        self._rank = self._gap_group.rank.sage()
     110        if len(generators) == self._rank:
     111            category = WellGeneratedComplexReflectionGroups()
     112            if all(str(W_comp).find('CoxeterGroup') >= 0 for W_comp in W_components):
     113                category = Category.join([category,CoxeterGroups()])
     114        else:
     115            category = ComplexReflectionGroups()
     116
     117        category = Category.join([category,PermutationGroups()]).Finite()
     118        if len(self._type) == 1:
     119            category = category.Irreducible()
     120
     121        PermutationGroup_generic.__init__(self, gens = generators, canonicalize=False, category = category)
     122
     123        from sage.sets.family import Family
     124        l_set = range(len(self.gens()))
     125        if self._index_set is None:
     126            self._index_set = Family(dict( (i,i) for i in l_set))
     127        else:
     128            assert sorted(self._index_set.values()) == l_set
     129        self._index_set_inverse = self._index_set.inverse_family()
     130        Nstar_set = range(self.nr_reflecting_hyperplanes())
     131        if self._hyperplane_index_set is None:
     132            self._hyperplane_index_set = Family(dict( (i,i) for i in Nstar_set))
     133        else:
     134            assert sorted(self._hyperplane_index_set.values()) == Nstar_set
     135        self._hyperplane_index_set_inverse = self._hyperplane_index_set.inverse_family()
     136        N_set = range(self.nr_reflections())
     137        if self._reflection_index_set is None:
     138            self._reflection_index_set = Family(dict( (i,i) for i in N_set))
     139        else:
     140            assert sorted(self._reflection_index_set.values()) == N_set
     141        self._reflection_index_set_inverse = self._reflection_index_set.inverse_family()
     142
     143    def _irrcomp_repr_(self,W_type):
     144        type_str = ''
     145        if "ST" in W_type:
     146            if W_type["ST"] in ZZ:
     147                type_str += "ST" + str(W_type["ST"])
     148            else:
     149                type_str += 'G' + str(W_type["ST"]).replace(' ','')
     150        else:
     151            type_str += str(W_type["series"])
     152            if W_type["series"] == "I":
     153                type_str += '2(' + str(W_type["bond"]) + ')'
     154            else:
     155                type_str += str(W_type["rank"])
     156        return type_str
     157
     158    def _repr_(self):
     159        r"""
     160        Returns the string representation of ``self``.
     161
     162        EXAMPLES::
     163
     164            sage: W = ComplexReflectionGroup(25,[4,1,4],[1,1,4],[5,5,2]); W
     165            Reducible finite complex reflection group of rank 12 and type ST25 x G(4,1,4) x A3 x I2(5)
     166        """
     167        type_str = ''
     168        for W_type in self._type:
     169            type_str += self._irrcomp_repr_(W_type)
     170            type_str += ' x '
     171        type_str = type_str[:-3]
     172        return 'Reducible finite complex reflection group of rank %s and type %s'%(self._rank,type_str)
     173
     174    def __iter__(self):
     175        r"""
     176        Returns an iterator going through all elements in ``self``.
     177
     178        EXAMPLES::
     179
     180            sage: W = ComplexReflectionGroup((1,1,3))
     181            sage: for w in W.__iter__(): print w
     182            ()
     183            (1,4)(2,3)(5,6)
     184            (1,3)(2,5)(4,6)
     185            (1,6,2)(3,5,4)
     186            (1,2,6)(3,4,5)
     187            (1,5)(2,4)(3,6)
     188        """
     189        if self._elements is not None and len(self._elements) == self.cardinality():
     190            for w in self._elements:
     191                yield w
     192        else:
     193            self._elements = []
     194            inv_dict = dict( (self._index_set[i],i) for i in self._index_set.keys() )
     195            for w,word in self.magma_closure_iter(I=self.gens(),return_word=True):
     196                if w._reduced_word is None:
     197                    w._reduced_word = Word( inv_dict[i] for i in word )
     198                self._elements.append(w)
     199                yield w
     200
     201    __len__ = ComplexReflectionGroups.Finite.ParentMethods.cardinality.__func__
     202
     203    @cached_method
     204    def index_set(self):
     205        r"""
     206        Returns the index set of the simple reflections of ``self``.
     207
     208        EXAMPLES::
     209
     210            sage: W = ComplexReflectionGroup((1,1,4))
     211            sage: W.index_set()
     212            [0, 1, 2]
     213            sage: W = ComplexReflectionGroup((1,1,4),index_set=[1,3,'asdf'])
     214            sage: W.index_set()
     215            [1, 3, 'asdf']
     216            sage: W = ComplexReflectionGroup((1,1,4),index_set={'a':0,'b':1,'c':2})
     217            sage: W.index_set()
     218            ['a', 'b', 'c']
     219        """
     220        return [ self._index_set_inverse[i] for i in xrange(len(self._index_set)) ]
     221
     222    def series(self):
     223        return [ self._type[i]['series'] for i in range(len(self._type)) ]
     224
     225    @cached_method
     226    def hyperplane_index_set(self):
     227        r"""
     228        Returns the index set of the hyperplanes of ``self``.
     229
     230        EXAMPLES::
     231
     232            sage: W = ComplexReflectionGroup((1,1,4))
     233            sage: W.hyperplane_index_set()
     234            [0, 1, 2, 3, 4, 5]
     235            sage: W = ComplexReflectionGroup((1,1,4),hyperplane_index_set=[1,3,'asdf',7,9,11])
     236            sage: W.hyperplane_index_set()
     237            [1, 3, 'asdf', 7, 9, 11]
     238            sage: W = ComplexReflectionGroup((1,1,4),hyperplane_index_set={'a':0,'b':1,'c':2,'d':3,'e':4,'f':5})
     239            sage: W.hyperplane_index_set()
     240            ['a', 'b', 'c', 'd', 'e', 'f']
     241        """
     242        return [ self._hyperplane_index_set_inverse[i] for i in xrange(len(self._hyperplane_index_set)) ]
     243
     244    @cached_method
     245    def distinguished_reflections(self):
     246        r"""
     247        Returns a finite family containing the distinguished reflections of ``self``,
     248        indexed by ``self.hyperplane_index_set()``.
     249        These are the reflections in ``self`` acting on the complement
     250        of the fixed hyperplane `H` as `\operatorname{exp}(2 \pi i / n)`, where `n`
     251        is the order of the reflection subgroup fixing `H`.
     252
     253       EXAMPLES::
     254
     255            sage: W = ComplexReflectionGroup((1,1,3))
     256            sage: W.distinguished_reflections()
     257            Finite family {0: (1,4)(2,3)(5,6), 1: (1,3)(2,5)(4,6), 2: (1,5)(2,4)(3,6)}
     258
     259            sage: W = ComplexReflectionGroup((1,1,3),hyperplane_index_set=['a','b','c'])
     260            sage: W.distinguished_reflections()
     261            Finite family {'a': (1,4)(2,3)(5,6), 'c': (1,5)(2,4)(3,6), 'b': (1,3)(2,5)(4,6)}
     262
     263            sage: W = ComplexReflectionGroup((3,1,1))
     264            sage: W.distinguished_reflections()
     265            Finite family {0: (1,2,3)}
     266
     267            sage: W = ComplexReflectionGroup((1,1,3),(3,1,2))
     268            sage: W.distinguished_reflections()
     269            Finite family {0: (1,6)(2,5)(7,8), 1: (1,5)(2,7)(6,8), 2: (3,9,15)(4,10,16)(12,17,23)(14,18,24)(20,25,29)(21,22,26)(27,28,30), 3: (3,11)(4,12)(9,13)(10,14)(15,19)(16,20)(17,21)(18,22)(23,27)(24,28)(25,26)(29,30), 4: (1,7)(2,6)(5,8), 5: (3,19)(4,25)(9,11)(10,17)(12,28)(13,15)(14,30)(16,18)(20,27)(21,29)(22,23)(24,26), 6: (4,21,27)(10,22,28)(11,13,19)(12,14,20)(16,26,30)(17,18,25)(23,24,29), 7: (3,13)(4,24)(9,19)(10,29)(11,15)(12,26)(14,21)(16,23)(17,30)(18,27)(20,22)(25,28)}
     270        """
     271        from sage.sets.family import Family
     272        # imports all distinguished reflections from gap, the Set is used as every such appears multiple times.
     273        T = [ self(str(r)) for r in self._gap_group.Reflections() ]
     274        # makes sure that the simple reflections come first
     275        gens = self.gens()
     276        R = [ t for t in gens ]
     277        for t in T:
     278            if t not in R:
     279                R.append(t)
     280        return Family(self._hyperplane_index_set.keys(), lambda i: R[self._hyperplane_index_set[i]] )
     281
     282    def distinguished_reflection(self, i):
     283        r"""
     284        Returns the ``i``-th distinguished reflection of ``self``.
     285        These are the reflections in ``self`` acting on the complement
     286        of the fixed hyperplane `H` as `\operatorname{exp}(2 \pi i / n)`, where `n`
     287        is the order of the reflection subgroup fixing `H`.
     288
     289       EXAMPLES::
     290
     291            sage: W = ComplexReflectionGroup((1,1,3))
     292            sage: W.distinguished_reflection(0)
     293            (1,4)(2,3)(5,6)
     294            sage: W.distinguished_reflection(1)
     295            (1,3)(2,5)(4,6)
     296            sage: W.distinguished_reflection(2)
     297            (1,5)(2,4)(3,6)
     298
     299            sage: W = ComplexReflectionGroup((3,1,1),hyperplane_index_set=['a'])
     300            sage: W.distinguished_reflection('a')
     301            (1,2,3)
     302
     303            sage: W = ComplexReflectionGroup((1,1,3),(3,1,2))
     304            sage: for i in range(W.nr_reflecting_hyperplanes()): print W.distinguished_reflection(i)
     305            (1,6)(2,5)(7,8)
     306            (1,5)(2,7)(6,8)
     307            (3,9,15)(4,10,16)(12,17,23)(14,18,24)(20,25,29)(21,22,26)(27,28,30)
     308            (3,11)(4,12)(9,13)(10,14)(15,19)(16,20)(17,21)(18,22)(23,27)(24,28)(25,26)(29,30)
     309            (1,7)(2,6)(5,8)
     310            (3,19)(4,25)(9,11)(10,17)(12,28)(13,15)(14,30)(16,18)(20,27)(21,29)(22,23)(24,26)
     311            (4,21,27)(10,22,28)(11,13,19)(12,14,20)(16,26,30)(17,18,25)(23,24,29)
     312            (3,13)(4,24)(9,19)(10,29)(11,15)(12,26)(14,21)(16,23)(17,30)(18,27)(20,22)(25,28)
     313        """
     314        assert i in self.hyperplane_index_set()
     315        return self.distinguished_reflections()[i]
     316
     317    @cached_method
     318    def reflection_index_set(self):
     319        r"""
     320        Returns the index set of the reflections of ``self``.
     321
     322        EXAMPLES::
     323
     324            sage: W = ComplexReflectionGroup((1,1,4))
     325            sage: W.reflection_index_set()
     326            [0, 1, 2, 3, 4, 5]
     327            sage: W = ComplexReflectionGroup((1,1,4),reflection_index_set=[1,3,'asdf',7,9,11])
     328            sage: W.reflection_index_set()
     329            [1, 3, 'asdf', 7, 9, 11]
     330            sage: W = ComplexReflectionGroup((1,1,4),reflection_index_set={'a':0,'b':1,'c':2,'d':3,'e':4,'f':5})
     331            sage: W.reflection_index_set()
     332            ['a', 'b', 'c', 'd', 'e', 'f']
     333        """
     334        return [ self._reflection_index_set_inverse[i] for i in xrange(len(self._reflection_index_set)) ]
     335
     336    @cached_method
     337    def reflections(self):
     338        r"""
     339        Returns a finite family containing the reflections of ``self``,
     340        indexed by ``self.reflection_index_set()``.
     341
     342       EXAMPLES::
     343
     344            sage: W = ComplexReflectionGroup((1,1,3))
     345            sage: W.reflections()
     346            Finite family {0: (1,4)(2,3)(5,6), 1: (1,3)(2,5)(4,6), 2: (1,5)(2,4)(3,6)}
     347
     348            sage: W = ComplexReflectionGroup((1,1,3),reflection_index_set=['a','b','c'])
     349            sage: W.reflections()
     350            Finite family {'a': (1,4)(2,3)(5,6), 'c': (1,5)(2,4)(3,6), 'b': (1,3)(2,5)(4,6)}
     351
     352            sage: W = ComplexReflectionGroup((3,1,1))
     353            sage: W.reflections()
     354            Finite family {0: (1,2,3), 1: (1,3,2)}
     355
     356            sage: W = ComplexReflectionGroup((1,1,3),(3,1,2))
     357            sage: W.reflections()
     358            Finite family {0: (1,6)(2,5)(7,8), 1: (1,5)(2,7)(6,8), 2: (3,9,15)(4,10,16)(12,17,23)(14,18,24)(20,25,29)(21,22,26)(27,28,30), 3: (3,11)(4,12)(9,13)(10,14)(15,19)(16,20)(17,21)(18,22)(23,27)(24,28)(25,26)(29,30), 4: (1,7)(2,6)(5,8), 5: (3,19)(4,25)(9,11)(10,17)(12,28)(13,15)(14,30)(16,18)(20,27)(21,29)(22,23)(24,26), 6: (4,21,27)(10,22,28)(11,13,19)(12,14,20)(16,26,30)(17,18,25)(23,24,29), 7: (3,13)(4,24)(9,19)(10,29)(11,15)(12,26)(14,21)(16,23)(17,30)(18,27)(20,22)(25,28), 8: (3,15,9)(4,16,10)(12,23,17)(14,24,18)(20,29,25)(21,26,22)(27,30,28), 9: (4,27,21)(10,28,22)(11,19,13)(12,20,14)(16,30,26)(17,25,18)(23,29,24)}
     359        """
     360        from sage.sets.family import Family
     361        T = self.distinguished_reflections().values()
     362        for i in xrange(self.nr_reflecting_hyperplanes()):
     363            T.extend( [ T[i]**j for j in range(2,T[i].order()) ] )
     364        return Family(self._reflection_index_set.keys(), lambda i: T[self._reflection_index_set[i]] )
     365
     366    def reflection(self,i):
     367        r"""
     368        Returns the ``i``-th reflection of ``self``
     369
     370       EXAMPLES::
     371
     372            sage: W = ComplexReflectionGroup((1,1,3))
     373            sage: W.reflection(0)
     374            (1,4)(2,3)(5,6)
     375            sage: W.reflection(1)
     376            (1,3)(2,5)(4,6)
     377            sage: W.reflection(2)
     378            (1,5)(2,4)(3,6)
     379
     380            sage: W = ComplexReflectionGroup((3,1,1),reflection_index_set=['a','b'])
     381            sage: W.reflection('a')
     382            (1,2,3)
     383            sage: W.reflection('b')
     384            (1,3,2)
     385        """
     386        assert i in self.reflection_index_set()
     387        return self.reflections()[i]
     388
     389    def reflection_character(self):
     390        r"""
     391        Returns the reflection characters of ``self``.
     392
     393        EXAMPLES::
     394
     395            sage: W = ComplexReflectionGroup((1,1,3))
     396            sage: W.reflection_character()
     397            [2, 0, -1]
     398        """
     399        return self._gap_group.ReflectionCharacter().sage()
     400
     401    def is_crystallographic(self):
     402        r"""
     403        Returns True if self is crystallographic, i.e., if the reflection representation of ``self``
     404        is defined over the rationals.
     405
     406        EXAMPLES::
     407
     408            sage: W = ComplexReflectionGroup((1,1,3)); W
     409            Irreducible finite complex reflection group of rank 2 and type A2
     410            sage: W.is_crystallographic()
     411            True
     412
     413            sage: W = ComplexReflectionGroup((2,1,3)); W
     414            Irreducible finite complex reflection group of rank 3 and type B3
     415            sage: W.is_crystallographic()
     416            True
     417
     418            sage: W = ComplexReflectionGroup(23); W
     419            Irreducible finite complex reflection group of rank 3 and type H3
     420            sage: W.is_crystallographic()
     421            False
     422
     423            sage: W = ComplexReflectionGroup((3,1,3)); W
     424            Irreducible finite complex reflection group of rank 3 and type G(3,1,3)
     425            sage: W.is_crystallographic()
     426            False
     427        """
     428        from sage.rings.all import QQ
     429        return all( t.as_matrix().base_ring() is QQ for t in self.simple_reflections() )
     430
     431    def _element_class(self):
     432        r"""
     433        A temporary workaround for compatibility with Sage's
     434        permutation groups
     435
     436        TESTS::
     437
     438            sage: W = ComplexReflectionGroup(23)                         # optional (require chevie)
     439            sage: W._element_class() is W.element_class                  # optional (require chevie)
     440            True
     441        """
     442        return self.element_class
     443
     444    def nr_irreducible_components(self):
     445        r"""
     446        Returns the number of irreducible components of ``self``.
     447
     448        EXAMPLES::
     449
     450            sage: W = ComplexReflectionGroup((1,1,3))
     451            sage: W.nr_irreducible_components()
     452            1
     453
     454            sage: W = ComplexReflectionGroup((1,1,3),(2,1,3))
     455            sage: W.nr_irreducible_components()
     456            2
     457        """
     458        return len(self._type)
     459
     460    def irreducible_components(self):
     461        r"""
     462        Returns a list containing the irreducible components of ``self`` as finite reflection groups.
     463
     464        EXAMPLES::
     465
     466            sage: W = ComplexReflectionGroup((1,1,3))
     467            sage: W.irreducible_components()
     468            [Irreducible finite complex reflection group of rank 2 and type A2]
     469
     470            sage: W = ComplexReflectionGroup((1,1,3),(2,1,3))
     471            sage: W.irreducible_components()
     472            [Irreducible finite complex reflection group of rank 2 and type A2,
     473            Irreducible finite complex reflection group of rank 3 and type B3]
     474        """
     475        if self.nr_irreducible_components() == 1:
     476            irr_comps = [self]
     477        else:
     478            irr_comps = []
     479            for W_type in self._type:
     480                if W_type["series"] == "A":
     481                    W_str = (1,1,W_type["rank"]+1)
     482                elif W_type["series"] == "B":
     483                    W_str = (2,1,W_type["rank"])
     484                elif W_type["series"] == "D":
     485                    W_str = (2,2,W_type["rank"])
     486                elif W_type["series"] == "E":
     487                    if W_type["rank"] == 6:
     488                        W_str = 35
     489                    elif W_type["rank"] == 7:
     490                        W_str = 36
     491                    elif W_type["rank"] == 8:
     492                        W_str = 37
     493                elif W_type["series"] == "F":
     494                    W_str = 28
     495                elif W_type["series"] == "G":
     496                    W_str = (6,6,2)
     497                elif W_type["series"] == "H":
     498                    if W_type["rank"] == 3:
     499                        W_str = 23
     500                    elif W_type["rank"] == 4:
     501                        W_str = 30
     502                elif W_type["series"] == "I":
     503                    W_str = (W_type["bond"],W_type["bond"],2)
     504                elif "ST" in W_type:
     505                    W_str = W_type["ST"]
     506
     507                else:
     508                    raise ValueError, "not yet implemented"
     509                irr_comps.append( ComplexReflectionGroup(W_str) )
     510        return irr_comps
     511
     512    @cached_method
     513    def conjugacy_classes_representatives(self):
     514        r"""
     515        Returns the shortest representatives of the conjugacy classes of ``self``.
     516
     517        EXAMPLES::
     518
     519            sage: W = ComplexReflectionGroup((1,1,3))
     520            sage: [ w.reduced_word() for w in W.conjugacy_classes_representatives() ]
     521            [word: , word: 0, word: 01]
     522
     523            sage: W = ComplexReflectionGroup((1,1,4))
     524            sage: sorted([ w.reduced_word() for w in W.conjugacy_classes_representatives() ])
     525            [word: , word: 0, word: 01, word: 012, word: 20]
     526
     527            sage: W = ComplexReflectionGroup((3,1,2))
     528            sage: [ w.reduced_word() for w in W.conjugacy_classes_representatives() ]
     529            [word: , word: 0, word: 00, word: 1010, word: 10100, word: 100100, word: 1, word: 01, word: 001]
     530
     531
     532            sage: W = ComplexReflectionGroup(23)
     533            sage: [ w.reduced_word() for w in W.conjugacy_classes_representatives() ]
     534            [word: , word: 0, word: 01, word: 20, word: 12, word: 012, word: 0101, word: 01012, word: 012010121, word: 210120101201010]
     535        """
     536        if self._conjugacy_classes_representatives is None:
     537            S = str(gap3('List(ConjugacyClasses(%s),Representative)'%self._gap_group._name))
     538            exec('self._conjugacy_classes_representatives='+gap_return(S))
     539        return self._conjugacy_classes_representatives
     540
     541    @cached_method
     542    def conjugacy_classes(self):
     543        r"""
     544        Returns the conjugacy classes of ``self``.
     545
     546        EXAMPLES::
     547
     548            sage: W = ComplexReflectionGroup((1,1,3))
     549            sage: for C in W.conjugacy_classes(): print C
     550            frozenset([()])
     551            frozenset([(1,3)(2,5)(4,6), (1,5)(2,4)(3,6), (1,4)(2,3)(5,6)])
     552            frozenset([(1,2,6)(3,4,5), (1,6,2)(3,5,4)])
     553
     554            sage: W = ComplexReflectionGroup((1,1,4))
     555            sage: sum( len(C) for C in  W.conjugacy_classes() ) == W.cardinality()
     556            True
     557
     558            sage: W = ComplexReflectionGroup((3,1,2))
     559            sage: sum( len(C) for C in  W.conjugacy_classes() ) == W.cardinality()
     560            True
     561
     562            sage: W = ComplexReflectionGroup(23)
     563            sage: sum( len(C) for C in  W.conjugacy_classes() ) == W.cardinality()
     564            True
     565       """
     566        from sage.sets.family import Family
     567        return Family(self.conjugacy_classes_representatives(), lambda w: w.conjugacy_class() )
     568
     569    def rank(self):
     570        r"""
     571        Returns the rank of ``self``. This is the dimension of the underlying vector space.
     572
     573        EXAMPLES::
     574
     575            sage: W = ComplexReflectionGroup((1,1,3))
     576            sage: W.rank()
     577            2
     578            sage: W = ComplexReflectionGroup((2,1,3))
     579            sage: W.rank()
     580            3
     581            sage: W = ComplexReflectionGroup((4,1,3))
     582            sage: W.rank()
     583            3
     584            sage: W = ComplexReflectionGroup((4,2,3))
     585            sage: W.rank()
     586            3
     587        """
     588        return self._rank
     589
     590    @cached_method
     591    def degrees(self):
     592        r"""
     593        Returns the degrees of ``self`` ordered within each irreducible component of ``self``.
     594
     595        EXAMPLES::
     596
     597            sage: W = ComplexReflectionGroup((1,1,4))
     598            sage: W.degrees()
     599            [2, 3, 4]
     600
     601            sage: W = ComplexReflectionGroup((2,1,4))
     602            sage: W.degrees()
     603            [2, 4, 6, 8]
     604
     605            sage: W = ComplexReflectionGroup((4,1,4))
     606            sage: W.degrees()
     607            [4, 8, 12, 16]
     608
     609            sage: W = ComplexReflectionGroup((4,2,4))
     610            sage: W.degrees()
     611            [4, 8, 12, 8]
     612
     613            sage: W = ComplexReflectionGroup((4,4,4))
     614            sage: W.degrees()
     615            [4, 8, 12, 4]
     616
     617        Examples of reducible types::
     618
     619            sage: W = ComplexReflectionGroup((1,1,4),(3,1,2)); W
     620            Reducible finite complex reflection group of rank 5 and type A3 x G(3,1,2)
     621            sage: W.degrees()
     622            [2, 3, 4, 3, 6]
     623
     624            sage: W = ComplexReflectionGroup((1,1,4),(6,1,12),23) # fails in GAP3
     625            sage: W.degrees()
     626            [2, 3, 4, 6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 2, 6, 10]
     627        """
     628        if self.is_irreducible():
     629            try:
     630                return self._gap_group.degrees.sage()
     631            except:
     632                return self._gap_group.ReflectionDegrees().sage()
     633        else:
     634            return add( [comp.degrees() for comp in self.irreducible_components()], [] )
     635
     636    cardinality = ComplexReflectionGroups.Finite.ParentMethods.cardinality.__func__
     637
     638    @cached_method
     639    def codegrees(self):
     640        r"""
     641        Returns the codegrees of ``self`` ordered within each irreducible component of ``self``.
     642
     643        EXAMPLES::
     644
     645            sage: W = ComplexReflectionGroup((1,1,4))
     646            sage: W.codegrees()
     647            [0, 1, 2]
     648
     649            sage: W = ComplexReflectionGroup((2,1,4))
     650            sage: W.codegrees()
     651            [0, 2, 4, 6]
     652
     653            sage: W = ComplexReflectionGroup((4,1,4))
     654            sage: W.codegrees()
     655            [0, 4, 8, 12]
     656
     657            sage: W = ComplexReflectionGroup((4,2,4))
     658            sage: W.codegrees()
     659            [0, 4, 8, 12]
     660
     661            sage: W = ComplexReflectionGroup((4,4,4))
     662            sage: W.codegrees()
     663            [8, 0, 4, 8]
     664
     665            sage: W = ComplexReflectionGroup((1,1,4),(3,1,2))
     666            sage: W.codegrees()
     667            [0, 1, 2, 0, 3]
     668           
     669            sage: W = ComplexReflectionGroup((1,1,4),(6,1,12),23) # fails in GAP3
     670            sage: W.codegrees()
     671            [0, 1, 2, 0, 6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 0, 4, 8]
     672        """
     673        if self.is_irreducible():
     674            if self.is_well_generated():
     675                h = self.coxeter_number()
     676                return [ h-d for d in reversed(self.degrees()) ]
     677            else:
     678                return self._gap_group.ReflectionCoDegrees().sage()
     679        else:
     680            return add( [comp.codegrees() for comp in self.irreducible_components()], [] )
     681
     682    @cached_method
     683    def reflection_eigenvalues_family(self):
     684        r"""
     685        Returns the reflection eigenvalues of ``self`` as a finite family indexed by the class representatives of ``self``.
     686        An eigenvalue `\zeta_n^k` is returned as the quotient `k/n` in the rationals.
     687
     688        EXAMPLES::
     689
     690            sage: W = ComplexReflectionGroup((1,1,3))
     691            sage: W.reflection_eigenvalues_family()
     692            Finite family {(): [0, 0], (1,4)(2,3)(5,6): [1/2, 0], (1,6,2)(3,5,4): [1/3, 2/3]}
     693
     694            sage: W = ComplexReflectionGroup((3,1,2))
     695            sage: W.reflection_eigenvalues_family()
     696            Finite family {(1,3,9)(2,16,24)(4,20,21)(5,7,13)(6,12,23)(8,19,17)(10,15,22)(11,18,14): [1/3, 1/3], (1,13,9,7,3,5)(2,14,24,18,16,11)(4,6,21,23,20,12)(8,22,17,15,19,10): [1/3, 5/6], (1,7,3,13,9,5)(2,8,16,19,24,17)(4,14,20,11,21,18)(6,15,12,22,23,10): [1/6, 2/3], (1,9,3)(2,10,4)(6,17,11)(8,18,12)(14,23,19)(15,20,16)(21,24,22): [2/3, 0], (1,3,9)(2,4,10)(6,11,17)(8,12,18)(14,19,23)(15,16,20)(21,22,24): [1/3, 0], (1,9,3)(2,20,22)(4,15,24)(5,7,13)(6,18,19)(8,23,11)(10,16,21)(12,14,17): [1/3, 2/3], (1,9,3)(2,24,16)(4,21,20)(5,13,7)(6,23,12)(8,17,19)(10,22,15)(11,14,18): [2/3, 2/3], (): [0, 0], (1,5)(2,6)(3,7)(4,8)(9,13)(10,14)(11,15)(12,16)(17,21)(18,22)(19,20)(23,24): [1/2, 0]}
     697
     698            sage: W = ComplexReflectionGroup(23)
     699            sage: W.reflection_eigenvalues_family()
     700            Finite family {(1,16)(2,5)(4,7)(6,9)(8,10)(11,13)(12,14)(17,20)(19,22)(21,24)(23,25)(26,28)(27,29): [1/2, 0, 0], (): [0, 0, 0], (1,24,17,16,9,2)(3,12,13,18,27,28)(4,21,29,19,6,14)(5,25,26,20,10,11)(7,23,30,22,8,15): [1/6, 1/2, 5/6], (1,8,4)(2,21,3)(5,10,11)(6,18,17)(7,9,12)(13,14,15)(16,23,19)(20,25,26)(22,24,27)(28,29,30): [1/3, 2/3, 0], (1,29,8,7,26,16,14,23,22,11)(2,9,25,3,4,17,24,10,18,19)(5,30,6,13,27,20,15,21,28,12): [3/10, 1/2, 7/10], (1,19,20,2,7)(3,6,11,13,9)(4,5,17,22,16)(8,12,15,14,10)(18,21,26,28,24)(23,27,30,29,25): [1/5, 4/5, 0], (1,16)(2,9)(3,18)(4,10)(5,6)(7,8)(11,14)(12,13)(17,24)(19,25)(20,21)(22,23)(26,29)(27,28): [1/2, 1/2, 0], (1,20,7,19,2)(3,11,9,6,13)(4,17,16,5,22)(8,15,10,12,14)(18,26,24,21,28)(23,30,25,27,29): [2/5, 3/5, 0], (1,23,26,29,22,16,8,11,14,7)(2,10,4,9,18,17,25,19,24,3)(5,21,27,30,28,20,6,12,15,13): [1/10, 1/2, 9/10], (1,16)(2,17)(3,18)(4,19)(5,20)(6,21)(7,22)(8,23)(9,24)(10,25)(11,26)(12,27)(13,28)(14,29)(15,30): [1/2, 1/2, 1/2]}
     701            """
     702        from sage.sets.family import Family
     703        class_representatives = self.conjugacy_classes_representatives()
     704        Ev_list = self._gap_group.ReflectionEigenvalues().sage()
     705        return Family( class_representatives, lambda w: Ev_list[class_representatives.index(w)] )
     706
     707    @cached_method
     708    def reflection_eigenvalues(self,w,test_class_repr=True):
     709        r"""
     710        Returns the reflection eigenvalue of ``w`` in ``self``.
     711
     712        .. seealso:: :meth:`reflection_eigenvalues_family`
     713
     714        EXAMPLES::
     715
     716            sage: W = ComplexReflectionGroup((1,1,3))
     717            sage: for w in W: print w.reduced_word(), W.reflection_eigenvalues(w)
     718             [0, 0]
     719            0 [1/2, 0]
     720            1 [1/2, 0]
     721            01 [1/3, 2/3]
     722            10 [1/3, 2/3]
     723            010 [1/2, 0]
     724        """
     725        if test_class_repr:
     726            w_repr = w.conjugacy_class_representative()
     727        else:
     728            w_repr = w
     729        return self.reflection_eigenvalues_family()[ w_repr ]
     730
     731    @cached_method
     732    def simple_roots(self):
     733        r"""
     734        Returns the *simple roots* of ``self``. These are the roots
     735        corresponding to the simple reflections.
     736
     737        EXAMPLES::
     738
     739            sage: W = ComplexReflectionGroup((1,1,3))
     740            sage: W.simple_roots()
     741            [(1, 0), (0, 1)]
     742
     743            sage: W = ComplexReflectionGroup((1,1,4),(2,1,2))
     744            sage: W.simple_roots()
     745            [(1, 0, 0, 0, 0), (0, 1, 0, 0, 0), (0, 0, 1, 0, 0), (0, 0, 0, 1, 0), (0, 0, 0, 0, 1)]
     746
     747            sage: W = ComplexReflectionGroup((3,1,2))
     748            sage: W.simple_roots()
     749            [(1, 0), (-1, 1)]
     750
     751            sage: W = ComplexReflectionGroup((1,1,4),(3,1,2))
     752            sage: W.simple_roots()
     753            [(1, 0, 0, 0, 0), (0, 1, 0, 0, 0), (0, 0, 1, 0, 0), (0, 0, 0, 1, 0), (0, 0, 0, -1, 1)]
     754        """
     755        return self.roots()[:len(self.gens())]
     756
     757    @cached_method
     758    def simple_coroots(self):
     759        r"""
     760        Returns the *simple coroots* of ``self``. These are the coroots
     761        corresponding to the simple reflections.
     762
     763        EXAMPLES::
     764
     765            sage: W = ComplexReflectionGroup((1,1,3))
     766            sage: W.simple_coroots()
     767            [[2, -1], [-1, 2]]
     768
     769            sage: W = ComplexReflectionGroup((1,1,4),(2,1,2))
     770            sage: W.simple_coroots()
     771            [[2, -1, 0, 0, 0], [-1, 2, -1, 0, 0], [0, -1, 2, 0, 0], [0, 0, 0, 2, -2], [0, 0, 0, -1, 2]]
     772
     773            sage: W = ComplexReflectionGroup((3,1,2))
     774            sage: W.simple_coroots()
     775            [[-2*E(3) - E(3)^2, 0], [-1, 1]]
     776
     777            sage: W = ComplexReflectionGroup((1,1,4),(3,1,2))
     778            sage: W.simple_coroots()
     779            [[2, -1, 0, 0, 0], [-1, 2, -1, 0, 0], [0, -1, 2, 0, 0], [0, 0, 0, -2*E(3) - E(3)^2, 0], [0, 0, 0, -1, 1]]
     780        """
     781        return self._gap_group.simpleCoroots.sage()
     782
     783    @cached_method
     784    def independent_roots(self):
     785        r"""
     786        Returns a collection of simple roots generating the underlying vector space of ``self``.
     787        For well-generated groups, these are all simple roots. Otherwise, a linearly independent
     788        subset of the simple roots is chosen.
     789
     790        EXAMPLES::
     791
     792            sage: W = ComplexReflectionGroup((1,1,3))
     793            sage: W.independent_roots()
     794            [(1, 0), (0, 1)]
     795
     796            sage: W = ComplexReflectionGroup((4,2,3))
     797            sage: W.simple_roots()
     798            [(1, 0, 0), (-E(4), 1, 0), (-1, 1, 0), (0, -1, 1)]
     799            sage: W.independent_roots()
     800            [(1, 0, 0), (-E(4), 1, 0), (0, -1, 1)]
     801        """
     802        Delta = self.simple_roots()
     803        if len(Delta) == self.rank():
     804            basis = Delta
     805        else:
     806            basis = []
     807            for alpha in Delta:
     808                if Matrix(basis+[alpha]).rank() == len(basis) + 1:
     809                    basis.append(alpha)
     810        return basis
     811
     812    @cached_method
     813    def base_change_matrix(self):
     814        r"""
     815        Returns the base change from the standard basis of the vector space of ``self`` to the basis given by the independent roots of ``self``.
     816
     817        FIXME:
     818
     819        - for non-well-generated groups there is a conflict with construction of the matrix for an element
     820
     821        EXAMPLES::
     822
     823            sage: W = ComplexReflectionGroup((1,1,3))
     824            sage: W.base_change_matrix()
     825            [1 0]
     826            [0 1]
     827
     828            sage: W = ComplexReflectionGroup(23)
     829            sage: W.base_change_matrix()
     830            [1 0 0]
     831            [0 1 0]
     832            [0 0 1]
     833
     834            sage: W = ComplexReflectionGroup((3,1,2))
     835            sage: W.base_change_matrix()
     836            [1 0]
     837            [1 1]
     838
     839            sage: W = ComplexReflectionGroup((4,2,2))
     840            sage: W.base_change_matrix()
     841            [   1    0]
     842            [E(4)    1]
     843        """
     844        return Matrix( self.independent_roots() ).inverse()
     845
     846    @cached_method
     847    def roots(self):
     848        r"""
     849        Returns all roots corresponding to all reflections of ``self``.
     850
     851        EXAMPLES::
     852
     853            sage: W = ComplexReflectionGroup((1,1,3))
     854            sage: W.roots()
     855            [(1, 0), (0, 1), (1, 1), (-1, 0), (0, -1), (-1, -1)]
     856
     857            sage: W = ComplexReflectionGroup((3,1,2))
     858            sage: W.roots()
     859            [(1, 0), (-1, 1), (E(3), 0), (-E(3), 1), (0, 1), (1, -1), (0, E(3)), (1, -E(3)), (E(3)^2, 0), (-E(3)^2, 1), (E(3), -1), (E(3), -E(3)), (0, E(3)^2), (1, -E(3)^2), (-1, E(3)), (-E(3), E(3)), (E(3)^2, -1), (E(3)^2, -E(3)), (E(3), -E(3)^2), (-E(3)^2, E(3)), (-1, E(3)^2), (-E(3), E(3)^2), (E(3)^2, -E(3)^2), (-E(3)^2, E(3)^2)]
     860
     861            sage: W = ComplexReflectionGroup((4,2,2))
     862            sage: W.roots()
     863            [(1, 0), (-E(4), 1), (-1, 1), (-1, 0), (E(4), 1), (1, 1), (0, -E(4)), (E(4), -1), (E(4), E(4)), (0, E(4)), (E(4), -E(4)), (0, 1), (1, -E(4)), (1, -1), (0, -1), (1, E(4)), (-E(4), 0), (-1, E(4)), (E(4), 0), (-E(4), E(4)), (-E(4), -1), (-E(4), -E(4)), (-1, -E(4)), (-1, -1)]
     864
     865            sage: W = ComplexReflectionGroup((1,1,4),(3,1,2))
     866            sage: W.roots()
     867            [(1, 0, 0, 0, 0), (0, 1, 0, 0, 0), (0, 0, 1, 0, 0), (0, 0, 0, 1, 0), (0, 0, 0, -1, 1), (1, 1, 0, 0, 0), (0, 1, 1, 0, 0), (1, 1, 1, 0, 0), (-1, 0, 0, 0, 0), (0, -1, 0, 0, 0), (0, 0, -1, 0, 0), (-1, -1, 0, 0, 0), (0, -1, -1, 0, 0), (-1, -1, -1, 0, 0), (0, 0, 0, E(3), 0), (0, 0, 0, -E(3), 1), (0, 0, 0, 0, 1), (0, 0, 0, 1, -1), (0, 0, 0, 0, E(3)), (0, 0, 0, 1, -E(3)), (0, 0, 0, E(3)^2, 0), (0, 0, 0, -E(3)^2, 1), (0, 0, 0, E(3), -1), (0, 0, 0, E(3), -E(3)), (0, 0, 0, 0, E(3)^2), (0, 0, 0, 1, -E(3)^2), (0, 0, 0, -1, E(3)), (0, 0, 0, -E(3), E(3)), (0, 0, 0, E(3)^2, -1), (0, 0, 0, E(3)^2, -E(3)), (0, 0, 0, E(3), -E(3)^2), (0, 0, 0, -E(3)^2, E(3)), (0, 0, 0, -1, E(3)^2), (0, 0, 0, -E(3), E(3)^2), (0, 0, 0, E(3)^2, -E(3)^2), (0, 0, 0, -E(3)^2, E(3)^2)]
     868        """
     869        roots = [ vector(root) for root in self._gap_group.roots.sage() ]
     870        for v in roots:
     871            v.set_immutable()
     872        return roots
     873
     874    @cached_method
     875    def braid_relations(self):
     876        r"""
     877        Returns the braid relations of ``self``.
     878
     879        EXAMPLES::
     880
     881            sage: W = ComplexReflectionGroup((1,1,3))
     882            sage: W.braid_relations()
     883            [[[2, 1, 2], [1, 2, 1]]]
     884
     885            sage: W = ComplexReflectionGroup((2,1,3))
     886            sage: W.braid_relations()
     887            [[[2, 1, 2, 1], [1, 2, 1, 2]], [[3, 1], [1, 3]], [[3, 2, 3], [2, 3, 2]]]
     888
     889            sage: W = ComplexReflectionGroup((2,2,3))
     890            sage: W.braid_relations()
     891            [[[2, 1, 2], [1, 2, 1]], [[3, 1], [1, 3]], [[3, 2, 3], [2, 3, 2]]]
     892        """
     893        return self._gap_group.BraidRelations().sage()
     894
     895    def fundamental_invariants(self):
     896        r"""
     897        Returns the fundamental invariants of ``self``.
     898
     899        EXAMPLES::
     900
     901            sage: W = ComplexReflectionGroup((1,1,3))
     902            sage: W.fundamental_invariants()
     903            [-2*x0^2 + 2*x0*x1 - 2*x1^2, 6*x0^2*x1 - 6*x0*x1^2]
     904        """
     905        from sage.rings.polynomial.all import PolynomialRing
     906
     907        I = [ str(p) for p in gap3('List(Invariants(%s),x->ApplyFunc(x,List([0..%s],i->Mvp(SPrint("x",i)))))'%(self._gap_group._name,self.rank()-1)) ]
     908        P = PolynomialRing(QQ,['x%s'%i for i in range(0,self.rank())])
     909        x = P.gens()
     910        for i in range(len(I)):
     911            I[i] = I[i].replace('^','**')
     912            for j in range(len(x)):
     913                I[i] = I[i].replace('x%s'%j,'*x[%s]'%j)
     914        I = [ eval(p) for p in I ]
     915        return I
     916
     917    def set_reflection_representation(self,refl_repr):
     918        self.one().as_matrix.clear_cache()
     919        if set( refl_repr.keys() ) != set( self.index_set() ):
     920            raise ValueError, "The reflection representation must be defined for the complete index set."
     921        self._reflection_representation = refl_repr
     922
     923    class Element(PermutationGroupElement):
     924
     925        _reduced_word=None
     926
     927        def apply_simple_reflection_right(self,i):
     928            r"""
     929            Returns the product of ``self`` with the ``i``-th simple reflection.
     930
     931            EXAMPLES::
     932
     933                sage: W = ComplexReflectionGroup((1,1,3))
     934                sage: for w in W: print w.apply_simple_reflection_right(0)
     935                (1,4)(2,3)(5,6)
     936                ()
     937                (1,2,6)(3,4,5)
     938                (1,5)(2,4)(3,6)
     939                (1,3)(2,5)(4,6)
     940                (1,6,2)(3,5,4)
     941            """
     942            assert i in self.parent().index_set()
     943            gen = self.parent().gens()[self.parent()._index_set[i]]
     944            return self*gen
     945
     946        def apply_simple_reflection_left(self,i):
     947            r"""
     948            Returns the product of ``self`` with the ``i``-th simple reflection.
     949
     950            EXAMPLES::
     951
     952                sage: W = ComplexReflectionGroup((1,1,3))
     953                sage: for w in W: print w.apply_simple_reflection_left(0)
     954                (1,4)(2,3)(5,6)
     955                ()
     956                (1,6,2)(3,5,4)
     957                (1,3)(2,5)(4,6)
     958                (1,5)(2,4)(3,6)
     959                (1,2,6)(3,4,5)
     960            """
     961            assert i in self.parent().index_set()
     962            gen = self.parent().gens()[self.parent()._index_set[i]]
     963            return gen*self
     964
     965        @cached_in_parent_method
     966        def conjugacy_class_representative(self):
     967            r"""
     968            Returns a representative of the conjugacy class of ``self``.
     969
     970            EXAMPLES::
     971
     972                sage: W = ComplexReflectionGroup((1,1,3))
     973                sage: for w in W: print w.reduced_word(), w.conjugacy_class_representative().reduced_word()
     974                0 0
     975                1 0
     976                01 01
     977                10 01
     978                010 0
     979            """
     980            W = self.parent()
     981            for w in W._conjugacy_classes.keys():
     982                if self in W._conjugacy_classes[w]:
     983                    return w
     984            return W.conjugacy_classes_representatives()[ gap3("PositionClass(%s,%s)"%(W._gap_group._name,self)).sage()-1 ]
     985
     986        def conjugacy_class(self):
     987            r"""
     988            Returns the conjugacy class of ``self``.
     989
     990            EXAMPLES::
     991
     992                sage: W = ComplexReflectionGroup((1,1,3))
     993                sage: for w in W: print w.conjugacy_class()
     994                frozenset([()])
     995                frozenset([(1,3)(2,5)(4,6), (1,5)(2,4)(3,6), (1,4)(2,3)(5,6)])
     996                frozenset([(1,3)(2,5)(4,6), (1,5)(2,4)(3,6), (1,4)(2,3)(5,6)])
     997                frozenset([(1,2,6)(3,4,5), (1,6,2)(3,5,4)])
     998                frozenset([(1,2,6)(3,4,5), (1,6,2)(3,5,4)])
     999                frozenset([(1,3)(2,5)(4,6), (1,5)(2,4)(3,6), (1,4)(2,3)(5,6)])
     1000            """
     1001            W = self.parent()
     1002            if self not in W.conjugacy_classes_representatives():
     1003                self = self.conjugacy_class_representative()
     1004            if self in W._conjugacy_classes.keys():
     1005                return W._conjugacy_classes[self]
     1006            gens = W.simple_reflections()
     1007            count = 0
     1008            orbit = [self]
     1009            orbit_set = set(orbit);
     1010            while count < len(orbit):
     1011                w = orbit[count]
     1012                count += 1
     1013                for s in gens:
     1014                    w_new = s*w*s**-1
     1015                    if w_new not in orbit_set:
     1016                        orbit.append(w_new)
     1017                        orbit_set.add(w_new)
     1018            orbit_set = frozenset(orbit_set)
     1019            W._conjugacy_classes[self] = orbit_set
     1020            return orbit_set
     1021
     1022        @cached_in_parent_method
     1023        def reduced_word(self):
     1024            r"""
     1025            Returns a word in the simple reflections to obtain ``self``
     1026
     1027            EXAMPLES::
     1028
     1029                sage: W = ComplexReflectionGroup((5,1,1),index_set=['a'],hyperplane_index_set=['x'],reflection_index_set=['A','B','C','D'])
     1030
     1031                sage: [ w.reduced_word() for w in W ]
     1032                [word: , word: a, word: aa, word: aaa, word: aaaa]
     1033           
     1034            .. seealso:: :meth:`reduced_word_in_reflections`
     1035            """
     1036            W = self.parent()
     1037            if self._reduced_word is None:
     1038                inv_dict = dict( (W._index_set[i],i) for i in W._index_set.keys() )                   
     1039                gens = [ W.simple_reflection(i) for i in W.index_set() ]
     1040                word = gap_factorization(self,gens,inv_dict)
     1041                self._reduced_word = Word(word)
     1042            return self._reduced_word
     1043
     1044        @cached_in_parent_method
     1045        def reduced_word_in_reflections(self):
     1046            r"""
     1047            Returns a word in the reflections to obtain ``self``
     1048
     1049            EXAMPLES::
     1050
     1051                sage: W = ComplexReflectionGroup((5,1,1),index_set=['a'],reflection_index_set=['A','B','C','D'])
     1052
     1053                sage: [ w.reduced_word_in_reflections() for w in W ]
     1054                [word: , word: A, word: B, word: C, word: D]
     1055           
     1056            .. seealso:: :meth:`reduced_word`
     1057            """
     1058            W = self.parent()
     1059            if self == W.one():
     1060                return Word([])
     1061            if W.is_real():
     1062                R = W.reflections()
     1063                r = self.reflection_length()
     1064                for i in range(len(R)):
     1065                    t = R[i]
     1066                    w = t*self
     1067                    if w.reflection_length() < r:
     1068                        return Word([i]) + w.reduced_word_in_reflections()
     1069            else:
     1070                inv_dict = dict( (W._reflection_index_set[i],i) for i in W._reflection_index_set.keys() )
     1071                gens = [ W.reflection(i) for i in W.reflection_index_set() ]
     1072                return Word(gap_factorization(self,gens,inv_dict))
     1073
     1074        @cached_in_parent_method
     1075        def length(self):
     1076            r"""
     1077            Returns the length of ``self`` in generating reflections. This is
     1078            the minimal numbers of generating reflections needed to obtain ``self``.
     1079
     1080            EXAMPLES::
     1081
     1082                tba
     1083            """
     1084            return len( self.reduced_word() )
     1085
     1086        @cached_in_parent_method
     1087        def reflection_length(self, in_unitary_group=False):
     1088            r"""
     1089            Returns the reflection length of ``self``. This is
     1090            the minimal numbers of reflections needed to obtain ``self``.
     1091
     1092            INPUT:
     1093
     1094            - in_unitary_group -- (default:False) if True, the reflection length is computed in the unitary group which is the dimension of the move space of ``self``.
     1095
     1096            EXAMPLES::
     1097
     1098                sage: W = ComplexReflectionGroup((1,1,3))
     1099                sage: sorted([ t.reflection_length() for t in W ])
     1100                [0, 1, 1, 1, 2, 2]
     1101
     1102                sage: W = ComplexReflectionGroup((2,1,2))
     1103                sage: sorted([ t.reflection_length() for t in W ])
     1104                [0, 1, 1, 1, 1, 2, 2, 2]
     1105
     1106                sage: W = ComplexReflectionGroup((2,2,2))
     1107                sage: sorted([ t.reflection_length() for t in W ])
     1108                [0, 1, 1, 2]
     1109
     1110                sage: W = ComplexReflectionGroup((3,1,2))
     1111                sage: sorted([ t.reflection_length() for t in W ])
     1112                [0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
     1113            """
     1114            W = self.parent()
     1115            if self in W.conjugacy_classes_representatives():
     1116                if in_unitary_group or W.is_real():
     1117                    return W.rank()-self.reflection_eigenvalues(test_class_repr=False).count(0)
     1118                else:
     1119                    return len(self.reduced_word_in_reflections())
     1120            else:
     1121                w = self.conjugacy_class_representative()
     1122                assert w in self.parent().conjugacy_classes_representatives()
     1123                return w.reflection_length(in_unitary_group=in_unitary_group)
     1124
     1125        @cached_in_parent_method
     1126        def conjugacy_class_representative(self):
     1127            conj = self.parent().conjugacy_classes()
     1128            for w in conj.keys():
     1129                if self in conj[w]:
     1130                    return w
     1131
     1132        @cached_in_parent_method
     1133        def right_coset_representatives(self):
     1134            r"""
     1135            Returns the right coset representatives of ``self``.
     1136
     1137            EXAMPLES::
     1138
     1139                sage: W = ComplexReflectionGroup((1,1,3))
     1140                sage: for w in W: print w.reduced_word(), [ v.reduced_word() for v in w.right_coset_representatives() ]
     1141                 [word: , word: 1, word: 0, word: 10, word: 01, word: 010]
     1142                0 [word: , word: 1, word: 10]
     1143                1 [word: , word: 0, word: 01]
     1144                01 [word: ]
     1145                10 [word: ]
     1146                010 [word: , word: 1, word: 0]
     1147            """
     1148            W = self.parent()
     1149            T = W.reflections()
     1150            T_fix = [ i+1 for i in T.keys() if self.fix_space().is_subspace(T[i].fix_space()) ]
     1151            S = str(gap3('ReducedRightCosetRepresentatives(%s,ReflectionSubgroup(%s,%s))'%(W._gap_group._name,W._gap_group._name,T_fix)))
     1152            exec('L = '+gap_return(S,coerce_obj='W'))
     1153            return L
     1154
     1155        def left_coset_representatives(self):
     1156            r"""
     1157            Returns the left coset representatives of ``self``.
     1158
     1159            .. seealso:: :meth:`right_coset_representatives`
     1160
     1161            EXAMPLES::
     1162
     1163                sage: W = ComplexReflectionGroup((1,1,3))
     1164                sage: for w in W: print w.reduced_word(), [ v.reduced_word() for v in w.left_coset_representatives() ]
     1165                 [word: , word: 1, word: 0, word: 01, word: 10, word: 010]
     1166                0 [word: , word: 1, word: 01]
     1167                1 [word: , word: 0, word: 10]
     1168                01 [word: ]
     1169                10 [word: ]
     1170                010 [word: , word: 1, word: 0]
     1171            """
     1172            return [ w**-1 for w in self.right_coset_representatives() ]
     1173
     1174        @cached_in_parent_method
     1175        def as_matrix(self):
     1176            r"""
     1177            Returns ``self`` as a matrix acting on the underlying vector space.
     1178
     1179            EXAMPLES::
     1180
     1181                sage: W = ComplexReflectionGroup((1,1,3))
     1182                sage: for w in W:
     1183                ...       print w.reduced_word()
     1184                ...       print w.as_matrix()
     1185                [1 0]
     1186                [0 1]
     1187                0
     1188                [-1  0]
     1189                [ 1  1]
     1190                1
     1191                [ 1  1]
     1192                [ 0 -1]
     1193                01
     1194                [-1 -1]
     1195                [ 1  0]
     1196                10
     1197                [ 0  1]
     1198                [-1 -1]
     1199                010
     1200                [ 0 -1]
     1201                [-1  0]
     1202            """
     1203            W = self.parent()
     1204            if W._reflection_representation is None:
     1205                Delta = W.simple_roots()
     1206                Phi = W.roots()
     1207                M = Matrix([ Phi[self(Phi.index(alpha)+1)-1] for alpha in Delta ])
     1208                return W.base_change_matrix() * M
     1209            else:
     1210                refl_repr = W._reflection_representation
     1211                id_mat = identity_matrix(QQ,refl_repr[W.index_set()[0]].nrows())
     1212                return prod( [refl_repr[i] for i in self.reduced_word()],id_mat  )
     1213
     1214        @cached_in_parent_method
     1215        def fix_space(self):
     1216            r"""
     1217            Returns the fix space of ``self``. This is the sub vector space of the
     1218            underlying vector space on which ``self`` acts trivially.
     1219
     1220            EXAMPLES::
     1221
     1222                sage: W = ComplexReflectionGroup((1,1,3))
     1223                sage: for w in W:
     1224                ...       print w.reduced_word()
     1225                ...       print w.fix_space()               
     1226                Vector space of degree 2 and dimension 2 over Universal Cyclotomic Field endowed with the Zumbroich basis
     1227                Basis matrix:
     1228                [1 0]
     1229                [0 1]
     1230                0
     1231                Vector space of degree 2 and dimension 1 over Universal Cyclotomic Field endowed with the Zumbroich basis
     1232                Basis matrix:
     1233                [0 1]
     1234                1
     1235                Vector space of degree 2 and dimension 1 over Universal Cyclotomic Field endowed with the Zumbroich basis
     1236                Basis matrix:
     1237                [1 0]
     1238                01
     1239                Vector space of degree 2 and dimension 0 over Universal Cyclotomic Field endowed with the Zumbroich basis
     1240                Basis matrix:
     1241                []
     1242                10
     1243                Vector space of degree 2 and dimension 0 over Universal Cyclotomic Field endowed with the Zumbroich basis
     1244                Basis matrix:
     1245                []
     1246                010
     1247                Vector space of degree 2 and dimension 1 over Universal Cyclotomic Field endowed with the Zumbroich basis
     1248                Basis matrix:
     1249                [ 1 -1]
     1250            """
     1251            return (self.as_matrix()-identity_matrix(UCF,self.parent().rank())).right_kernel()
     1252
     1253        @cached_in_parent_method
     1254        def reflection_eigenvalues(self,test_class_repr=True):
     1255            r"""
     1256            Returns the reflection eigenvalues of ``self``.
     1257            """
     1258            return self.parent().reflection_eigenvalues(self,test_class_repr=test_class_repr)
     1259
     1260        @cached_in_parent_method
     1261        def galois_conjugates(self):
     1262            r"""
     1263            Returns all Galois conjugates of ``self``.
     1264
     1265            EXAMPLES::
     1266
     1267                tba
     1268            """
     1269            rk = self.parent().rank()
     1270            M = self.as_matrix()
     1271            L = [ UCF(x) for x in M.list() ]
     1272            m = lcm([ x.field_order() for x in L ])
     1273            L_gals = [ x.galois_conjugates(m) for x in L ]
     1274            conjugates = []
     1275            for i in range(len(L_gals[0])):
     1276                conjugates.append( Matrix(rk, [ X[i] for X in L_gals ] ) )
     1277            return conjugates
     1278
     1279        def __cmp__(self, other):
     1280            r"""
     1281            Without this comparison method, the initialization of this
     1282            permutation group fails ...
     1283            """
     1284            return super(FiniteComplexReflectionGroup.Element, self).__cmp__(other)
     1285
     1286class IrreducibleFiniteComplexReflectionGroup(FiniteComplexReflectionGroup):
     1287
     1288    def _repr_(self):
     1289        r"""
     1290        Returns the string representation of ``self``.
     1291
     1292        EXAMPLES::
     1293
     1294            sage: W = ComplexReflectionGroup((1,1,3)); W
     1295            Irreducible finite complex reflection group of rank 2 and type A2
     1296        """
     1297        type_str = self._irrcomp_repr_(self._type[0])
     1298        return 'Irreducible finite complex reflection group of rank %s and type %s'%(self._rank,type_str)
     1299
     1300    @cached_method
     1301    def a_coxeter_element(self):
     1302        r"""
     1303        Returns a Coxeter element of a well-generated, irreducible reflection group. This is an element
     1304        having a regular eigenvector (a vector not contained in any recflecting hyperplane of ``self``).
     1305
     1306        REMARK:
     1307
     1308        - ``self`` is assumed to be well-generated.
     1309
     1310        EXAMPLES::
     1311
     1312            sage: W = ComplexReflectionGroup((1,1,4))
     1313            sage: W.a_coxeter_element().reduced_word()
     1314            word: 012
     1315
     1316            sage: W = ComplexReflectionGroup((2,1,4))
     1317            sage: W.a_coxeter_element().reduced_word()
     1318            word: 0123
     1319
     1320            sage: W = ComplexReflectionGroup((4,1,4))
     1321            sage: W.a_coxeter_element().reduced_word()
     1322            word: 0123
     1323
     1324            sage: W = ComplexReflectionGroup((4,4,4))
     1325            sage: W.a_coxeter_element().reduced_word()
     1326            word: 0123
     1327        """
     1328        assert self.is_irreducible()
     1329        assert self.is_well_generated()
     1330        inverse_index = dict([(self._index_set[i],i) for i in self._index_set.keys()])
     1331        return self.from_word( inverse_index[i] for i in sorted(self._index_set.values()) )
     1332
     1333    @cached_method
     1334    def coxeter_elements(self):
     1335        r"""
     1336        Returns the (unique) conjugacy class in ``self`` containing all Coxeter elements.
     1337
     1338        REMARK:
     1339
     1340        - ``self`` is assumed to be well-generated.
     1341        - This works even beyond real reflection groups, but the conjugacy class is not unique and we only obtain one such class.
     1342
     1343        EXAMPLES::
     1344
     1345            sage: W = ComplexReflectionGroup((1,1,3))
     1346            sage: [ c.reduced_word() for c in W.coxeter_elements() ]
     1347            [word: 10, word: 01]
     1348
     1349            sage: W = ComplexReflectionGroup((1,1,4))
     1350            sage: [ c.reduced_word() for c in W.coxeter_elements() ]
     1351            [word: 01201, word: 12010, word: 210, word: 012, word: 201, word: 120]
     1352        """
     1353        return self.a_coxeter_element().conjugacy_class()
     1354
     1355    @cached_method
     1356    def standard_coxeter_elements(self):
     1357        r"""
     1358        Returns all standard Coxeter elements in ``self``. This is the set of all
     1359        elements in self obtained from any product of the simple reflections in ``self``.
     1360
     1361        REMARK:
     1362
     1363        - ``self`` is assumed to be well-generated.
     1364        - This works even beyond real reflection groups, but the conjugacy class is not unique and we only obtain one such class.
     1365
     1366        EXAMPLES::
     1367
     1368            tba
     1369        """
     1370        assert self.is_irreducible()
     1371        assert self.is_well_generated()
     1372        from sage.combinat.permutation import Permutations
     1373        return set( self.from_word(w) for w in Permutations(self.index_set()) )
     1374
     1375    def elements_below_coxeter_element(self, c=None):
     1376        r"""
     1377        Returns all elements in ``self`` in the interval `[1,c]` in the absolute order of ``self``.
     1378        This order is defines by `\omega \leq_R \tau \Leftrightarrow \ell_R(\omega) + \ell_R(\omega^{-1} \tau) = \ell_R(\tau)``.
     1379
     1380        REMARK:
     1381
     1382        - ``self`` is assumed to be well-generated.
     1383
     1384        INPUT:
     1385
     1386        - c -- (default:None) if an element ``c`` is given, it is used as the maximal element in the interval. If a list is given,
     1387                the union of the various maximal elements is computed.
     1388
     1389        EXAMPLES::
     1390
     1391            sage: W = ComplexReflectionGroup((1,1,3))
     1392
     1393            sage: [ w.reduced_word() for w in W.elements_below_coxeter_element() ]
     1394            [word: , word: 0, word: 1, word: 01, word: 010]
     1395
     1396            sage: [ w.reduced_word() for w in W.elements_below_coxeter_element(W.from_word([1,0])) ]
     1397            [word: , word: 0, word: 1, word: 10, word: 010]
     1398
     1399            sage: [ w.reduced_word() for w in W.elements_below_coxeter_element(W.from_word([1])) ]
     1400            [word: , word: 1]
     1401        """
     1402        if c in self:
     1403            cs = [c]
     1404        elif c is None:
     1405            cs = [self.a_coxeter_element()]
     1406        else:
     1407            cs = list(c)
     1408        l = cs[0].reflection_length(in_unitary_group=True)
     1409        R = self.reflections()
     1410        f = lambda pi: any( pi.reflection_length(in_unitary_group=True) + (c*pi**-1).reflection_length(in_unitary_group=True) == l for c in cs )
     1411        # first computing the conjugacy classes only needed if the interaction with gap3 is slow due to a bug
     1412        #self.conjugacy_classes()
     1413        return filter(f,self)
     1414        #return set( self.magma_closure_iter(I=R, predicate=lambda pi: pi.reflection_length(in_unitary_group=True) + (c*pi**-1).reflection_length(in_unitary_group=True) == l) )
     1415
     1416    @cached_method
     1417    def noncrossing_partition_lattice(self, c=None, L=None):
     1418        r"""
     1419        Returns the the interval `[1,c]` in the absolute order of ``self`` as a finite lattice.
     1420
     1421        .. seealso:: :meth:`elements_below_coxeter_element`
     1422
     1423        REMARK:
     1424
     1425        - ``self`` is assumed to be well-generated.
     1426
     1427        INPUT:
     1428
     1429        - c -- (default:None) if an element ``c`` in ``self`` is given, it is used as the maximal element in the interval.
     1430
     1431        - L -- (default:None) if a subset ``L`` (must be hashable!) of ``self`` is given, it is used as the underlying set. Only cover relations are checked though.
     1432
     1433        EXAMPLES::
     1434
     1435            sage: W = ComplexReflectionGroup((1,1,3))
     1436
     1437            sage: [ w.reduced_word() for w in W.noncrossing_partition_lattice() ]
     1438            [word: , word: 0, word: 1, word: 010, word: 01]
     1439
     1440            sage: [ w.reduced_word() for w in W.noncrossing_partition_lattice(W.from_word([1,0])) ]
     1441            [word: , word: 0, word: 1, word: 010, word: 10]
     1442
     1443            sage: [ w.reduced_word() for w in W.noncrossing_partition_lattice(W.from_word([1])) ]
     1444            [word: , word: 1]
     1445        """
     1446        from sage.combinat.posets.all import Poset, LatticePoset
     1447        R = self.reflections()
     1448        if L is None:
     1449            L = self.elements_below_coxeter_element(c=c)
     1450        rels = []
     1451        for pi in L:
     1452            for t in R:
     1453                tau = pi*t
     1454                if tau in L and pi.reflection_length(in_unitary_group=True) + 1 == tau.reflection_length(in_unitary_group=True):
     1455                    rels.append([pi,tau])
     1456        P = Poset(([],rels), cover_relations=True, facade=True)
     1457        if P.is_lattice():
     1458            return LatticePoset(P)
     1459        else:
     1460            return P
     1461
     1462    def generalized_noncrossing_partitions(self, m, c=None, positive=False):
     1463        from sage.combinat.combination import Combinations
     1464        NC = self.noncrossing_partition_lattice(c=c)
     1465        one = self.one()
     1466        if c is None:
     1467            c = self.a_coxeter_element()
     1468        chains = NC.chains()
     1469        NCm = set()
     1470        iter = chains.breadth_first_search_iterator()
     1471        chain = iter.next()
     1472        chain = iter.next()
     1473        while len(chain) <= m:
     1474            chain.append( c )
     1475            for i in range(len(chain)-1,0,-1):
     1476                chain[i] = chain[i-1]**-1 * chain[i]
     1477            k = m+1 - len(chain)
     1478            for positions in Combinations(range(m+1),k):
     1479                ncm = []
     1480                for l in range(m+1):
     1481                    if l in positions:
     1482                        ncm.append( one )
     1483                    else:
     1484                        l_prime = l - len( [ i for i in positions if i <= l ] )
     1485                        ncm.append( chain[l_prime] )
     1486                if not positive or prod(ncm[:-1]).has_full_support():
     1487                    NCm.add(tuple(ncm))
     1488            try:
     1489                chain = iter.next()
     1490            except StopIteration:
     1491                chain = range(m+1)
     1492        return NCm
     1493
     1494    @cached_method
     1495    def absolute_poset(self):
     1496        r"""
     1497        Returns the poset induced by the absolute order of ``self`` as a finite lattice.
     1498
     1499        .. seealso:: :meth:`noncrossing_partition_lattice`
     1500
     1501        EXAMPLES::
     1502
     1503            sage: P = ComplexReflectionGroup((1,1,3)).absolute_poset(); P
     1504            Finite poset containing 6 elements
     1505
     1506            sage: [ w.reduced_word() for w in P ]
     1507            [word: , word: 0, word: 1, word: 010, word: 01, word: 10]
     1508        """
     1509        return self.noncrossing_partition_lattice(L=self)
     1510
     1511    class Element(FiniteComplexReflectionGroup.Element):
     1512
     1513        @cached_in_parent_method
     1514        def is_coxeter_element(self,which_primitive=1,test_class_repr=True):
     1515            r"""
     1516            Returns True if ``self`` is a Coxeter element.
     1517
     1518            .. seealso:: :meth:`a_coxeter_element`
     1519
     1520            EXAMPLES::
     1521
     1522                sage: W = ComplexReflectionGroup((1,1,3))
     1523                sage: for w in W: print w.reduced_word(), w.is_coxeter_element()
     1524                 False
     1525                0 False
     1526                1 False
     1527                01 True
     1528                10 True
     1529                010 False
     1530            """
     1531            assert self.parent().is_well_generated()
     1532            h = self.parent().coxeter_number()
     1533            # to check regularity for a Coxeter number h, we get that an eigenvector is regular for free
     1534            return any( QQ(ev).denom() == h and QQ(ev).numer() == which_primitive for ev in self.reflection_eigenvalues(test_class_repr=test_class_repr) )
     1535
     1536        @cached_in_parent_method
     1537        def is_h_regular(self,test_class_repr=True):
     1538            r"""
     1539            Returns True if self is regular. I.e., self has an eigenvector
     1540            with eigenvalue `h` and which does not lie in any reflecting hyperplane.
     1541            Here, `h` denotes the *Coxeter number* of ``self.parent()``.
     1542
     1543            EXAMPLES::
     1544
     1545                sage: W = ComplexReflectionGroup((1,1,3))
     1546                sage: for w in W: print w.reduced_word(), w.is_h_regular()
     1547                 False
     1548                0 False
     1549                1 False
     1550                01 True
     1551                10 True
     1552                010 False
     1553            """
     1554            assert self.parent().is_well_generated()
     1555            h = self.parent().coxeter_number()
     1556            # to check regularity for a Coxeter number h, we get that an eigenvector is regular for free
     1557            return any( QQ(ev).denom() == h for ev in self.reflection_eigenvalues(test_class_repr=test_class_repr) )
     1558
     1559        @cached_in_parent_method
     1560        def is_regular(self,h,test_class_repr=True):
     1561            r"""
     1562            Returns True if self is regular. I.e., self has an eigenvector
     1563            with eigenvalue `h` and which does not lie in any reflecting hyperplane.
     1564            Here, `h` denotes the *Coxeter number* of ``self.parent()``.
     1565
     1566            EXAMPLES::
     1567
     1568                sage: W = ComplexReflectionGroup((1,1,3))
     1569                sage: for w in W: print w.reduced_word(), w.is_regular(W.coxeter_number())
     1570                 False
     1571                0 False
     1572                1 False
     1573                01 True
     1574                10 True
     1575                010 False
     1576            """
     1577            assert self.parent().is_well_generated()
     1578            evs = self.reflection_eigenvalues(test_class_repr=test_class_repr)
     1579            for ev in evs:
     1580                ev = QQ(ev)
     1581                if h == ev.denom():
     1582                    M = Matrix(UCF,(self.as_matrix()-E(ev.denom(),ev.numer())*identity_matrix(self.parent().rank())))
     1583                    V = M.right_kernel()
     1584                    if not any( V.is_subspace(H) for H in self.parent().reflecting_hyperplanes() ):
     1585                        return True
     1586            return False
     1587
     1588def ComplexReflectionGroup(*args,**kwds):
     1589    r"""
     1590    Construct a finite (complex) reflection group as a Sage permutation group by
     1591    fetching the permutation representation of the generators from chevie's database.
     1592
     1593    INPUT:
     1594
     1595    can be one of the following:
     1596
     1597    - (a) integer between 4 and 37, which denotes an exeptional irreducible complex reflection group
     1598    - (b) triple (r,p,n) with p divides r, which denotes the group G(r,p,n)
     1599    - (c) list containing objects in (a) and (b)
     1600
     1601    EXAMPLES:
     1602   
     1603    Finite reflection groups can be constructed from
     1604
     1605    the complex infinite family `G(r,p,n)` with `p` divides `r`::
     1606
     1607        sage: W = ComplexReflectionGroup((1,1,4)); W
     1608        Irreducible finite complex reflection group of rank 3 and type A3
     1609
     1610        sage: W = ComplexReflectionGroup((2,1,3)); W
     1611        Irreducible finite complex reflection group of rank 3 and type B3
     1612
     1613    Chevalley-Shepard-Todd exceptional classification types::
     1614
     1615        sage: W = ComplexReflectionGroup(23); W
     1616         Irreducible finite complex reflection group of rank 3 and type H3
     1617
     1618    lists containing the above::
     1619
     1620        sage: W = ComplexReflectionGroup((1,1,4),(2,1,3)); W
     1621        Reducible finite complex reflection group of rank 6 and type A3 x B3
     1622    """
     1623    assert is_chevie_available()
     1624    gap3.load_package("chevie")
     1625
     1626    W_types = []
     1627    for arg in args:
     1628        if type(arg) is list:
     1629            X = tuple(arg)
     1630        else:
     1631            X = arg
     1632        assert is_Matrix(X) or isinstance(X,CartanMatrix) or isinstance(X,tuple) or ( X in ZZ and 4 <= X <= 37 ), "The input is not valid."
     1633        if X == (2,2,2):
     1634            W_types.extend([(1,1,2),(1,1,2)])
     1635        else:
     1636            W_types.append(X)
     1637
     1638    for index_set_kwd in ['index_set','hyperplane_index_set','reflection_index_set']:
     1639        index_set = kwds.get(index_set_kwd, None)
     1640        if index_set is not None:
     1641            from sage.sets.family import Family
     1642            if type(index_set) in [list,tuple]:
     1643                kwds[index_set_kwd] = Family(index_set, lambda x: index_set.index(x))
     1644            elif type(index_set) is dict:
     1645                kwds[index_set_kwd] = Family(index_set)
     1646            else:
     1647                raise ValueError, 'The keyword %s must be a list, tuple, or dict'%index_set_kwd
     1648
     1649    if len(W_types) == 1:
     1650        cls = IrreducibleFiniteComplexReflectionGroup
     1651    else:
     1652        cls = FiniteComplexReflectionGroup
     1653    return cls(tuple(W_types), index_set=kwds.get('index_set', None),
     1654                               hyperplane_index_set=kwds.get('hyperplane_index_set', None),
     1655                               reflection_index_set=kwds.get('reflection_index_set', None) )
     1656
     1657def gap_factorization(w,gens,inv_dict):
     1658    gap3.execute('W := GroupWithGenerators(%s)'%str(gens))
     1659    gap3.execute(gap_factorization_code)
     1660    fac = gap3('MinimalWord(W,%s)'%str(w)).sage()
     1661    return [ inv_dict[i-1] for i in fac ]
     1662
     1663gap_factorization_code = '# MinimalWord(G,w) \n \
     1664# given a permutation group G find some expression of minimal length in the \n \
     1665# generators of G and their inverses of the element w (an inverse is \n \
     1666# representated by a negative index). \n \
     1667# To speed up  later calls to  the same function  the fields G.base, G.words, \n \
     1668# G.nbwordslength are kept. \n \
     1669MinimalWord:=function(G,w) \n \
     1670  local decode,i,p,g,h,n,bag,nbe,nbf,new,gens,inds; \n \
     1671# to save space elements of G are represented as image of the base, and \n \
     1672# words are represented as: index of previous elt, last generator applied; \n \
     1673  if not IsBound(G.base) then \n \
     1674    StabChain(G);g:=G; G.base:=[]; \n \
     1675    while IsBound(g.orbit) do Add(G.base,g.orbit[1]); g:=g.stabilizer; od; \n \
     1676  fi; \n \
     1677  w:=OnTuples(G.base,w); \n \
     1678  if not IsBound(G.words) then \n \
     1679    G.words:=[G.base]; G.lastmult:=[[0,0]]; \n \
     1680    G.nbwordslength:=[1]; \n \
     1681  fi; \n \
     1682  gens:=ShallowCopy(G.generators);inds:=[1..Length(gens)]; \n \
     1683#  for g in G.generators do \n \
     1684#    if g<>g^-1 then Add(gens,g^-1);Add(inds,-Position(gens,g));fi; \n \
     1685#  od; \n \
     1686  bag:=Set(G.words); \n \
     1687  nbe:=0;nbf:=0; \n \
     1688  decode:=function(i)local w;w:=[]; \n \
     1689    while i<>1 do Add(w,G.lastmult[i][2]); i:=G.lastmult[i][1];od; \n \
     1690    return Reversed(w); \n \
     1691  end; \n \
     1692  while true do \n \
     1693    if w in bag then return decode(Position(G.words,w));fi; \n \
     1694    new:=Length(G.words); \n \
     1695    for g in [1..Length(gens)] do \n \
     1696      for h in [1+Sum(G.nbwordslength{[1..Length(G.nbwordslength)-1]})..new] do \n \
     1697         n:=OnTuples(G.words[h],gens[g]); \n \
     1698         if n in bag then \n \
     1699           nbe:=nbe+1;# if nbe mod 500=1 then Print(".\c");fi; \n \
     1700         else \n \
     1701           nbf:=nbf+1;# if nbf mod 500=1 then Print("*\c");fi; \n \
     1702       Add(G.words,n);Add(G.lastmult,[h,inds[g]]);AddSet(bag,n); \n \
     1703         fi; \n \
     1704       od; \n \
     1705    od; \n \
     1706    Add(G.nbwordslength,Length(G.words)-new); \n \
     1707    Print("\n",G.nbwordslength[Length(G.nbwordslength)]," elements of length ", \n \
     1708      Length(G.nbwordslength)-1); \n \
     1709  od; \n \
     1710end;'
     1711
     1712def gap_return(S,coerce_obj='self'):
     1713    S = S.replace(' ','').replace('\n','')
     1714    S = S.replace(',(','\',check=False),%s(\'('%coerce_obj).replace('[','[%s(\''%coerce_obj).replace(']','\',check=False)]')
     1715    return S
     1716
     1717@cached_function
     1718def is_chevie_available():
     1719    r"""
     1720    Tests whether the GAP3 Chevie package is available
     1721
     1722    EXAMPLES::
     1723
     1724        sage: from sage.combinat.root_system.coxeter_group import is_chevie_available
     1725        sage: is_chevie_available() # random
     1726        False
     1727        sage: is_chevie_available() in [True, False]
     1728        True
     1729    """
     1730    try:
     1731        from sage.interfaces.gap3 import gap3
     1732        gap3.load_package("chevie")
     1733        return True
     1734    except:
     1735        return False
  • 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  
    1 """
    2 Coxeter Groups
     1r"""
     2Coxeter groups
     3
     4AUTHORS:
     5
     6- Christian Stump
     7
     8.. note::
     9
     10    - For definitions and classification types of finite complex reflection groups, see http://en.wikipedia.org/wiki/Complex_reflection_group.
     11    - Uses the GAP3 package *chevie*.
     12
     13Version: 2011-04-26
     14
     15EXAMPLES::
     16
     17
    318"""
    419#*****************************************************************************
    5 #       Copyright (C) 2010 Nicolas Thiery <nthiery at users.sf.net>
     20#       Copyright (C) 2011 Christian Stump <christian.stump at lacim.ca>
    621#
    722#  Distributed under the terms of the GNU General Public License (GPL)
    823#
    924#                  http://www.gnu.org/licenses/
    1025#*****************************************************************************
    11 
    12 from sage.misc.cachefunc import cached_function, cached_method
     26from copy import copy
     27from sage.misc.all import prod
     28from sage.misc.cachefunc import cached_function, cached_method, cached_in_parent_method
    1329from sage.categories.category import Category
    14 from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups
    1530from sage.categories.finite_permutation_groups import FinitePermutationGroups
    1631from sage.groups.perm_gps.permgroup_element import PermutationGroupElement
    1732from sage.combinat.root_system.weyl_group import WeylGroup
    from sage.structure.unique_representatio 
    1934from sage.structure.parent import Parent
    2035from sage.combinat.root_system.cartan_type import CartanType
    2136from sage.groups.perm_gps.permgroup import PermutationGroup_generic
     37from sage.rings.all import ZZ, QQ
     38from sage.matrix.all import Matrix, identity_matrix
     39from sage.matrix.matrix import is_Matrix
     40from sage.interfaces.gap3 import GAP3Record, gap3
     41from sage.interfaces.gap import gap
     42from sage.combinat.words.word import Word
     43from sage.rings.arith import gcd, lcm
     44from sage.combinat.root_system.complex_reflection_group import FiniteComplexReflectionGroup, IrreducibleFiniteComplexReflectionGroup, is_chevie_available
     45from sage.categories.coxeter_groups import CoxeterGroups
     46from sage.combinat.root_system.cartan_matrix import CartanMatrix
    2247
    23 def CoxeterGroup(cartan_type, implementation = None):
    24     """
    25     INPUT:
    26 
    27      - ``cartan_type`` -- a cartan type (or coercible into; see :class:`CartanType`)
    28      - ``implementation`` -- "permutation", "matrix", or None (default: None)
    29 
    30     Returns an implementation of the Coxeter group of type
    31     ``cartan_type``.
    32 
    33     EXAMPLES:
    34 
    35     If ``implementation`` is not specified, a permutation
    36     representation is returned whenever possible (finite irreducible
    37     Cartan type, with the GAP3 Chevie package available)::
    38 
    39         sage: W = CoxeterGroup(["A",2])
    40         sage: W                                   # optional (requires chevie)
    41         Permutation Group with generators [(1,3)(2,5)(4,6), (1,4)(2,3)(5,6)]
    42 
    43     Otherwise, a Weyl group is returned::
    44 
    45         sage: W = CoxeterGroup(["A",3,1])
    46         sage: W
    47         Weyl Group of type ['A', 3, 1] (as a matrix group acting on the root space)
    48 
    49     We now use the ``implementation`` option::
    50 
    51         sage: W = CoxeterGroup(["A",2], implementation = "permutation") # optional (requires chevie)
    52         sage: W                                                         # optional (requires chevie)
    53         Permutation Group with generators [(1,3)(2,5)(4,6), (1,4)(2,3)(5,6)]
    54         sage: W.category()                       # optional (requires chevie)
    55         Join of Category of finite permutation groups and Category of finite coxeter groups
    56 
    57         sage: W = CoxeterGroup(["A",2], implementation = "matrix")
    58         sage: W
    59         Weyl Group of type ['A', 2] (as a matrix group acting on the ambient space)
    60 
    61         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
    65 
    66         sage: W = CoxeterGroup(["A",4,1], implementation = "permutation")
    67         Traceback (most recent call last):
    68         ...
    69         NotImplementedError: Coxeter group of type ['A', 4, 1] as permutation group not implemented
    70 
    71     """
    72     assert implementation in ["permutation", "matrix", None]
    73     cartan_type = CartanType(cartan_type)
    74 
    75     if implementation is None:
    76         if cartan_type.is_finite() and cartan_type.is_irreducible() and is_chevie_available():
    77             implementation = "permutation"
    78         else:
    79             implementation = "matrix"
    80 
    81     if implementation == "permutation" and is_chevie_available() and \
    82        cartan_type.is_finite() and cartan_type.is_irreducible():
    83         return CoxeterGroupAsPermutationGroup(cartan_type)
    84     elif implementation == "matrix" and cartan_type.is_crystalographic():
    85         return WeylGroup(cartan_type)
    86     else:
    87         raise NotImplementedError, "Coxeter group of type %s as %s group not implemented "%(cartan_type, implementation)
    88 
    89 @cached_function
    90 def is_chevie_available():
    91     r"""
    92     Tests whether the GAP3 Chevie package is available
    93 
    94     EXAMPLES::
    95 
    96         sage: from sage.combinat.root_system.coxeter_group import is_chevie_available
    97         sage: is_chevie_available() # random
    98         False
    99         sage: is_chevie_available() in [True, False]
    100         True
    101     """
    102     try:
    103         from sage.interfaces.gap3 import gap3
    104         gap3.load_package("chevie")
    105         return True
    106     except:
    107         return False
    108 
    109 class CoxeterGroupAsPermutationGroup(UniqueRepresentation, PermutationGroup_generic):
    110 
    111     @staticmethod
    112     def __classcall__(cls, cartan_type):
    113         """
     48class FiniteCoxeterGroup(FiniteComplexReflectionGroup):
     49    def __init__(self, W_types, index_set=None, hyperplane_index_set=None, reflection_index_set=None):
     50        r"""
    11451        TESTS::
    11552
    116             sage: from sage.combinat.root_system.coxeter_group import CoxeterGroupAsPermutationGroup
    117             sage: W1 = CoxeterGroupAsPermutationGroup(CartanType(["H",3])) # optional (require chevie)
    118             sage: W2 = CoxeterGroupAsPermutationGroup(["H",3])             # optional (require chevie)
    119             sage: W1 is W2                                                 # optional (require chevie)
    120             True
     53            sage: W = CoxeterGroups().example()
     54            sage: TestSuite(W).run()
    12155        """
    122         cartan_type = CartanType(cartan_type)
    123         return super(CoxeterGroupAsPermutationGroup, cls).__classcall__(cls, cartan_type)
     56        W_types = tuple( tuple( W_type ) if isinstance(W_type,(list,tuple)) else W_type for W_type in W_types )
     57        cartan_types = []
     58        for W_type in W_types:
     59            W_type = CartanType(W_type)
     60            assert W_type.is_finite()
     61            assert W_type.is_irreducible()
     62            cartan_types.append( W_type )
     63        if len(W_types) == 1:
     64            cls = IrreducibleFiniteComplexReflectionGroup
     65        else:
     66            cls = FiniteComplexReflectionGroup
     67        cls.__init__(self, W_types, index_set=index_set,
     68                                    hyperplane_index_set=hyperplane_index_set,
     69                                    reflection_index_set=reflection_index_set,
     70                                    is_coxeter_group = True)
     71        N = self.nr_reflections()
     72        self._is_positive_root = [None] + [ True ] * N + [False]*N
    12473
    125     def __init__(self, cartan_type):
     74    __iter__ = CoxeterGroups.ParentMethods.__iter__.__func__
     75
     76    def _repr_(self):
     77        r"""
     78        Returns the string representation of ``self``.
     79
     80        EXAMPLES::
     81       
     82            sage: W = CoxeterGroup(['A',3],['B',2],['I',5],['I',6]); W
     83            Reducible finite Coxeter group of rank 9 and type A3 x B2 x I2(5) x G2
    12684        """
    127         Construct this Coxeter group as a Sage permutation group, by
    128         fetching the permutation representation of the generators from
    129         Chevie's database.
     85        type_str = ''
     86        for W_type in self._type:
     87            type_str += self._irrcomp_repr_(W_type)
     88            type_str += ' x '
     89        type_str = type_str[:-3]
     90        return 'Reducible finite Coxeter group of rank %s and type %s'%(self._rank,type_str)
    13091
    131         TESTS::
    132 
    133             sage: from sage.combinat.root_system.coxeter_group import CoxeterGroupAsPermutationGroup
    134             sage: W = CoxeterGroupAsPermutationGroup(CartanType(["H",3])) # optional (require chevie)
    135             sage: TestSuite(W).run()             # optional (require chevie)
    136         """
    137         assert cartan_type.is_finite()
    138         assert cartan_type.is_irreducible()
    139         self._semi_simple_rank = cartan_type.n
    140         from sage.interfaces.gap3 import gap3
    141         gap3.load_package("chevie")
    142         self._gap_group = gap3('CoxeterGroup("%s",%s)'%(cartan_type.letter,cartan_type.n))
    143         # Following #9032, x.N is an alias for x.numerical_approx in every Sage object ...
    144         N = self._gap_group.__getattr__("N").sage()
    145         generators = [str(x) for x in self._gap_group.generators]
    146         self._is_positive_root = [None] + [ True ] * N + [False]*N
    147         PermutationGroup_generic.__init__(self, gens = generators,
    148                                           category = Category.join([FinitePermutationGroups(), FiniteCoxeterGroups()]))
    149 
    150     def _element_class(self):
    151         """
    152         A temporary workaround for compatibility with Sage's
    153         permutation groups
    154 
    155         TESTS::
    156 
    157             sage: W = CoxeterGroup(["H",3])                                  # optional (require chevie)
    158             sage: W._element_class() is W.element_class                      # optional (require chevie)
    159             True
    160         """
    161         return self.element_class
    162 
    163     def index_set(self):
    164         """
    165         Returns the index set of this Coxeter group
     92    @cached_method
     93    def bipartite_index_set(self):
     94        r"""
     95        Returns the bipartite index set of a finite real reflection group.
    16696
    16797        EXAMPLES::
    16898
    169             sage: W = CoxeterGroup(["H",3], implementation = "permutation")  # optional (requires chevie)
    170             sage: W.index_set() # optional (requires chevie)
    171             [1, 2, 3]
     99            sage: W = CoxeterGroup(["A",5])
     100            sage: W.bipartite_index_set()
     101            [[0, 2, 4], [1, 3]]
    172102
     103            sage: W = CoxeterGroup(["A",5],index_set=['a','b','c','d','e'])
     104            sage: W.bipartite_index_set()
     105            [['a', 'c', 'e'], ['b', 'd']]
    173106        """
    174         return range(1, self._semi_simple_rank+1)
     107        index_family = self._index_set
     108        keys = index_family.keys()
     109        L,R = self._gap_group.BipartiteDecomposition().sage()
     110        L = [ i for i in keys if index_family[i]+1 in L ]
     111        R = [ i for i in keys if index_family[i]+1 in R ]
     112        return [L,R]
    175113
    176     @cached_method
    177     def reflection(self, i):
    178         """
    179         Returns the `i`-th reflection of ``self``.
    180 
    181         For `i` in `1,\dots,n`, this gives the `i`-th simple
    182         reflection of ``self``.
    183 
    184         TODO: those tests fail; double check them
     114    def irreducible_components(self):
     115        r"""
     116        Returns a list containing the irreducible components of ``self`` as finite reflection groups.
    185117
    186118        EXAMPLES::
    187119
    188             sage: W = CoxeterGroup(["H",3], implementation = "permutation") # optional (requires chevie)
    189             sage: W.simple_reflection(1) # optional (requires chevie)
    190             (1,4)(2,3)(5,6)
    191             sage: W.simple_reflection(2) # optional (requires chevie)
    192             (1,3)(2,5)(4,6)
    193             sage: W.simple_reflection(3) # optional (requires chevie)
    194             (1,5)(2,4)(3,6)
    195             sage: W.reflection(4)        # optional (requires chevie)
    196             (1,4)(2,3)(5,6)
    197             sage: W.reflection(5)        # optional (requires chevie)
    198             (1,3)(2,5)(4,6)
    199             sage: W.reflection(6)        # optional (requires chevie)
    200             (1,5)(2,4)(3,6)
     120            tba
    201121        """
    202         return self(str(self._gap_group.Reflection(i)))
     122        if self.nr_irreducible_components() == 1:
     123            irr_comps = [self]
     124        else:
     125            irr_comps = []
     126            for W_type in self._type:
     127                W_str = [ W_type["series"], W_type["rank"] ]
     128                if W_type["series"] == "I":
     129                    W_str[1] = W_type["bond"]
     130                irr_comps.append( CoxeterGroup(W_str) )
     131        return irr_comps
    203132
    204     simple_reflection = reflection
     133    def cartan_type(self):
     134        if len(self._type) == 1:
     135            ct = self._type[0]
     136            return CartanType([ct['series'],ct['rank']])
     137        else:
     138            return [ W.cartan_type() for W in self.irreducible_components() ]
    205139
    206     class Element(PermutationGroupElement):
     140    @cached_method
     141    def cartan_matrix(self):
     142        from sage.matrix.constructor import matrix
     143        return matrix(self._gap_group.CartanMat().sage())
    207144
    208         def has_descent(self, i, side = 'right', positive=False):
    209             """
    210             Returns whether `i` is a (left/right) descent of ``self``.
     145    def simple_root(self,i):
     146        return self.simple_roots()[self._index_set[i]]
    211147
    212             See :meth:`.descents` for a description of the options.
     148    def positive_roots(self):
     149        return self.roots()[:self.nr_reflections()]
    213150
    214             EXAMPLES::
     151    def almost_positive_roots(self):
     152        return [ -beta for beta in self.simple_roots() ] + self.positive_roots()
    215153
    216                 sage: W = CoxeterGroup(["A",3])
    217                 sage: s = W.simple_reflections()
    218                 sage: w = s[1] * s[2] * s[3]
    219                 sage: w.has_descent(3)
    220                 True
    221                 sage: [ w.has_descent(i)                  for i in [1,2,3] ]
    222                 [False, False, True]
    223                 sage: [ w.has_descent(i, side = 'left')   for i in [1,2,3] ]
    224                 [True, False, False]
    225                 sage: [ w.has_descent(i, positive = True) for i in [1,2,3] ]
    226                 [True, True, False]
     154    def root_to_reflection(self,root):
     155        Phi = self.roots()
     156        R = self.reflections()
     157        i = Phi.index(root)+1
     158        j = Phi.index(-root)+1
     159        for r in R:
     160            if r(i) == j:
     161                return r
     162        raise ValueError, "There is a bug in root_to_reflection!"
    227163
    228             This implementation is a plain copy of that of
    229             ``CoxeterGroups``. It is there as a workaround since
    230             `PermutationGroupElement` currently redefines abusively
    231             :meth:`has_descent` as if the group was the full symmetric
    232             group.
    233             """
    234             assert isinstance(positive, bool)
    235             if side == 'right':
    236                 return self.has_right_descent(i) != positive
    237             else:
    238                 assert side == 'left'
    239                 return self.has_left_descent(i)  != positive
     164    def reflection_to_positive_root(self,r):
     165        Phi = self.roots()
     166        N = len(Phi)/2
     167        for i in range(1,N+1):
     168            if r(i) == i+N:
     169                return Phi[i-1]
     170        raise ValueError, "There is a bug in reflection_to_positive_root!"
     171
     172    @cached_method
     173    def fundamental_weights(self):
     174        m = self.cartan_matrix().transpose().inverse()
     175        S = self.simple_roots()
     176        zero = S[0] - S[0]
     177        weights = [ sum( [ m[i,j] * S[j] for j in range(len(S)) ], zero ) for i in range(len(S)) ]
     178        for weight in weights:
     179            weight.set_immutable()
     180        return weights
     181
     182    def fundamental_weight(self,i):
     183        return self.fundamental_weights()[self._index_set[i]]
     184
     185    def permutahedron(self,coefficients=None):
     186        n = self.rank()
     187        weights = self.fundamental_weights()
     188        if coefficients is None:
     189            coefficients = [1]*n
     190        v = sum( coefficients[i] * weights[i] for i in range(n) )
     191        from sage.geometry.polyhedron.constructor import Polyhedron
     192        return Polyhedron( vertices=[ v*(~w).as_matrix() for w in self] )
     193
     194    class Element(FiniteComplexReflectionGroup.Element):
     195
     196        has_descent = CoxeterGroups.ElementMethods.has_descent.__func__
     197        reduced_word = cached_in_parent_method(CoxeterGroups.ElementMethods.reduced_word.__func__)
    240198
    241199        def has_left_descent(self, i):
    242200            r"""
    class CoxeterGroupAsPermutationGroup(Uni 
    245203
    246204            EXAMPLES::
    247205
    248                 sage: W = CoxeterGroup(["A",3], implementation = "permutation") # optional (requires chevie)
    249                 sage: s = W.simple_reflections() # optional (requires chevie)
    250                 sage: (s[1]*s[2]).has_left_descent(1) # optional (requires chevie)
     206                sage: W = CoxeterGroup(["A",3])
     207                sage: s = W.simple_reflections()
     208                sage: (s[1]*s[2]).has_left_descent(1)
    251209                True
    252                 sage: (s[1]*s[2]).has_left_descent(2) # optional (requires chevie)
     210                sage: (s[1]*s[2]).has_left_descent(2)
    253211                False
    254212            """
    255             return not self.parent()._is_positive_root[self(i)]
     213            W = self.parent()
     214            assert i in W.index_set()
     215            return not W._is_positive_root[self(W._index_set[i]+1)]
    256216
    257         def __cmp__(self, other):
    258             r"""
    259             Without this comparison method, the initialization of this
    260             permutation group fails ...
     217        def act_on_root(self,root):
     218            Phi = self.parent().roots()
     219            return Phi[ (~self)(Phi.index(root)+1)-1 ]
    261220
    262             EXAMPLES::
     221        def inversion_set(self):
     222            Phi_plus = set(self.parent().positive_roots())
     223            return [ root for root in Phi_plus if self.act_on_root(root) not in Phi_plus ]
    263224
    264                 sage: W = CoxeterGroup(["B",3], implementation = "permutation") # optional (requires chevie)
    265                 sage: cmp(W.an_element(), W.one())        # optional (requires chevie)
    266                 1
    267             """
    268             return super(CoxeterGroupAsPermutationGroup.Element, self).__cmp__(other)
     225class IrreducibleFiniteCoxeterGroup(FiniteCoxeterGroup, IrreducibleFiniteComplexReflectionGroup):
     226
     227    def _repr_(self):
     228        r"""
     229        Returns the string representation of ``self``.
     230
     231        EXAMPLES::
     232
     233            sage: for i in [2..7]: print CoxeterGroup(["I",i])
     234            Reducible finite Coxeter group of rank 2 and type A1 x A1
     235            Irreducible finite Coxeter group of rank 2 and type A2
     236            Irreducible finite Coxeter group of rank 2 and type B2
     237            Irreducible finite Coxeter group of rank 2 and type I2(5)
     238            Irreducible finite Coxeter group of rank 2 and type G2
     239            Irreducible finite Coxeter group of rank 2 and type I2(7)
     240        """
     241        type_str = self._irrcomp_repr_(self._type[0])
     242        return 'Irreducible finite Coxeter group of rank %s and type %s'%(self._rank,type_str)
     243
     244    class Element(FiniteCoxeterGroup.Element,IrreducibleFiniteComplexReflectionGroup.Element):
     245        pass
     246
     247def CoxeterGroup(*args,**kwds):
     248    """
     249    INPUT:
     250
     251     - every argument should be a finite cartan type, or coercible into; see :class:`CartanType`)
     252
     253    OUTPUT:
     254
     255    Returns the Coxeter group as a finite reflection group, see :func:`ComplexReflectionGroup`.
     256
     257    .. warning:: works only if the GAP3 package Chevie is available, use :func:`WeylGroup` otherwise.
     258
     259    EXAMPLES::
     260
     261        sage: W = CoxeterGroup(["A",2]); W                  # optional (requires chevie)
     262        Permutation Group with generators [(1,3)(2,5)(4,6), (1,4)(2,3)(5,6)]
     263
     264        sage: W.category()                                  # optional (requires chevie)
     265        Join of Category of finite permutation groups and Category of finite coxeter groups
     266    """
     267    assert is_chevie_available()
     268    gap3.load_package("chevie")
     269
     270    W_types = []
     271    for arg in args:
     272        if type(arg) is list:
     273            X = tuple(arg)
     274        else:
     275            X = arg
     276        assert is_Matrix(X) or isinstance(X,CartanMatrix) or isinstance(X,tuple), "The input is not valid."
     277        if X == ('I',2):
     278            W_types.extend([('A',1),('A',1)])
     279        else:
     280            W_types.append(X)
     281
     282    for index_set_kwd in ['index_set','hyperplane_index_set','reflection_index_set']:
     283        index_set = kwds.get(index_set_kwd, None)
     284        if index_set is not None:
     285            from sage.sets.family import Family
     286            if type(index_set) in [list,tuple]:
     287                kwds[index_set_kwd] = Family(index_set, lambda x: index_set.index(x))
     288            elif type(index_set) is dict:
     289                kwds[index_set_kwd] = Family(index_set)
     290            else:
     291                raise ValueError, 'The keyword %s must be a list, tuple, or dict'%index_set_kwd
     292
     293    if len(W_types) == 1:
     294        cls = IrreducibleFiniteCoxeterGroup
     295    else:
     296        cls = FiniteCoxeterGroup
     297    return cls(tuple(W_types), index_set=kwds.get('index_set', None),
     298                               hyperplane_index_set=kwds.get('hyperplane_index_set', None),
     299                               reflection_index_set=kwds.get('reflection_index_set', None) )
  • 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 class DynkinDiagram_class(DiGraph, Carta 
    231231        """
    232232        return self._cartan_type
    233233
     234    def is_finite(self):
     235        if self.cartan_type():
     236            return self.cartan_type().is_finite()
     237
     238    def is_affine(self):
     239        if self.cartan_type():
     240            return self.cartan_type().is_affine()
     241
    234242    def rank(self):
    235243        r"""
    236244        Returns the index set for this Dynkin diagram
    class DynkinDiagram_class(DiGraph, Carta 
    268276            [ 0 -1  2]
    269277        """
    270278        from sage.matrix.constructor import identity_matrix
    271         from sage.rings.all import ZZ
     279        from sage.rings.all import ZZ, UCF
    272280        index_set = self.index_set()
    273281        reverse = dict((index_set[i], i) for i in range(len(index_set)))
    274282        m = 2*identity_matrix(ZZ, len(self.index_set()), sparse=True)
    275283        for (i,j,l) in self.edge_iterator():
     284            if l not in ZZ:
     285                m = m.base_extend(UCF)
    276286            m[reverse[j], reverse[i]] = -l
    277287        m.set_immutable()
    278288        return m
  • sage/combinat/root_system/root_lattice_realizations.py

    diff --git a/sage/combinat/root_system/root_lattice_realizations.py b/sage/combinat/root_system/root_lattice_realizations.py
    a b from sage.categories.coxeter_groups impo 
    2727from sage.categories.category_types import Category_over_base_ring
    2828from sage.categories.modules_with_basis import ModulesWithBasis
    2929from sage.sets.family import Family
    30 from sage.rings.all import ZZ, QQ
    31 from sage.combinat.backtrack import TransitiveIdeal, TransitiveIdealGraded
     30from sage.rings.all import ZZ, QQ, UCF
     31from sage.combinat.backtrack import TransitiveIdealGraded
    3232from sage.misc.superseded import deprecated_function_alias
    3333from sage.structure.element import Element
    3434from copy import copy
    class RootLatticeRealizations(Category_o 
    505505            Algorithm: generate them from the simple roots by applying
    506506            successive reflections toward the positive chamber.
    507507            """
    508             assert self.cartan_type().is_finite()
     508            #assert self.cartan_type().is_finite() or self.weyl_group().is_finite()
    509509            return TransitiveIdealGraded(attrcall('pred'), self.simple_roots())
    510510
    511511        @cached_method
    class RootLatticeRealizations(Category_o 
    691691                        rels.append((root,root_cover))
    692692            return Poset((pos_roots,rels),cover_relations=True,facade=facade)
    693693
     694        def positive_root_poset(self,facade=False):
     695            Phi = self.positive_roots()
     696            from sage.combinat.posets.posets import Poset
     697            covers = [ (beta,beta.simple_reflection(i)) for beta in Phi for i in beta.descents() ]
     698            return Poset((Phi,covers),cover_relations=True,facade=facade)           
     699
    694700        def almost_positive_roots(self):
    695701            r"""
    696702            Returns the almost positive roots of ``self``
    class RootLatticeRealizations(Category_o 
    721727            Algorithm: negate the positive roots
    722728
    723729            """
    724             assert self.cartan_type().is_finite()
     730            assert self.cartan_type().is_finite() or self.weyl_group().is_finite()
    725731            from sage.combinat.combinat import MapCombinatorialClass
    726732            return MapCombinatorialClass(self.positive_roots(), attrcall('__neg__'), "The negative roots of %s"%self)
    727733            # Todo: use this instead once TransitiveIdeal will be a proper enumerated set
    class RootLatticeRealizations(Category_o 
    743749            """
    744750            return self.root_system.coroot_lattice()
    745751
    746         def coroot_space(self, base_ring = QQ):
     752        def coroot_space(self, base_ring = UCF):
    747753            """
    748754            Returns the coroot space over ``base_ring``
    749755
    class RootLatticeRealizations(Category_o 
    18151821                sage: len(L.fundamental_weights()[2].orbit())
    18161822                6
    18171823            """
    1818             return [x for x in TransitiveIdeal(attrcall('simple_reflections'), [self])]
     1824            return [x for x in TransitiveIdealGraded(attrcall('simple_reflections'), [self])]
    18191825
    18201826        ##########################################################################
    18211827        #
    class RootLatticeRealizations(Category_o 
    21682174                sage: sorted([len(x.greater()) for x in L.rho().orbit()])
    21692175                [1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 8, 8, 8, 8, 12, 12, 12, 24]
    21702176            """
    2171             return [x for x in TransitiveIdeal(attrcall('succ'), [self])]
     2177            return [x for x in TransitiveIdealGraded(attrcall('succ'), [self])]
    21722178
    21732179        def smaller(self):
    21742180            r"""
    class RootLatticeRealizations(Category_o 
    21882194                sage: sorted([len(x.smaller()) for x in L.rho().orbit()])
    21892195                [1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 8, 8, 8, 8, 12, 12, 12, 24]
    21902196            """
    2191             return [x for x in TransitiveIdeal(attrcall('pred'), [self])]
     2197            return [x for x in TransitiveIdealGraded(attrcall('pred'), [self])]
    21922198
    21932199        ##########################################################################
    21942200        # Level
    class RootLatticeRealizations(Category_o 
    23512357            alphavee = self.parent().coroot_lattice().basis()
    23522358            return [i for i in index_set if self.scalar(alphavee[i]) == 0]
    23532359
     2360        def to_negative(self):
     2361            if not self.is_positive_root():
     2362                return []
     2363            i = self.first_descent(positive=True)
     2364            return self.simple_reflection(i).to_negative() + [i]
     2365
     2366        def length(self):
     2367            return len(self.to_negative())
     2368
    23542369        def is_parabolic_root(self, index_set):
    23552370            r"""
    23562371            Supposing that `self` is a root, is it in the parabolic subsystem with Dynkin nodes `index_set`?
  • sage/combinat/root_system/root_space.py

    diff --git a/sage/combinat/root_system/root_space.py b/sage/combinat/root_system/root_space.py
    a b Root lattices and root spaces 
    99#*****************************************************************************
    1010
    1111from sage.misc.cachefunc import ClearCacheOnPickle, cached_method, cached_in_parent_method
    12 from sage.rings.all import ZZ
     12from sage.rings.all import ZZ, QQ, UCF
    1313from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement
    1414from root_lattice_realizations import RootLatticeRealizations
    1515from sage.misc.cachefunc import cached_in_parent_method
    class RootSpace(ClearCacheOnPickle, Comb 
    6767        from sage.categories.homset import Hom
    6868        from sage.categories.sets_with_partial_maps import SetsWithPartialMaps
    6969        self.root_system = root_system
     70        if base_ring is None:
     71            if root_system.cartan_type().is_crystalographic():
     72                base_ring = QQ
     73            else:
     74                base_ring = UCF
    7075        CombinatorialFreeModule.__init__(self, base_ring,
    7176                                         root_system.index_set(),
    7277                                         prefix = "alphacheck" if root_system.dual_side else "alpha",
  • sage/combinat/root_system/root_system.py

    diff --git a/sage/combinat/root_system/root_system.py b/sage/combinat/root_system/root_system.py
    a b class RootSystem(UniqueRepresentation, S 
    269269            self.dual_side = True
    270270            self.dual = as_dual_of
    271271
     272    def is_crystalographic(self):
     273        r"""
     274        Returns True if self is crystallographic.
     275        """
     276        return self._cartan_type.is_crystalographic()
    272277
    273278    def _test_root_lattice_realizations(self, **options):
    274279        """
    class RootSystem(UniqueRepresentation, S 
    284289        tester = self._tester(**options)
    285290        options.pop('tester', None)
    286291        from sage.misc.sage_unittest import TestSuite
    287         TestSuite(self.root_lattice()).run(**options)
     292
     293        is_crystalographic = self.is_crystalographic()
     294        if is_crystalographic:
     295            TestSuite(self.root_lattice()).run(**options)
    288296        TestSuite(self.root_space()).run(**options)
    289         TestSuite(self.weight_lattice()).run(**options)
     297        if is_crystalographic:
     298            TestSuite(self.weight_lattice()).run(**options)
    290299        TestSuite(self.weight_space()).run(**options)
    291300        if self.cartan_type().is_affine():
    292             TestSuite(self.weight_lattice(extended=True)).run(**options)
     301            if is_crystalographic:
     302                TestSuite(self.weight_lattice(extended=True)).run(**options)
    293303            TestSuite(self.weight_space(extended=True)).run(**options)
    294         if self.ambient_lattice() is not None:
     304        if is_crystalographic and self.ambient_lattice() is not None:
    295305            TestSuite(self.ambient_lattice()).run(**options)
    296306        if self.ambient_space() is not None:
    297307            TestSuite(self.ambient_space()).run(**options)
    class RootSystem(UniqueRepresentation, S 
    373383        return self.cartan_type().is_finite()
    374384
    375385    @cached_method
     386    def is_affine(self):
     387        """
     388        Returns True if self is an affine root system.
     389       
     390        EXAMPLES::
     391       
     392            sage: RootSystem(["A",3]).is_affine()
     393            False
     394            sage: RootSystem(["A",3,1]).is_affine()
     395            True
     396        """
     397        return self.cartan_type().is_affine()
     398
     399    @cached_method
    376400    def is_irreducible(self):
    377401        """
    378402        Returns True if self is an irreducible root system.
    class RootSystem(UniqueRepresentation, S 
    412436            sage: RootSystem(['A',3]).root_lattice()
    413437            Root lattice of the Root system of type ['A', 3]
    414438        """
     439        assert self.is_crystalographic(), "The root lattice is only defined for crystallographic root systems."
    415440        return self.root_space(ZZ)
    416441
    417442    @cached_method
    418     def root_space(self, base_ring=QQ):
     443    def root_space(self, base_ring=None):
    419444        """
    420445        Returns the root space associated to self.
    421446       
    class RootSystem(UniqueRepresentation, S 
    455480            sage: Phi.cover_relations()
    456481            [[alpha[1], alpha[1] + alpha[2]], [alpha[2], alpha[1] + alpha[2]], [alpha[1] + alpha[2], alpha[1] + 2*alpha[2]]]
    457482        """
     483        assert self.is_crystalographic(), "The root lattice is only defined for crystallographic root systems."
    458484        return self.root_lattice().root_poset(restricted=restricted,facade=facade)
    459485
    460486    def coroot_lattice(self):
    class RootSystem(UniqueRepresentation, S 
    466492            sage: RootSystem(['A',3]).coroot_lattice()
    467493            Coroot lattice of the Root system of type ['A', 3]
    468494        """
     495        assert self.is_crystalographic(), "The root lattice is only defined for crystallographic root systems."
    469496        return self.dual.root_lattice()
    470497   
    471     def coroot_space(self, base_ring=QQ):
     498    def coroot_space(self, base_ring=None):
    472499        """
    473500        Returns the coroot space associated to self.
    474501       
    class RootSystem(UniqueRepresentation, S 
    498525            sage: RootSystem(['A',3,1]).weight_space(extended = True)
    499526            Extended weight space over the Rational Field of the Root system of type ['A', 3, 1]
    500527        """
     528        assert self.is_crystalographic(), "The root lattice is only defined for crystallographic root systems."
    501529        return WeightSpace(self, ZZ, extended = extended)
    502530
    503531    @cached_method
    504     def weight_space(self, base_ring=QQ, extended = False):
     532    def weight_space(self, base_ring=None, extended = False):
    505533        """
    506534        Returns the weight space associated to self.
    507535
    class RootSystem(UniqueRepresentation, S 
    541569            sage: RootSystem(['A',3,1]).coweight_lattice(extended = True)
    542570            Extended coweight lattice of the Root system of type ['A', 3, 1]
    543571        """
     572        assert self.is_crystalographic(), "The root lattice is only defined for crystallographic root systems."
    544573        return self.dual.weight_lattice(extended = extended)
    545574
    546     def coweight_space(self, base_ring=QQ, extended = False):
     575    def coweight_space(self, base_ring=None, extended = False):
    547576        """
    548577        Returns the coweight space associated to self.
    549578
    class RootSystem(UniqueRepresentation, S 
    588617            sage: RootSystem(['F',4]).ambient_lattice()
    589618            sage: RootSystem(['G',2]).ambient_lattice()
    590619        """
     620        assert self.is_crystalographic(), "The root lattice is only defined for crystallographic root systems."
    591621        return self.ambient_space(ZZ)
    592622
    593623    @cached_method
    594     def ambient_space(self, base_ring=QQ):
     624    def ambient_space(self, base_ring=None):
    595625        r"""
    596626        Returns the usual ambient space for this root_system, if it is
    597627        implemented, and None otherwise. This is a `\QQ`-module, endowed with
  • sage/combinat/root_system/type_H.py

    diff --git a/sage/combinat/root_system/type_H.py b/sage/combinat/root_system/type_H.py
    a b Root system data for type H 
    99#*****************************************************************************
    1010
    1111from cartan_type import CartanType_standard_finite, CartanType_simple
     12from sage.rings.universal_cyclotomic_field.universal_cyclotomic_field import E
     13
    1214class CartanType(CartanType_standard_finite, CartanType_simple):
    1315    def __init__(self, n):
    1416        """
    class CartanType(CartanType_standard_fin 
    3941        """
    4042        assert n in [3, 4]
    4143        CartanType_standard_finite.__init__(self, "H", n)
     44
     45    def dynkin_diagram(self):
     46        """
     47        Returns the Dynkin diagram of type H.
     48
     49        EXAMPLES::
     50
     51            sage: a = CartanType(['H',3]).dynkin_diagram()
     52            sage: a
     53            H3
     54            sage: sorted(a.edges())
     55        """
     56        from dynkin_diagram import DynkinDiagram_class
     57        n = self.n
     58        g = DynkinDiagram_class(self)
     59        g.add_edge(1,2)
     60        g.add_edge(2,3)
     61        g.add_edge(n-1,n,-E(5)**2-E(5)**3)
     62        g.add_edge(n,n-1,-E(5)**2-E(5)**3)
     63        return g
     64
     65    def ascii_art(self, label = lambda x: x):
     66        """
     67        Returns an ascii art representation of the Dynkin diagram
     68
     69        EXAMPLES::
     70
     71            sage: print CartanType(['A',0]).ascii_art()
     72            sage: print CartanType(['A',1]).ascii_art()
     73            O
     74            1
     75            sage: print CartanType(['A',3]).ascii_art()
     76            O---O---O
     77            1   2   3
     78            sage: print CartanType(['A',5]).ascii_art(label = lambda x: x+2)
     79            O---O---O---O---O
     80            3   4   5   6   7
     81        """
     82        n = self.n
     83        ret  = (n-2)*"O---" + "O=5=O\n"
     84        ret += "   ".join("%s"%label(i) for i in range(1,n+1))
     85        return ret
  • sage/combinat/root_system/type_I.py

    diff --git a/sage/combinat/root_system/type_I.py b/sage/combinat/root_system/type_I.py
    a b Root system data for type I 
    99#*****************************************************************************
    1010
    1111from cartan_type import CartanType_standard_finite, CartanType_simple
     12from sage.rings.universal_cyclotomic_field.all import UCF,E
    1213class CartanType(CartanType_standard_finite, CartanType_simple):
    1314    def __init__(self, n):
    1415        """
    class CartanType(CartanType_standard_fin 
    4344        assert n >= 1
    4445        CartanType_standard_finite.__init__(self, "I", n)
    4546
     47    def _repr_(self, compact = False):
     48        """
     49        TESTS::
     50
     51            sage: ct = CartanType(['I',5])
     52            sage: repr(ct)
     53            "['I', 5]"
     54            sage: ct._repr_(compact=True)
     55            'I2(5)'
     56        """
     57        format = 'I2(%s)' if compact else "['I', %s]"
     58        return format%self.n
     59
     60    def dynkin_diagram(self):
     61        """
     62        Returns a Dynkin diagram for type G.
     63
     64        EXAMPLES::
     65
     66            sage: g = CartanType(['G',2]).dynkin_diagram()
     67            sage: g
     68              3
     69            O=<=O
     70            1   2
     71            G2
     72            sage: sorted(g.edges())
     73            [(1, 2, 1), (2, 1, 3)]
     74        """
     75        from dynkin_diagram import DynkinDiagram_class
     76        g = DynkinDiagram_class(self)
     77        bond = self.n
     78        if bond % 2 == 0:
     79            label1 = 1
     80        else:
     81            label1 = E(2*bond)+E(2*bond)**-1
     82        g.add_edge(1,2,label1)
     83        label2 = -(2+E(bond)+E(bond)**-1)/label1
     84        g.add_edge(2,1,-label2)
     85        return g
     86
     87    def ascii_art(self, label = lambda x: x):
     88        """
     89        Returns an ascii art representation of the Dynkin diagram
     90
     91        EXAMPLES::
     92
     93            sage: print CartanType(['I',5]).ascii_art(label = lambda x: x+2)
     94              X
     95            O=<=O
     96            3   4
     97        """
     98        return "  X\nO=<=O\n%s   %s"%tuple(label(i) for i in (1,2))
     99
    46100    def rank(self):
    47101        """
    48102        Type `I_p` is of rank 2
  • sage/combinat/root_system/type_dual.py

    diff --git a/sage/combinat/root_system/type_dual.py b/sage/combinat/root_system/type_dual.py
    a b class CartanType(UniqueRepresentation, S 
    5151            False
    5252
    5353        """
    54         assert type.is_crystalographic()
    5554        self._dual = type
    5655        self.n = self._dual.n
    5756        if type.is_affine():
  • sage/combinat/root_system/weight_space.py

    diff --git a/sage/combinat/root_system/weight_space.py b/sage/combinat/root_system/weight_space.py
    a b from sage.misc.cachefunc import cached_m 
    1212from sage.sets.family import Family
    1313from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement
    1414from weight_lattice_realizations import WeightLatticeRealizations
     15from sage.rings.all import QQ, UCF
    1516
    1617class WeightSpace(CombinatorialFreeModule):
    1718    r"""
    class WeightSpace(CombinatorialFreeModul 
    178179            basis_keys = tuple(basis_keys) + ("delta",)
    179180
    180181        self.root_system = root_system
     182        if base_ring is None:
     183            if root_system.cartan_type().is_crystalographic():
     184                base_ring = QQ
     185            else:
     186                base_ring = UCF
    181187        CombinatorialFreeModule.__init__(self, base_ring,
    182188                                         basis_keys,
    183189                                         prefix = "Lambdacheck" if root_system.dual_side else "Lambda",
  • 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 class WeylGroup_gens(ClearCacheOnPickle, 
    275275       
    276276            sage: W = WeylGroup("B2",prefix="s")
    277277            sage: refdict = W.reflections(); refdict
    278             Finite family {s1: (1, -1), s2*s1*s2: (1, 1), s1*s2*s1: (1, 0), s2: (0, 1)}
     278            Finite family {s1*s2*s1: (1, 0), s2: (0, 1), s1: (1, -1), s2*s1*s2: (1, 1)}
    279279            sage: [refdict[r]+r.action(refdict[r]) for r in refdict.keys()]
    280280            [(0, 0), (0, 0), (0, 0), (0, 0)]
    281  
    282281        """
    283282        ret = {}
    284283        try:
    class WeylGroup_gens(ClearCacheOnPickle, 
    636635            d[x] = [y for y in g if x.length() < y.length() and ref.has_key(x*y.inverse())]
    637636        return DiGraph(d)
    638637
    639 
    640638class ClassicalWeylSubgroup(WeylGroup_gens):
    641639    """
    642640    A class for Classical Weyl Subgroup of an affine Weyl Group
  • sage/combinat/subsets_pairwise.py

    diff --git a/sage/combinat/subsets_pairwise.py b/sage/combinat/subsets_pairwise.py
    a b class PairwiseCompatibleSubsets(SearchFo 
    8383    #    ambient = Set(ambient)
    8484    #    return super(PairwiseCompatibleSubsets, cls).__classcall__(cls, ambient, predicate)
    8585
    86     __len__ = None
    87 
    8886    def __init__(self, ambient, predicate, maximal = False, element_class = Set_object_enumerated):
    8987        """
    9088        TESTS::