Ticket #6588: trac_6588-categories-root_systems-nt-before-reindentation.patch

File trac_6588-categories-root_systems-nt-before-reindentation.patch, 161.7 KB (added by nthiery, 8 years ago)

This contains the user-readable diff. Do not apply!

  • sage/algebras/affine_nil_temperley_lieb.py

    # HG changeset patch
    # User Nicolas M. Thiery <nthiery@users.sf.net>
    # Date 1331588460 -3600
    # Node ID f712c57ba27ce9f75347a6e7f0979da9bd63f42d
    # Parent  103dbe1d3dae544d2b3650209c2e72fd117c7a66
    #6588: Categories for root systems
    
    - RootLatticeRealization and friends are now categories
    - Use abstract_methods where appropriate
    - More tests for scalar products
    - Iterator for any Coxeter group, and weak order ideals thereof
    - Enumerated set for grassmannian elements, and is_grasmmannian test
    - Cleanup of an_element
    - Facade option for weak_poset's and bruhat_poset's of finite coxeter groups
    - weak_poset's of finite coxeter groups are lattices; added link weak_lattice -> weak_poset
    - to_coroot_lattice_morphism: renamed to to_coroot_lattice_space, and
      moved from RootLatticeRealization to RootSpace (it does not make
      sense for, e.g., the weight lattice).
    - Moved the implementation of associated_coroot in root_lattice_realization to root_space where it belongs
    - Added systematic tests for associated_coroot
    - Fixed further missing features revealed by this test:
      - reducible Cartan types where not seen as finite/simply laced/crystallographic as appropriate
      - symmetrizer needed to be generalized to reducible cartan types (including D2)
      - the relabelling for reducible cartan types was broken for affine types
    - Implemented the embeddings of the root lattice/space in root lattice realizations
    - Implemented the embeddings of the weight lattice/space in weight lattice realizations
    - Conversion from the root space to the root lattice
    - Added method register_as_conversion to morphisms (to be extracted in a separate patch)
    - Fixed imports (extraneous ones, and a missing one reported by M. Shimozono and others)
    - Implementation of coxeter_matrix and coxeter_diagram (for crystallographic types)
    - 100% doctests on sage.combinat.root_system, except for weyl_group and weyl_characters
    - Added systematic consistency check between the simple_root and simple_roots methods
    - same thing for fundamental_weight and fundamental_weights
    - Fixed a SL vs GL glitch when obtaining simple roots for reducible cartan types revealed by the above
    - Implemented the extended weight lattice/space for affine types
    * * *
    - Bring CoxeterGroups to 100% doctests
    - Add minimal documentation to AffineWeylGroups
    
    diff --git a/sage/algebras/affine_nil_temperley_lieb.py b/sage/algebras/affine_nil_temperley_lieb.py
    a b class AffineNilTemperleyLiebTypeA(Combin 
    4040        True
    4141        sage: a[0]*a[3]*a[0]
    4242        0
    43         sage: A.an_element() # todo: not implemented (see #6588)
    44         3*a0 + 3*a0*a1 + 1
    4543        sage: A.an_element()
    46         a0
     44        2*a0 + 3*a0*a1 + 1 + a0*a1*a2*a3
    4745    """
    4846
    4947    def __init__(self, n, R = ZZ, prefix = 'a'):
  • sage/algebras/iwahori_hecke_algebra.py

    diff --git a/sage/algebras/iwahori_hecke_algebra.py b/sage/algebras/iwahori_hecke_algebra.py
    a b class IwahoriHeckeAlgebraT(Combinatorial 
    4949        sage: w0
    5050        s1*s2*s3*s1*s2*s1
    5151        sage: H.an_element()
    52         3*s1*s2 + 2*s1 + 2
     52        s1*s2*s3 + 3*s1*s2 + 2*s1 + 1
    5353
    5454    Iwahori Hecke algebras have proved to be fundamental. See for example:
    5555
  • sage/algebras/nil_coxeter_algebra.py

    diff --git a/sage/algebras/nil_coxeter_algebra.py b/sage/algebras/nil_coxeter_algebra.py
    a b class NilCoxeterAlgebra(IwahoriHeckeAlge 
    4040        sage: u2*u1*u2 == u1*u2*u1
    4141        True
    4242        sage: U.an_element()
    43         u0
    44        
     43        2*u0 + 3*u0*u1 + 1 + u0*u1*u2*u3
    4544    """
    4645
    4746    def __init__(self, W, base_ring = QQ, prefix='u'):
  • sage/categories/affine_weyl_groups.py

    diff --git a/sage/categories/affine_weyl_groups.py b/sage/categories/affine_weyl_groups.py
    a b from sage.misc.cachefunc import cached_m 
    1212from sage.categories.category import Category
    1313from sage.categories.category_singleton import Category_singleton
    1414from sage.categories.weyl_groups import WeylGroups
     15from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets
    1516
    1617class AffineWeylGroups(Category_singleton):
     18    """
     19    The category of affine Weyl groups
     20
     21    .. todo:: add a description of this category
     22
     23    .. seealso::
     24
     25        - :wikipedia:`Affine_weyl_group`
     26        - :class:`WeylGroups`, :class:`WeylGroup`
     27
     28    EXAMPLES::
     29
     30        sage: C = AffineWeylGroups(); C
     31        Category of affine weyl groups
     32        sage: C.super_categories()
     33        [Category of weyl groups, Category of infinite enumerated sets]
     34
     35        sage: C.example()
     36        NotImplemented
     37        sage: W = WeylGroup(["A",4,1]); W
     38        Weyl Group of type ['A', 4, 1] (as a matrix group acting on the root space)
     39        sage: W.category()
     40        Category of affine weyl groups
     41
     42    TESTS::
     43
     44        sage: TestSuite(C).run()
     45    """
    1746
    1847    @cached_method
    1948    def super_categories(self):
    class AffineWeylGroups(Category_singleto 
    2150        EXAMPLES::
    2251
    2352            sage: AffineWeylGroups().super_categories()
    24             [Category of weyl groups]
     53            [Category of weyl groups, Category of infinite enumerated sets]
    2554        """
    26         return [WeylGroups()]
     55        return [WeylGroups(), InfiniteEnumeratedSets()]
    2756
    2857    class ParentMethods:
    2958
    class AffineWeylGroups(Category_singleto 
    7099    class ElementMethods:
    71100        def is_affine_grassmannian(self):
    72101            """
    73             INPUT:
    74              - self: an element of an affine Weyl group
    75            
    76             Tests whether self is Grassmannian, i.e. any of the following
    77             equivalent properties hold:
     102            Tests whether ``self`` is affine Grassmannian
     103
     104            An element of an affine Weyl group is *affine Grassmannian*
     105            if any of the following equivalent properties holds:
     106
    78107             - all reduced words for self end with 0.
    79108             - self is the identity, or 0 is its single right descent.
    80109             - self is a mimimal coset representative for W / cl W.
    class AffineWeylGroups(Category_singleto 
    88117                sage: w=W.from_reduced_word([2,0])
    89118                sage: w.is_affine_grassmannian()
    90119                False
    91                 sage: W.unit().is_affine_grassmannian()
     120                sage: W.one().is_affine_grassmannian()
    92121                True
    93122            """
    94123            return self.descents() in [[], [self.parent().special_node()]]
  • sage/categories/coxeter_groups.py

    diff --git a/sage/categories/coxeter_groups.py b/sage/categories/coxeter_groups.py
    a b Coxeter Groups 
    1212from sage.misc.cachefunc import cached_method, cached_in_parent_method
    1313from sage.misc.abstract_method import abstract_method
    1414from sage.misc.constant_function import ConstantFunction
    15 from sage.categories.category import Category
     15from sage.misc.misc import attrcall
    1616from sage.categories.category_singleton import Category_singleton
    1717from sage.categories.groups import Groups
     18from sage.categories.enumerated_sets import EnumeratedSets
    1819from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
    19 from sage.combinat.backtrack import SearchForest
     20from sage.structure.sage_object import have_same_parent
    2021from sage.combinat.finite_class import FiniteCombinatorialClass
    2122from sage.misc.flatten import flatten
    2223
    class CoxeterGroups(Category_singleton): 
    3839        sage: C                            # todo: uppercase for Coxeter
    3940        Category of coxeter groups
    4041        sage: C.super_categories()
    41         [Category of groups]
     42        [Category of groups, Category of enumerated sets]
    4243
    4344        sage: W = C.example(); W
    4445        The symmetric group on {0, ..., 3}
    class CoxeterGroups(Category_singleton): 
    101102        EXAMPLES::
    102103
    103104            sage: CoxeterGroups().super_categories()
    104             [Category of groups]
     105            [Category of groups, Category of enumerated sets]
    105106        """
    106         return [Groups()]
     107        return [Groups(), EnumeratedSets()]
    107108
    108109    class ParentMethods:
    109110
    class CoxeterGroups(Category_singleton): 
    112113            """
    113114            Returns the index set of (the simple reflections of)
    114115            ``self``, as a list (or iterable).
     116
     117            EXAMPLES::
     118
     119                sage: W = FiniteCoxeterGroups().example(); W
     120                The 5-th dihedral group of order 10
     121                sage: W.index_set()
     122                [1, 2]
    115123            """
    116124            # return self.simple_reflections().keys()
    117125
    118         @cached_method
    119         def an_element(self):
     126        def _an_element_(self):
    120127            """
    121128            Implements: :meth:`Sets.ParentMethods.an_element` by
    122129            returning the product of the simple reflections (a Coxeter
    class CoxeterGroups(Category_singleton): 
    127134                sage: W=CoxeterGroups().example()
    128135                sage: W
    129136                The symmetric group on {0, ..., 3}
    130                 sage: W.an_element()
     137                sage: W.an_element()               # indirect doctest
    131138                (1, 2, 3, 0)
    132139
    133140            """
    134141            return self.prod(self.simple_reflections())
    135142
    136         an_element_force = an_element
    137 
    138143        def some_elements(self):
    139144            """
    140145            Implements :meth:`Sets.ParentMethods.some_elements` by
    class CoxeterGroups(Category_singleton): 
    167172                sage: W.order()   
    168173                24
    169174            """
    170             return list(self.simple_reflections()) + [ self.one(), self.an_element_force() ]
     175            return list(self.simple_reflections()) + [ self.one(), self.an_element() ]
     176
     177        def __iter__(self):
     178            r"""
     179            Returns an iterator over the elements of this Coxeter group.
     180
     181            EXAMPLES::
     182
     183                sage: D5 = FiniteCoxeterGroups().example(5)
     184                sage: sorted(list(D5)) # indirect doctest (but see :meth:`._test_enumerated_set_iter_list`)
     185                [(),
     186                 (1,),
     187                 (1, 2),
     188                 (1, 2, 1),
     189                 (1, 2, 1, 2),
     190                 (1, 2, 1, 2, 1),
     191                 (2,),
     192                 (2, 1),
     193                 (2, 1, 2),
     194                 (2, 1, 2, 1)]
     195
     196                sage: W = WeylGroup(["A",2,1])
     197                sage: g = iter(W)
     198                sage: g.next()
     199                [1 0 0]
     200                [0 1 0]
     201                [0 0 1]
     202                sage: g.next()
     203                [-1  1  1]
     204                [ 0  1  0]
     205                [ 0  0  1]
     206                sage: g.next()
     207                [ 0 -1  2]
     208                [ 1 -1  1]
     209                [ 0  0  1]
     210            """
     211            return iter(self.weak_order_ideal(predicate = ConstantFunction(True)))
     212
     213        def weak_order_ideal(self, predicate, side ="right", category = None):
     214            """
     215            Returns a weak order ideal defined by a predicate
     216
     217            INPUT:
     218
     219            - ``predicate``: a predicate on the elements of ``self`` defining an
     220              weak order ideal in ``self``
     221            - ``side``: "left" or "right" (default: "right")
     222
     223            OUTPUT: an enumerated set
     224
     225            EXAMPLES::
     226
     227                sage: D6 = FiniteCoxeterGroups().example(5)
     228                sage: I = D6.weak_order_ideal(predicate = lambda w: w.length() <= 3)
     229                sage: I.cardinality()
     230                7
     231                sage: list(I)
     232                [(), (1,), (1, 2), (1, 2, 1), (2,), (2, 1), (2, 1, 2)]
     233
     234            We now consider an infinite Coxeter group::
     235
     236                sage: W = WeylGroup(["A",1,1])
     237                sage: I = W.weak_order_ideal(predicate = lambda w: w.length() <= 2)
     238                sage: list(iter(I))
     239                [[1 0]
     240                 [0 1],
     241                 [-1  2]
     242                 [ 0  1],
     243                 [ 3 -2]
     244                 [ 2 -1],
     245                 [ 1  0]
     246                 [ 2 -1],
     247                 [-1  2]
     248                 [-2  3]]
     249
     250            Even when the result is finite, some features of
     251            :class:`FiniteEnumeratedSets` are not available::
     252
     253                sage: I.cardinality() # todo: not implemented
     254                5
     255                sage: list(I)         # todo: not implemented
     256
     257            unless this finiteness is explicitly specified::
     258
     259                sage: I = W.weak_order_ideal(predicate = lambda w: w.length() <= 2,
     260                ...                          category = FiniteEnumeratedSets())
     261                sage: I.cardinality()
     262                5
     263                sage: list(I)
     264                [[1 0]
     265                 [0 1],
     266                 [-1  2]
     267                 [ 0  1],
     268                 [ 3 -2]
     269                 [ 2 -1],
     270                 [ 1  0]
     271                 [ 2 -1],
     272                 [-1  2]
     273                 [-2  3]]
     274
     275            .. rubric:: Background
     276
     277            The weak order is returned as a :class:`SearchForest`.
     278            This is achieved by assigning to each element `u1` of the
     279            ideal a single ancestor `u=u1 s_i`, where `i` is the
     280            smallest descent of `u`.
     281
     282            This allows for iterating through the elements in
     283            roughly Constant Amortized Time and constant memory
     284            (taking the operations and size of the generated objects
     285            as constants).
     286            """
     287            from sage.combinat.backtrack import SearchForest
     288            def succ(u):
     289                for i in u.descents(positive = True, side = side):
     290                    u1 = u.apply_simple_reflection(i, side)
     291                    if i == u1.first_descent(side = side) and predicate(u1):
     292                        yield u1
     293                return
     294            from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups
     295            default_category = FiniteEnumeratedSets() if self in FiniteCoxeterGroups() else EnumeratedSets()
     296            return SearchForest((self.one(),), succ, category = default_category.or_subcategory(category))
     297
     298        def grassmannian_elements(self, side = "right"):
     299            """
     300            INPUT:
     301
     302            - ``side``: "left" or "right" (default: "right")
     303
     304            Returns the left or right grassmanian elements of self, as an enumerated set
     305
     306            EXAMPLES::
     307
     308                sage: S = CoxeterGroups().example()
     309                sage: G = S.grassmannian_elements()
     310                sage: G.cardinality()
     311                12
     312                sage: G.list()
     313                [(0, 1, 2, 3), (1, 0, 2, 3), (2, 0, 1, 3), (3, 0, 1, 2), (0, 2, 1, 3), (1, 2, 0, 3), (0, 3, 1, 2), (1, 3, 0, 2), (2, 3, 0, 1), (0, 1, 3, 2), (0, 2, 3, 1), (1, 2, 3, 0)]
     314                sage: sorted(tuple(w.descents()) for w in G)
     315                [(), (0,), (0,), (0,), (1,), (1,), (1,), (1,), (1,), (2,), (2,), (2,)]
     316                sage: G = S.grassmannian_elements(side = "left")
     317                sage: G.cardinality()
     318                12
     319                sage: sorted(tuple(w.descents(side = "left")) for w in G)
     320                [(), (0,), (0,), (0,), (1,), (1,), (1,), (1,), (1,), (2,), (2,), (2,)]
     321            """
     322            order_side = "left" if side == "right" else "right"
     323            return self.weak_order_ideal(attrcall("is_grassmannian", side = side), side = order_side)
    171324
    172325        def from_reduced_word(self, word):
    173326            r"""
    class CoxeterGroups(Category_singleton): 
    549702        @abstract_method(optional = True)
    550703        def has_right_descent(self, i):
    551704            """
    552             Returns whether i is a right descent of self.
     705            Returns whether ``i`` is a right descent of self.
    553706
    554 #            EXAMPLES::
    555 #
    556 #                sage:
     707            EXAMPLES::
     708
     709                sage: W = CoxeterGroups().example(); W
     710                The symmetric group on {0, ..., 3}
     711                sage: w = W.an_element(); w
     712                (1, 2, 3, 0)
     713                sage: w.has_right_descent(0)
     714                False
     715                sage: w.has_right_descent(1)
     716                False
     717                sage: w.has_right_descent(2)
     718                True
    557719            """
    558720
    559721        def has_left_descent(self, i):
    class CoxeterGroups(Category_singleton): 
    562724
    563725            This default implementation uses that a left descent of
    564726            `w` is a right descent of `w^{-1}`.
     727
     728            EXAMPLES::
     729
     730                sage: W = CoxeterGroups().example(); W
     731                The symmetric group on {0, ..., 3}
     732                sage: w = W.an_element(); w
     733                (1, 2, 3, 0)
     734                sage: w.has_left_descent(0)
     735                True
     736                sage: w.has_left_descent(1)
     737                False
     738                sage: w.has_left_descent(2)
     739                False
     740
     741            TESTS::
     742
     743                sage: w.has_left_descent.__module__
     744                'sage.categories.coxeter_groups'
    565745            """
    566746            return (~self).has_right_descent(i)
    567747
    class CoxeterGroups(Category_singleton): 
    635815                index_set=self.parent().index_set()
    636816            return [ i for i in index_set if self.has_descent(i, side = side, positive = positive) ]
    637817
     818        def is_grassmannian(self, side = "right"):
     819            """
     820            INPUT:
     821
     822            - ``side`` - "left" or "right" (default: "right")
     823
     824            Tests whether ``self`` is Grassmannian, i.e. it has at
     825            most one descent on the right (resp. on the left).
     826
     827            EXAMPLES::
     828
     829                sage: W = CoxeterGroups().example(); W
     830                The symmetric group on {0, ..., 3}
     831                sage: s = W.simple_reflections()
     832                sage: W.one().is_grassmannian()
     833                True
     834                sage: s[1].is_grassmannian()
     835                True
     836                sage: (s[1]*s[2]).is_grassmannian()
     837                True
     838                sage: (s[0]*s[1]).is_grassmannian()
     839                True
     840                sage: (s[1]*s[2]*s[1]).is_grassmannian()
     841                False
     842
     843                sage: (s[0]*s[2]*s[1]).is_grassmannian(side = "left")
     844                False
     845                sage: (s[0]*s[2]*s[1]).is_grassmannian(side = "right")
     846                True
     847                sage: (s[0]*s[2]*s[1]).is_grassmannian()
     848                True
     849            """
     850            return len(self.descents(side = side)) <= 1
     851
    638852        def reduced_word_reverse_iterator(self):
    639853            """
    640854            Returns a reverse iterator on a reduced word for self.
    class CoxeterGroups(Category_singleton): 
    8751089                sage: w0.binary_factorizations().category()
    8761090                Category of finite enumerated sets
    8771091            """
     1092            from sage.combinat.backtrack import SearchForest
    8781093            W = self.parent()
    8791094            if not predicate(W.one()):
    8801095                return FiniteCombinatorialClass([])
    class CoxeterGroups(Category_singleton): 
    8911106            """
    8921107            INPUT:
    8931108
    894             - "word": A sequence of indices of Coxeter generators
    895             - "side": Indicates multiplying from left or right
     1109            - ``word`` -- A sequence of indices of Coxeter generators
     1110            - ``side`` -- Indicates multiplying from left or right
    8961111
    897             Returns the result of the (left/right) multiplication of   
    898             word to self.  self is not changed.
     1112            Returns the result of the (left/right) multiplication of
     1113            word to self.  ``self`` is not changed.
    8991114
    900             EXAMPLE::
     1115            EXAMPLES::
    9011116
    9021117               sage: W=CoxeterGroups().example()
    903                sage: w=W.an_element()
    904                sage: w
     1118               sage: w=W.an_element(); w
    9051119               (1, 2, 3, 0)
    9061120               sage: w.apply_simple_reflections([0,1])
    9071121               (2, 3, 1, 0)
    class CoxeterGroups(Category_singleton): 
    9171131
    9181132        def apply_simple_reflection_left(self, i):
    9191133            """
     1134            Returns ``self`` multiplied by the simple reflection ``s[i]`` on the left
    9201135
    921             ... multiplies s[i] by x...
     1136            This low level method is used intensively. Coxeter groups
     1137            are encouraged to override this straightforward
     1138            implementation whenever a faster approach exists.
    9221139
     1140            EXAMPLES::
     1141
     1142                sage: W=CoxeterGroups().example()
     1143                sage: w = W.an_element(); w
     1144                (1, 2, 3, 0)
     1145                sage: w.apply_simple_reflection_left(0)
     1146                (0, 2, 3, 1)
     1147                sage: w.apply_simple_reflection_left(1)
     1148                (2, 1, 3, 0)
     1149                sage: w.apply_simple_reflection_left(2)
     1150                (1, 3, 2, 0)
     1151
     1152            TESTS::
     1153
     1154                sage: w.apply_simple_reflection_left.__module__
     1155                'sage.categories.coxeter_groups'
    9231156            """
    9241157            s = self.parent().simple_reflections()
    9251158            return s[i] * self
    9261159
    9271160        def apply_simple_reflection_right(self, i):
    9281161            """
     1162            Returns ``self`` multiplied by the simple reflection ``s[i]`` on the right
    9291163
    930             ... multiplies x by s[i] ...
     1164            This low level method is used intensively. Coxeter groups
     1165            are encouraged to override this straightforward
     1166            implementation whenever a faster approach exists.
    9311167
     1168            EXAMPLES::
     1169
     1170                sage: W=CoxeterGroups().example()
     1171                sage: w = W.an_element(); w
     1172                (1, 2, 3, 0)
     1173                sage: w.apply_simple_reflection_right(0)
     1174                (2, 1, 3, 0)
     1175                sage: w.apply_simple_reflection_right(1)
     1176                (1, 3, 2, 0)
     1177                sage: w.apply_simple_reflection_right(2)
     1178                (1, 2, 0, 3)
     1179
     1180            TESTS::
     1181
     1182                sage: w.apply_simple_reflection_right.__module__
     1183                'sage.categories.coxeter_groups'
    9321184            """
    9331185            s = self.parent().simple_reflections()
    9341186            return self * s[i]
    9351187
    9361188        def apply_simple_reflection(self, i, side = 'right'):
    9371189            """
     1190            Returns ``self`` multiplied by the simple reflection ``s[i]``
    9381191
    939             ... multiplies x by s[i] ...
     1192            INPUT:
    9401193
     1194            - ``i`` -- an element of the index set
     1195            - ``side`` -- "left" or "right" (default: "right")
     1196
     1197            This default implementation simply calls
     1198            :meth:`apply_simple_reflection_left` or
     1199            :meth:`apply_simple_reflection_right`.
     1200
     1201            EXAMPLES::
     1202
     1203                sage: W=CoxeterGroups().example()
     1204                sage: w = W.an_element(); w
     1205                (1, 2, 3, 0)
     1206                sage: w.apply_simple_reflection(0, side = "left")
     1207                (0, 2, 3, 1)
     1208                sage: w.apply_simple_reflection(1, side = "left")
     1209                (2, 1, 3, 0)
     1210                sage: w.apply_simple_reflection(2, side = "left")
     1211                (1, 3, 2, 0)
     1212
     1213                sage: w.apply_simple_reflection(0, side = "right")
     1214                (2, 1, 3, 0)
     1215                sage: w.apply_simple_reflection(1, side = "right")
     1216                (1, 3, 2, 0)
     1217                sage: w.apply_simple_reflection(2, side = "right")
     1218                (1, 2, 0, 3)
     1219
     1220            By default, ``side`` is "right"::
     1221
     1222                sage: w.apply_simple_reflection(0)
     1223                (2, 1, 3, 0)
     1224
     1225            TESTS::
     1226
     1227                sage: w.apply_simple_reflection_right.__module__
     1228                'sage.categories.coxeter_groups'
    9411229            """
    9421230            if side == 'right':
    9431231                return self.apply_simple_reflection_right(i)
    class CoxeterGroups(Category_singleton): 
    9451233                return self.apply_simple_reflection_left(i)
    9461234
    9471235        def _mul_(self, other):
    948             """
    949             Returns the product of self and other, called when computing
    950             self*other
     1236            r"""
     1237            Returns the product of ``self`` and ``other``
     1238
     1239            This default implementation computes a reduced word of
     1240            ``other`` using :meth:`reduced_word`, and applies the
     1241            corresponding simple reflections on ``self`` using
     1242            :meth:`apply_simple_reflections`.
    9511243
    9521244            EXAMPLES::
    9531245
    954                 sage: W=WeylGroup(['B',7])         
    955                 sage: w=W.an_element()
    956                 sage: u=w.inverse()
    957                 sage: u*w
    958                 [1 0 0 0 0 0 0]
    959                 [0 1 0 0 0 0 0]
    960                 [0 0 1 0 0 0 0]
    961                 [0 0 0 1 0 0 0]
    962                 [0 0 0 0 1 0 0]
    963                 [0 0 0 0 0 1 0]
    964                 [0 0 0 0 0 0 1]
     1246                sage: W = FiniteCoxeterGroups().example(); W
     1247                The 5-th dihedral group of order 10
     1248                sage: w = W.an_element()
     1249                sage: w
     1250                (1, 2)
     1251                sage: w._mul_(w)
     1252                (1, 2, 1, 2)
     1253                sage: w._mul_(w)._mul_(w)
     1254                (2, 1, 2, 1)
    9651255
     1256            This method is called when computing ``self*other``::
     1257
     1258                sage: w * w
     1259                (1, 2, 1, 2)
     1260
     1261            TESTS::
     1262
     1263                sage: w._mul_.__module__
     1264                'sage.categories.coxeter_groups'
    9661265            """
    9671266            return self.apply_simple_reflections(other.reduced_word())
    9681267
    class CoxeterGroups(Category_singleton): 
    10321331
    10331332                sage: P = W.bruhat_poset()
    10341333
    1035 
    10361334            The algorithm is taken from Stembridge's coxeter/weyl package for Maple.
    10371335            """
    10381336            desc = self.first_descent()
    class CoxeterGroups(Category_singleton): 
    11441442                True
    11451443
    11461444            """
     1445            assert have_same_parent(self, other)
    11471446            # could first compare the length, when that information is cheap
    11481447            desc = other.first_descent()
    11491448            if desc is not None:
    class CoxeterGroups(Category_singleton): 
    12061505                ...           assert u.permutohedron_lequal(v) == P4toW(u).weak_le(P4toW(v))
    12071506                ...           assert u.permutohedron_lequal(v, side='left') == P4toW(u).weak_le(P4toW(v), side='left')
    12081507            """
     1508            assert have_same_parent(self, other)
    12091509            # could first compare the length, when that information is cheap
    12101510            prefix_side = 'left' if side == 'right' else 'right'
    12111511
  • 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 class DihedralGroup(UniqueRepresentation 
    153153        from sage.misc.functional import parent
    154154        return parent(x) is self
    155155
    156     # temporary workaround while an_element is overriden by Parent
    157     an_element = CoxeterGroups.ParentMethods.an_element_force
    158 
    159156    @cached_method
    160157    def one(self):
    161158        r"""
  • 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 
    151151        assert i in self.index_set()
    152152        return self(tuple(range(i)+[i+1,i]+range(i+2,self.n)))
    153153
    154     # temporary woraround while an_element is overriden by Parent
    155     an_element = CoxeterGroups.ParentMethods.an_element_force
    156 
    157154    def product(self, x, y):
    158155        """
    159156        Implements :meth:`Semigroups.ParentMethods.product`.
  • sage/categories/finite_coxeter_groups.py

    diff --git a/sage/categories/finite_coxeter_groups.py b/sage/categories/finite_coxeter_groups.py
    a b from sage.misc.lazy_attribute import laz 
    1414from sage.categories.category import Category
    1515from sage.categories.coxeter_groups import CoxeterGroups
    1616from sage.categories.finite_groups import FiniteGroups
    17 from sage.combinat.backtrack import search_forest_iterator
    1817
    1918class FiniteCoxeterGroups(Category):
    2019    r"""
    class FiniteCoxeterGroups(Category): 
    5756        return [CoxeterGroups(), FiniteGroups()]
    5857
    5958    class ParentMethods:
    60         def __iter__(self):
    61             r"""
    62             Returns an iterator over the elements of this finite Coxeter group.
    63 
    64             EXAMPLES::
    65 
    66                 sage: D5 = FiniteCoxeterGroups().example(5)
    67                 sage: sorted(list(D5)) # indirect doctest (but see :meth:`._test_enumerated_set_iter_list`)
    68                 [(),
    69                  (1,),
    70                  (1, 2),
    71                  (1, 2, 1),
    72                  (1, 2, 1, 2),
    73                  (1, 2, 1, 2, 1),
    74                  (2,),
    75                  (2, 1),
    76                  (2, 1, 2),
    77                  (2, 1, 2, 1)]
    78             """
    79             def succ(u):
    80                 for i in u.descents(positive = True, side = "right"):
    81                     u1 = u.apply_simple_reflection(i, "right")
    82                     if i == u1.first_descent():
    83                         yield u1
    84                 return
    85             return search_forest_iterator((self.one(),), succ)
    86 
    8759        @lazy_attribute
    8860        def w0(self):
    8961            r"""
    class FiniteCoxeterGroups(Category): 
    143115                    w = w.apply_simple_reflection(i)
    144116
    145117        @cached_method
    146         def bruhat_poset(self):
     118        def bruhat_poset(self, facade = False):
    147119            """
    148120            Returns the Bruhat poset of ``self``
    149121
    class FiniteCoxeterGroups(Category): 
    168140                sage: P.is_join_semilattice()
    169141                False
    170142
    171             See also :class:`Poset`.
     143            By default, the elements of `P` are aware that they belong
     144            to `P`::
     145
     146                sage: P.an_element().parent()
     147                Finite poset containing 24 elements
     148
     149            If instead one wants the elements to be plain elements of
     150            the Coxeter group, one can use the ``facade`` option::
     151
     152                sage: P = W.bruhat_poset(facade = True)
     153                sage: P.an_element().parent()
     154                Weyl Group of type ['A', 3] (as a matrix group acting on the ambient space)
     155
     156            .. see also:: :func:`Poset` for more on posets and facade posets.
    172157
    173158            TESTS::
    174159
    175160                sage: [len(WeylGroup(["A", n]).bruhat_poset().cover_relations()) for n in [1,2,3]]
    176161                [1, 8, 58]
    177162
    178             TODO:
     163            .. todo::
    179164
    180             - Use the symmetric group in the examples (for nicer
    181               output), and print the edges for a stronger test.
    182             - The constructed poset should be lazy, in order to
    183               handle large / infinite Coxeter groups.
     165                - Use the symmetric group in the examples (for nicer
     166                  output), and print the edges for a stronger test.
     167                - The constructed poset should be lazy, in order to
     168                  handle large / infinite Coxeter groups.
    184169            """
    185170            from sage.combinat.posets.posets import Poset
    186171            covers = tuple([u, v] for v in self for u in v.bruhat_lower_covers() )
    187             return Poset((self, covers), cover_relations = True)
     172            return Poset((self, covers), cover_relations = True, facade=facade)
    188173
    189174        @cached_method
    190         def weak_poset(self, side = "right"):
     175        def weak_poset(self, side = "right", facade = False):
    191176            """
    192177            INPUT:
    193178
    194             - ``side`` -- "left" or "right" (default: "right")
     179            - ``side`` -- "left", "right", or "twosided" (default: "right")
     180            - ``facade`` -- a boolean (default: False)
    195181
    196182            Returns the left (resp. right) poset for weak order.  In
    197183            this poset, `u` is smaller than `v` if some reduced word
    class FiniteCoxeterGroups(Category): 
    203189                sage: W = WeylGroup(["A", 2])
    204190                sage: P = W.weak_poset()
    205191                sage: P
    206                 Finite poset containing 6 elements
     192                Finite lattice containing 6 elements
    207193                sage: P.show()
    208194
    209195            This poset is in fact a lattice::
    210196
    211197                sage: W = WeylGroup(["B", 3])
    212198                sage: P = W.weak_poset(side = "left")
    213                 sage: P.is_join_semilattice(), P.is_meet_semilattice() # todo: implement is_lattice
    214                 (True, True)
     199                sage: P.is_lattice()
     200                True
     201
     202            so this method has an alias :meth:`weak_lattice`::
     203
     204                sage: W.weak_lattice(side = "left") is W.weak_poset(side = "left")
     205                True
    215206
    216207            As a bonus feature, one can create the left-right weak
    217208            poset::
    class FiniteCoxeterGroups(Category): 
    225216            This is the transitive closure of the union of left and
    226217            right order. In this poset, `u` is smaller than `v` if
    227218            some reduced word of `u` is a factor of some reduced word
    228             of `v`.
     219            of `v`. Note that this is not a lattice::
     220
     221                sage: P.is_lattice()
     222                False
     223
     224            By default, the elements of `P` are aware of that they
     225            belong to `P`::
     226
     227                sage: P.an_element().parent()
     228                Finite poset containing 6 elements
     229
     230            If instead one wants the elements to be plain elements of
     231            the Coxeter group, one can use the ``facade`` option::
     232
     233                sage: P = W.weak_poset(facade = True)
     234                sage: P.an_element().parent()
     235                Weyl Group of type ['A', 2] (as a matrix group acting on the ambient space)
     236
     237            .. see also:: :func:`Poset` for more on posets and facade posets.
    229238
    230239            TESTS::
    231240
    class FiniteCoxeterGroups(Category): 
    234243                sage: [len(WeylGroup(["A", n]).weak_poset(side = "left" ).cover_relations()) for n in [1,2,3]]
    235244                [1, 6, 36]
    236245
    237             TODO:
     246            .. todo::
    238247
    239             - Use the symmetric group in the examples (for nicer
    240               output), and print the edges for a stronger test.
    241             - The constructed poset should be lazy, in order to
    242               handle large / infinite Coxeter groups.
    243 
     248                - Use the symmetric group in the examples (for nicer
     249                  output), and print the edges for a stronger test.
     250                - The constructed poset should be lazy, in order to
     251                  handle large / infinite Coxeter groups.
    244252            """
    245253            from sage.combinat.posets.posets import Poset
     254            from sage.combinat.posets.lattices import LatticePoset
    246255            if side == "twosided":
    247256                covers = tuple([u, v] for u in self for v in u.upper_covers(side="left")+u.upper_covers(side="right") )
     257                return Poset((self, covers), cover_relations = True, facade = facade)
    248258            else:
    249259                covers = tuple([u, v] for u in self for v in u.upper_covers(side=side) )
    250             return Poset((self, covers), cover_relations = True)
     260                return LatticePoset((self, covers), cover_relations = True, facade = facade)
     261
     262        weak_lattice = weak_poset
    251263
    252264    class ElementMethods:
    253265
  • sage/categories/morphism.pyx

    diff --git a/sage/categories/morphism.pyx b/sage/categories/morphism.pyx
    a b cdef class Morphism(Map): 
    115115        """
    116116        self.codomain().register_coercion(self)
    117117
     118    def register_as_conversion(self):
     119        """
     120        Register this morphism as a conversion to Sage's coercion model
     121
     122        (see :mod:`sage.structure.coerce`).
     123
     124        EXAMPLES:
     125
     126        Let us declare a conversion from the symmetric group to `\ZZ`
     127        through the sign map::
     128
     129            sage: S = SymmetricGroup(4)
     130            sage: phi = Hom(S, ZZ)(lambda x: ZZ(x.sign()))
     131            sage: x = S.an_element(); x
     132            (1,2,3,4)
     133            sage: phi(x)
     134            -1
     135            sage: phi.register_as_conversion()
     136            sage: ZZ(x)
     137            -1
     138        """
     139        self.codomain().register_conversion(self)
     140
    118141cdef class FormalCoercionMorphism(Morphism):
    119142    def __init__(self, parent):
    120143        Morphism.__init__(self, parent)
  • 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
    12 from sage.categories.category import Category
    1312from sage.categories.category_singleton import Category_singleton
    1413from sage.categories.coxeter_groups import CoxeterGroups
    15 import sage.combinat.sf
    1614from sage.rings.infinity import infinity
    1715from sage.rings.rational_field import QQ
    1816
    class WeylGroups(Category_singleton): 
    9795                sage: W.from_reduced_word([3,2,0]) in PF
    9896                True
    9997            """
    100             # Don't remove this line which makes sure the pieri factor
     98            # Do not remove this line which makes sure the pieri factor
    10199            # code is properly inserted inside the cartan types
    102100            import sage.combinat.root_system.pieri_factors
    103101            ct = self.cartan_type()
    class WeylGroups(Category_singleton): 
    272270            x = R.gens()
    273271            if self.is_one():
    274272                return R(1)
    275             ct = W.cartan_type()
    276273
    277274            return R(sum(2**(pieri_factors.stanley_symm_poly_weight(u))*x[u.length()-1] * v.stanley_symmetric_function_as_polynomial(max_length = u.length())
    278275                           for (u,v) in self.left_pieri_factorizations(max_length)
    class WeylGroups(Category_singleton): 
    320317                .. [Pon2010] S. Pon. Types B and D affine Stanley symmetric functions, unpublished PhD Thesis, UC Davis, 2010.
    321318
    322319            """
     320            import sage.combinat.sf
    323321            m = sage.combinat.sf.all.SFAMonomial(QQ)
    324322            return m.from_polynomial_exp(self.stanley_symmetric_function_as_polynomial())
  • 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 spaces 
    88#  Distributed under the terms of the GNU General Public License (GPL)
    99#                  http://www.gnu.org/licenses/
    1010#*****************************************************************************
     11from sage.misc.cachefunc import cached_method
    1112from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement
    12 from root_lattice_realization import RootLatticeRealizationElement
    13 from weight_lattice_realization import WeightLatticeRealization
     13from weight_lattice_realization import WeightLatticeRealizations
    1414from sage.rings.all import ZZ, QQ
    1515from sage.misc.cachefunc import ClearCacheOnPickle
    1616
    17 class AmbientSpace(ClearCacheOnPickle, CombinatorialFreeModule, WeightLatticeRealization):
     17class AmbientSpace(ClearCacheOnPickle, CombinatorialFreeModule):
    1818    r"""
    1919    Abstract class for ambient spaces
    2020
    class AmbientSpace(ClearCacheOnPickle, C 
    3838    This will be cleaned up!
    3939
    4040    TESTS::
    41         sage: types = CartanType.samples(finite=True, crystalographic = True)
     41
     42        sage: types = CartanType.samples(finite=True, crystalographic = True)+[CartanType(["A",2],["C",5])]
    4243        sage: for e in [ct.root_system().ambient_space() for ct in types]:
    4344        ...       if e is not None:
    4445        ...            TestSuite(e).run()
    class AmbientSpace(ClearCacheOnPickle, C 
    5657        CombinatorialFreeModule.__init__(self, base_ring,
    5758                                         range(0,self.dimension()),
    5859                                         element_class = AmbientSpaceElement,
    59                                          prefix='e')
     60                                         prefix='e',
     61                                         category = WeightLatticeRealizations(base_ring))
    6062
    6163        # FIXME: here for backward compatibility;
    6264        # Should we use dimension everywhere?
    class AmbientSpace(ClearCacheOnPickle, C 
    7072    def _test_norm_of_simple_roots(self, **options):
    7173        """
    7274        Tests that the norm of the roots is, up to an overal constant factor,
    73         the norm of the roots is given by the symmetrizer of the Cartan matrix.
     75        given by the symmetrizer of the Cartan matrix.
    7476
    75         Not yet implemented for reducible Cartan types.
     77        .. seealso:: :class:`TestSuite`
     78
     79        EXAMPLES::
     80
     81            sage: e = RootSystem(['F',4]).ambient_space()
     82            sage: e._test_norm_of_simple_roots()
    7683        """
    7784        tester = self._tester(**options)
    7885        T = self.cartan_type()
    79         if T.is_reducible():
    80             return
    8186        D = T.symmetrizer()
    8287        alpha = self.simple_roots()
    83         tester.assertEquals(len( set( alpha[i].scalar(alpha[i]) / D[i] for i in self.index_set() ) ), 1)
     88        for C in T.dynkin_diagram().connected_components():
     89            tester.assertEquals(len( set( alpha[i].scalar(alpha[i]) / D[i] for i in C ) ), 1)
    8490
    8591    # FIXME: attribute or method?
    8692    def dimension(self):
    class AmbientSpace(ClearCacheOnPickle, C 
    115121    def _repr_(self):
    116122        """
    117123        EXAMPLES::
    118        
    119             sage: RootSystem(['A',4]).ambient_lattice()
     124
     125            sage: RootSystem(['A',4]).ambient_lattice()    # indirect doctest
    120126            Ambient lattice of the Root system of type ['A', 4]
    121127            sage: RootSystem(['B',4]).ambient_space()
    122128            Ambient space of the Root system of type ['B', 4]
    class AmbientSpace(ClearCacheOnPickle, C 
    214220        # (i.e. scalar and associated coroot are implemented)
    215221        return lambda v: v - root.base_ring()(2*root.inner_product(v)/root.inner_product(root))*root
    216222
     223    @cached_method
     224    def fundamental_weight(self, i):
     225        """
     226        Returns the fundamental weight `\Lambda_i` in ``self``
     227
     228        In several of the ambient spaces, it is more convenient to
     229        construct all fundamental weights at once. To support this, we
     230        provide this default implementation of ``fundamental_weight``
     231        using the method ``fundamental_weights``. Beware that this
     232        will cause a loop if neither ``fundamental_weight`` nor
     233        ``fundamental_weights`` is implemented.
     234
     235        EXAMPLES::
     236
     237            sage: e =  RootSystem(['F',4]).ambient_space()
     238            sage: e.fundamental_weight(3)
     239            (3/2, 1/2, 1/2, 1/2)
     240
     241            sage: e =  RootSystem(['G',2]).ambient_space()
     242            sage: e.fundamental_weight(1)
     243            (1, 0, -1)
     244
     245            sage: e =  RootSystem(['E',6]).ambient_space()
     246            sage: e.fundamental_weight(3)
     247            (-1/2, 1/2, 1/2, 1/2, 1/2, -5/6, -5/6, 5/6)
     248        """
     249        return self.fundamental_weights()[i]
     250
    217251    def __cmp__(self, other):
    218252        """
    219253        EXAMPLES::
    class AmbientSpace(ClearCacheOnPickle, C 
    277311                x = x.coerce_to_sl()
    278312        return x
    279313
    280 class AmbientSpaceElement(CombinatorialFreeModuleElement, RootLatticeRealizationElement):
     314class AmbientSpaceElement(CombinatorialFreeModuleElement):
    281315    def __hash__(self):
    282316        """
    283317        EXAMPLES::
    class AmbientSpaceElement(CombinatorialF 
    293327    def _repr_(self):
    294328        """
    295329        EXAMPLES::
    296        
     330
    297331            sage: e = RootSystem(['A',2]).ambient_space()
    298             sage: e.simple_root(0)
     332            sage: e.simple_root(0)    # indirect doctest
    299333            (-1, 0, 0)
    300334        """
    301335        return str(self.to_vector())
    class AmbientSpaceElement(CombinatorialF 
    354388        """
    355389        return self.parent().rho().scalar(self) > 0
    356390
    357     def is_dominant_weight(self): # Or is_dominant_integral_weight?
    358         """
    359         Tests whether ``self`` is a dominant element of the weight lattice
    360 
    361         TODO: EXAMPLES
    362 
    363         TODO: generalize to any root lattice realization
    364         """
    365         alphacheck = self.parent().simple_coroots()
    366         vp = [self.inner_product(alphacheck[i]) for i in self.parent().index_set()]
    367         return all(v in ZZ and v >= 0 for v in vp)
    368 
    369391    def coerce_to_sl(self):
    370392        """
    371393        For type ['A',r], this coerces the element of the ambient space into the
  • 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 automatically translated into the previo 
    310310#  Distributed under the terms of the GNU General Public License (GPL)
    311311#                  http://www.gnu.org/licenses/
    312312#*****************************************************************************
     313from types import ClassType as classobj
    313314from sage.misc.cachefunc import cached_method
    314315from sage.misc.abstract_method import abstract_method
    315316from sage.rings.all import ZZ
    class CartanTypeFactory(SageObject): 
    478479
    479480    def _repr_(self):
    480481        """
    481             sage: CartanType
     482        EXAMPLES::
     483
     484            sage: CartanType    # indirect doctest
    482485            CartanType
    483486        """
    484487        return "CartanType"
    class CartanTypeFactory(SageObject): 
    552555
    553556    @cached_method
    554557    def _samples(self):
     558        """
     559        Returns a sample of all implemented Cartan types
     560
     561        .. note:: this is intended to be used through :meth:`samples`
     562
     563        EXAMPLES::
     564
     565            sage: CartanType._samples()
     566            [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 2], ['D', 3], ['D', 5], ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2], ['I', 5], ['H', 3], ['H', 4], ['A', 1, 1], ['A', 5, 1], ['B', 1, 1], ['B', 5, 1], ['C', 1, 1], ['C', 5, 1], ['D', 3, 1], ['D', 5, 1], ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*, ['BC', 1, 2], ['BC', 5, 2]]
     567        """
    555568        finite_crystalographic = \
    556569            [CartanType (t)       for t in [['A', 1], ['A', 5], ['B', 1], ['B', 5],
    557570                                            ['C', 1], ['C', 5], ['D', 2], ['D', 3], ['D', 5],
    class CartanType_abstract(object): 
    605618        """
    606619        return None
    607620
    608     def _add_abstract_superclass(self, cls):
     621    def _add_abstract_superclass(self, classes):
     622        """
     623        Adds abstract super-classes to the class of ``self``
     624
     625        INPUT:
     626
     627        - ``classes`` -- an abstract class or tuple thereof
     628
     629        EXAMPLES::
     630
     631            sage: C = CartanType(["A",3,1])
     632            sage: class MyCartanType:
     633            ...       def my_method(self):
     634            ...           return 'I am here!'
     635            sage: C._add_abstract_superclass(MyCartanType)
     636            sage: C.__class__
     637            <class 'sage.combinat.root_system.type_A_affine.CartanType_with_superclass_with_superclass'>
     638            sage: C.__class__.__bases__
     639            (<class 'sage.combinat.root_system.type_A_affine.CartanType_with_superclass'>,
     640             <class __main__.MyCartanType at ...>)
     641            sage: C.my_method()
     642            'I am here!'
     643
     644        .. todo:: Generalize to SageObject?
     645        """
    609646        from sage.structure.dynamic_class import dynamic_class
    610         self.__class__ = dynamic_class(self.__class__.__name__+"_with_superclass", (self.__class__, cls))
     647        assert isinstance(classes, (tuple, type, classobj))
     648        if not isinstance(classes, tuple):
     649            classes = (classes,)
     650        bases = (self.__class__,) + classes
     651        self.__class__ = dynamic_class(self.__class__.__name__+"_with_superclass", bases)
    611652
    612653    @abstract_method
    613654    def rank(self):
    class CartanType_abstract(object): 
    664705    @abstract_method(optional = True)
    665706    def coxeter_diagram(self):
    666707        """
    667         Returns the Coxeter diagram for self.
     708        Returns the Coxeter diagram for ``self``.
     709
     710        EXAMPLES::
     711
     712            sage: CartanType(['B',3]).coxeter_diagram()
     713            Graph on 3 vertices
     714            sage: CartanType(['A',3]).coxeter_diagram().edges()
     715            [(1, 2, 3), (2, 3, 3)]
     716            sage: CartanType(['B',3]).coxeter_diagram().edges()
     717            [(1, 2, 3), (2, 3, 4)]
     718            sage: CartanType(['G',2]).coxeter_diagram().edges()
     719            [(1, 2, 6)]
     720            sage: CartanType(['F',4]).coxeter_diagram().edges()
     721            [(1, 2, 3), (2, 3, 4), (3, 4, 3)]
     722
     723        This is currently implemented only for crystallographic types::
     724
     725            sage: CartanType(['H',3]).coxeter_diagram
     726            NotImplemented
    668727        """
    669728
     729    @cached_method
     730    def coxeter_matrix(self):
     731        """
     732        Returns the Coxeter matrix for this type.
     733
     734        EXAMPLES::
     735
     736            sage: CartanType(['A', 4]).coxeter_matrix()
     737            [1 3 2 2]
     738            [3 1 3 2]
     739            [2 3 1 3]
     740            [2 2 3 1]
     741        """
     742        from sage.matrix.constructor import matrix
     743        from sage.rings.all import ZZ
     744        index_set = self.index_set()
     745        reverse = dict((index_set[i], i) for i in range(len(index_set)))
     746        m = matrix(ZZ,len(index_set), lambda i,j: 1 if i==j else 2)
     747        for (i,j,l) in self.coxeter_diagram().edge_iterator():
     748            m[reverse[i], reverse[j]] = l
     749            m[reverse[j], reverse[i]] = l
     750        m.set_immutable()
     751        return m
     752
    670753    def dual(self):
    671754        """
    672755        Returns the dual cartan type, possibly just as a formal dual.
    class CartanType_abstract(object): 
    869952        return False
    870953
    871954    def is_implemented(self):
     955        """
     956        Checks whether the Cartan datum for ``self`` is actually implemented
     957
     958        EXAMPLES::
     959
     960            sage: CartanType(["A",4,1]).is_implemented()
     961            True
     962            sage: CartanType(['H',3]).is_implemented()
     963            False
     964
     965        .. todo::
     966
     967            Implemente Cartan datum for non crystallographic types,
     968            and update the implementation of this method accordingly,
     969            say by testing the coxeter diagram instead.
     970        """
    872971        try:
    873972            self.dynkin_diagram()
    874973            return True
    class CartanType_crystalographic(CartanT 
    9211020        from sage.combinat.root_system.cartan_matrix import cartan_matrix
    9221021        return cartan_matrix(self)
    9231022
     1023    @cached_method
     1024    def coxeter_diagram(self):
     1025        """
     1026        Returns the Coxeter diagram for ``self``
     1027
     1028        This implementation constructs it from the Dynkin diagram
     1029
     1030        .. seealso:: :meth:`CartanType_abstract.coxeter_diagram`
     1031
     1032        EXAMPLES::
     1033
     1034            sage: CartanType(['A',3]).coxeter_diagram()
     1035            Graph on 3 vertices
     1036            sage: CartanType(['A',3]).coxeter_diagram().edges()
     1037            [(1, 2, 3), (2, 3, 3)]
     1038            sage: CartanType(['B',3]).coxeter_diagram().edges()
     1039            [(1, 2, 3), (2, 3, 4)]
     1040            sage: CartanType(['G',2]).coxeter_diagram().edges()
     1041            [(1, 2, 6)]
     1042            sage: CartanType(['F',4]).coxeter_diagram().edges()
     1043            [(1, 2, 3), (2, 3, 4), (3, 4, 3)]
     1044            sage: CartanType(['A',2,2]).coxeter_diagram().edges()
     1045            [(0, 1, +Infinity)]
     1046        """
     1047        from sage.rings.infinity import infinity
     1048        scalarproducts_to_order = { 0: 2,  1: 3,  2: 4,  3: 6, 4: infinity }
     1049        from sage.graphs.all import Graph
     1050        coxeter_diagram = Graph(multiedges=False)
     1051        a = self.dynkin_diagram()
     1052        I = self.index_set()
     1053        coxeter_diagram.add_vertices(I)
     1054        for i in I:
     1055            for j in a.neighbors_out(i):
     1056                # avoid adding the edge twice
     1057                if not coxeter_diagram.has_edge(i,j):
     1058                    coxeter_diagram.add_edge(i,j, scalarproducts_to_order[a[i,j]*a[j,i]])
     1059        return coxeter_diagram
     1060
    9241061    def is_crystalographic(self):
    9251062        """
    9261063        Implements :meth:`CartanType_abstract.is_crystalographic`
    class CartanType_crystalographic(CartanT 
    9331070        """
    9341071        return True
    9351072
     1073    @cached_method
    9361074    def symmetrizer(self):
    9371075        """
     1076        Returns the symmetrizer of the Cartan matrix of ``self``
     1077
    9381078        A Cartan matrix `M` is symmetrizable if there exists a non
    9391079        trivial diagonal matrix `D` such that `DM` is a symmetric
    9401080        matrix, that is `DM = M^tD`. In that case, `D` is unique, up
    9411081        to a scalar factor for each connected component of the Dynkin
    9421082        diagram.
    943        
    944         This method currently assumes that the Cartan type is irreducible.
    9451083
    946         This method computes the unique minimal such `D` with non
    947         negative integral coefficients. If `D` exists, it is returned
    948         as a family. Otherwise None is returned.
     1084        This method computes the unique minimal such `D` with positive
     1085        integral coefficients. If `D` exists, it is returned as a
     1086        family. Otherwise ``None`` is returned.
     1087
     1088        The coefficients are coerced to ``base_ring``.
    9491089
    9501090        EXAMPLES::
    9511091
    class CartanType_crystalographic(CartanT 
    9641104            O=<=O---O---O---O=<=O
    9651105            1   2   2   2   2   4
    9661106
     1107       Here is the symmetrizer of some reducible Cartan types::
     1108
     1109            sage: T = CartanType(["D", 2])
     1110            sage: print T.ascii_art(T.symmetrizer().__getitem__)
     1111            O   O
     1112            1   1
     1113
     1114            sage: T = CartanType(["B",5],["BC",5, 2])
     1115            sage: print T.ascii_art(T.symmetrizer().__getitem__)
     1116            O---O---O---O=>=O
     1117            2   2   2   2   1
     1118            O=<=O---O---O---O=<=O
     1119            1   2   2   2   2   4
     1120
    9671121        Property: up to an overall scalar factor, this gives the norm
    9681122        of the simple roots in the ambient space::
    9691123
    class CartanType_crystalographic(CartanT 
    9781132            2   2   2   2   4
    9791133
    9801134        """
    981         assert self.is_irreducible()
    9821135        from sage.matrix.constructor import matrix, diagonal_matrix
    9831136        m = self.cartan_matrix()
    9841137        n = m.nrows()
    class CartanType_crystalographic(CartanT 
    9871140            M[i, n * i + j]  = m[i,j]
    9881141            M[j, n * i + j] -= m[j,i]
    9891142        kern = M.integer_kernel()
    990         assert kern.dimension() <= 1
    991         if kern.dimension() == 0:
     1143        c = len(self.dynkin_diagram().connected_components())
     1144        if kern.dimension() < c:
     1145            # the Cartan matrix is not symmetrizable
    9921146            return None
    993         D = kern.basis()[0]
     1147        assert kern.dimension() == c
     1148        # Now the basis contains one vector v per connected component
     1149        # C of the dynkin diagram, or equivalently diagonal block of
     1150        # the Cartan matrix. The support of v is exactly that
     1151        # connected component, and it symmetrizes the corresponding
     1152        # diagonal block of the Cartan matrix. We sum all those vectors.
     1153        D = sum(kern.basis())
    9941154        assert diagonal_matrix(D) * m == m.transpose() * diagonal_matrix(D)
    9951155        I = self.index_set()
    9961156        return Family( dict( (I[i], D[i]) for i in range(n) ) )
    class CartanType_affine(CartanType_simpl 
    11401300    @abstract_method
    11411301    def special_node(self):
    11421302        r"""
     1303        Returns a special node of the Dynkin diagram
    11431304
    1144         A special node is a node of the Dynkin diagram such that
     1305        A *special* node is a node of the Dynkin diagram such that
    11451306        pruning it yields a Dynkin diagram for the associated
    11461307        classical type (see :meth:`.classical`).
    11471308
    class CartanType_affine(CartanType_simpl 
    12371398            sage: RootSystem(['BC',4,2]).cartan_type().acheck()
    12381399            Finite family {0: 1, 1: 2, 2: 2, 3: 2, 4: 2}
    12391400
     1401        ``acheck`` is a shortcut for row_annihilator::
     1402
     1403            sage: RootSystem(['BC',4,2]).cartan_type().row_annihilator()
     1404            Finite family {0: 1, 1: 2, 2: 2, 3: 2, 4: 2}
     1405
    12401406        FIXME:
    12411407         - The current implementation assumes that the Cartan matrix
    12421408           is indexed by `[0,1,...]`, in the same order as the index set.
    class CartanType_affine(CartanType_simpl 
    12771443            Finite family {0: 1, 1: 2, 2: 3, 3: 4, 4: 2}
    12781444            sage: RootSystem(['BC',4,2]).cartan_type().a()
    12791445            Finite family {0: 2, 1: 2, 2: 2, 3: 2, 4: 1}
     1446
     1447        ``a`` is a shortcut for col_annihilator::
     1448
     1449            sage: RootSystem(['BC',4,2]).cartan_type().col_annihilator()
     1450            Finite family {0: 2, 1: 2, 2: 2, 3: 2, 4: 1}
    12801451        """
    12811452        return self.row_annihilator(self.cartan_matrix().transpose())
    12821453
    class CartanType_standard_finite(UniqueR 
    15461717    def _repr_(self, compact = False):
    15471718        """
    15481719        TESTS::
    1549        
     1720
    15501721            sage: ct = CartanType(['A',3])
    15511722            sage: repr(ct)
    15521723            "['A', 3]"
     1724            sage: ct._repr_(compact=True)
     1725            'A3'
    15531726        """
    15541727        format = '%s%s' if compact else "['%s', %s]"
    15551728        return format%(self.letter, self.n)
    class CartanType_standard_affine(UniqueR 
    17221895    def _repr_(self, compact = False):
    17231896        """
    17241897        TESTS::
    1725        
     1898
    17261899            sage: ct = CartanType(['A',3, 1])
    17271900            sage: repr(ct)
    17281901            "['A', 3, 1]"
     1902            sage: ct._repr_(compact=True)
     1903            'A3~'
    17291904        """
    17301905        if compact:
    17311906            return '%s%s~'%(self.letter, self.n)
  • sage/combinat/root_system/coxeter_matrix.py

    diff --git a/sage/combinat/root_system/coxeter_matrix.py b/sage/combinat/root_system/coxeter_matrix.py
    a b from sage.rings.all import ZZ 
    2121
    2222def coxeter_matrix_as_function(t):
    2323    """
    24     Returns the coxeter matrix associated to the Cartan type t.
    25    
     24    Returns the coxeter matrix, as a function
     25
     26    INPUT:
     27
     28    - ``t`` -- a Cartan type
     29
    2630    EXAMPLES::
    27    
     31
    2832        sage: from sage.combinat.root_system.coxeter_matrix import coxeter_matrix_as_function
    2933        sage: f = coxeter_matrix_as_function(['A',4])
    3034        sage: matrix([[f(i,j) for j in range(1,5)] for i in range(1,5)])
    def coxeter_matrix_as_function(t): 
    3337        [2 3 1 3]
    3438        [2 2 3 1]
    3539    """
    36     a = CartanType(t).dynkin_diagram()
    37     scalarproducts_to_order = { 0: 2,  1: 3,  2: 4,  3: 6
    38                                 # 4 should be infinity
    39                                 }
     40    t = CartanType(t)
     41    m = t.coxeter_matrix()
     42    index_set = t.index_set()
     43    reverse = dict((index_set[i], i) for i in range(len(index_set)))
     44    return lambda i,j: m[reverse[i], reverse[j]]
    4045
    41     return lambda i,j: 1 if i == j else scalarproducts_to_order[a[i,j]*a[j,i]]
    42    
    43    
    4446def coxeter_matrix(t):
    4547    """
    4648    Returns the Coxeter matrix of type t.
    def coxeter_matrix(t): 
    9294        [1 6]
    9395        [6 1]
    9496    """
    95     ct = CartanType(t)
    96     cf = coxeter_matrix_as_function(ct)
    97     index_set = ct.index_set()
    98     MS = MatrixSpace(ZZ, len(index_set))
    99     m = MS(0)
    100     for i in range(len(index_set)):
    101         for j in range(len(index_set)):
    102             m[i,j] = cf(index_set[i],index_set[j])
    103     return m
     97    return CartanType(t).coxeter_matrix()
  • 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 
    129129    def _repr_(self):
    130130        """
    131131        EXAMPLES::
    132        
    133             sage: DynkinDiagram(['G',2])
     132
     133            sage: DynkinDiagram(['G',2])     # indirect doctest
    134134              3
    135135            O=<=O
    136136            1   2
    class DynkinDiagram_class(DiGraph, Carta 
    161161            self.add_edge(j,i,1)
    162162
    163163    def __hash__(self):
     164        """
     165        EXAMPLES::
     166
     167            sage: hash(CartanType(['A',3]).dynkin_diagram()) # indirect doctest
     168            286820813001824631
     169
     170        """
    164171        # Should assert for immutability!
    165172
    166173        #return hash(self.cartan_type(), self.vertices(), tuple(self.edges()))
    167         # FIMXE: self.edges() currently tests at some point whether
     174        # FIXME: self.edges() currently tests at some point whether
    168175        # self is a vertex of itself which causes an infinite
    169176        # recursion loop. Current workaround: call self.edge_iterator directly
    170177        return hash((self.cartan_type(), tuple(self.vertices()), tuple(self.edge_iterator(self.vertices()))))
    class DynkinDiagram_class(DiGraph, Carta 
    304311        Implements :meth:`CartanType_abstract.is_crystalographic`
    305312
    306313        A Dynkin diagram always corresponds to a crystalographic root system.
     314
     315        EXAMPLES::
     316
     317            sage: CartanType(['F',4]).dynkin_diagram().is_crystalographic()
     318            True
    307319        """
    308320        return True
    309321
  • sage/combinat/root_system/root_lattice_realization.py

    diff --git a/sage/combinat/root_system/root_lattice_realization.py b/sage/combinat/root_system/root_lattice_realization.py
    a b Root lattice realization 
    1616#                  http://www.gnu.org/licenses/
    1717#*****************************************************************************
    1818
    19 from sage.misc.all import cached_method, attrcall
     19from sage.misc.abstract_method import abstract_method, AbstractMethod
     20from sage.misc.all import attrcall
     21from sage.misc.cachefunc import cached_method
    2022from sage.misc.lazy_attribute import lazy_attribute
     23from sage.categories.category_types import Category_over_base_ring
     24from sage.categories.modules_with_basis import ModulesWithBasis
    2125from sage.sets.family import Family
    22 from sage.rings.all import ZZ
    23 from sage.structure.sage_object import SageObject
     26from sage.rings.all import ZZ, QQ
    2427from sage.combinat.backtrack import TransitiveIdeal
    2528
    26 class RootLatticeRealization(SageObject):
     29class RootLatticeRealizations(Category_over_base_ring):
     30  r"""
     31  The category of root lattice realizations over a given base ring
     32
     33  A *root lattice realization* `L` over a base ring `R` is a free
     34  module (or vector space if `R` is a field) endowed with an embedding
     35  of the root lattice of some root system.
     36
     37  Typical root lattice realizations over `\ZZ` include the root
     38  lattice, weight lattice, and ambient lattice. Typical root lattice
     39  realizations over `\QQ` include the root space, weight space, and
     40  ambient space.
     41
     42  To describe the embedding, a root lattice realization must
     43  implement a method
     44  :meth:`~RootLatticeRealizations.ParentMethods.simple_root`(i)
     45  returning for each `i` in the index set the image of the simple root
     46  `\alpha_i` under the embedding.
     47
     48  A root lattice realization must further implement a method on elements
     49  :meth:`~RootLatticeRealizations.ElementMethods.scalar`, computing
     50  the scalar product with elements of the coroot lattice or coroot space.
     51
     52  Using those, this category provides tools for reflections, roots,
     53  the Weyl group and its action, ...
     54
     55  .. seealso::
     56
     57      - :class:`~sage.combinat.root_system.root_system.RootSystem`
     58      - :class:`~sage.combinat.root_system.weight_lattice_realizations.WeightLatticeRealizations`
     59      - :class:`~sage.combinat.root_system.root_space.RootSpace`
     60      - :class:`~sage.combinat.root_system.weight_space.WeightSpace`
     61      - :class:`~sage.combinat.root_system.ambient_space.AmbientSpace`
     62
     63  EXAMPLES:
     64
     65  Here, we consider the root system of type `A_7`, and embed the root
     66  lattice element `x = \alpha_2 + 2 \alpha_6` in several root lattice
     67  realizations::
     68
     69      sage: R = RootSystem(["A",7])
     70      sage: alpha = R.root_lattice().simple_roots()
     71      sage: x = alpha[2] + 2 * alpha[5]
     72
     73      sage: L = R.root_space()
     74      sage: L(x)
     75      alpha[2] + 2*alpha[5]
     76
     77      sage: L = R.weight_lattice()
     78      sage: L(x)
     79      -Lambda[1] + 2*Lambda[2] - Lambda[3] - 2*Lambda[4] + 4*Lambda[5] - 2*Lambda[6]
     80
     81      sage: L = R.ambient_space()
     82      sage: L(x)
     83      (0, 1, -1, 0, 2, -2, 0, 0)
     84
     85  We embed the root space element `x = \alpha_2 + 1/2 \alpha_6` in
     86  several root lattice realizations::
     87
     88      sage: alpha = R.root_space().simple_roots()
     89      sage: x = alpha[2] + 1/2 * alpha[5]
     90
     91      sage: L = R.weight_space()
     92      sage: L(x)
     93      -Lambda[1] + 2*Lambda[2] - Lambda[3] - 1/2*Lambda[4] + Lambda[5] - 1/2*Lambda[6]
     94
     95      sage: L = R.ambient_space()
     96      sage: L(x)
     97      (0, 1, -1, 0, 1/2, -1/2, 0, 0)
     98
     99  Of course, one can't embed the root space in the weight lattice::
     100
     101      sage: L = R.weight_lattice()
     102      sage: L(x)
     103      Traceback (most recent call last):
     104      ...
     105      TypeError: do not know how to make x (= alpha[2] + 1/2*alpha[5]) an element of self (=Weight lattice of the Root system of type ['A', 7])
     106
     107  If `K_1` is a subring of `K_2`, then one could in theory have
     108  an embedding from the root space over `K_1` to any root
     109  lattice realization over `K_2`; this is not implemented::
     110
     111      sage: K1 = QQ
     112      sage: K2 = QQ['q']
     113      sage: L = R.weight_space(K2)
     114
     115      sage: alpha = R.root_space(K2).simple_roots()
     116      sage: L(alpha[1])
     117      2*Lambda[1] - Lambda[2]
     118
     119      sage: alpha = R.root_space(K1).simple_roots()
     120      sage: L(alpha[1])
     121      Traceback (most recent call last):
     122      ...
     123      TypeError: do not know how to make x (= alpha[1]) an element of self (=Weight space over the Univariate Polynomial Ring in q over Rational Field of the Root system of type ['A', 7])
     124
     125  By a slight abuse, the embedding of the root lattice is not actually
     126  required to be faithful. Typically for an affine root system, the
     127  null root of the root lattice is killed in the non extended weight
     128  lattice::
     129
     130      sage: R = RootSystem(["A", 3, 1])
     131      sage: delta = R.root_lattice().null_root()
     132      sage: L = R.weight_lattice()
     133      sage: L(delta)
     134      0
     135
     136  TESTS::
     137
     138      sage: TestSuite(L).run()
     139  """
     140
     141  @cached_method
     142  def super_categories(self):
     143      """
     144      EXAMPLES::
     145
     146          sage: from sage.combinat.root_system.root_lattice_realization import RootLatticeRealizations
     147          sage: RootLatticeRealizations(QQ).super_categories()
     148          [Category of modules with basis over Rational Field]
     149      """
     150      return [ModulesWithBasis(self.base_ring())]
     151
     152  class ParentMethods:
     153
     154    def __init_extra__(self):
     155        """
     156        Registers the embedding of the root lattice into ``self``
     157
     158        Also registers the embedding of the root space over the same
     159        base field `K` into ``self`` if `K` is not `\ZZ`.
     160
     161        EXAMPLES:
     162
     163        We embed the simple root `\alpha_2` of the root lattice in
     164        the weight lattice::
     165
     166            sage: R = RootSystem(["A",3])
     167            sage: alpha = R.root_lattice().simple_roots()
     168            sage: L = R.weight_lattice()
     169            sage: L(alpha[2])
     170            -Lambda[1] + 2*Lambda[2] - Lambda[3]
     171
     172        .. note::
     173
     174            More examples are given in :class:`RootLatticeRealizations`;
     175            The embeddings are systematically tested in
     176            :meth:`_test_root_lattice_realization`.
     177        """
     178        from root_space import RootSpace
     179        K = self.base_ring()
     180        # If self is the root lattice or the root space, we don't want
     181        # to register its trivial embedding into itself. This builds
     182        # the domains from which we want to register an embedding.
     183        domains = []
     184        if not isinstance(self, RootSpace) or K is not ZZ:
     185            domains.append(self.root_system.root_lattice())
     186        if not isinstance(self, RootSpace):
     187            domains.append(self.root_system.root_space(K))
     188        # Build and register the embeddings
     189        for domain in domains:
     190            domain.module_morphism(self.simple_root,
     191                                   codomain = self
     192                                   ).register_as_coercion()
     193
    27194    def cartan_type(self):
    28195        """
    29196        EXAMPLES::
    class RootLatticeRealization(SageObject) 
    55222        """
    56223        return self.root_system.dynkin_diagram()
    57224
    58     def _name_string_helper(self, name, capitalize=True, base_ring=True, type=True):
     225    def _name_string_helper(self, name, capitalize=True, base_ring=True, type=True, prefix=""):
    59226        """
    60227        EXAMPLES::
    61228       
    class RootLatticeRealization(SageObject) 
    68235            'Root space'
    69236            sage: r._name_string_helper("root", capitalize=False, base_ring=False, type=False)
    70237            'root space'
     238
     239            sage: r = RootSystem(['A',4]).coroot_space()
     240            sage: r._name_string_helper("weight", prefix="extended ")
     241            "Extended coweight space over the Rational Field of the Root system of type ['A', 4]"
    71242        """
    72         s = ""
     243        s = prefix
    73244        if self.root_system.dual_side:
    74245            s += "co"
    75246
    class RootLatticeRealization(SageObject) 
    101272
    102273    def _test_root_lattice_realization(self, **options):
    103274        """
    104         Runs sanity checks on this root lattice realization:
    105          - scalar products between simple roots and simple coroots
    106          - ...
     275        Runs sanity checks on this root lattice realization
    107276
    108         See also: :class:`Test`
     277        - embedding of the root lattice
     278        - embedding of the root space over the same base ring
     279        - scalar products between simple roots and simple coroots
     280        - ...
    109281
    110         Examples::
     282        .. seealso:: :class:`TestSuite`
     283
     284        EXAMPLES::
     285
    111286            sage: RootSystem(['A',3]).root_lattice()._test_root_lattice_realization()
    112287        """
    113288        tester = self._tester(**options)
    class RootLatticeRealization(SageObject) 
    116291        tester.assertEqual(alpha     .keys(), self.index_set())
    117292        tester.assertEqual(alphacheck.keys(), self.index_set())
    118293
     294        # Check the consistency between simple_root and simple_roots
     295        for i in self.index_set():
     296            tester.assertEqual(self.simple_root(i), alpha[i])
     297
     298        # Check the embeddings from the root lattice and the root space over the same base ring
     299        root_lattice = self.root_system.root_lattice()
     300        root_space   = self.root_system.root_space  (self.base_ring())
     301        tester.assert_(self.coerce_map_from(root_lattice) is not None)
     302        tester.assert_(self.coerce_map_from(root_space  ) is not None)
     303        for i in self.index_set():
     304            # This embedding maps simple roots to simple roots
     305            tester.assertEqual(self(root_lattice.simple_root(i)), alpha[i])
     306            tester.assertEqual(self(root_space   .simple_root(i)), alpha[i])
     307
     308        # Check that the scalar products match with the Dynkin diagram
    119309        dynkin_diagram = self.dynkin_diagram()
    120310        for i in self.index_set():
    121311            for j in self.index_set():
    122312                tester.assertEqual(alpha[j].scalar(alphacheck[i]), dynkin_diagram[i,j])
    123313
     314        # Check associated_coroot, if it is implemented
     315        if not isinstance(self.element_class.associated_coroot, AbstractMethod):
     316            for i in self.index_set():
     317                tester.assertEqual(alpha[i].associated_coroot(), alphacheck[i])
     318
    124319        if self.cartan_type().is_affine():
     320            # Check that the null root is orthogonal to all coroots
     321            # and similarly for the null coroot
    125322            nullroot = self.null_root()
    126323            nullcoroot = self.null_coroot()
    127324            for k in alpha.keys():
    class RootLatticeRealization(SageObject) 
    129326                assert (alpha[k].scalar(nullcoroot)).is_zero()
    130327
    131328        # Todo: add tests of highest root, roots, has_descent, ...
    132        
    133329
    134330    ##########################################################################
    135331    # highest root
    class RootLatticeRealization(SageObject) 
    189385    # simple roots
    190386    ##########################################################################
    191387
    192     @cached_method
     388    @abstract_method
    193389    def simple_root(self, i):
    194390        """
    195         Returns the `i^{th}` simple root.  This should be overridden by any
    196         subclass.
     391        Returns the `i^{th}` simple root.
     392
     393        This should be overridden by any subclass, and typically
     394        implemented as a cached method for efficiency.
    197395
    198396        EXAMPLES::
    199        
     397
    200398            sage: r = RootSystem(["A",3]).root_lattice()
    201399            sage: r.simple_root(1)
    202400            alpha[1]
    203401
    204402        TESTS::
    205        
    206             sage: from sage.combinat.root_system.root_lattice_realization import RootLatticeRealization
    207             sage: RootLatticeRealization().simple_root(1)
     403
     404            sage: super(sage.combinat.root_system.root_space.RootSpace, r).simple_root(1)
    208405            Traceback (most recent call last):
    209406            ...
    210             NotImplementedError
    211            
     407            NotImplementedError: <abstract method simple_root at ...>
    212408        """
    213         raise NotImplementedError
    214409
    215410    @cached_method
    216411    def simple_roots(self):
    class RootLatticeRealization(SageObject) 
    400595        """
    401596        return self.root_system.coroot_lattice()
    402597
    403     def coroot_space(self):
     598    def coroot_space(self, base_ring = QQ):
    404599        """
    405         Returns the coroot lattice.
     600        Returns the coroot space over ``base_ring``
     601
     602        INPUT:
     603
     604        - ``base_ring`` -- a ring (default: `\QQ`)
    406605
    407606        EXAMPLES::
    408        
     607
    409608            sage: RootSystem(['A',2]).root_lattice().coroot_space()
    410609            Coroot space over the Rational Field of the Root system of type ['A', 2]
    411610
     611            sage: RootSystem(['A',2]).root_lattice().coroot_space(QQ['q'])
     612            Coroot space over the Univariate Polynomial Ring in q over Rational Field of the Root system of type ['A', 2]
     613
    412614        """
    413         return self.root_system.coroot_space()
     615        return self.root_system.coroot_space(base_ring = base_ring)
    414616
    415617
    416618    def simple_coroot(self, i):
    class RootLatticeRealization(SageObject) 
    694896            sage: pi
    695897            pi
    696898        """
     899        assert to_negative == True # Not implemented otherwise!!!!!
    697900        res = self.alpha().zip(self.projection, self.alphacheck())
    698901        # Should this use rename to set a nice name for this family?
    699902        res.rename("pi")
    700903        return res
    701    
     904
    702905    @lazy_attribute
    703906    def pi(self):
    704         return self.simple_projections()
     907        r"""
     908        The simple projections of ``self``
    705909
    706     @lazy_attribute
    707     def opi(self):
    708         return self.simple_projections(to_negative=False)
     910        .. seealso:: :meth:`simple_projections`
    709911
    710     def to_coroot_lattice_morphism(self):
    711         """
    712         Returns a morphism to the coroot lattice using the symmetrizer of the Cartan matrix.
     912        .. warning:: this shortcut is deprecated
    713913
    714914        EXAMPLES::
    715915
    716             sage: R = RootSystem(['A',3]).root_space()
    717             sage: alpha = R.simple_roots()
    718             sage: f = R.to_coroot_lattice_morphism()
    719             sage: f(alpha[1])
    720             alphacheck[1]
    721             sage: f(alpha[1]+alpha[2])
    722             alphacheck[1] + alphacheck[2]
    723             sage: S = RootSystem(['G',2]).root_space()
    724             sage: alpha = S.simple_roots()
    725             sage: f = S.to_coroot_lattice_morphism()
    726             sage: f(alpha[1])
    727             alphacheck[1]
    728             sage: f(alpha[1]+alpha[2])
    729             alphacheck[1] + 3*alphacheck[2]
     916            sage: space = RootSystem(['A',2]).weight_lattice()
     917            sage: pi = space.pi
     918            sage: x = space.simple_roots()
     919            sage: pi[1](x[2])
     920            -Lambda[1] + 2*Lambda[2]
    730921        """
    731         return self.module_morphism(diagonal=(lambda i : self.cartan_type().symmetrizer()[i]), codomain=self.coroot_space())
    732 
     922        # _test_not_implemented_methods apparently evaluates all lazy
     923        # attributes, which means that we can't use deprecation here!
     924        # from sage.misc.misc import deprecation
     925        # deprecation("The lazy attribute pi is deprecated; please use the simple_projections method.", 'Sage Version 5.0')
     926        return self.simple_projections()
    733927
    734928    ##########################################################################
    735929    # Weyl group
    class RootLatticeRealization(SageObject) 
    9541148            orbits.append(orbit)
    9551149        return orbits
    9561150
    957 class RootLatticeRealizationElement(object):
     1151  class ElementMethods:
     1152
     1153    @abstract_method
    9581154    def scalar(self, lambdacheck):
    9591155        """
    960         The natural pairing between this and the coroot lattice.  This should be overridden
    961         in subclasses.
     1156        The natural pairing with the coroot lattice
     1157
     1158        INPUT:
     1159
     1160        - ``self`` -- an element of a root lattice realization
     1161        - ``lambdacheck`` -- an element of the coroot lattice or coroot space
     1162
     1163        OUTPUT: the scalar product of ``self`` and ``lambdacheck``
    9621164
    9631165        EXAMPLES::
    964        
    965             sage: r = RootSystem(['A',4]).root_lattice()
    966             sage: cr = RootSystem(['A',4]).coroot_lattice()
    967             sage: a1 = r.simple_root(1)
    968             sage: ac1 = cr.simple_root(1)
    969             sage: a1.scalar(ac1)
     1166
     1167            sage: L = RootSystem(['A',4]).root_lattice()
     1168            sage: alpha      = L.simple_roots()
     1169            sage: alphacheck = L.simple_coroots()
     1170            sage: alpha[1].scalar(alphacheck[1])
    9701171            2
     1172            sage: alpha[1].scalar(alphacheck[2])
     1173            -1
     1174            sage: matrix([ [ alpha[i].scalar(alphacheck[j])
     1175            ...              for i in L.index_set() ]
     1176            ...            for j in L.index_set() ])
     1177            [ 2 -1  0  0]
     1178            [-1  2 -1  0]
     1179            [ 0 -1  2 -1]
     1180            [ 0  0 -1  2]
    9711181
    9721182        TESTS::
    973        
    974             sage: from sage.combinat.root_system.root_lattice_realization import RootLatticeRealizationElement
    975             sage: RootLatticeRealizationElement.scalar(a1, ac1)
     1183
     1184            sage: super(sage.combinat.root_system.root_space.RootSpaceElement,alpha[1]).scalar(alphacheck[1])
    9761185            Traceback (most recent call last):
    9771186            ...
    978             NotImplementedError
    979 
     1187            NotImplementedError: <abstract method scalar at ...>
    9801188        """
    981         raise NotImplementedError
    982 
    9831189
    9841190    ##########################################################################
    9851191    # Action and orbits w.r.t. the Weyl group
    class RootLatticeRealizationElement(obje 
    9871193
    9881194    def simple_reflection(self, i):
    9891195        """
    990         The image of self by the `i^{th}` simple reflection.
     1196        Returns the image of ``self`` by the `i`-th simple reflection.
    9911197
    9921198        EXAMPLES::
    993        
     1199
    9941200            sage: alpha = RootSystem(["A", 3]).root_lattice().alpha()
    9951201            sage: alpha[1].simple_reflection(2)
    9961202            alpha[1] + alpha[2]
    9971203
     1204            sage: Q = RootSystem(['A', 3, 1]).weight_lattice(extended = True)
     1205            sage: Lambda = Q.fundamental_weights()
     1206            sage: L = Lambda[0] + Q.null_root()
     1207            sage: L.simple_reflection(0)
     1208            -Lambda[0] + Lambda[1] + Lambda[3]
    9981209        """
    9991210        # Subclasses should optimize whenever possible!
    1000         return self.parent().simple_reflections()[i](self)
     1211        return self.parent().simple_reflection(i)(self)
    10011212
    10021213    def simple_reflections(self):
    10031214        """
    10041215        The images of self by all the simple reflections
     1216
     1217        EXAMPLES::
     1218
     1219            sage: alpha = RootSystem(["A", 3]).root_lattice().alpha()
     1220            sage: alpha[1].simple_reflections()
     1221            [-alpha[1], alpha[1] + alpha[2], alpha[1]]
    10051222        """
    10061223        return [s(self) for s in self.parent().simple_reflections()]
    10071224
    class RootLatticeRealizationElement(obje 
    10321249    #
    10331250    ##########################################################################
    10341251
     1252    @abstract_method(optional=True)
    10351253    def associated_coroot(self):
    10361254        """
    1037         Returns the coroot associated to this root.
     1255        Returns the coroot associated to this root
    10381256
    10391257        EXAMPLES::
    1040        
     1258
    10411259            sage: alpha = RootSystem(["A", 3]).root_space().simple_roots()
    10421260            sage: alpha[1].associated_coroot()
    10431261            alphacheck[1]
    10441262        """
    1045         #assert(self in self.parent().roots() is not False)
    1046         f = self.parent().to_coroot_lattice_morphism()
    1047         return (2/self.scalar(f(self)))*f(self);
    10481263
    10491264    ##########################################################################
    10501265    # Descents
    class RootLatticeRealizationElement(obje 
    12231438        """
    12241439        return self.first_descent(index_set, not positive) is None
    12251440
     1441    def is_dominant_weight(self): # Or is_dominant_integral_weight?
     1442        """
     1443        Tests whether ``self`` is a dominant element of the weight lattice
     1444
     1445        EXAMPLES::
     1446
     1447            sage: L = RootSystem(['A',2]).ambient_lattice()
     1448            sage: Lambda = L.fundamental_weights()
     1449            sage: [x.is_dominant() for x in Lambda]
     1450            [True, True]
     1451            sage: (3*Lambda[1]+Lambda[2]).is_dominant()
     1452            True
     1453            sage: (Lambda[1]-Lambda[2]).is_dominant()
     1454            False
     1455            sage: (-Lambda[1]+Lambda[2]).is_dominant()
     1456            False
     1457
     1458        .. warning::
     1459
     1460            The current implementation tests that the scalar products
     1461            with the coroots are all in `\NN`, which is not
     1462            sufficient. For example, if `x` is the sum of a dominant
     1463            element of the weight lattice plus some other element
     1464            orthogonal to all coroots, then the current implementation
     1465            erroneously reports `x` to be a dominant weight::
     1466
     1467                sage: x = Lambda[1] + L([-1,-1,-1])
     1468                sage: x.is_dominant_weight()
     1469                True
     1470        """
     1471        alphacheck = self.parent().simple_coroots()
     1472        from sage.rings.semirings.non_negative_integer_semiring import NN
     1473        return all(self.inner_product(alphacheck[i]) in NN
     1474                   for i in self.parent().index_set())
     1475
     1476
    12261477    ##########################################################################
    12271478    # weak order
    12281479    ##########################################################################
  • 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  
    11"""
    2 Root lattices and root spaces
     2Root lattice and root spaces of a root system
    33"""
    44#*****************************************************************************
    55#       Copyright (C) 2008-2009 Nicolas M. Thiery <nthiery at users.sf.net>
    Root lattices and root spaces 
    88#                  http://www.gnu.org/licenses/
    99#*****************************************************************************
    1010
     11from sage.misc.cachefunc import ClearCacheOnPickle, cached_method
     12from sage.rings.all import ZZ
    1113from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement
    12 from root_lattice_realization import RootLatticeRealization, RootLatticeRealizationElement
    13 from sage.misc.cachefunc import ClearCacheOnPickle
     14from root_lattice_realization import RootLatticeRealizations
    1415
    1516# TODO: inheriting from ClearCacheOnPickle is a technical detail unrelated to root spaces
    1617# could we abstract this somewhere higher?
    1718
    18 class RootSpace(ClearCacheOnPickle, CombinatorialFreeModule, RootLatticeRealization):
     19class RootSpace(ClearCacheOnPickle, CombinatorialFreeModule):
    1920    r"""
     21    The root space of a root system over a given base ring
     22
    2023    INPUT:
    21      - root_system: a root system
    22      - base_ring: a ring `R`
    2324
    24     The root space (or lattice if base_ring is ZZ) of a root system,
    25     that is the formal free module `\bigoplus_i R \alpha_i` generated
    26     by the simple roots `\alpha_i`.
     25    - ``root_system`` - a root system
     26    - ``base_ring``: a ring `R`
     27
     28    The *root space* (or lattice if ``base_ring`` is `\ZZ`) of a root
     29    system is the formal free module `\bigoplus_i R \alpha_i`
     30    generated by the simple roots `(\alpha_i)_{i\in I}` of the root system.
    2731
    2832    This class is also used for coroot spaces (or lattices).
    2933
     34    .. seealso::
     35
     36        - :meth:`RootSystem`
     37        - :meth:`RootSystem.root_lattice` and :meth:`RootSystem.root_space`
     38        - :meth:`~sage.combinat.root_system.root_lattice_realizations.RootLatticeRealizations`
     39
    3040    Todo: standardize the variable used for the root space in the examples (P?)
    3141
    3242    TESTS::
    3343
    34         sage: for ct in CartanType.samples():
     44        sage: for ct in CartanType.samples()+[CartanType(["A",2],["C",5,1])]:
    3545        ...       if ct.is_implemented():
    3646        ...           P = ct.root_system().root_space()
    3747        ...           TestSuite(P).run()
    class RootSpace(ClearCacheOnPickle, Comb 
    5262            sage: s = P.simple_reflections()
    5363
    5464        """
     65        from sage.categories.morphism import SetMorphism
     66        from sage.categories.homset import Hom
     67        from sage.categories.sets_with_partial_maps import SetsWithPartialMaps
    5568        self.root_system = root_system
    56         basis_name = "alphacheck" if root_system.dual_side else "alpha"
    57         basis_name_latex  = "\\alpha^\\vee" if root_system.dual_side else "\\alpha"
    5869        CombinatorialFreeModule.__init__(self, base_ring,
    5970                                         root_system.index_set(),
    60                                          element_class = RootSpaceElement,
    61                                          prefix=basis_name,
    62                                          latex_prefix=basis_name_latex)
     71                                         prefix = "alphacheck" if root_system.dual_side else "alpha",
     72                                         latex_prefix = "\\alpha^\\vee" if root_system.dual_side else "\\alpha",
     73                                         category = RootLatticeRealizations(base_ring))
     74        if base_ring is not ZZ:
     75            # Register the partial conversion back from ``self`` to the root lattice
     76            # See :meth:`_to_root_lattice` for tests
     77            root_lattice = self.root_system.root_lattice()
     78            SetMorphism(Hom(self, root_lattice, SetsWithPartialMaps()),
     79                        self._to_root_lattice
     80                        ).register_as_conversion()
    6381
    6482    def _repr_(self):
    6583        """
    66         TESTS::
    67             sage: RootSystem(['A',4]).root_lattice()
     84        EXAMPLES::
     85
     86            sage: RootSystem(['A',4]).root_lattice()    # indirect doctest
    6887            Root lattice of the Root system of type ['A', 4]
    6988            sage: RootSystem(['B',4]).root_space()
    7089            Root space over the Rational Field of the Root system of type ['B', 4]
    class RootSpace(ClearCacheOnPickle, Comb 
    86105        return self._name_string_helper("root", capitalize=capitalize, base_ring=base_ring, type=type)
    87106     
    88107    simple_root = CombinatorialFreeModule.monomial
    89    
    90108
    91 class RootSpaceElement(CombinatorialFreeModuleElement, RootLatticeRealizationElement):
     109    @cached_method
     110    def to_coroot_space_morphism(self):
     111        """
     112        Returns the ``nu`` map to the coroot space over the same base ring, using the symmetrizer of the Cartan matrix
     113
     114        It does not map the root lattice to the coroot lattice, but
     115        has the property that any root is mapped to some scalar
     116        multiple of its associated coroot.
     117
     118        EXAMPLES::
     119
     120            sage: R = RootSystem(['A',3]).root_space()
     121            sage: alpha = R.simple_roots()
     122            sage: f = R.to_coroot_space_morphism()
     123            sage: f(alpha[1])
     124            alphacheck[1]
     125            sage: f(alpha[1]+alpha[2])
     126            alphacheck[1] + alphacheck[2]
     127
     128            sage: R = RootSystem(['A',3]).root_lattice()
     129            sage: alpha = R.simple_roots()
     130            sage: f = R.to_coroot_space_morphism()
     131            sage: f(alpha[1])
     132            alphacheck[1]
     133            sage: f(alpha[1]+alpha[2])
     134            alphacheck[1] + alphacheck[2]
     135
     136            sage: S = RootSystem(['G',2]).root_space()
     137            sage: alpha = S.simple_roots()
     138            sage: f = S.to_coroot_space_morphism()
     139            sage: f(alpha[1])
     140            alphacheck[1]
     141            sage: f(alpha[1]+alpha[2])
     142            alphacheck[1] + 3*alphacheck[2]
     143        """
     144        R = self.base_ring()
     145        C = self.cartan_type().symmetrizer().map(R)
     146        return self.module_morphism(diagonal = C.__getitem__,
     147                                    codomain=self.coroot_space(R))
     148
     149    def _to_root_lattice(self, x):
     150        """
     151        Tries to convert ``x`` to the root lattice
     152
     153        INPUT:
     154
     155        - ``x`` -- an element of ``self``
     156
     157        EXAMPLES::
     158
     159            sage: R = RootSystem(['A',3])
     160            sage: root_space = R.root_space()
     161            sage: x = root_space.an_element(); x
     162            2*alpha[1] + 2*alpha[2] + 3*alpha[3]
     163            sage: root_space._to_root_lattice(x)
     164            2*alpha[1] + 2*alpha[2] + 3*alpha[3]
     165            sage: root_space._to_root_lattice(x).parent()
     166            Root lattice of the Root system of type ['A', 3]
     167
     168        This will fail if ``x`` does not have integral coefficients::
     169
     170            sage: root_space._to_root_lattice(x/2)
     171            Traceback (most recent call last):
     172            ...
     173            ValueError: alpha[1] + alpha[2] + 3/2*alpha[3] does not have integral coefficients
     174
     175        .. note::
     176
     177            For internal use only; instead use a conversion::
     178
     179                sage: R.root_lattice()(x)
     180                2*alpha[1] + 2*alpha[2] + 3*alpha[3]
     181                sage: R.root_lattice()(x/2)
     182                Traceback (most recent call last):
     183                ...
     184                ValueError: alpha[1] + alpha[2] + 3/2*alpha[3] does not have integral coefficients
     185
     186        .. todo:: generalize diagonal module morphisms to implement this
     187        """
     188        try:
     189            return self.root_system.root_lattice().sum_of_terms( (i, ZZ(c)) for (i,c) in x)
     190        except TypeError:
     191            raise ValueError, "%s does not have integral coefficients"%x
     192
     193class RootSpaceElement(CombinatorialFreeModuleElement):
    92194    def scalar(self, lambdacheck):
    93195        """
    94196        The scalar product between the root lattice and
    95197        the coroot lattice.
    96198
    97199        EXAMPLES::
    98        
    99             sage: r = RootSystem(['A',4]).root_lattice()
    100             sage: cr = RootSystem(['A',4]).coroot_lattice()
    101             sage: a1 = r.simple_root(1)
    102             sage: ac1 = cr.simple_root(1)
    103             sage: a1.scalar(ac1)
     200
     201            sage: L = RootSystem(['B',4]).root_lattice()
     202            sage: alpha      = L.simple_roots()
     203            sage: alphacheck = L.simple_coroots()
     204            sage: alpha[1].scalar(alphacheck[1])
    104205            2
     206            sage: alpha[1].scalar(alphacheck[2])
     207            -1
    105208
     209        The scalar products between the roots and coroots are given by
     210        the Cartan matrix::
     211
     212            sage: matrix([ [ alpha[i].scalar(alphacheck[j])
     213            ...              for i in L.index_set() ]
     214            ...            for j in L.index_set() ])
     215            [ 2 -1  0  0]
     216            [-1  2 -1  0]
     217            [ 0 -1  2 -1]
     218            [ 0  0 -2  2]
     219
     220            sage: L.cartan_type().cartan_matrix()
     221            [ 2 -1  0  0]
     222            [-1  2 -1  0]
     223            [ 0 -1  2 -1]
     224            [ 0  0 -2  2]
    106225        """
    107226        # Find some better test
    108227        assert lambdacheck in self.parent().coroot_lattice() or lambdacheck in self.parent().coroot_space()
    class RootSpaceElement(CombinatorialFree 
    126245            sage: w.is_positive_root()
    127246            False
    128247        """
    129         for c in self.coefficients():
    130             if c < 0:
    131                 return False
    132         return True
     248        return all( c>= 0 for c in self.coefficients() )
    133249
     250    def associated_coroot(self):
     251        r"""
     252        Returns the coroot associated to this root
     253
     254        OUTPUT:
     255
     256        An element of the coroot space over the same base ring; in
     257        particular the result is in the coroot lattice whenever
     258        ``self`` is in the root lattice.
     259
     260        EXAMPLES::
     261
     262            sage: L = RootSystem(["B", 3]).root_space()
     263            sage: alpha = L.simple_roots()
     264            sage: alpha[1].associated_coroot()
     265            alphacheck[1]
     266            sage: alpha[1].associated_coroot().parent()
     267            Coroot space over the Rational Field of the Root system of type ['B', 3]
     268
     269            sage: L.highest_root()
     270            alpha[1] + 2*alpha[2] + 2*alpha[3]
     271            sage: L.highest_root().associated_coroot()
     272            alphacheck[1] + 2*alphacheck[2] + alphacheck[3]
     273
     274            sage: alpha = RootSystem(["B", 3]).root_lattice().simple_roots()
     275            sage: alpha[1].associated_coroot()
     276            alphacheck[1]
     277            sage: alpha[1].associated_coroot().parent()
     278            Coroot lattice of the Root system of type ['B', 3]
     279
     280        """
     281        #assert(self in self.parent().roots() is not False)
     282        scaled_coroot = self.parent().to_coroot_space_morphism()(self)
     283        s = self.scalar(scaled_coroot)
     284        return scaled_coroot.map_coefficients(lambda c: (2*c) // s)
     285
     286RootSpace.Element = RootSpaceElement
  • 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 Documentation 
    1515-------------
    1616
    1717 - :mod:`sage.combinat.root_system`                 This current overview
    18  - :class:`CartanType`                              An introduction to Cartan types 
     18 - :class:`CartanType`                              An introduction to Cartan types
    1919 - :class:`RootSystem`                              An introduction to root systems
     20 - The ``Lie Methods and Related Combinatorics thematic`` tutorial
    2021
    2122See also
    2223--------
    class RootSystem(UniqueRepresentation, S 
    5758        Root system of type ['B', 3]
    5859   
    5960    ``R`` models the root system abstractly. It comes equipped with various
    60     realizations of the root and weight lattices, where all computation
     61    realizations of the root and weight lattices, where all computations
    6162    take place. Let us play first with the root lattice::
    6263   
    6364        sage: space = R.root_lattice()
    class RootSystem(UniqueRepresentation, S 
    199200   
    200201    The coweight lattice and space are defined similarly. Note that, to
    201202    limit confusion, all the output have been tweaked appropriately.
    202    
     203
     204    .. seealso::
     205
     206        - :mod:`sage.combinat.root_system`
     207        - :class:`RootSpace`
     208        - :class:`WeightSpace`
     209        - :class:`AmbientSpace`
     210        - :class:`~sage.combinat.root_system.root_lattice_realization.RootLatticeRealizations`
     211        - :class:`~sage.combinat.root_system.weight_lattice_realization.WeightLatticeRealizations`
     212
    203213    TESTS::
    204    
     214
    205215        sage: R = RootSystem(['C',3])
    206         sage: R == loads(dumps(R))
    207         True
     216        sage: TestSuite(R).run()
    208217        sage: L = R.ambient_space()
    209         sage: s = L.simple_reflections()
     218        sage: s = L.simple_reflections() # this used to break the testsuite below due to caching an unpicklable method
    210219        sage: s = L.simple_projections() # todo: not implemented
    211         sage: L == loads(dumps(L))
    212         True
     220        sage: TestSuite(L).run()
    213221        sage: L = R.root_space()
    214222        sage: s = L.simple_reflections()
    215         sage: L == loads(dumps(L))
    216         True
    217    
     223        sage: TestSuite(L).run()
     224
    218225    ::
    219    
    220         sage: for T in CartanType.samples(finite=True,crystalographic=True):
     226
     227        sage: for T in CartanType.samples(crystalographic=True):
    221228        ...       TestSuite(RootSystem(T)).run()
    222     """ 
     229    """
    223230
    224231    @staticmethod
    225232    def __classcall__(cls, cartan_type, as_dual_of=None):
     233        """
     234        Straighten arguments to enable unique representation
     235
     236        .. seealso:: :class:`UniqueRepresentation`
     237
     238        TESTS::
     239
     240            sage: RootSystem(["A",3]) is RootSystem(CartanType(["A",3]))
     241            True
     242            sage: RootSystem(["B",3], as_dual_of=None) is RootSystem("B3")
     243            True
     244        """
    226245        return super(RootSystem, cls).__classcall__(cls, CartanType(cartan_type), as_dual_of)
    227246
    228247    def __init__(self, cartan_type, as_dual_of=None):
    class RootSystem(UniqueRepresentation, S 
    269288        TestSuite(self.root_space()).run(**options)
    270289        TestSuite(self.weight_lattice()).run(**options)
    271290        TestSuite(self.weight_space()).run(**options)
     291        if self.cartan_type().is_affine():
     292            TestSuite(self.weight_lattice(extended=True)).run(**options)
     293            TestSuite(self.weight_space(extended=True)).run(**options)
    272294        if self.ambient_lattice() is not None:
    273295            TestSuite(self.ambient_lattice()).run(**options)
    274296        if self.ambient_space() is not None:
    class RootSystem(UniqueRepresentation, S 
    277299    def _repr_(self):
    278300        """
    279301        EXAMPLES::
    280        
    281             sage: RootSystem(['A',3])
     302
     303            sage: RootSystem(['A',3])    # indirect doctest
    282304            Root system of type ['A', 3]
     305            sage: RootSystem(['B',3]).dual    # indirect doctest
     306            Dual of root system of type ['B', 3]
    283307        """
    284308        if self.dual_side:
    285309            return "Dual of root system of type %s"%self.dual.cartan_type()
    class RootSystem(UniqueRepresentation, S 
    454478        """
    455479        return self.dual.root_space(base_ring)
    456480
    457     def weight_lattice(self):
     481    @cached_method
     482    def weight_lattice(self, extended = False):
    458483        """
    459484        Returns the weight lattice associated to self.
    460        
     485
     486        .. see also::
     487
     488            - :meth:`weight_space`
     489            - :meth:`coweight_space`, :meth:`coweight_lattice`
     490            - :class:`~sage.combinat.root_system.WeightSpace`
     491
    461492        EXAMPLES::
    462        
     493
    463494            sage: RootSystem(['A',3]).weight_lattice()
    464495            Weight lattice of the Root system of type ['A', 3]
     496
     497            sage: RootSystem(['A',3,1]).weight_space(extended = True)
     498            Extended weight space over the Rational Field of the Root system of type ['A', 3, 1]
    465499        """
    466         return self.weight_space(ZZ)
     500        return WeightSpace(self, ZZ, extended = extended)
    467501
    468502    @cached_method
    469     def weight_space(self, base_ring=QQ):
     503    def weight_space(self, base_ring=QQ, extended = False):
    470504        """
    471505        Returns the weight space associated to self.
    472        
     506
     507        .. see also::
     508
     509            - :meth:`weight_lattice`
     510            - :meth:`coweight_space`, :meth:`coweight_lattice`
     511            - :class:`~sage.combinat.root_system.WeightSpace`
     512
    473513        EXAMPLES::
    474        
     514
    475515            sage: RootSystem(['A',3]).weight_space()
    476516            Weight space over the Rational Field of the Root system of type ['A', 3]
     517
     518            sage: RootSystem(['A',3,1]).weight_space(extended = True)
     519            Extended weight space over the Rational Field of the Root system of type ['A', 3, 1]
    477520        """
    478         return WeightSpace(self, base_ring)
     521        return WeightSpace(self, base_ring, extended = extended)
    479522
    480     def coweight_lattice(self):
     523    def coweight_lattice(self, extended = False):
    481524        """
    482525        Returns the coweight lattice associated to self.
    483        
     526
     527        This is the weight lattice of the dual root system.
     528
     529        .. see also::
     530
     531            - :meth:`coweight_space`
     532            - :meth:`weight_space`, :meth:`weight_lattice`
     533            - :class:`~sage.combinat.root_system.WeightSpace`
     534
    484535        EXAMPLES::
    485        
     536
    486537            sage: RootSystem(['A',3]).coweight_lattice()
    487538            Coweight lattice of the Root system of type ['A', 3]
     539
     540            sage: RootSystem(['A',3,1]).coweight_lattice(extended = True)
     541            Extended coweight lattice of the Root system of type ['A', 3, 1]
    488542        """
    489         return self.dual.weight_lattice()
    490    
    491     def coweight_space(self, base_ring=QQ):
     543        return self.dual.weight_lattice(extended = extended)
     544
     545    def coweight_space(self, base_ring=QQ, extended = False):
    492546        """
    493         Returns the weight space associated to self.
    494        
     547        Returns the coweight space associated to self.
     548
     549        This is the weight space of the dual root system.
     550
     551        .. see also::
     552
     553            - :meth:`coweight_lattice`
     554            - :meth:`weight_space`, :meth:`weight_lattice`
     555            - :class:`~sage.combinat.root_system.WeightSpace`
     556
    495557        EXAMPLES::
    496        
     558
    497559            sage: RootSystem(['A',3]).coweight_space()
    498560            Coweight space over the Rational Field of the Root system of type ['A', 3]
     561
     562            sage: RootSystem(['A',3,1]).coweight_space(extended=True)
     563            Extended coweight space over the Rational Field of the Root system of type ['A', 3, 1]
    499564        """
    500         return self.dual.weight_space(base_ring)
     565        return self.dual.weight_space(base_ring, extended = extended)
    501566
    502567
    503568    def ambient_lattice(self):
  • sage/combinat/root_system/type_A_affine.py

    diff --git a/sage/combinat/root_system/type_A_affine.py b/sage/combinat/root_system/type_A_affine.py
    a b class CartanType(CartanType_standard_unt 
    5959
    6060        EXAMPLES::
    6161
    62             sage: a = DynkinDiagram(['A',3,1])
     62            sage: a = CartanType(['A',3,1]).dynkin_diagram()
    6363            sage: a
    6464             0
    6565             O-------+
  • sage/combinat/root_system/type_BC_affine.py

    diff --git a/sage/combinat/root_system/type_BC_affine.py b/sage/combinat/root_system/type_BC_affine.py
    a b class CartanType(CartanType_standard_aff 
    7272
    7373        EXAMPLES::
    7474
    75             sage: c = DynkinDiagram(['BC',3,2])
     75            sage: c = CartanType(['BC',3,2]).dynkin_diagram()
    7676            sage: c
    7777            O=<=O---O=<=O
    7878            0   1   2   3
    class CartanType(CartanType_standard_aff 
    8080            sage: sorted(c.edges())
    8181            [(0, 1, 1), (1, 0, 2), (1, 2, 1), (2, 1, 1), (2, 3, 1), (3, 2, 2)]
    8282
    83             sage: c = DynkinDiagram(["A", 6, 2]) # should be the same as above; did fail at some point!
     83            sage: c = CartanType(["A", 6, 2]).dynkin_diagram() # should be the same as above; did fail at some point!
    8484            sage: c
    8585            O=<=O---O=<=O
    8686            0   1   2   3
    class CartanType(CartanType_standard_aff 
    8888            sage: sorted(c.edges())
    8989            [(0, 1, 1), (1, 0, 2), (1, 2, 1), (2, 1, 1), (2, 3, 1), (3, 2, 2)]
    9090
    91             sage: c = DynkinDiagram(['BC',2,2])
     91            sage: c = CartanType(['BC',2,2]).dynkin_diagram()
    9292            sage: c
    9393            O=<=O=<=O
    9494            0   1   2
    class CartanType(CartanType_standard_aff 
    9696            sage: sorted(c.edges())
    9797            [(0, 1, 1), (1, 0, 2), (1, 2, 1), (2, 1, 2)]
    9898
    99             sage: c = DynkinDiagram(['BC',1,2])
     99            sage: c = CartanType(['BC',1,2]).dynkin_diagram()
    100100            sage: c
    101101              4
    102102            O=<=O
  • sage/combinat/root_system/type_B_affine.py

    diff --git a/sage/combinat/root_system/type_B_affine.py b/sage/combinat/root_system/type_B_affine.py
    a b class CartanType(CartanType_standard_unt 
    5252
    5353        EXAMPLES::
    5454
    55             sage: b = DynkinDiagram(['B',3,1])
     55            sage: b = CartanType(['B',3,1]).dynkin_diagram()
    5656            sage: b
    5757                O 0
    5858                |
    class CartanType(CartanType_standard_unt 
    6363            sage: sorted(b.edges())
    6464            [(0, 2, 1), (1, 2, 1), (2, 0, 1), (2, 1, 1), (2, 3, 2), (3, 2, 1)]
    6565
    66             sage: b = DynkinDiagram(['B',2,1]); b
     66            sage: b = CartanType(['B',2,1]).dynkin_diagram(); b
    6767            O=>=O=<=O
    6868            0   2   1
    6969            B2~
    7070            sage: sorted(b.edges())
    7171            [(0, 2, 2), (1, 2, 2), (2, 0, 1), (2, 1, 1)]
    7272
    73             sage: b = DynkinDiagram(['B',1,1]); b
     73            sage: b = CartanType(['B',1,1]).dynkin_diagram(); b
    7474            O<=>O
    7575            0   1
    7676            B1~
  • sage/combinat/root_system/type_C_affine.py

    diff --git a/sage/combinat/root_system/type_C_affine.py b/sage/combinat/root_system/type_C_affine.py
    a b class CartanType(CartanType_standard_unt 
    5151
    5252        EXAMPLES::
    5353
    54             sage: c = DynkinDiagram(['C',3,1])
     54            sage: c = CartanType(['C',3,1]).dynkin_diagram()
    5555            sage: c
    5656             O=>=O---O=<=O
    5757             0   1   2   3
  • sage/combinat/root_system/type_D_affine.py

    diff --git a/sage/combinat/root_system/type_D_affine.py b/sage/combinat/root_system/type_D_affine.py
    a b class CartanType(CartanType_standard_unt 
    5353
    5454        EXAMPLES:
    5555
    56            sage: d = DynkinDiagram(['D', 6, 1])
     56           sage: d = CartanType(['D', 6, 1]).dynkin_diagram()
    5757           sage: d
    5858              0 O       O 6
    5959                |       |
    class CartanType(CartanType_standard_unt 
    6565           [(0, 2, 1), (1, 2, 1), (2, 0, 1), (2, 1, 1), (2, 3, 1),
    6666            (3, 2, 1), (3, 4, 1), (4, 3, 1), (4, 5, 1), (4, 6, 1), (5, 4, 1), (6, 4, 1)]
    6767
    68            sage: d = DynkinDiagram(['D', 4, 1])
     68           sage: d = CartanType(['D', 4, 1]).dynkin_diagram()
    6969           sage: d
    7070               O 4
    7171               |
    class CartanType(CartanType_standard_unt 
    8585            (3, 2, 1),
    8686            (4, 2, 1)]
    8787
    88            sage: d = DynkinDiagram(['D', 3, 1])
     88           sage: d = CartanType(['D', 3, 1]).dynkin_diagram()
    8989           sage: d
    9090           0
    9191           O-------+
  • sage/combinat/root_system/type_E.py

    diff --git a/sage/combinat/root_system/type_E.py b/sage/combinat/root_system/type_E.py
    a b class CartanType(CartanType_standard_fin 
    473473
    474474        EXAMPLES::
    475475
    476             sage: e = DynkinDiagram(['E',6])
     476            sage: e = CartanType(['E',6]).dynkin_diagram()
    477477            sage: e
    478478                    O 2
    479479                    |
    class CartanType(CartanType_standard_fin 
    483483            E6
    484484            sage: sorted(e.edges())
    485485            [(1, 3, 1), (2, 4, 1), (3, 1, 1), (3, 4, 1), (4, 2, 1), (4, 3, 1), (4, 5, 1), (5, 4, 1), (5, 6, 1), (6, 5, 1)]
    486             sage: e = DynkinDiagram(['E',7])
     486            sage: e = CartanType(['E',7]).dynkin_diagram()
    487487            sage: e
    488488                    O 2
    489489                    |
    class CartanType(CartanType_standard_fin 
    495495            [(1, 3, 1), (2, 4, 1), (3, 1, 1), (3, 4, 1), (4, 2, 1),
    496496             (4, 3, 1), (4, 5, 1), (5, 4, 1), (5, 6, 1), (6, 5, 1),
    497497             (6, 7, 1), (7, 6, 1)]
    498             sage: e = DynkinDiagram(['E',8])
     498            sage: e = CartanType(['E',8]).dynkin_diagram()
    499499            sage: e
    500500                    O 2
    501501                    |
  • sage/combinat/root_system/type_E_affine.py

    diff --git a/sage/combinat/root_system/type_E_affine.py b/sage/combinat/root_system/type_E_affine.py
    a b class CartanType(CartanType_standard_unt 
    5353
    5454        EXAMPLES::
    5555
    56             sage: e = DynkinDiagram(['E', 6, 1])
     56            sage: e = CartanType(['E', 6, 1]).dynkin_diagram()
    5757            sage: e
    5858                    O 0
    5959                    |
    class CartanType(CartanType_standard_unt 
    7878             (5, 6, 1),
    7979             (6, 5, 1)]
    8080
    81             sage: e = DynkinDiagram(['E', 7, 1])
     81            sage: e = CartanType(['E', 7, 1]).dynkin_diagram()
    8282            sage: e
    8383                        O 2
    8484                        |
    class CartanType(CartanType_standard_unt 
    9090            [(0, 1, 1), (1, 0, 1), (1, 3, 1), (2, 4, 1), (3, 1, 1), (3, 4, 1),
    9191             (4, 2, 1), (4, 3, 1), (4, 5, 1), (5, 4, 1), (5, 6, 1),
    9292             (6, 5, 1), (6, 7, 1), (7, 6, 1)]
    93             sage: e = DynkinDiagram(['E', 8, 1])
     93            sage: e = CartanType(['E', 8, 1]).dynkin_diagram()
    9494            sage: e
    9595                    O 2
    9696                    |
  • sage/combinat/root_system/type_F.py

    diff --git a/sage/combinat/root_system/type_F.py b/sage/combinat/root_system/type_F.py
    a b Root system data for type F 
    1010#                  http://www.gnu.org/licenses/
    1111#*****************************************************************************
    1212import ambient_space
     13from sage.misc.cachefunc import cached_method
    1314from sage.rings.all import ZZ
    1415from sage.combinat.family import Family
    1516
    class AmbientSpace(ambient_space.Ambient 
    181182                        3: v*(3*self.monomial(0)+self.monomial(1)+self.monomial(2)+self.monomial(3)),
    182183                        4: self.monomial(0)})
    183184
    184 
    185 
    186185from cartan_type import CartanType_standard_finite, CartanType_simple, CartanType_crystalographic
    187186class CartanType(CartanType_standard_finite, CartanType_simple, CartanType_crystalographic):
    188187    def __init__(self):
    class CartanType(CartanType_standard_fin 
    223222
    224223        EXAMPLES::
    225224
    226             sage: f = DynkinDiagram(['F',4])
     225            sage: f = CartanType(['F',4]).dynkin_diagram()
    227226            sage: f
    228227            O---O=>=O---O
    229             1   2   3   4   
     228            1   2   3   4
    230229            F4
    231230            sage: sorted(f.edges())
    232231            [(1, 2, 1), (2, 1, 1), (2, 3, 2), (3, 2, 1), (3, 4, 1), (4, 3, 1)]
  • sage/combinat/root_system/type_F_affine.py

    diff --git a/sage/combinat/root_system/type_F_affine.py b/sage/combinat/root_system/type_F_affine.py
    a b class CartanType(CartanType_standard_unt 
    5454
    5555        EXAMPLES::
    5656
    57             sage: f = DynkinDiagram(['F', 4, 1])
     57            sage: f = CartanType(['F', 4, 1]).dynkin_diagram()
    5858            sage: f
    5959            O---O---O=>=O---O
    6060            0   1   2   3   4
  • sage/combinat/root_system/type_G.py

    diff --git a/sage/combinat/root_system/type_G.py b/sage/combinat/root_system/type_G.py
    a b class CartanType(CartanType_standard_fin 
    116116
    117117        EXAMPLES::
    118118
    119             sage: g = DynkinDiagram(['G',2])
     119            sage: g = CartanType(['G',2]).dynkin_diagram()
    120120            sage: g
    121121              3
    122122            O=<=O
  • sage/combinat/root_system/type_G_affine.py

    diff --git a/sage/combinat/root_system/type_G_affine.py b/sage/combinat/root_system/type_G_affine.py
    a b class CartanType(CartanType_standard_unt 
    5454
    5555        EXAMPLES::
    5656
    57             sage: g = DynkinDiagram(['G',2,1])
     57            sage: g = CartanType(['G',2,1]).dynkin_diagram()
    5858            sage: g
    5959              3
    6060            O=<=O---O
  • 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 
    122122
    123123    def __cmp__(self, other):
    124124        """
     125        EXAMPLES::
     126
     127            sage: B4     = CartanType(['B', 4])
     128            sage: B4dual = CartanType(['B', 4]).dual()
     129            sage: F4dual = CartanType(['F', 4]).dual()
     130            sage: cmp(F4dual, F4dual)
     131            0
     132            sage: cmp(F4dual, B4dual)
     133            1
     134            sage: cmp(B4dual, F4dual)
     135            -1
     136            sage: cmp(B4dual, B4)
     137            1
     138
     139        .. todo:: do we really need a cmp, or just eq?
    125140        """
    126141        if other.__class__ != self.__class__:
    127142            return cmp(self.__class__, other.__class__)
    class CartanType(UniqueRepresentation, S 
    211226
    212227
    213228###########################################################################
    214 class CartanType_affine(sage.combinat.root_system.cartan_type.CartanType_affine):
     229from cartan_type import CartanType_affine
     230class CartanType_affine(CartanType_affine):
    215231    def classical(self):
    216232        """
    217233        Returns the classical Cartan type associated with self (which should be affine)
  • sage/combinat/root_system/type_reducible.py

    diff --git a/sage/combinat/root_system/type_reducible.py b/sage/combinat/root_system/type_reducible.py
    a b  
    1 from sage.combinat.root_system.cartan_type import CartanType_abstract, CartanType_simple
     1from sage.misc.cachefunc import cached_method
     2from sage.combinat.root_system.cartan_type import CartanType_abstract, CartanType_simple, CartanType_finite, CartanType_simply_laced, CartanType_crystalographic
    23from sage.matrix.constructor import block_diagonal_matrix
    34from sage.sets.family import Family
    45import ambient_space
    class CartanType(SageObject, CartanType_ 
    1213
    1314    def __init__(self, types):
    1415        """
    15         Reducible root systems are ones that can be factored as
    16         direct products. Strictly speaking type D2 (corresponding
    17         to orthogonal groups of degree 4) are reducible since they
    18         are isomorphic to A1xA1. However type D2 is considered
    19         irreducible for our purposes.
     16        Reducible root systems are ones that can be factored as direct
     17        products. Strictly speaking type `D_2` (corresponding to
     18        orthogonal groups of degree 4) is reducible since it is
     19        isomorphic to `A_1\times A_1`. However type `D_2` is not built
     20        using this class for our purposes.
    2021
    2122        INPUT:
    2223
    2324        - ``types`` - a list of simple Cartan types
    24            
     25
    2526        EXAMPLES::
    26        
    27            sage: [t1,t2]=[CartanType(x) for x in ['A',1],['B',2]]
    28            sage: CartanType([t1,t2])
    29            A1xB2
    30            sage: t = CartanType("A2xB2")
    31            sage: t == loads(dumps(t))
    32            True
     27
     28            sage: [t1,t2]=[CartanType(x) for x in ['A',1],['B',2]]
     29            sage: CartanType([t1,t2])
     30            A1xB2
     31            sage: t = CartanType("A2xB2")
     32
     33        A reducible Cartan type is finite (resp. crystalographic,
     34        simply laced) if all its components are::
     35
     36            sage: t.is_finite()
     37            True
     38            sage: t.is_crystalographic()
     39            True
     40            sage: t.is_simply_laced()
     41            False
     42
     43        This is implemented by inserting the appropriate abstract
     44        super classes (see :meth:`~sage.combinat.root_system.cartan_type.CartanType_abstract._add_abstract_superclass`)::
     45
     46            sage: t.__class__.mro()
     47            [<class 'sage.combinat.root_system.type_reducible.CartanType_with_superclass'>, <class 'sage.combinat.root_system.type_reducible.CartanType'>, <type 'sage.structure.sage_object.SageObject'>, <class 'sage.combinat.root_system.cartan_type.CartanType_finite'>, <class 'sage.combinat.root_system.cartan_type.CartanType_crystalographic'>, <class 'sage.combinat.root_system.cartan_type.CartanType_abstract'>, <type 'object'>]
     48
     49        The index set of the reducible Cartan type is obtained by
     50        relabelling successively the nodes of the Dynkin diagrams of
     51        the components by 1,2,...::
     52
     53            sage: t = CartanType(["A",4], ["BC",5,2], ["C",3])
     54            sage: t.index_set()
     55            [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
     56
     57            sage: t.dynkin_diagram()
     58            O---O---O---O
     59            1   2   3   4
     60            O=<=O---O---O---O=<=O
     61            5   6   7   8   9   10
     62            O---O=<=O
     63            11   12   13
     64            A4xBC5~xC3
     65
     66        TESTS:
     67
     68        Internally, this relabelling is stored as a dictionary::
     69
     70            sage: sorted(t._index_relabelling.iteritems())
     71            [((0, 1), 1), ((0, 2), 2), ((0, 3), 3), ((0, 4), 4),
     72             ((1, 0), 5), ((1, 1), 6), ((1, 2), 7), ((1, 3), 8), ((1, 4), 9), ((1, 5), 10),
     73             ((2, 1), 11), ((2, 2), 12), ((2, 3), 13)]
     74
     75        Similarly, the attribute `_shifts` specifies by how much the
     76        indices of the bases of the ambient spaces of the components
     77        are shifted in the ambient space of this Cartan type::
     78
     79            sage: t = CartanType("A2xB2")
     80            sage: t._shifts
     81            [0, 3, 5]
     82            sage: A = t.root_system().ambient_space(); A
     83            Ambient space of the Root system of type A2xB2
     84            sage: A.ambient_spaces()
     85            [Ambient space of the Root system of type ['A', 2], Ambient space of the Root system of type ['B', 2]]
     86            sage: x = A.ambient_spaces()[0]([2,1,0]); x
     87            (2, 1, 0)
     88            sage: A.inject_weights(0,x)
     89            (2, 1, 0, 0, 0)
     90            sage: x = A.ambient_spaces()[1]([1,0]); x
     91            (1, 0)
     92            sage: A.inject_weights(1,x)
     93            (0, 0, 0, 1, 0)
     94
     95
     96
     97        More tests::
     98
     99            sage: TestSuite(t).run()
    33100        """
    34101        self._types = types
    35102        self.affine = False
     103        indices = (None,) + tuple( (i, j)
     104                                   for i in range(len(types))
     105                                   for j in types[i].index_set() )
     106        self._indices = indices
     107        self._index_relabelling = dict((indices[i], i) for i in range(1, len(indices)))
     108
    36109        self._spaces = [t.root_system().ambient_space() for t in types]
    37         self._shifts = [sum(l.n for l in self._spaces[:k]) for k in range(len(types))]
    38         # fails for dual root systems
    39         try:
    40             self._shifts.append(sum(t.root_system().ambient_space().dimension() for t in types))
    41         except:
    42             pass
    43         self._rshifts = [sum(l[1] for l in types[:k]) for k in range(len(types))]
     110        if all(l is not None for l in self._spaces):
     111            self._shifts = [sum(l.dimension() for l in self._spaces[:k])
     112                            for k in range(len(types)+1)]
     113
    44114        self.tools = root_system.type_reducible
     115        # a direct product of finite Cartan types is again finite;
     116        # idem for simply laced and crystalographic.
     117        super_classes = tuple( cls
     118                               for cls in (CartanType_finite, CartanType_simply_laced, CartanType_crystalographic)
     119                               if all(isinstance(t, cls) for t in types) )
     120        self._add_abstract_superclass(super_classes)
    45121
    46122    def _repr_(self, compact = True): # We should make a consistent choice here
    47123        """
    48124        EXAMPLES::
    49        
    50            sage: CartanType("A2","B2")
     125
     126           sage: CartanType("A2","B2")    # indirect doctest
    51127           A2xB2
    52128
    53129           sage: CartanType("A2",CartanType("F4").dual())
    class CartanType(SageObject, CartanType_ 
    95171        """
    96172        return "reducible"
    97173
    98     def is_finite(self):
    99         """
    100         EXAMPLES::
    101        
    102             sage: ct = CartanType(['A',2],['B',2])
    103             sage: ct.is_finite()
    104             True
    105         """
    106         return all(t.is_finite() for t in self.component_types())
    107 
    108174    def rank(self):
    109175        """
    110176        Returns the rank of self.
    class CartanType(SageObject, CartanType_ 
    129195        """
    130196        return range(1, self.rank()+1)
    131197
    132     def root_system(self):
    133         """
    134         Returns the root system associated to self.
    135 
    136         EXAMPLES::
    137        
    138             sage: CartanType(['A',4], ['B', 2]).root_system()
    139             Root system of type A4xB2
    140 
    141         """
    142         import root_system
    143         return root_system.RootSystem(self)
    144 
    145198    def cartan_matrix(self, subdivide=True):
    146199        """
    147200        Returns the Cartan matrix associated with self. By default
    class CartanType(SageObject, CartanType_ 
    166219        """
    167220        return block_diagonal_matrix([t.cartan_matrix() for t in self._types], subdivide=subdivide)
    168221
    169     def dynkin_diagram(t):
     222    def dynkin_diagram(self):
    170223        """
    171224        Returns a Dynkin diagram for type reducible.
    172225
    class CartanType(SageObject, CartanType_ 
    192245            F4xA2
    193246
    194247        """
    195         from dynkin_diagram import DynkinDiagram, DynkinDiagram_class
    196         g = DynkinDiagram_class(t)
    197         for i in range(len(t._types)):
    198             for [e1, e2, l] in DynkinDiagram(t._types[i]).edges():
    199                 shift = t._rshifts[i]
    200                 g.add_edge(e1+shift, e2+shift, label=l)
     248        from dynkin_diagram import DynkinDiagram_class
     249        relabelling = self._index_relabelling
     250        g = DynkinDiagram_class(self)
     251        for i in range(len(self._types)):
     252            for [e1, e2, l] in self._types[i].dynkin_diagram().edges():
     253                g.add_edge(relabelling[i,e1], relabelling[i,e2], label=l)
    201254        return g
    202255
    203256    def ascii_art(self, label = lambda x: x):
    class CartanType(SageObject, CartanType_ 
    205258        Returns an ascii art representation of this reducible Cartan type
    206259
    207260        EXAMPLES::
     261
    208262            sage: print CartanType("F4xA2").ascii_art(label = lambda x: x+2)
    209263            O---O=>=O---O
    210264            3   4   5   6
    211265            O---O
    212266            7   8
     267
     268            sage: print CartanType(["BC",5,2], ["A",4]).ascii_art()
     269            O=<=O---O---O---O=<=O
     270            1   2   3   4   5   6
     271            O---O---O---O
     272            7   8   9   10
     273
     274            sage: print CartanType(["A",4], ["BC",5,2], ["C",3]).ascii_art()
     275            O---O---O---O
     276            1   2   3   4
     277            O=<=O---O---O---O=<=O
     278            5   6   7   8   9   10
     279            O---O=<=O
     280            11   12   13
    213281        """
    214282        types = self.component_types()
    215         return "\n".join(types[i].ascii_art(label = lambda x: label(x+self._rshifts[i]))
     283        relabelling = self._index_relabelling
     284        return "\n".join(types[i].ascii_art(label = lambda x: label(relabelling[i,x]))
    216285                         for i in range(len(types)))
    217286
     287    @cached_method
     288    def is_finite(self):
     289        """
     290        EXAMPLES::
     291
     292            sage: ct1 = CartanType(['A',2],['B',2])
     293            sage: ct1.is_finite()
     294            True
     295            sage: ct2 = CartanType(['A',2],['B',2,1])
     296            sage: ct2.is_finite()
     297            False
     298
     299        TESTS::
     300
     301            sage: isinstance(ct1, sage.combinat.root_system.cartan_type.CartanType_finite)
     302            True
     303            sage: isinstance(ct2, sage.combinat.root_system.cartan_type.CartanType_finite)
     304            False
     305        """
     306        return all(t.is_finite() for t in self.component_types())
     307
    218308    def is_irreducible(self):
    219309        """
    220310        Report that this Cartan type is not irreducible.
    class AmbientSpace(ambient_space.Ambient 
    318408        """
    319409        shift = self.root_system.cartan_type()._shifts[i]
    320410        return self._from_dict( dict([(shift+k, c) for (k,c) in v ]))
    321        
    322     def simple_roots(self):
     411
     412    @cached_method
     413    def simple_root(self, i):
    323414        """
    324415        EXAMPLES::
    325        
    326             sage: RootSystem("A1xB2").ambient_space().simple_roots()
     416
     417            sage: A = RootSystem("A1xB2").ambient_space()
     418            sage: A.simple_root(2)
     419            (0, 0, 1, -1)
     420            sage: A.simple_roots()
    327421            Finite family {1: (1, -1, 0, 0), 2: (0, 0, 1, -1), 3: (0, 0, 0, 1)}
    328422        """
    329         res = []
    330         for i, ambient_space in enumerate(self.ambient_spaces()):
    331             res.extend(self.inject_weights(i, v) for v in ambient_space.simple_roots())
    332         return Family(dict([i,res[i-1]] for i in range(1,len(res)+1)))
     423        assert i in self.index_set()
     424        (i, j) = self.cartan_type()._indices[i]
     425        return self.inject_weights(i, self.ambient_spaces()[i].simple_root(j))
    333426
    334     def simple_coroots(self):
     427    @cached_method
     428    def simple_coroot(self, i):
    335429        """
    336430        EXAMPLES:
    337431
    338             sage: RootSystem("A1xB2").ambient_space().simple_coroots()
     432            sage: A = RootSystem("A1xB2").ambient_space()
     433            sage: A.simple_coroot(2)
     434            (0, 0, 1, -1)
     435            sage: A.simple_coroots()
    339436            Finite family {1: (1, -1, 0, 0), 2: (0, 0, 1, -1), 3: (0, 0, 0, 2)}
    340437        """
    341         cr = []
    342         for i, ambient_space in enumerate(self.ambient_spaces()):
    343             cr.extend(self.inject_weights(i, v) for v in ambient_space.simple_coroots())
    344         return Family(dict([i,cr[i-1]] for i in range(1,len(cr)+1)))
     438        assert i in self.index_set()
     439        (i, j) = self.cartan_type()._indices[i]
     440        return self.inject_weights(i, self.ambient_spaces()[i].simple_coroot(j))
    345441
    346442    def positive_roots(self):
    347443        """
    348444        EXAMPLES::
    349        
     445
    350446            sage: RootSystem("A1xA2").ambient_space().positive_roots()
    351447            [(1, -1, 0, 0, 0), (0, 0, 1, -1, 0), (0, 0, 1, 0, -1), (0, 0, 0, 1, -1)]
    352448        """
  • sage/combinat/root_system/type_relabel.py

    diff --git a/sage/combinat/root_system/type_relabel.py b/sage/combinat/root_system/type_relabel.py
    a b class CartanType_affine(sage.combinat.ro 
    316316        return self._type.classical().relabel(self._relabelling)
    317317
    318318    def special_node(self):
     319        r"""
     320        Returns a special node of the Dynkin diagram
     321
     322        .. seealso:: :meth:`~sage.combinat.root_system.CartanType_affine.special_node`
     323
     324        It is obtained by relabelling of the special node of the non
     325        relabelled Dynkin diagram.
     326
     327        EXAMPLES::
     328
     329            sage: CartanType(['B', 3, 1]).special_node()
     330            0
     331            sage: CartanType(['B', 3, 1]).relabel({1:2, 2:3, 3:0, 0:1}).special_node()
     332            1
     333        """
    319334        return self._relabelling[self._type.special_node()]
    320335
    321336    def is_untwisted_affine(self):
  • sage/combinat/root_system/weight_lattice_realization.py

    diff --git a/sage/combinat/root_system/weight_lattice_realization.py b/sage/combinat/root_system/weight_lattice_realization.py
    a b  
     1from sage.misc.abstract_method import abstract_method
     2from sage.misc.cachefunc import cached_method
    13from sage.misc.misc import prod
     4from sage.categories.category_types import Category_over_base_ring
    25from sage.combinat.family import Family
    3 from root_lattice_realization import RootLatticeRealization
     6from root_lattice_realization import RootLatticeRealizations
    47
    5 class WeightLatticeRealization(RootLatticeRealization):
     8class WeightLatticeRealizations(Category_over_base_ring):
     9  r"""
     10  The category of weight lattice realizations over a given base ring
     11
     12  A *weight lattice realization* `L` over a base ring `R` is a free
     13  module (or vector space if `R` is a field) endowed with an embedding
     14  of the root lattice of some root system. By restriction, this
     15  embedding defines an embedding of the root lattice of this root
     16  system, which makes `L` a root lattice realization.
     17
     18  Typical weight lattice realizations over `\ZZ` include the weight
     19  lattice, and ambient lattice. Typical weight lattice realizations
     20  over `\QQ` include the weight space, and ambient space.
     21
     22  To describe the embedding, a weight lattice realization must
     23  implement a method
     24  :meth:`~RootLatticeRealizations.ParentMethods.fundamental_weight`(i)
     25  returning for each `i` in the index set the image of the fundamental
     26  weight `\Lambda_i` under the embedding.
     27
     28  In order to be a proper root lattice realization, a weight lattice
     29  realization should also implement the scalar product with the coroot
     30  lattice; on the other hand, the embedding of the simple roots is
     31  given for free.
     32
     33  .. seealso::
     34
     35      - :class:`~sage.combinat.root_system.root_system.RootSystem`
     36      - :class:`~sage.combinat.root_system.root_lattice_realizations.RootLatticeRealizations`
     37      - :class:`~sage.combinat.root_system.weight_space.WeightSpace`
     38      - :class:`~sage.combinat.root_system.ambient_space.AmbientSpace`
     39
     40  EXAMPLES:
     41
     42  Here, we consider the root system of type `A_7`, and embed the weight
     43  lattice element `x = \Lambda_1 + 2 \Lambda_3` in several root lattice
     44  realizations::
     45
     46      sage: R = RootSystem(["A",7])
     47      sage: Lambda = R.weight_lattice().fundamental_weights()
     48      sage: x = Lambda[2] + 2 * Lambda[5]
     49
     50      sage: L = R.weight_space()
     51      sage: L(x)
     52      Lambda[2] + 2*Lambda[5]
     53
     54      sage: L = R.ambient_lattice()
     55      sage: L(x)
     56      (3, 3, 2, 2, 2, 0, 0, 0)
     57
     58  We embed the weight space element `x = \Lambda_1 + 1/2 \Lambda_3` in
     59  the ambient space::
     60
     61      sage: Lambda = R.weight_space().fundamental_weights()
     62      sage: x = Lambda[2] + 1/2 * Lambda[5]
     63
     64      sage: L = R.ambient_space()
     65      sage: L(x)
     66      (3/2, 3/2, 1/2, 1/2, 1/2, 0, 0, 0)
     67
     68  Of course, one can't embed the weight space in the ambient lattice::
     69
     70      sage: L = R.ambient_lattice()
     71      sage: L(x)
     72      Traceback (most recent call last):
     73      ...
     74      TypeError: do not know how to make x (= Lambda[2] + 1/2*Lambda[5]) an element of self (=Ambient lattice of the Root system of type ['A', 7])
     75
     76  If `K_1` is a subring of `K_2`, then one could in theory have an
     77  embedding from the weight space over `K_1` to any weight lattice
     78  realization over `K_2`; this is not implemented::
     79
     80      sage: K1 = QQ
     81      sage: K2 = QQ['q']
     82      sage: L = R.ambient_space(K2)
     83
     84      sage: Lambda = R.weight_space(K2).fundamental_weights()
     85      sage: L(Lambda[1])
     86      (1, 0, 0, 0, 0, 0, 0, 0)
     87
     88      sage: Lambda = R.weight_space(K1).fundamental_weights()
     89      sage: L(Lambda[1])
     90      Traceback (most recent call last):
     91      ...
     92      TypeError: do not know how to make x (= Lambda[1]) an element of self (=Ambient space of the Root system of type ['A', 7])
     93  """
     94
     95  @cached_method
     96  def super_categories(self):
     97      """
     98      EXAMPLES::
     99
     100          sage: from sage.combinat.root_system.weight_lattice_realization import WeightLatticeRealizations
     101          sage: WeightLatticeRealizations(QQ).super_categories()
     102          [Category of root lattice realizations over Rational Field]
     103      """
     104      return [RootLatticeRealizations(self.base_ring())]
     105
     106  class ParentMethods:
     107
     108    @abstract_method
     109    def fundamental_weight(self, i):
     110        """
     111        Returns the `i^{th}` fundamental weight
     112
     113        INPUT:
     114
     115        - ``i`` -- an element of the index set
     116
     117        By a slight notational abuse, for an affine type this method
     118        should also accept ``"delta"`` as input, and return the image
     119        of `\delta` of the extended weight lattice in this
     120        realization.
     121
     122        This should be overridden by any subclass, and typically
     123        be implemented as a cached method for efficiency.
     124
     125        EXAMPLES::
     126
     127            sage: L = RootSystem(["A",3]).ambient_lattice()
     128            sage: L.fundamental_weight(1)
     129            (1, 0, 0, 0)
     130
     131            sage: L = RootSystem(["A",3,1]).weight_lattice(extended=True)
     132            sage: L.fundamental_weight(1)
     133            Lambda[1]
     134            sage: L.fundamental_weight("delta")
     135            delta
     136
     137        TESTS::
     138
     139            sage: super(sage.combinat.root_system.weight_space.WeightSpace, L).fundamental_weight(1)
     140            Traceback (most recent call last):
     141            ...
     142            NotImplementedError: <abstract method fundamental_weight at ...>
     143        """
     144
     145    def is_extended(self):
     146      """
     147      Returns whether this is a realization of the extended weight lattice
     148
     149      .. seealso:: :class:`sage.combinat.root_system.weight_space.WeightSpace`
     150
     151      EXAMPLES::
     152
     153          sage: RootSystem(["A",3,1]).weight_lattice().is_extended()
     154          False
     155          sage: RootSystem(["A",3,1]).weight_lattice(extended=True).is_extended()
     156          True
     157
     158      This method is irrelevant for finite root systems, since the
     159      weight lattice need not be extended to ensure that the root
     160      lattice embeds faithfully::
     161
     162          sage: RootSystem(["A",3]).weight_lattice().is_extended()
     163          False
     164
     165      """
     166      return False
     167
     168    def __init_extra__(self):
     169        """
     170        Registers the embedding of the weight lattice into ``self``
     171
     172        Also registers the embedding of the weight space over the same
     173        base field `K` into ``self`` if `K` is not `\ZZ`.
     174
     175        If ``self`` is a realization of the extended weight lattice,
     176        then the embeddings from the extended weight space/lattices
     177        are registered instead.
     178
     179        EXAMPLES:
     180
     181        We embed the fundamental weight `\Lambda_1` of the weight
     182        lattice in the ambient lattice::
     183
     184            sage: R = RootSystem(["A",3])
     185            sage: Lambda = R.root_lattice().simple_roots()
     186            sage: L = R.ambient_space()
     187            sage: L(Lambda[2])
     188            (0, 1, -1, 0)
     189
     190        .. note::
     191
     192            More examples are given in :class:`WeightLatticeRealizations`;
     193            The embeddings are systematically tested in
     194            :meth:`_test_weight_lattice_realization`.
     195        """
     196        from sage.rings.all import ZZ
     197        from weight_space import WeightSpace
     198        K = self.base_ring()
     199        # If self is the root lattice or the root space, we don't want
     200        # to register its trivial embedding into itself. This builds
     201        # the domains from which we want to register an embedding.
     202        domains = []
     203        if not isinstance(self, WeightSpace) or K is not ZZ:
     204            domains.append(self.root_system.weight_lattice(extended=self.is_extended()))
     205        if not isinstance(self, WeightSpace):
     206            domains.append(self.root_system.weight_space(K,extended=self.is_extended()))
     207        # Build and register the embeddings
     208        for domain in domains:
     209            domain.module_morphism(self.fundamental_weight,
     210                                   codomain = self
     211                                   ).register_as_coercion()
     212
     213
    6214    def _test_weight_lattice_realization(self, **options):
    7215        """
    8         Runs sanity checks on this weight lattice realization:
    9          - scalar products between the fundamental weights and simple coroots
    10          - rho, highest_root, ...
     216        Runs sanity checks on this weight lattice realization
    11217
    12         See also: :class:`Test``
     218        - scalar products between the fundamental weights and simple coroots
     219        - embeddings from the weight lattice and weight space
     220        - rho, highest_root, ...
     221
     222        .. seealso:: :class:`TestSuite`
    13223
    14224        EXAMPLES::
    15             sage: RootSystem(['A',3]).root_lattice()._test_root_lattice_realization()
     225
     226            sage: RootSystem(['A',3]).weight_lattice()._test_weight_lattice_realization()
    16227        """
    17         tester = self._tester(**options)
     228        from sage.rings.all import ZZ
     229        tester     = self._tester(**options)
    18230        Lambda     = self.fundamental_weights()
    19231        alphacheck = self.simple_coroots()
    20232        tester.assertEqual(Lambda.keys(), self.index_set())
    21233
     234        # Check the consistency between simple_root and simple_roots
     235        for i in self.index_set():
     236            tester.assertEqual(self.fundamental_weight(i), Lambda[i])
     237
     238        # Check the embeddings from:
     239        # - the weight lattice
     240        # - the weight space over the same base ring
     241        #
     242        # For an affine root system, this will check the embedding of
     243        # the extended ones, and also of the non extended ones if this
     244        # realization is not extended
     245        domains = [self.root_system.weight_space(base_ring, extended = extended)
     246                   for base_ring in set([ZZ, self.base_ring()])
     247                   for extended  in set([self.cartan_type().is_affine(), self.is_extended()])]
     248        for domain in domains:
     249            tester.assert_(self.coerce_map_from(domain) is not None)
     250            for i in self.index_set():
     251                # This embedding maps fundamental weights to fundamental weights
     252                tester.assertEqual(self(domain.fundamental_weight(i)), Lambda[i])
     253            if self.cartan_type().is_affine():
     254                tester.assertEqual(self(domain.null_root()), self.null_root())
     255
     256        # Check that the fundamental weights form the dual basis of the simple coroots
    22257        for i in self.index_set():
    23258            assert(Lambda[i].is_dominant())
    24259            for j in self.index_set():
    class WeightLatticeRealization(RootLatti 
    28263        if self.root_system.is_finite() and self.root_system.is_irreducible():
    29264            tester.assert_(self.highest_root().is_dominant())
    30265
    31     # Should this be a method or an attribute?
    32     # same question for the roots, ...
    33     # Should this use rename to set a nice name for this family?
     266    @cached_method
    34267    def fundamental_weights(self):
    35268        r"""
    36269        Returns the family `(\Lambda_i)_{i\in I}` of the fundamental weights.
    class WeightLatticeRealization(RootLatti 
    42275            sage: [f[i] for i in [1,2,3]]
    43276            [(1, 0, 0, 0), (1, 1, 0, 0), (1, 1, 1, 0)]
    44277        """
    45         if not hasattr(self,"_fundamental_weights"):
    46             self._fundamental_weights = Family(self.index_set(),
    47                                                self.fundamental_weight)
    48             # self._fundamental_weights.rename("Lambda")
    49             # break some doctests.
    50         return self._fundamental_weights
     278        return Family(self.index_set(), self.fundamental_weight)
     279        # It would be nice to give this family a nice name with
     280        # ``rename``, but this currently break some doctests.
     281
     282    @cached_method
     283    def simple_root(self, i):
     284        r"""
     285        Returns the `i`-th simple root
     286
     287        This default implementation takes the `i`-th simple root in
     288        the weight lattice and embeds it in ``self``.
     289
     290        EXAMPLES:
     291
     292        Since all the weight lattice realizations in Sage currently
     293        implement a simple_root method, we have to call this one by
     294        hand::
     295
     296            sage: from sage.combinat.root_system.weight_lattice_realization import WeightLatticeRealizations
     297            sage: simple_root = WeightLatticeRealizations(QQ).parent_class.simple_root.f
     298            sage: L = RootSystem("A3").ambient_space()
     299            sage: simple_root(L, 1)
     300            (1, -1, 0, 0)
     301            sage: simple_root(L, 2)
     302            (0, 1, -1, 0)
     303            sage: simple_root(L, 3)
     304            (1, 1, 2, 0)
     305
     306        Note that this last root differs from the one implemented in
     307        ``L`` by a multiple of the vector ``(1,1,1,1)``::
     308
     309            sage: L.simple_roots()
     310            Finite family {1: (1, -1, 0, 0), 2: (0, 1, -1, 0), 3: (0, 0, 1, -1)}
     311
     312        This is a harmless artefact of the `SL` versus `GL`
     313        interpretation of type `A`; see the thematic tutorial on Lie
     314        Methods and Related Combinatorics in Sage for details.
     315        """
     316        assert i in self.index_set()
     317        alphai = self.root_system.weight_lattice().simple_root(i)
     318        # Note: it would be nicer to just return ``self(alpha[i])``,
     319        # However the embedding from the weight lattice is defined
     320        # after the embedding from the root lattice, and the later
     321        # uses the simple roots. So we compute that embedding by hand.
     322        Lambda = self.fundamental_weights()
     323        return self.linear_combination( (Lambda[j], c) for j,c in alphai )
    51324
    52325    def rho(self):
    53326        """
    class WeightLatticeRealization(RootLatti 
    259532        `f\circ w^{-1}` permutes the simple roots.
    260533        """
    261534        alpha = self.simple_roots()
    262         rho = self.rho()
    263535        w = self.weyl_group().from_reduced_word(self.reduced_word_of_alcove_morphism(f))
    264536        # Now, we have d = f w^-1
    265537        winv = ~w
    class WeightLatticeRealization(RootLatti 
    333605    #    assert( t == self.plus(t.scalar(alphac[i]) * Lambda[i] for i in self.index_set() ) )
    334606    #    t = self.plus( t.scalar(alphac[i]) * c[i] * Lambda[i] for i in self.index_set() )
    335607
    336     # TODO: move to WeightLatticeRealizations() when this category will exist
    337608    def _test_reduced_word_of_translation(self, elements=None, **options):
    338609        r"""
    339610        Tests the method :meth:`reduced_word_of_translation`.
    class WeightLatticeRealization(RootLatti 
    378649        for t in elements:
    379650            t = t - self.base_ring()(t.level()/Lambda[0].level()) * Lambda[0]
    380651            w = self.weyl_group().from_reduced_word(self.reduced_word_of_translation(t))
    381             tester.assertEquals(w.action(rho), rho + rho.level()*t)
     652            if self.null_root().is_zero():
     653                # The following formula is only valid when the null root is zero
     654                tester.assertEquals(w.action(rho), rho + rho.level()*t)
     655                # TODO: fix this formula to take delta into account,
     656                # and remove the above condition
    382657            if test_automorphism:
    383658                permutation = [None for i in self.index_set()]
    384659                for i in self.index_set():
  • 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  
    11"""
    2 Root lattices and root spaces
     2Weight lattice and weight spaces of a root system
    33"""
    44#*****************************************************************************
    55#       Copyright (C) 2008-2009 Nicolas M. Thiery <nthiery at users.sf.net>
    Root lattices and root spaces 
    88#                  http://www.gnu.org/licenses/
    99#*****************************************************************************
    1010
     11from sage.misc.cachefunc import cached_method
     12from sage.sets.family import Family
    1113from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement
    12 from root_lattice_realization import RootLatticeRealizationElement
    13 from weight_lattice_realization import WeightLatticeRealization
     14from weight_lattice_realization import WeightLatticeRealizations
    1415
    15 
    16 class WeightSpace(CombinatorialFreeModule, WeightLatticeRealization):
     16class WeightSpace(CombinatorialFreeModule):
    1717    r"""
    1818    INPUT:
    19      - root_system: a root system
    20      - base_ring: a ring `R`
    2119
    22     The weight space (or lattice if base_ring is ZZ) of a root system,
    23     that is the formal free module `\bigoplus_i R \Lambda_i` generated
    24     by the simple fundamental weights `\Lambda_i`.
     20    - ``root_system`` -- a root system
     21    - ``base_ring`` -- a ring `R`
     22    - ``extended`` -- a boolean (default: False)
     23
     24    The weight space (or lattice if ``base_ring`` is `\ZZ`) of a root
     25    system is the formal free module `\bigoplus_i R \Lambda_i`
     26    generated by the fundamental weights `(\Lambda_i)_{i\in I}` of the
     27    root system.
    2528
    2629    This class is also used for coweight spaces (or lattices).
    2730
     31    .. seealso::
     32
     33        - :meth:`RootSystem`
     34        - :meth:`RootSystem.weight_lattice` and :meth:`RootSystem.weight_space`
     35        - :meth:`~sage.combinat.root_system.weight_lattice_realizations.WeightLatticeRealizations`
     36
     37    EXAMPLES::
     38
     39        sage: Q = RootSystem(['A', 3]).weight_lattice(); Q
     40        Weight lattice of the Root system of type ['A', 3]
     41        sage: Q.simple_roots()
     42        Finite family {1: 2*Lambda[1] - Lambda[2], 2: -Lambda[1] + 2*Lambda[2] - Lambda[3], 3: -Lambda[2] + 2*Lambda[3]}
     43
     44        sage: Q = RootSystem(['A', 3, 1]).weight_lattice(); Q
     45        Weight lattice of the Root system of type ['A', 3, 1]
     46        sage: Q.simple_roots()
     47        Finite family {0: 2*Lambda[0] -   Lambda[1]               -   Lambda[3],
     48                       1:  -Lambda[0] + 2*Lambda[1] -   Lambda[2],
     49                       2:                -Lambda[1] + 2*Lambda[2] -   Lambda[3],
     50                       3:  -Lambda[0]               -   Lambda[2] + 2*Lambda[3]}
     51
     52    For infinite types, the Cartan matrix is singular, and therefore
     53    the embedding of the root lattice is not faithful::
     54
     55        sage: sum(Q.simple_roots())
     56        0
     57
     58    In particular, the null root is zero::
     59
     60        sage: Q.null_root()
     61        0
     62
     63    This can be compensated by extending the basis of the weight space
     64    and slightly deforming the simple roots to make them linearly
     65    independent, without affecting the scalar product with the
     66    coroots. This feature is currently only implemented for affine
     67    types. In that case, if ``extended`` is set, then the basis of the
     68    weight space is extended by an element `\delta`::
     69
     70        sage: Q = RootSystem(['A', 3, 1]).weight_lattice(extended = True); Q
     71        Extended weight lattice of the Root system of type ['A', 3, 1]
     72        sage: Q.basis().keys()
     73        {0, 1, 2, 3, 'delta'}
     74
     75    And the simple root `\alpha_0` associated to the special node is
     76    deformed as follows::
     77
     78        sage: Q.simple_roots()
     79        Finite family {0: 2*Lambda[0] -   Lambda[1]               -   Lambda[3] + delta,
     80                       1:  -Lambda[0] + 2*Lambda[1] -   Lambda[2],
     81                       2:                -Lambda[1] + 2*Lambda[2] -   Lambda[3],
     82                       3:  -Lambda[0]               -   Lambda[2] + 2*Lambda[3]}
     83
     84    Now, the null root is nonzero::
     85
     86        sage: Q.null_root()
     87        delta
     88
     89    .. warning::
     90
     91        By a slight notational abuse, the extra basis element used to
     92        extend the fundamental weights is called ``\delta`` in the
     93        current implementation. However, in the literature,
     94        ``\delta`` usually denotes instead the null root. Most of the
     95        time, those two objects coincide, but not for type `BC` (aka.
     96        `A_{2n}^{(2)}). Therefore we currently have::
     97
     98            sage: Q = RootSystem(["A",4,2]).weight_lattice(extended=True)
     99            sage: Q.simple_root(0)
     100            2*Lambda[0] - Lambda[1] + delta
     101            sage: Q.null_root()
     102            2*delta
     103
     104        whereas, with the standard notations from the literature, one
     105        would expect to get respectively `2\Lambda_0 -\Lambda_1 +1/2
     106        \delta` and `\delta`.
     107
     108        Other than this notational glitch, the implementation remains
     109        correct for type `BC`.
     110
     111        The notations may get improved in a subsequent version, which
     112        might require changing the index of the extra basis
     113        element. To guarantee backward compatibility in code not
     114        included in Sage, it is recommended to use the following idiom
     115        to get that index::
     116
     117            sage: F = Q.basis_extension(); F
     118            Finite family {'delta': delta}
     119            sage: index = F.keys()[0]; index
     120            'delta'
     121
     122        Then, for example, the coefficient of an element of the
     123        extended weight lattice on that basis element can be recovered
     124        with::
     125
     126            sage: Q.null_root()[index]
     127            2
     128
    28129    TESTS::
    29130
    30131        sage: for ct in CartanType.samples():
    class WeightSpace(CombinatorialFreeModul 
    32133        ...           P = ct.root_system().weight_space()
    33134        ...           TestSuite(P).run()
    34135        ...
     136        sage: for ct in CartanType.samples(affine=True):
     137        ...       if ct.is_implemented():
     138        ...           P = ct.root_system().weight_space(extended=True)
     139        ...           TestSuite(P).run()
    35140    """
    36141
    37     def __init__(self, root_system, base_ring):
     142    @staticmethod
     143    def __classcall_private__(cls, root_system, base_ring, extended=False):
    38144        """
     145        Guarantees Unique representation
     146
     147        .. seealso:: :class:`UniqueRepresentation`
     148
     149        TESTS::
     150
     151            sage: R = RootSystem(['A',4])
     152            sage: from sage.combinat.root_system.weight_space import WeightSpace
     153            sage: WeightSpace(R, QQ) is WeightSpace(R, QQ, False)
     154            True
     155        """
     156        return super(WeightSpace, cls).__classcall__(cls, root_system, base_ring, extended)
     157
     158
     159    def __init__(self, root_system, base_ring, extended):
     160        """
     161        TESTS::
     162
     163            sage: R = RootSystem(['A',4])
     164            sage: from sage.combinat.root_system.weight_space import WeightSpace
     165            sage: Q = WeightSpace(R, QQ); Q
     166            Weight space over the Rational Field of the Root system of type ['A', 4]
     167            sage: TestSuite(Q).run()
     168
     169            sage: WeightSpace(R, QQ, extended = True)
     170            Traceback (most recent call last):
     171            ...
     172            AssertionError: extended weight lattices are only implemented for affine root systems
     173        """
     174        basis_keys = root_system.index_set()
     175        self._extended = extended
     176        if extended:
     177            assert root_system.cartan_type().is_affine(), "extended weight lattices are only implemented for affine root systems"
     178            basis_keys = tuple(basis_keys) + ("delta",)
     179
     180        self.root_system = root_system
     181        CombinatorialFreeModule.__init__(self, base_ring,
     182                                         basis_keys,
     183                                         prefix = "Lambdacheck" if root_system.dual_side else "Lambda",
     184                                         latex_prefix = "\\Lambda^\\vee" if root_system.dual_side else "\\Lambda",
     185                                         category = WeightLatticeRealizations(base_ring))
     186
     187        if root_system.cartan_type().is_affine() and not extended:
     188            # For an affine type, register the quotient map from the
     189            # extended weight lattice/space to the weight lattice/space
     190            domain = root_system.weight_space(base_ring, extended=True)
     191            domain.module_morphism(self.fundamental_weight,
     192                                   codomain = self
     193                                   ).register_as_coercion()
     194
     195    def is_extended(self):
     196        """
     197        Returns whether this is an extended weight lattice
     198
     199        .. seealso: :meth:`~sage.combinat.root_sytem.weight_lattice_realization.ParentMethods.is_extended`
     200
    39201        EXAMPLES::
    40        
    41             sage: Q = RootSystem(['A',4]).weight_lattice()
    42             sage: s = Q.simple_reflections()
    43202
     203            sage: RootSystem(["A",3,1]).weight_lattice().is_extended()
     204            False
     205            sage: RootSystem(["A",3,1]).weight_lattice(extended=True).is_extended()
     206            True
    44207        """
    45         self.root_system = root_system
    46         basis_name = "Lambdacheck" if root_system.dual_side else "Lambda"
    47         CombinatorialFreeModule.__init__(self, base_ring,
    48                                          root_system.index_set(),
    49                                          element_class = WeightSpaceElement,
    50                                          prefix=basis_name)
     208        return self._extended
    51209
    52210    def _repr_(self):
    53211        """
    54212        TESTS::
    55        
    56             sage: RootSystem(['A',4]).weight_lattice()
     213
     214            sage: RootSystem(['A',4]).weight_lattice()    # indirect doctest
    57215            Weight lattice of the Root system of type ['A', 4]
    58216            sage: RootSystem(['B',4]).weight_space()
    59217            Weight space over the Rational Field of the Root system of type ['B', 4]
    class WeightSpace(CombinatorialFreeModul 
    68226    def _name_string(self, capitalize=True, base_ring=True, type=True):
    69227        """
    70228        EXAMPLES::
    71        
     229
    72230            sage: RootSystem(['A',4]).weight_lattice()._name_string()
    73231            "Weight lattice of the Root system of type ['A', 4]"
    74232        """
    75         return self._name_string_helper("weight", capitalize=capitalize, base_ring=base_ring, type=type)
     233        return self._name_string_helper("weight",
     234                                        capitalize=capitalize, base_ring=base_ring, type=type,
     235                                        prefix="extended " if self.is_extended() else "")
    76236
    77     fundamental_weight = CombinatorialFreeModule.monomial
     237    @cached_method
     238    def fundamental_weight(self, i):
     239        """
     240        Returns the `i`-th fundamental weight
    78241
     242        INPUT:
     243
     244        - ``i`` -- an element of the index set or ``"delta"``
     245
     246        By a slight notational abuse, for an affine type this method
     247        also accepts ``"delta"`` as input, and returns the image of
     248        `\delta` of the extended weight lattice in this realization.
     249
     250        .. seealso: :meth:`~sage.combinat.root_sytem.weight_lattice_realization.ParentMethods.fundamental_weight`
     251
     252        EXAMPLES::
     253
     254            sage: Q = RootSystem(["A",3]).weight_lattice()
     255            sage: Q.fundamental_weight(1)
     256            Lambda[1]
     257
     258            sage: Q = RootSystem(["A",3,1]).weight_lattice(extended=True)
     259            sage: Q.fundamental_weight(1)
     260            Lambda[1]
     261            sage: Q.fundamental_weight("delta")
     262            delta
     263        """
     264        if i == "delta":
     265            assert self.cartan_type().is_affine()
     266            if self.is_extended():
     267                return self.monomial(i)
     268            else:
     269                return self.zero()
     270        else:
     271            assert i in self.index_set()
     272            return self.monomial(i)
     273
     274    @cached_method
     275    def basis_extension(self):
     276        r"""
     277        Return the basis elements used to extend the fundamental weights
     278
     279        EXAMPLES::
     280
     281            sage: Q = RootSystem(["A",3,1]).weight_lattice()
     282            sage: Q.basis_extension()
     283            Family ()
     284
     285            sage: Q = RootSystem(["A",3,1]).weight_lattice(extended=True)
     286            sage: Q.basis_extension()
     287            Finite family {'delta': delta}
     288
     289        This method is irrelevant for finite types::
     290
     291            sage: Q = RootSystem(["A",3]).weight_lattice()
     292            sage: Q.basis_extension()
     293            Family ()
     294        """
     295        if self.is_extended():
     296            return Family(["delta"], self.monomial)
     297        else:
     298            return Family([])
     299
     300
     301    @cached_method
    79302    def simple_root(self, j):
    80303        """
    81304        Returns the `j^{th}` simple root
    82        
     305
    83306        TESTS::
    84        
    85             sage: R = RootSystem(["C",4])
    86             sage: R.weight_lattice().simple_root(3)
     307
     308            sage: L = RootSystem(["C",4]).weight_lattice()
     309            sage: L.simple_root(3)
    87310            -Lambda[2] + 2*Lambda[3] - Lambda[4]
    88311
    89             sage: R.weight_lattice().simple_roots()
    90             Finite family {1: 2*Lambda[1] - Lambda[2], 2: -Lambda[1] + 2*Lambda[2] - Lambda[3], 3: -Lambda[2] + 2*Lambda[3] - Lambda[4], 4: -2*Lambda[3] + 2*Lambda[4]}
     312        Its coefficients are given by the corresponding column of the
     313        Cartan matrix::
    91314
     315            sage: L.cartan_type().cartan_matrix()[:,2]
     316            [ 0]
     317            [-1]
     318            [ 2]
     319            [-1]
     320
     321            sage: L.simple_roots()
     322            Finite family {1: 2*Lambda[1] - Lambda[2],
     323                           2: -Lambda[1] + 2*Lambda[2] - Lambda[3],
     324                           3: -Lambda[2] + 2*Lambda[3] - Lambda[4],
     325                           4: -2*Lambda[3] + 2*Lambda[4]}
     326
     327        For the extended weight lattice of an affine type, the simple
     328        root associated to the special node is deformed by `\delta`::
     329
     330            sage: L = RootSystem(["C",4,1]).weight_lattice(extended=True)
     331            sage: L.simple_root(0)
     332            2*Lambda[0] - 2*Lambda[1] + delta
    92333        """
    93334        assert(j in self.index_set())
    94         return self._from_dict(dict([(i,c) for (i,c) in self.root_system.dynkin_diagram().column(j)]))
     335        result = self.sum_of_terms(self.root_system.dynkin_diagram().column(j))
     336        if self._extended and j == self.cartan_type().special_node():
     337            result = result + self.monomial("delta")
     338        return result
    95339
     340    def _repr_term(self, m):
     341        r"""
     342        Customized monomial printing for extended weight lattices
    96343
    97 class WeightSpaceElement(CombinatorialFreeModuleElement, RootLatticeRealizationElement):
     344        EXAMPLES::
     345
     346            sage: L = RootSystem(["C",4,1]).weight_lattice(extended=True)
     347            sage: L.simple_root(0)             # indirect doctest
     348            2*Lambda[0] - 2*Lambda[1] + delta
     349
     350            sage: L = RootSystem(["C",4,1]).coweight_lattice(extended=True)
     351            sage: L.simple_root(0)             # indirect doctest
     352            2*Lambdacheck[0] - Lambdacheck[1] + deltacheck
     353        """
     354        if m == "delta":
     355            return "deltacheck" if self.root_system.dual_side else "delta"
     356        else:
     357            return super(WeightSpace, self)._repr_term(m)
     358
     359    def _latex_term(self, m):
     360        r"""
     361        Customized monomial typesetting for extended weight lattices
     362
     363        EXAMPLES::
     364
     365            sage: L = RootSystem(["C",4,1]).weight_lattice(extended=True)
     366            sage: latex(L.simple_root(0))             # indirect doctest
     367            2\Lambda_{0} - 2\Lambda_{1} + \delta
     368
     369            sage: L = RootSystem(["C",4,1]).coweight_lattice(extended=True)
     370            sage: latex(L.simple_root(0))             # indirect doctest
     371            2\Lambda^\vee_{0} - \Lambda^\vee_{1} + \delta^\vee
     372        """
     373        if m == "delta":
     374            return "\\delta^\\vee" if self.root_system.dual_side else "\\delta"
     375        else:
     376            return super(WeightSpace, self)._latex_term(m)
     377
     378
     379class WeightSpaceElement(CombinatorialFreeModuleElement):
     380
    98381    def scalar(self, lambdacheck):
    99382        """
    100383        The canonical scalar product between the weight lattice and
    101384        the coroot lattice.
    102385
    103         TODO: merge with_apply_multi_module_morphism
     386        .. todo::
     387
     388            - merge with_apply_multi_module_morphism
     389            - allow for any root space / lattice
     390            - define properly the return type (depends on the base rings of the two spaces)
     391            - make this robust for extended weight lattices (`i` might be "delta")
    104392
    105393        EXAMPLES::
    106        
    107             sage: R = RootSystem(["C",4])
    108             sage: w = R.weight_lattice().simple_root(1)
    109             sage: cw = R.coweight_lattice().simple_root(1)
    110             sage: w.scalar(cw)
    111             5
     394
     395            sage: L = RootSystem(["C",4,1]).weight_lattice()
     396            sage: Lambda     = L.fundamental_weights()
     397            sage: alphacheck = L.simple_coroots()
     398            sage: Lambda[1].scalar(alphacheck[1])
     399            1
     400            sage: Lambda[1].scalar(alphacheck[2])
     401            0
     402
     403        The fundamental weights and the simple coroots are dual bases:
     404
     405            sage: matrix([ [ Lambda[i].scalar(alphacheck[j])
     406            ...              for i in L.index_set() ]
     407            ...            for j in L.index_set() ])
     408            [1 0 0 0 0]
     409            [0 1 0 0 0]
     410            [0 0 1 0 0]
     411            [0 0 0 1 0]
     412            [0 0 0 0 1]
     413
     414        Note that the scalar product is not yet implemented between
     415        the weight space and the coweight space; in any cases, that
     416        won't be the job of this method::
     417
     418            sage: R = RootSystem(["A",3])
     419            sage: alpha = R.weight_space().roots()
     420            sage: alphacheck = R.coweight_space().roots()
     421            sage: alpha[1].scalar(alphacheck[1])
     422            Traceback (most recent call last):
     423              ...
     424              assert lambdacheck in self.parent().coroot_lattice() or lambdacheck in self.parent().coroot_space()
     425            AssertionError
    112426        """
     427        # TODO: Find some better test
     428        assert lambdacheck in self.parent().coroot_lattice() or lambdacheck in self.parent().coroot_space()
    113429        zero = self.parent().base_ring().zero()
    114430        if len(self) < len(lambdacheck):
    115431            return sum( (lambdacheck[i]*c for (i,c) in self), zero)
    class WeightSpaceElement(CombinatorialFr 
    132448            sage: w.is_dominant()
    133449            False
    134450        """
    135         for c in self.coefficients():
    136             if c < 0:
    137                 return False
    138         return True
     451        return all(c >= 0 for c in self.coefficients())
     452
     453WeightSpace.Element = WeightSpaceElement
  • sage/combinat/root_system/weyl_group.py

    diff --git a/sage/combinat/root_system/weyl_group.py b/sage/combinat/root_system/weyl_group.py
    a b from sage.misc.cachefunc import cached_m 
    4545from sage.misc.misc import deprecated_function_alias
    4646from sage.combinat.root_system.cartan_type import CartanType
    4747from sage.matrix.constructor import matrix, diagonal_matrix
    48 from sage.combinat.root_system.root_lattice_realization import RootLatticeRealization
     48from sage.combinat.root_system.root_lattice_realization import RootLatticeRealizations
    4949from sage.structure.unique_representation import UniqueRepresentation
    5050from sage.categories.all import WeylGroups, FiniteWeylGroups, AffineWeylGroups
    5151from sage.sets.family import Family
    def WeylGroup(x, prefix=None): 
    9696        12
    9797        sage: w.length() # length function on Weyl group
    9898        4
    99    
     99
    100100    The default representation of Weyl group elements is as matrices.
    101101    If you prefer, you may specify a prefix, in which case the
    102102    elements are represented as products of simple reflections.
    def WeylGroup(x, prefix=None): 
    117117        [ 1  0  0]
    118118
    119119    ::
    120    
     120
    121121        sage: L = G.domain()
    122122        sage: fw = L.fundamental_weights(); fw
    123123        Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3/2, 1/2, 1/2, 1/2), 4: (1, 0, 0, 0)}
    def WeylGroup(x, prefix=None): 
    125125        (11/2, 5/2, 3/2, 1/2)
    126126        sage: w.action(rho) # action of G on weight lattice
    127127        (5, -1, 3, 2)
    128        
    129     TESTS:
     128
     129    TESTS::
     130
    130131        sage: TestSuite(WeylGroup(["A",3])).run()
    131132        sage: TestSuite(WeylGroup(["A",3, 1])).run()
    132133
    def WeylGroup(x, prefix=None): 
    139140        sage: w.reduced_word()
    140141        [2, 0]
    141142    """
    142     if isinstance(x, RootLatticeRealization):
     143    if x in RootLatticeRealizations:
    143144        return WeylGroup_gens(x, prefix=prefix)
    144145
    145146    ct = CartanType(x)
    class WeylGroup_gens(ClearCacheOnPickle, 
    389390    #         [0 1]]
    390391    #    """
    391392    #    return [self._element_constructor_(a._matrix_(QQ)) for a in self._gap_().Elements()]
     393
    392394    def list(self):
    393395        """
    394396        Returns a list of the elements of self.
    395397
    396398        EXAMPLES::
    397        
     399
    398400            sage: G = WeylGroup(['A',1])
    399401            sage: G.list()
    400402            [[1 0]
    401403             [0 1], [0 1]
    402404             [1 0]]
    403405
     406            sage: G = WeylGroup(['A',3,1])
     407            sage: G.list()
     408            Traceback (most recent call last):
     409              ...
     410            NotImplementedError: infinite list
     411
    404412        This overrides the implementation of MatrixGroup_gap.
    405413        Those seem typical timings (without the overriding):
    406414   
    class WeylGroup_gens(ClearCacheOnPickle, 
    418426            CPU times: user 3.26 s, sys: 0.02 s, total: 3.28 s
    419427            Wall time: 3.29 s
    420428
     429        Note: listing the matrices in GAP is much faster than the
     430        timings above suggest; the slowness apparently comes from the
     431        interface with GAP, and are therefore highly subject to
     432        improvement.
    421433        """
    422         return self._list_from_iterator()
     434        if hasattr(self, "_list_from_iterator"):
     435            return self._list_from_iterator()
     436        else:
     437            raise NotImplementedError, "infinite list"
    423438
    424439    def character_table(self):
    425440        """
    class WeylGroup_gens(ClearCacheOnPickle, 
    623638
    624639class ClassicalWeylSubgroup(WeylGroup_gens):
    625640    """
    626     A class for Classical Weyl Subgroup of a Weyl Group
     641    A class for Classical Weyl Subgroup of an affine Weyl Group
    627642
    628643    EXAMPLES::
    629644
    class ClassicalWeylSubgroup(WeylGroup_ge 
    634649        Category of finite weyl groups
    635650        sage: G.cardinality()
    636651        24
     652        sage: G.index_set()
     653        [1, 2, 3]
    637654        sage: TestSuite(G).run()
    638655
    639656    TESTS::
  • sage/structure/parent.pyx

    diff --git a/sage/structure/parent.pyx b/sage/structure/parent.pyx
    a b cdef class Parent(category_object.Catego 
    18771877            ...
    18781878            TypeError: ...
    18791879        """
    1880         assert not self._coercions_used, "coercions must all be registered up before use"
     1880        assert not (self._coercions_used and mor.domain() in self._convert_from_hash), "conversion from %s to %s already registered or discovered"%(mor.domain(), self)
    18811881        if isinstance(mor, map.Map):
    18821882            if mor.codomain() is not self:
    18831883                raise ValueError, "Map's codomain must be self"