Ticket #14085: trac_14085-root_system-ambient_spaces-nt.patch

File trac_14085-root_system-ambient_spaces-nt.patch, 84.3 KB (added by nthiery, 7 years ago)
  • doc/en/reference/combinat/root_systems.rst

    # HG changeset patch
    # User Nicolas M. Thiery <nthiery@users.sf.net>
    # Date 1361758403 18000
    # Node ID 2b586097fd04064a5d8a84fafc2f8db2ac389e1a
    # Parent  fced4fee486dd2690d02e1b0a315e1fca47f6c54
    #14085: Ambient spaces for dual and affine root systems
    
    diff --git a/doc/en/reference/combinat/root_systems.rst b/doc/en/reference/combinat/root_systems.rst
    a b Root Systems 
    2121
    2222   ../sage/combinat/root_system/weyl_characters
    2323
     24   ../sage/combinat/root_system/type_affine
    2425   ../sage/combinat/root_system/type_dual
    2526   ../sage/combinat/root_system/type_reducible
    2627   ../sage/combinat/root_system/type_relabel
  • sage/categories/crystals.py

    diff --git a/sage/categories/crystals.py b/sage/categories/crystals.py
    a b class Crystals(Category_singleton): 
    134134
    135135        def weight_lattice_realization(self):
    136136            """
    137             Returns the weight lattice realization for the root system
    138             associated to ``self``. This default implementation uses
    139             the ambient space of the root system.
     137            Returns the weight lattice realization used to express weights.
     138
     139            This default implementation uses the ambient space of the
     140            root system for (non relabelled) finite types and the
     141            weight lattice otherwise. This is a legacy from when
     142            ambient spaces were partially implemented, and may be
     143            changed in the future.
    140144
    141145            EXAMPLES::
    142146
    class Crystals(Category_singleton): 
    148152                Weight lattice of the Root system of type ['A', 2, 1]
    149153            """
    150154            F = self.cartan_type().root_system()
    151             if F.ambient_space() is None:
     155            if F.is_finite() and F.ambient_space() is not None:
     156                return F.ambient_space()
     157            else:
    152158                return F.weight_lattice()
    153             else:
    154                 return F.ambient_space()
    155159
    156160        def cartan_type(self):
    157161            """
  • sage/combinat/crystals/kirillov_reshetikhin.py

    diff --git a/sage/combinat/crystals/kirillov_reshetikhin.py b/sage/combinat/crystals/kirillov_reshetikhin.py
    a b class KirillovReshetikhinGenericCrystal( 
    340340
    341341    def module_generator(self):
    342342        r"""
    343         Yields the module generator of weight `s \Lambda_r` of a Kirillov-Reshetikhin crystal `B^{r,s}`
     343        Returns the unique module generator of classical weight `s \Lambda_r` of a Kirillov-Reshetikhin crystal `B^{r,s}`
    344344
    345345        EXAMPLES::
    346346
    class KirillovReshetikhinGenericCrystal( 
    359359        Lambda = R.fundamental_weights()
    360360        r = self.r()
    361361        s = self.s()
    362         c = R.null_coroot()[r]
    363         return [ b for b in self.module_generators if b.weight() == s*Lambda[r] - s*c*Lambda[0] ][0]
     362        weight = s*Lambda[r] - s*Lambda[0] * Lambda[r].level() / Lambda[0].level()
     363        return [ b for b in self.module_generators if b.weight() == weight][0]
    364364
    365365    def r(self):
    366366        """
  • sage/combinat/root_system/ambient_space.py

    diff --git a/sage/combinat/root_system/ambient_space.py b/sage/combinat/root_system/ambient_space.py
    a b Ambient lattices and ambient spaces 
    33"""
    44#*****************************************************************************
    55#       Copyright (C) 2008-2009 Daniel Bump
    6 #       Copyright (C) 2008-2009 Nicolas M. Thiery <nthiery at users.sf.net>,
     6#       Copyright (C) 2008-2013 Nicolas M. Thiery <nthiery at users.sf.net>
    77#
    88#  Distributed under the terms of the GNU General Public License (GPL)
    99#                  http://www.gnu.org/licenses/
    class AmbientSpace(ClearCacheOnPickle, C 
    1818    r"""
    1919    Abstract class for ambient spaces
    2020
    21     Any implementation of this class should implement a class method
    22     smallest_base_ring as described below, and a method dimension
    23     working on a partially initialized instance with just root_system
    24     as attribute. There is no safe default implementation for the later,
    25     so none is provided.
     21    All subclasses should implement a class method
     22    ``smallest_base_ring`` taking a cartan type as input, and a method
     23    ``dimension`` working on a partially initialized instance with
     24    just ``root_system`` as attribute. There is no safe default
     25    implementation for the later, so none is provided.
    2626
    2727    EXAMPLES::
    2828
    2929        sage: AL = RootSystem(['A',2]).ambient_lattice()
    3030
     31    .. NOTE:: This is only used so far for finite root systems.
     32
    3133    Caveat: Most of the ambient spaces currently have a basis indexed
    3234    by `0,\dots, n`, unlike the usual mathematical convention::
    3335
    class AmbientSpace(ClearCacheOnPickle, C 
    3739
    3840    This will be cleaned up!
    3941
     42    .. SEEALSO::
     43
     44        - :class:`sage.combinat.root_system.type_A.AmbientSpace`
     45        - :class:`sage.combinat.root_system.type_B.AmbientSpace`
     46        - :class:`sage.combinat.root_system.type_C.AmbientSpace`
     47        - :class:`sage.combinat.root_system.type_D.AmbientSpace`
     48        - :class:`sage.combinat.root_system.type_E.AmbientSpace`
     49        - :class:`sage.combinat.root_system.type_F.AmbientSpace`
     50        - :class:`sage.combinat.root_system.type_G.AmbientSpace`
     51        - :class:`sage.combinat.root_system.type_dual.AmbientSpace`
     52        - :class:`sage.combinat.root_system.type_affine.AmbientSpace`
     53
    4054    TESTS::
    4155
    42         sage: types = CartanType.samples(finite=True, crystalographic = True)+[CartanType(["A",2],["C",5])]
     56        sage: types = CartanType.samples(crystalographic = True)+[CartanType(["A",2],["C",5])]
    4357        sage: for e in [ct.root_system().ambient_space() for ct in types]:
    44         ...       if e is not None:
    4558        ...            TestSuite(e).run()
    46 
    4759    """
    4860    def __init__(self, root_system, base_ring):
    4961        """
    5062        EXAMPLES::
    51        
     63
    5264            sage: e = RootSystem(['A',3]).ambient_lattice()
    5365            sage: s = e.simple_reflections()
    5466
     67            sage: L = RootSystem(['A',3]).coroot_lattice()
     68            sage: e.has_coerce_map_from(L)
     69            True
     70            sage: e(L.simple_root(1))
     71            (1, -1, 0, 0)
    5572        """
    5673        self.root_system = root_system
    5774        CombinatorialFreeModule.__init__(self, base_ring,
    class AmbientSpace(ClearCacheOnPickle, C 
    5976                                         element_class = AmbientSpaceElement,
    6077                                         prefix='e',
    6178                                         category = WeightLatticeRealizations(base_ring))
     79        coroot_lattice = self.root_system.coroot_lattice()
     80        coroot_lattice.module_morphism(self.simple_coroot, codomain=self).register_as_coercion()
    6281
    6382        # FIXME: here for backward compatibility;
    6483        # Should we use dimension everywhere?
    class AmbientSpace(ClearCacheOnPickle, C 
    94113        Returns the dimension of this ambient space.
    95114
    96115        EXAMPLES::
    97        
     116
    98117            sage: from sage.combinat.root_system.ambient_space import AmbientSpace
    99118            sage: e = RootSystem(['F',4]).ambient_space()
    100119            sage: AmbientSpace.dimension(e)
    class AmbientSpace(ClearCacheOnPickle, C 
    104123
    105124        """
    106125        raise NotImplementedError
    107    
     126
    108127    @classmethod
    109     def smallest_base_ring(cls):
     128    def smallest_base_ring(cls, cartan_type=None):
    110129        """
    111130        Returns the smallest ground ring over which the ambient space can be realized.
    112131
     132        This class method will get called with the cartan type as
     133        input. This default implementation returns `\QQ`; subclasses
     134        should override it as appropriate.
     135
    113136        EXAMPLES::
    114        
     137
    115138            sage: e = RootSystem(['F',4]).ambient_space()
    116139            sage: e.smallest_base_ring()
    117140            Rational Field
    class AmbientSpace(ClearCacheOnPickle, C 
    129152
    130153        """
    131154        return self._name_string()
    132    
     155
    133156    def _name_string(self, capitalize=True, base_ring=False, type=True):
    134157        """
    135158        EXAMPLES::
    136        
     159
    137160            sage: RootSystem(['A',4]).ambient_lattice()._name_string()
    138161            "Ambient lattice of the Root system of type ['A', 4]"
    139162
    class AmbientSpace(ClearCacheOnPickle, C 
    143166    def __call__(self, v):
    144167        """
    145168        TESTS::
    146        
     169
    147170            sage: R = RootSystem(['A',4]).ambient_lattice()
    148171            sage: R([1,2,3,4,5])
    149172            (1, 2, 3, 4, 5)
    class AmbientSpace(ClearCacheOnPickle, C 
    161184    def __getitem__(self,i):
    162185        """
    163186        Note that indexing starts at 1.
    164        
     187
    165188        EXAMPLES::
    166        
     189
    167190            sage: e = RootSystem(['A',2]).ambient_lattice()
    168191            sage: e[1]
    169192            (1, 0, 0)
    class AmbientSpace(ClearCacheOnPickle, C 
    179202    def coroot_lattice(self):
    180203        """
    181204        EXAMPLES::
    182        
     205
    183206            sage: e = RootSystem(["A", 3]).ambient_lattice()
    184207            sage: e.coroot_lattice()
    185208            Ambient lattice of the Root system of type ['A', 3]
    class AmbientSpace(ClearCacheOnPickle, C 
    191214        Returns the i-th simple coroot, as an element of this space
    192215
    193216        EXAMPLES::
    194        
     217
    195218            sage: R = RootSystem(["A",3])
    196219            sage: L = R.ambient_lattice()
    197220            sage: L.simple_coroot(1)
    class AmbientSpace(ClearCacheOnPickle, C 
    200223            (0, 1, -1, 0)
    201224            sage: L.simple_coroot(3)
    202225            (0, 0, 1, -1)
    203         """       
     226        """
    204227        return self.simple_root(i).associated_coroot()
    205228
    206229    def reflection(self, root, coroot=None):
    207230        """
    208231        EXAMPLES::
    209        
     232
    210233            sage: e = RootSystem(["A", 3]).ambient_lattice()
    211234            sage: a = e.simple_root(0); a
    212235            (-1, 0, 0, 0)
    class AmbientSpace(ClearCacheOnPickle, C 
    252275    def __cmp__(self, other):
    253276        """
    254277        EXAMPLES::
    255        
     278
    256279            sage: e1 = RootSystem(['A',3]).ambient_lattice()
    257280            sage: e2 = RootSystem(['B',3]).ambient_lattice()
    258281            sage: e1 == e1
    class AmbientSpace(ClearCacheOnPickle, C 
    287310        into the subspace corresponding to the semisimple derived group.
    288311        This arises with Cartan type A, E6 and E7.
    289312
    290         EXAMPLES:
     313        EXAMPLES::
    291314
    292315            sage: RootSystem("A2").ambient_space().from_vector_notation((1,0,0))
    293316            (1, 0, 0)
    class AmbientSpaceElement(CombinatorialF 
    316339    def __hash__(self):
    317340        """
    318341        EXAMPLES::
    319        
     342
    320343            sage: e = RootSystem(['A',2]).ambient_space()
    321344            sage: hash(e.simple_root(0))
    322345            -4601450286177489034          # 64-bit
    323             549810038                     # 32-bit 
     346            549810038                     # 32-bit
    324347        """
    325348        return hash(tuple(sorted([(m,c) for m,c in self._monomial_coefficients.iteritems()])))
    326        
     349
    327350    # For backward compatibility
    328351    def _repr_(self):
    329352        """
    class AmbientSpaceElement(CombinatorialF 
    334357            (-1, 0, 0)
    335358        """
    336359        return str(self.to_vector())
    337    
     360
    338361    def inner_product(self, lambdacheck):
    339362        """
    340363        The scalar product with elements of the coroot lattice
    341364        embedded in the ambient space.
    342365
    343366        EXAMPLES::
    344        
     367
    345368            sage: e = RootSystem(['A',2]).ambient_space()
    346369            sage: a = e.simple_root(0); a
    347370            (-1, 0, 0)
    class AmbientSpaceElement(CombinatorialF 
    357380                continue
    358381            result += c*self_mc[t]
    359382        return result
    360        
     383
    361384    scalar = inner_product
    362385    dot_product = inner_product
    363386
    364387    def associated_coroot(self):
    365388        """
    366389        EXAMPLES::
    367        
     390
    368391            sage: e = RootSystem(['F',4]).ambient_space()
    369392            sage: a = e.simple_root(0); a
    370393            (1/2, -1/2, -1/2, -1/2)
    class AmbientSpaceElement(CombinatorialF 
    378401    def is_positive_root(self):
    379402        """
    380403        EXAMPLES::
    381    
     404
    382405            sage: R = RootSystem(['A',3]).ambient_space()
    383406            sage: r=R.simple_root(1)+R.simple_root(2)
    384407            sage: r.is_positive_root()
    class AmbientSpaceElement(CombinatorialF 
    449472        EXAMPLES::
    450473
    451474            sage: [b.coerce_to_e6() for b in RootSystem("E8").ambient_space().basis()]
    452             [(1, 0, 0, 0, 0, 0, 0, 0), (0, 1, 0, 0, 0, 0, 0, 0), (0, 0, 1, 0, 0, 0, 0, 0), 
    453             (0, 0, 0, 1, 0, 0, 0, 0), (0, 0, 0, 0, 1, 0, 0, 0), (0, 0, 0, 0, 0, 1/3, 1/3, -1/3), 
     475            [(1, 0, 0, 0, 0, 0, 0, 0), (0, 1, 0, 0, 0, 0, 0, 0), (0, 0, 1, 0, 0, 0, 0, 0),
     476            (0, 0, 0, 1, 0, 0, 0, 0), (0, 0, 0, 0, 1, 0, 0, 0), (0, 0, 0, 0, 0, 1/3, 1/3, -1/3),
    454477            (0, 0, 0, 0, 0, 1/3, 1/3, -1/3), (0, 0, 0, 0, 0, -1/3, -1/3, 1/3)]
    455478        """
    456479        x = self
  • 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 
    329329from types import ClassType as classobj
    330330from sage.misc.cachefunc import cached_method
    331331from sage.misc.abstract_method import abstract_method
     332from sage.misc.lazy_import import LazyImport
    332333from sage.rings.all import ZZ
    333334from sage.structure.sage_object import SageObject
    334335from sage.structure.unique_representation import UniqueRepresentation
    335336from sage.sets.family import Family
    336337
    337338# TODO:
    338 # Implement type_dual.AmbientSpace
    339 # Implement dual ambient space
    340 # Implement affinisation of ambient space
    341339# Implement the Kac conventions by relabeling/dual/... of the above
    342340# Implement coxeter diagrams for non crystalographic
    343341
    class CartanTypeFactory(SageObject): 
    522520             ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2], ['I', 5], ['H', 3], ['H', 4],
    523521             ['A', 1, 1], ['A', 5, 1], ['B', 1, 1], ['B', 5, 1],
    524522             ['C', 1, 1], ['C', 5, 1], ['D', 3, 1], ['D', 5, 1],
    525              ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1],
    526              ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*,
    527              ['BC', 1, 2], ['BC', 5, 2]]
     523             ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['BC', 1, 2], ['BC', 5, 2],
     524             ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*, ['BC', 1, 2]^*, ['BC', 5, 2]^*]
    528525
    529526        The finite, affine and crystalographic options allow
    530527        respectively for restricting to (non) finite, (non) affine,
    class CartanTypeFactory(SageObject): 
    533530            sage: CartanType.samples(finite=True)
    534531            [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 2], ['D', 3], ['D', 5],
    535532             ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2], ['I', 5], ['H', 3], ['H', 4]]
    536        
     533
    537534            sage: CartanType.samples(affine=True)
    538535            [['A', 1, 1], ['A', 5, 1], ['B', 1, 1], ['B', 5, 1],
    539536             ['C', 1, 1], ['C', 5, 1], ['D', 3, 1], ['D', 5, 1],
    540              ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1],
    541              ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*,
    542              ['BC', 1, 2], ['BC', 5, 2]]
    543        
     537             ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['BC', 1, 2], ['BC', 5, 2],
     538             ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*, ['BC', 1, 2]^*, ['BC', 5, 2]^*]
     539
    544540            sage: CartanType.samples(crystalographic=True)
    545541            [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 2], ['D', 3], ['D', 5],
    546542             ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2],
    547543             ['A', 1, 1], ['A', 5, 1], ['B', 1, 1], ['B', 5, 1],
    548544             ['C', 1, 1], ['C', 5, 1], ['D', 3, 1], ['D', 5, 1],
    549              ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1],
    550              ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*,
    551              ['BC', 1, 2], ['BC', 5, 2]]
     545             ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['BC', 1, 2], ['BC', 5, 2],
     546             ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*, ['BC', 1, 2]^*, ['BC', 5, 2]^*]
    552547
    553548            sage: CartanType.samples(crystalographic=False)
    554549            [['I', 5], ['H', 3], ['H', 4]]
    555550
    556         Todo: add some reducible Cartan types (suggestions?)
    557        
     551        .. TODO:: add some reducible Cartan types (suggestions?)
     552
    558553        TESTS::
    559554
    560555            sage: for ct in CartanType.samples(): TestSuite(ct).run()
    class CartanTypeFactory(SageObject): 
    579574        EXAMPLES::
    580575
    581576            sage: CartanType._samples()
    582             [['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]]
     577            [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 2], ['D', 3], ['D', 5],
     578             ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['G', 2], ['I', 5], ['H', 3], ['H', 4],
     579             ['A', 1, 1], ['A', 5, 1], ['B', 1, 1], ['B', 5, 1],
     580             ['C', 1, 1], ['C', 5, 1], ['D', 3, 1], ['D', 5, 1],
     581             ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['BC', 1, 2], ['BC', 5, 2],
     582             ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*, ['BC', 1, 2]^*, ['BC', 5, 2]^*]
    583583        """
    584584        finite_crystalographic = \
    585585            [CartanType (t)       for t in [['A', 1], ['A', 5], ['B', 1], ['B', 5],
    class CartanTypeFactory(SageObject): 
    594594        return finite_crystalographic + \
    595595            [CartanType(t)        for t in [["I", 5], ["H", 3], ["H", 4]]] + \
    596596            [t.affine()           for t in finite_crystalographic if t.is_irreducible()] + \
    597             [CartanType(t).dual() for t in [["B", 5, 1], ["C", 4, 1], ["F", 4, 1], ["G", 2, 1]]] + \
    598             [CartanType(t)        for t in [["BC", 1, 2], ["BC", 5, 2], ]] #+ \
     597            [CartanType(t)        for t in [["BC", 1, 2], ["BC", 5, 2]]] + \
     598            [CartanType(t).dual() for t in [["B", 5, 1], ["C", 4, 1], ["F", 4, 1], ["G", 2, 1],["BC", 1, 2], ["BC", 5, 2]]] #+ \
    599599            # [ g ]
    600600
     601    _colors = {1: 'blue',    -1: 'blue',
     602               2: 'red',     -2: 'red',
     603               3: 'green',   -3: 'green',
     604               4: 'cyan',    -4: 'cyan',
     605               5: 'magenta', -5: 'magenta',
     606               6: 'yellow',  -6: 'yellow'}
     607
     608    @classmethod
     609    def color(cls, i):
     610        """
     611        Default color scheme for the vertices of a dynkin diagram (and associated objects)
     612
     613        EXAMPLES::
     614
     615            sage: CartanType.color(1)
     616            'blue'
     617            sage: CartanType.color(2)
     618            'red'
     619            sage: CartanType.color(3)
     620            'green'
     621
     622        The default color is black. Well, some sort of black, because
     623        plots don't handle well plain black::
     624
     625            sage: CartanType.color(0)
     626            (0.1, 0.1, 0.1)
     627
     628        Negative indices get the same color as their positive counterparts::
     629
     630            sage: CartanType.color(-1)
     631            'blue'
     632            sage: CartanType.color(-2)
     633            'red'
     634            sage: CartanType.color(-3)
     635            'green'
     636        """
     637        return cls._colors.get(i, (0.1, 0.1, 0.1))
    601638
    602639CartanType = CartanTypeFactory()
    603640
    class CartanType_abstract(object): 
    957994             [['D', 3, 1], True], [['D', 5, 1], True],
    958995             [['E', 6, 1], True], [['E', 7, 1], True], [['E', 8, 1], True],
    959996             [['F', 4, 1], False], [['G', 2, 1], False],
     997             [['BC', 1, 2], False], [['BC', 5, 2], False],
    960998             [['B', 5, 1]^*, False], [['C', 4, 1]^*, False], [['F', 4, 1]^*, False], [['G', 2, 1]^*, False],
    961              [['BC', 1, 2], False], [['BC', 5, 2], False]]
     999             [['BC', 1, 2]^*, False], [['BC', 5, 2]^*, False]]
    9621000        """
    9631001        return False
    9641002
    class CartanType_affine(CartanType_simpl 
    12631301    """
    12641302    An abstract class for simple affine Cartan types
    12651303    """
     1304
     1305    AmbientSpace = LazyImport('sage.combinat.root_system.type_affine', 'AmbientSpace')
     1306
    12661307    def is_finite(self):
    12671308        """
    12681309        EXAMPLES::
    class CartanType_affine(CartanType_simpl 
    16801721        tester.assertTrue( self.classical().dual() == self.dual().classical() )
    16811722        tester.assertTrue( self.special_node() == self.dual().special_node() )
    16821723
    1683 
    16841724##############################################################################
    16851725# Concrete base classes
    16861726
  • sage/combinat/root_system/root_lattice_realizations.py

    diff --git a/sage/combinat/root_system/root_lattice_realizations.py b/sage/combinat/root_system/root_lattice_realizations.py
    a b Root lattice realizations 
    2020
    2121from sage.misc.abstract_method import abstract_method, AbstractMethod
    2222from sage.misc.all import attrcall
    23 from sage.misc.cachefunc import cached_method
     23from sage.misc.cachefunc import cached_method, cached_in_parent_method
    2424from sage.misc.lazy_attribute import lazy_attribute
    2525from sage.categories.coxeter_groups import CoxeterGroups
    2626from sage.categories.category_types import Category_over_base_ring
    from sage.rings.all import ZZ, QQ 
    3030from sage.combinat.backtrack import TransitiveIdeal, TransitiveIdealGraded
    3131from sage.misc.superseded import deprecated_function_alias
    3232from sage.structure.element import Element
    33 from copy import copy
    3433
    3534class RootLatticeRealizations(Category_over_base_ring):
    3635    r"""
    class RootLatticeRealizations(Category_o 
    175174                sage: L(alpha[2])
    176175                -Lambda[1] + 2*Lambda[2] - Lambda[3]
    177176
    178             .. note::
     177            .. NOTE::
    179178
    180179                More examples are given in :class:`RootLatticeRealizations`;
    181180                The embeddings are systematically tested in
    class RootLatticeRealizations(Category_o 
    196195                domain.module_morphism(self.simple_root,
    197196                                       codomain = self
    198197                                       ).register_as_coercion()
     198            if self.cartan_type().is_affine():
     199                self._to_classical.register_as_conversion()
    199200
    200201        def cartan_type(self):
    201202            """
    class RootLatticeRealizations(Category_o 
    295296            tester = self._tester(**options)
    296297            alpha = self.simple_roots()
    297298            alphacheck = self.simple_coroots()
     299            R = self.base_ring()
    298300            tester.assertEqual(alpha     .keys(), self.index_set())
    299301            tester.assertEqual(alphacheck.keys(), self.index_set())
    300302
    class RootLatticeRealizations(Category_o 
    304306
    305307            # Check the embeddings from the root lattice and the root space over the same base ring
    306308            root_lattice = self.root_system.root_lattice()
    307             root_space   = self.root_system.root_space  (self.base_ring())
     309            root_space   = self.root_system.root_space  (R)
    308310            tester.assert_(self.coerce_map_from(root_lattice) is not None)
    309311            tester.assert_(self.coerce_map_from(root_space  ) is not None)
    310312            for i in self.index_set():
    class RootLatticeRealizations(Category_o 
    316318            dynkin_diagram = self.dynkin_diagram()
    317319            for i in self.index_set():
    318320                for j in self.index_set():
    319                     tester.assertEqual(alpha[j].scalar(alphacheck[i]), dynkin_diagram[i,j])
     321                    tester.assertEqual(alpha[j].scalar(alphacheck[i]), R(dynkin_diagram[i,j]))
    320322
    321323            # Check associated_coroot, if it is implemented
    322324            if not isinstance(self.element_class.associated_coroot, AbstractMethod):
    class RootLatticeRealizations(Category_o 
    328330                # and similarly for the null coroot
    329331                nullroot = self.null_root()
    330332                nullcoroot = self.null_coroot()
    331                 for k in alpha.keys():
    332                     assert (nullroot.scalar(alphacheck[k])).is_zero()
    333                     assert (alpha[k].scalar(nullcoroot)).is_zero()
     333                special_node = self.cartan_type().special_node()
     334                for i in alpha.keys():
     335                    tester.assert_(nullroot.scalar(alphacheck[i]).is_zero())
     336                    tester.assert_(alpha[i].scalar(nullcoroot).is_zero())
     337                # Check the projection on the classical space
     338                classical = self.classical()
     339                alpha_classical = classical.alpha()
     340                for i in alpha.keys():
     341                    if i != special_node or self.cartan_type().is_untwisted_affine():
     342                        tester.assertEqual(classical(alpha[i]), alpha_classical[i])
    334343
    335344            # Todo: add tests of highest root, roots, has_descent, ...
    336345
    class RootLatticeRealizations(Category_o 
    901910            coef = self.cartan_type().acheck()
    902911            return sum(coef[k]*self.simple_coroots()[k] for k in coef.keys())
    903912
     913
     914        ##########################################################################
     915        # fundamental weights
     916        ##########################################################################
     917
     918        def fundamental_weights_from_simple_roots(self):
     919            r"""
     920            Return the fundamental weights.
     921
     922            This is computed from the simple roots by using the
     923            inverse of the Cartan matrix. This method is therefore
     924            only valid for finite types and if this realization of the
     925            root lattice is large enough to contain them.
     926
     927            EXAMPLES:
     928
     929            In the root space, we retrieve the inverse of the Cartan matrix::
     930
     931                sage: L = RootSystem(["B",3]).root_space()
     932                sage: L.fundamental_weights_from_simple_roots()
     933                Finite family {1:     alpha[1] +   alpha[2] +     alpha[3],
     934                               2:     alpha[1] + 2*alpha[2] +   2*alpha[3],
     935                               3: 1/2*alpha[1] +   alpha[2] + 3/2*alpha[3]}
     936                sage: ~L.cartan_type().cartan_matrix()
     937                [  1   1 1/2]
     938                [  1   2   1]
     939                [  1   2 3/2]
     940
     941            In the weight lattice and the ambient space, we retrieve
     942            the fundamental weights::
     943
     944                sage: L = RootSystem(["B",3]).weight_lattice()
     945                sage: L.fundamental_weights_from_simple_roots()
     946                Finite family {1: Lambda[1], 2: Lambda[2], 3: Lambda[3]}
     947
     948                sage: L = RootSystem(["B",3]).ambient_space()
     949                sage: L.fundamental_weights()
     950                Finite family {1: (1, 0, 0), 2: (1, 1, 0), 3: (1/2, 1/2, 1/2)}
     951                sage: L.fundamental_weights_from_simple_roots()
     952                Finite family {1: (1, 0, 0), 2: (1, 1, 0), 3: (1/2, 1/2, 1/2)}
     953
     954            However the fundamental weights do not belong to the root
     955            lattice::
     956
     957                sage: L = RootSystem(["B",3]).root_lattice()
     958                sage: L.fundamental_weights_from_simple_roots()
     959                Traceback (most recent call last):
     960                ...
     961                ValueError: The fundamental weights do not live in this realization of the root lattice
     962
     963            Beware of the usual `GL_n` vs `SL_n` catch in type `A`::
     964
     965                sage: L = RootSystem(["A",3]).ambient_space()
     966                sage: L.fundamental_weights()
     967                Finite family {1: (1, 0, 0, 0), 2: (1, 1, 0, 0), 3: (1, 1, 1, 0)}
     968                sage: L.fundamental_weights_from_simple_roots()
     969                Finite family {1: (3/4, -1/4, -1/4, -1/4), 2: (1/2, 1/2, -1/2, -1/2), 3: (1/4, 1/4, 1/4, -3/4)}
     970
     971                sage: L = RootSystem(["A",3]).ambient_lattice()
     972                sage: L.fundamental_weights_from_simple_roots()
     973                Traceback (most recent call last):
     974                ...
     975                ValueError: The fundamental weights do not live in this realization of the root lattice
     976            """
     977            # We first scale the inverse of the Cartan matrix to be
     978            # with integer coefficients; then the linear combination
     979            # of the simple roots is guaranteed to live in this space,
     980            # and then we rely on division by d to fail gracefuly.
     981            M = self.cartan_type().cartan_matrix()
     982            d = M.det()
     983            if not d:
     984                raise TypeError("The Cartan matrix is not invertible")
     985            M = d*~M
     986            fundamental_weights = [self.linear_combination(zip(self.simple_roots(), column))
     987                                   for column in M.columns()]
     988            try:
     989                fundamental_weights = [x/d for x in fundamental_weights]
     990            except ValueError:
     991                raise ValueError("The fundamental weights do not live in this realization of the root lattice")
     992            return Family(dict(zip(self.index_set(),fundamental_weights)))
     993
     994
    904995        ##########################################################################
    905996        # reflections
    906997        ##########################################################################
    class RootLatticeRealizations(Category_o 
    13091400                orbits.append(orbit)
    13101401            return orbits
    13111402
     1403
     1404        ##########################################################################
     1405        # Methods for affine root lattice realizations
     1406        # Should eventually go in an Affine nested class
     1407        ##########################################################################
     1408
     1409        @cached_method
     1410        def classical(self):
     1411            """
     1412            Return the corresponding root/weight/ambient lattice/space.
     1413
     1414            EXAMPLES::
     1415
     1416                sage: RootSystem(["A",4,1]).root_lattice().classical()
     1417                Root lattice of the Root system of type ['A', 4]
     1418                sage: RootSystem(["A",4,1]).weight_lattice().classical()
     1419                Weight lattice of the Root system of type ['A', 4]
     1420                sage: RootSystem(["A",4,1]).ambient_space().classical()
     1421                Ambient space of the Root system of type ['A', 4]
     1422            """
     1423            from root_space import RootSpace
     1424            from weight_space import WeightSpace
     1425            R = self.cartan_type().classical().root_system()
     1426            if isinstance(self, RootSpace):
     1427                return R.root_space(self.base_ring())
     1428            elif isinstance(self, WeightSpace):
     1429                return R.weight_space(self.base_ring())
     1430            else:
     1431                return R.ambient_space(self.base_ring())
     1432
     1433        @lazy_attribute
     1434        def _to_classical(self):
     1435            r"""
     1436            The projection onto the classical ambient space.
     1437
     1438            EXAMPLES::
     1439
     1440                sage: L = RootSystem(["A",2,1]).ambient_space()
     1441                sage: e = L.basis()
     1442                sage: L._to_classical(e["delta"])
     1443                (0, 0, 0)
     1444                sage: L._to_classical(e["deltacheck"])
     1445                (0, 0, 0)
     1446                sage: L._to_classical(e[0])
     1447                (1, 0, 0)
     1448                sage: L._to_classical(e[1])
     1449                (0, 1, 0)
     1450                sage: L._to_classical(e[2])
     1451                (0, 0, 1)
     1452            """
     1453            return self.module_morphism(self._to_classical_on_basis, codomain = self.classical())
     1454
     1455        def _classical_alpha_0(self):
     1456            """
     1457            Return the projection of `\alpha_0` in the classical space.
     1458
     1459            EXAMPLES:
     1460
     1461            This is the opposite of the highest root in the untwisted case::
     1462
     1463                sage: L = RootSystem(["B",3,1]).root_space()
     1464                sage: L._to_classical_on_basis(0)
     1465                -alpha[1] - 2*alpha[2] - 2*alpha[3]
     1466                sage: L.classical().highest_root()
     1467                alpha[1] + 2*alpha[2] + 2*alpha[3]
     1468
     1469            But not in the other cases::
     1470
     1471                sage: L = RootSystem(CartanType(["B",3,1]).dual()).root_space()
     1472                sage: L._to_classical_on_basis(0)
     1473                -alpha[1] - 2*alpha[2] - alpha[3]
     1474                sage: L.classical().highest_root()
     1475                2*alpha[1] + 2*alpha[2] + alpha[3]
     1476            """
     1477            cartan_type  = self.cartan_type()
     1478            special_node = cartan_type.special_node()
     1479            a = self.cartan_type().col_annihilator()
     1480            classical = self.classical()
     1481            return -classical.sum(a[i] * self.simple_root(i)
     1482                                  for i in self.index_set() if i != special_node) \
     1483                                  / a[special_node]
     1484
    13121485    class ElementMethods:
    13131486
    13141487        @abstract_method
    13151488        def scalar(self, lambdacheck):
    13161489            """
    1317             The natural pairing with the coroot lattice
     1490            Implement the natural pairing with the coroot lattice.
    13181491
    13191492            INPUT:
    13201493
    class RootLatticeRealizations(Category_o 
    18051978                raise ValueError, "%s does not belong to a lattice of affine Cartan type"%self
    18061979            return self.scalar(self.parent().null_coroot())
    18071980
     1981        @cached_in_parent_method
     1982        def to_simple_root(self, reduced_word=False):
     1983            r"""
     1984            Return (the index of) a simple root in the orbit of the positive root ``self``.
     1985
     1986            INPUT:
     1987
     1988            - ``self`` -- a positive root
     1989            - ``reduced_word`` -- a boolean (default: ``False``)
     1990
     1991            OUTPUT:
     1992
     1993            - The index `i` of a simple root `\alpha_i`.
     1994              If ``reduced_word`` is True, this returns instead a pair
     1995              ``(i, word)``, where word is a sequence of reflections
     1996              mapping `\alpha_i` up the root poset to ``self``.
     1997
     1998            EXAMPLES::
     1999
     2000                sage: L = RootSystem(["A",3]).root_lattice()
     2001                sage: for alpha in L.positive_roots():
     2002                ...       print alpha, alpha.to_simple_root()
     2003                alpha[1] 1
     2004                alpha[2] 2
     2005                alpha[3] 3
     2006                alpha[1] + alpha[2] 2
     2007                alpha[2] + alpha[3] 3
     2008                alpha[1] + alpha[2] + alpha[3] 3
     2009                sage: for alpha in L.positive_roots():
     2010                ...        print alpha, alpha.to_simple_root(reduced_word=True)
     2011                alpha[1] (1, ())
     2012                alpha[2] (2, ())
     2013                alpha[3] (3, ())
     2014                alpha[1] + alpha[2] (2, (1,))
     2015                alpha[2] + alpha[3] (3, (2,))
     2016                alpha[1] + alpha[2] + alpha[3] (3, (1, 2))
     2017
     2018            ALGORITHM:
     2019
     2020            This method walks from ``self`` down to the antidominant
     2021            chamber by applying successively the simple reflection
     2022            given by the first descent. Since ``self`` is a positive
     2023            root, each step goes down the root poset, and one must
     2024            eventually cross a simple root `\alpha_i`.
     2025
     2026            .. SEEALSO::
     2027
     2028                - :meth:`first_descent`
     2029                - :meth:`to_dominant_chamber`
     2030
     2031            .. WARNING::
     2032
     2033                The behavior is not specified if the input is not a
     2034                positive root. For a finite root system, this is
     2035                currently caught (albeit with a not perfect message)::
     2036
     2037                    sage: alpha = L.simple_roots()
     2038                    sage: (2*alpha[1]).to_simple_root()
     2039                    Traceback (most recent call last):
     2040                    ...
     2041                    ValueError: -2*alpha[1] - 2*alpha[2] - 2*alpha[3] is not a positive root
     2042
     2043                For an infinite root systems, this method may run into
     2044                an infinite reccursion if the input is not a positive
     2045                root.
     2046            """
     2047            F = self.parent().simple_roots().inverse_family()
     2048            try:
     2049                j = F[self]
     2050                if reduced_word:
     2051                    return (j, ())
     2052                else:
     2053                    return j
     2054            except KeyError:
     2055                pass
     2056            j = self.first_descent(positive=True)
     2057            if j is None:
     2058                raise ValueError, "%s is not a positive root"%self
     2059            result = self.simple_reflection(j).to_simple_root(reduced_word=reduced_word)
     2060            if reduced_word:
     2061                return (result[0], (j,) + result[1])
     2062            else:
     2063                return result
     2064
     2065        @cached_in_parent_method
     2066        def associated_reflection(self):
     2067            r"""
     2068            Given a positive root ``self``, returns a reduced word for the reflection orthogonal to ``self``.
     2069
     2070            Since the answer is cached, it is a tuple instead of a list.
     2071
     2072            EXAMPLES::
     2073
     2074                sage: RootSystem(['C',3]).root_lattice().simple_root(3).weyl_action([1,2]).associated_reflection()
     2075                (1, 2, 3, 2, 1)
     2076                sage: RootSystem(['C',3]).root_lattice().simple_root(2).associated_reflection()
     2077                (2,)
     2078
     2079            """
     2080            i, reduced_word = self.to_simple_root(reduced_word=True)
     2081            return reduced_word + (i,) + tuple(reversed(reduced_word))
    18082082
    18092083        def translation(self, x):
    18102084            """
    class RootLatticeRealizations(Category_o 
    19612235
    19622236            - ``index_set`` -- the Dynkin node set of the parabolic subsystem.
    19632237
     2238            .. TODO:: This implementation is only valid in the root or weight lattice
     2239
    19642240            EXAMPLES::
    19652241
    19662242                sage: alpha = RootSystem(['A',3]).root_lattice().from_vector(vector([1,1,0]))
  • 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 class RootSpace(ClearCacheOnPickle, Comb 
    147147
    148148    def _to_root_lattice(self, x):
    149149        """
    150         Tries to convert ``x`` to the root lattice
     150        Try to convert ``x`` to the root lattice.
    151151
    152152        INPUT:
    153153
    class RootSpace(ClearCacheOnPickle, Comb 
    189189        except TypeError:
    190190            raise ValueError, "%s does not have integral coefficients"%x
    191191
     192    @cached_method
     193    def _to_classical_on_basis(self, i):
     194        r"""
     195        Implement the projection onto the corresponding classical root space or lattice, on the basis.
     196
     197        EXAMPLES::
     198
     199            sage: L = RootSystem(["A",3,1]).root_space()
     200            sage: L._to_classical_on_basis(0)
     201            -alpha[1] - alpha[2] - alpha[3]
     202            sage: L._to_classical_on_basis(1)
     203            alpha[1]
     204            sage: L._to_classical_on_basis(2)
     205            alpha[2]
     206        """
     207        if i == self.cartan_type().special_node():
     208            return self._classical_alpha_0()
     209        else:
     210            return self.classical().simple_root(i)
     211
    192212class RootSpaceElement(CombinatorialFreeModuleElement):
    193213    def scalar(self, lambdacheck):
    194214        """
    class RootSpaceElement(CombinatorialFree 
    396416        W = self.parent().weyl_group()
    397417        return (W.demazure_product(word)).reduced_word()
    398418
    399     @cached_in_parent_method
    400     def associated_reflection(self):
    401         r"""
    402         Given a positive root ``self``, returns a reduced word for the reflection orthogonal to ``self``.
    403 
    404         Since the answer is cached, it is a tuple instead of a list.
    405 
    406         EXAMPLES::
    407 
    408             sage: RootSystem(['C',3]).root_lattice().simple_root(3).weyl_action([1,2]).associated_reflection()
    409             (1, 2, 3, 2, 1)
    410             sage: RootSystem(['C',3]).root_lattice().simple_root(2).associated_reflection()
    411             (2,)
    412 
    413         """
    414 
    415         i = self.first_descent(positive=True)
    416         if not self.is_positive_root() or i is None:
    417             raise ValueError, "%s is not a positive root"%self
    418         supp = self.support()
    419         if len(supp) == 1:
    420             if not (self[i] == 1):
    421                 raise ValueError, "%s is not a positive root"%self
    422             return tuple([i])
    423         return tuple([i]+list(self.simple_reflection(i).associated_reflection())+[i])
    424 
    425419RootSpace.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 class RootSystem(UniqueRepresentation, S 
    6565        sage: space
    6666        Root lattice of the Root system of type ['B', 3]
    6767   
    68     It is the free `\ZZ`-module
    69     `\bigoplus_i \ZZ.\alpha_i` spanned by the simple
    70     roots::
     68    This is the free `\ZZ`-module `\bigoplus_i \ZZ.\alpha_i` spanned
     69    by the simple roots::
    7170   
    7271        sage: space.base_ring()
    7372        Integer Ring
    class RootSystem(UniqueRepresentation, S 
    163162        Lambda[2]
    164163        sage: s[1](Lambda[3])
    165164        Lambda[3]
    166    
    167     The root system may also come equipped with an ambient space, that
    168     is a simultaneous realization of the weight lattice and the coroot
    169     lattice in a Euclidean vector space. This is implemented on a type
    170     by type basis, and is not always available. When the coefficients
    171     permit it, this is also available as an ambient lattice.
    172    
    173     TODO: Demo: signed permutations realization of type B
    174    
     165
     166    .. RUBRIC:: Ambient spaces
     167
     168    The root system may also come equipped with an ambient space.
     169    This is a `\QQ`-module, endowed with its canonical Euclidean
     170    scalar product, which admits simultaneous embeddings of the
     171    (extended) weight and the (extended) coweight lattice, and
     172    therefore the root and the coroot lattice. This is implemented on
     173    a type by type basis for the finite crystalographic root systems
     174    following Bourbaki's conventions and is extended to the affine
     175    cases. Coefficients permitting, this is also available as an
     176    ambient lattice.
     177
     178    .. SEEALSO:: :meth:`ambient_space` and :meth:`ambient_lattice` for details
     179
     180    In finite type `A`, we recover the natural representation of the
     181    symmetric group as group of permutation matrices::
     182
     183        sage: RootSystem(["A",2]).ambient_space().weyl_group().simple_reflections()
     184        Finite family {1: [0 1 0]
     185                          [1 0 0]
     186                          [0 0 1],
     187                       2: [1 0 0]
     188                          [0 0 1]
     189                          [0 1 0]}
     190
     191    In type `B`, `C`, and `D`, we recover the natural representation
     192    of the Weyl group as groups of signed permutation matrices::
     193
     194        sage: RootSystem(["B",3]).ambient_space().weyl_group().simple_reflections()
     195        Finite family {1: [0 1 0]
     196                          [1 0 0]
     197                          [0 0 1],
     198                       2: [1 0 0]
     199                          [0 0 1]
     200                          [0 1 0],
     201                       3: [ 1  0  0]
     202                          [ 0  1  0]
     203                          [ 0  0 -1]}
     204
     205    In (untwisted) affine types `A`, ..., `D`, one can recover from
     206    the ambient space the affine permutation representation, in window
     207    notation. Let us consider the ambient space for affine type `A`::
     208
     209        sage: L = RootSystem(["A",2,1]).ambient_space(); L
     210        Ambient space of the Root system of type ['A', 2, 1]
     211
     212    Define the "identity" by an appropriate vector at level -3::
     213
     214        sage: e = L.basis(); Lambda = L.fundamental_weights()
     215        sage: id = e[0] + 2*e[1] + 3*e[2]  - 3*Lambda[0]
     216
     217    The corresponding permutation is obtained by projecting it onto
     218    the classical ambient space::
     219
     220        sage: L.classical()
     221        Ambient space of the Root system of type ['A', 2]
     222        sage: L.classical()(id)
     223        (1, 2, 3)
     224
     225    Here is the orbit of the identity under the action of the finite
     226    group::
     227
     228        sage: W = L.weyl_group()
     229        sage: S3 = [ w.action(id) for w in W.classical() ]
     230        sage: [L.classical()(x) for x in S3]
     231        [(1, 2, 3), (2, 1, 3), (3, 1, 2), (3, 2, 1), (1, 3, 2), (2, 3, 1)]
     232
     233    And the action of `s_0` on these yields::
     234
     235        sage: s = W.simple_reflections()
     236        sage: [L.classical()(s[0].action(x)) for x in S3]
     237        [(0, 2, 4), (0, 1, 5), (-1, 1, 6), (-2, 2, 6), (-1, 3, 4), (-2, 3, 5)]
     238
     239    .. RUBRIC:: Dual root systems
     240
    175241    The root system is aware of its dual root system::
    176242   
    177243        sage: R.dual
    class RootSystem(UniqueRepresentation, S 
    568634
    569635    def ambient_lattice(self):
    570636        r"""
    571         Returns the usual ambient lattice for this root_system, if it
    572         exists and is implemented, and None otherwise. This is a
    573         `\ZZ`-module, endowed with its canonical euclidean
    574         scalar product, which embeds simultaneously the root lattice
    575         and the coroot lattice (what about the weight lattice?)
    576        
     637        Return the ambient lattice for this root_system.
     638
     639        This is the ambient space, over `\ZZ`.
     640
     641        .. SEEALSO::
     642
     643            - :meth:`ambient_space`
     644            - :meth:`root_lattice`
     645            - :meth:`weight_lattice`
     646
    577647        EXAMPLES::
    578        
     648
    579649            sage: RootSystem(['A',4]).ambient_lattice()
    580650            Ambient lattice of the Root system of type ['A', 4]
    581        
    582         ::
    583        
     651            sage: RootSystem(['A',4,1]).ambient_lattice()
     652            Ambient lattice of the Root system of type ['A', 4, 1]
     653
     654        Except in type A, only an ambient space can be realized::
     655
    584656            sage: RootSystem(['B',4]).ambient_lattice()
    585657            sage: RootSystem(['C',4]).ambient_lattice()
    586658            sage: RootSystem(['D',4]).ambient_lattice()
    class RootSystem(UniqueRepresentation, S 
    593665    @cached_method
    594666    def ambient_space(self, base_ring=QQ):
    595667        r"""
    596         Returns the usual ambient space for this root_system, if it is
    597         implemented, and None otherwise. This is a `\QQ`-module, endowed with
    598         its canonical euclidean scalar product, which embeds simultaneously
    599         the root lattice and the coroot lattice (what about the weight
    600         lattice?). An alternative base ring can be provided as an option;
    601         it must contain the smallest ring over which the ambient space can
    602         be defined (`\ZZ` or `\QQ`, depending on the type).
    603        
     668        Return the usual ambient space for this root_system.
     669
     670        INPUT:
     671
     672        - ``base_ring`` -- a base ring (default: `\QQ`)
     673
     674        This is a ``base_ring``-module, endowed with its canonical
     675        Euclidean scalar product, which admits simultaneous embeddings
     676        into the weight and the coweight lattice, and therefore the
     677        root and the coroot lattice, and preserves scalar products
     678        between elements of the coroot lattice and elements of the
     679        root or weight lattice (and dually).
     680
     681        There is no mechanical way to define the ambient space just
     682        from the Cartan matrix. Instead is is constructed from hard
     683        coded type by type data, according to the usual Bourbaki
     684        conventions. Such data is provided for all the finite
     685        (crystalographic) types. From this data, ambient spaces can be
     686        built as well for dual types, reducible types and affine
     687        types. When no data is available, or if the base ring is not
     688        large enough, None is returned.
     689
     690        .. WARNING:: for affine types
     691
     692        .. SEEALSO::
     693
     694            - The section on ambient spaces in :class:`RootSystem`
     695            - :meth:`ambient_lattice`
     696            - :class:`~sage.combinat.root_system.ambient_space.AmbientSpace`
     697            - :class:`~sage.combinat.root_system.ambient_space.type_affine.AmbientSpace`
     698            - :meth:`root_space`
     699            - :meth:`weight:space`
     700
    604701        EXAMPLES::
    605702       
    606703            sage: RootSystem(['A',4]).ambient_space()
    class RootSystem(UniqueRepresentation, S 
    635732       
    636733            sage: RootSystem(['G',2]).ambient_space()
    637734            Ambient space of the Root system of type ['G', 2]
     735
     736        An alternative base ring can be provided as an option::
     737
     738            sage: e = RootSystem(['B',3]).ambient_space(RR)
     739            sage: TestSuite(e).run()
     740
     741        It should contain the smallest ring over which the ambient
     742        space can be defined (`\ZZ` in type `A` or `\QQ` otherwise).
     743        Otherwise ``None`` is returned::
     744
     745            sage: RootSystem(['B',2]).ambient_space(ZZ)
     746
     747        The base ring should also be totally ordered. In practice,
     748        only `\ZZ` and `\QQ` are really supported at this point, but
     749        you are welcome to experiment::
     750
     751            sage: e = RootSystem(['G',2]).ambient_space(RR)
     752            sage: TestSuite(e).run()
     753            Failure in _test_root_lattice_realization:
     754            Traceback (most recent call last):
     755            ...
     756            AssertionError: 2.00000000000000 != 2.00000000000000
     757            ------------------------------------------------------------
     758            The following tests failed: _test_root_lattice_realization
    638759        """
    639         # Intention: check that the ambient_space is implemented and that
    640         # base_ring contains the smallest base ring for this ambient space
    641760        if not hasattr(self.cartan_type(),"AmbientSpace"):
    642761            return None
    643762        AmbientSpace = self.cartan_type().AmbientSpace
    644         if base_ring == ZZ and AmbientSpace.smallest_base_ring() == QQ:
     763        if not base_ring.has_coerce_map_from(AmbientSpace.smallest_base_ring(self.cartan_type())):
    645764            return None
    646765        return AmbientSpace(self, base_ring)
    647    
     766
    648767
    649768def WeylDim(ct, coeffs):
    650769    """
  • sage/combinat/root_system/type_A.py

    diff --git a/sage/combinat/root_system/type_A.py b/sage/combinat/root_system/type_A.py
    a b class AmbientSpace(ambient_space.Ambient 
    2323        True
    2424    """
    2525    @classmethod
    26     def smallest_base_ring(cls):
     26    def smallest_base_ring(cls, cartan_type=None):
    2727        """
     28        Returns the smallest base ring the ambient space can be defined upon
     29
     30        .. SEEALSO:: :meth:`~sage.combinat.root_system.ambient_space.AmbientSpace.smallest_base_ring`
     31
    2832        EXAMPLES::
    29        
     33
    3034            sage: e = RootSystem(["A",3]).ambient_space()
    3135            sage: e.smallest_base_ring()
    3236            Integer Ring
  • sage/combinat/root_system/type_C.py

    diff --git a/sage/combinat/root_system/type_C.py b/sage/combinat/root_system/type_C.py
    a b Root system data for type C 
    44#*****************************************************************************
    55#       Copyright (C) 2008-2009 Daniel Bump
    66#       Copyright (C) 2008-2009 Justin Walker
    7 #       Copyright (C) 2008-2009 Nicolas M. Thiery <nthiery at users.sf.net>,
     7#       Copyright (C) 2008-2013 Nicolas M. Thiery <nthiery at users.sf.net>
    88#
    99#  Distributed under the terms of the GNU General Public License (GPL)
    1010#                  http://www.gnu.org/licenses/
    Root system data for type C 
    1212import ambient_space
    1313
    1414class  AmbientSpace(ambient_space.AmbientSpace):
     15    """
     16    EXAMPLES::
    1517
    16 # The coroots can't be defined with integer coefficients!
    17 #    @classmethod
    18 #    def smallest_base_ring(cls):
    19 #        return ZZ;
     18        sage: e = RootSystem(['C',2]).ambient_space(); e
     19        Ambient space of the Root system of type ['C', 2]
     20
     21    One cannot construct the ambient lattice because the fundamental
     22    coweights have rational coefficients::
     23
     24        sage: e.smallest_base_ring()
     25        Rational Field
     26
     27        sage: RootSystem(['B',2]).ambient_space().fundamental_weights()
     28        Finite family {1: (1, 0), 2: (1/2, 1/2)}
     29
     30    TESTS::
     31
     32        sage: TestSuite(e).run()
     33    """
     34
    2035
    2136    def dimension(self):
    2237        """
  • 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 Root system data for type G 
    44#*****************************************************************************
    55#       Copyright (C) 2008-2009 Daniel Bump
    66#       Copyright (C) 2008-2009 Justin Walker
    7 #       Copyright (C) 2008-2009 Nicolas M. Thiery <nthiery at users.sf.net>,
     7#       Copyright (C) 2008-2013 Nicolas M. Thiery <nthiery at users.sf.net>
    88#
    99#  Distributed under the terms of the GNU General Public License (GPL)
    1010#                  http://www.gnu.org/licenses/
    1111#*****************************************************************************
    1212import ambient_space
    13 from sage.combinat.family import Family
    14 
    15 # TODO: check whether this can be defined over ZZ
     13from sage.sets.family import Family
    1614
    1715class AmbientSpace(ambient_space.AmbientSpace):
    1816    """
    1917    EXAMPLES::
    20    
    21         sage: e = RootSystem(['G',2]).ambient_space()
    2218
    23     TESTS:
     19        sage: e = RootSystem(['G',2]).ambient_space(); e
     20        Ambient space of the Root system of type ['G', 2]
    2421
    25         sage: e == loads(dumps(e))
    26         True
     22    One can not construct the ambient lattice because the simple
     23    coroots have rational coefficients::
     24
     25        sage: e.simple_coroots()
     26        Finite family {1: (0, 1, -1), 2: (1/3, -2/3, 1/3)}
     27        sage: e.smallest_base_ring()
     28        Rational Field
     29
     30    TESTS::
     31
     32        sage: TestSuite(e).run()
    2733        sage: [WeylDim(['G',2],[a,b]) for a,b in [[0,0], [1,0], [0,1], [1,1]]] # indirect doctest
    2834        [1, 7, 14, 64]
    29 
    3035    """
    3136
    3237    def dimension(self):
  • new file sage/combinat/root_system/type_affine.py

    diff --git a/sage/combinat/root_system/type_affine.py b/sage/combinat/root_system/type_affine.py
    new file mode 100644
    - +  
     1"""
     2Root system data for affine Cartan types
     3"""
     4#*****************************************************************************
     5#       Copyright (C) 2013 Nicolas M. Thiery <nthiery at users.sf.net>,
     6#
     7#  Distributed under the terms of the GNU General Public License (GPL)
     8#                  http://www.gnu.org/licenses/
     9#*****************************************************************************
     10from sage.misc.cachefunc import cached_method
     11from sage.misc.lazy_attribute import lazy_attribute
     12from sage.combinat.free_module import CombinatorialFreeModule
     13from weight_lattice_realizations import WeightLatticeRealizations
     14
     15class AmbientSpace(CombinatorialFreeModule):
     16    r"""
     17    Ambient space for affine types.
     18
     19    This is constructed from the data in the corresponding classical
     20    ambient space. Namely, this space is obtained by adding two
     21    elements `\delta` and `\delta^\vee` to the basis of the classical
     22    ambient space, and by endowing it with the canonical scalar product.
     23
     24    The coefficient of an element in `\delta^\vee`, thus its scalar
     25    product with `\delta^\vee` gives its level, and dualy for the
     26    colevel. The canonical projection onto the classical ambient space
     27    (by killing `\delta` and `\delta^\vee`) maps the simple roots
     28    (except `\alpha_0`) onto the corresponding classical simple roots,
     29    and similarly for the coroots, fundamental weights, ...
     30    Altogether, this uniquely determines the embedding of the root,
     31    coroot, weight, and coweight lattices. See :meth:`simple_root` and
     32    :meth:`fundamental_weight` for the details.
     33
     34    .. WARNING::
     35
     36        In type `BC`, the null root is in fact::
     37
     38            sage: R = RootSystem(["BC",3,2]).ambient_space()
     39            sage: R.null_root()
     40            2*e['delta']
     41
     42    .. WARNING::
     43
     44        In the literature one often considers a larger affine ambient
     45        space obtained from the classical ambient space by adding four
     46        dimensions, namely for the fundamental weight `\Lambda_0` the
     47        fundamental coweight `\Lambda^\vee_0`, the null root `\delta`,
     48        and the null coroot `c` (aka central element).  In this larger
     49        ambient space, the scalar product is degenerate: `\langle
     50        \delta,\delta\rangle=0` and similarly for the null coroot.
     51
     52        In the current implementation, `\Lambda_0` and the null coroot
     53        are identified:
     54
     55            sage: L = RootSystem(["A",3,1]).ambient_space()
     56            sage: Lambda = L.fundamental_weights()
     57            sage: Lambda[0]
     58            e['deltacheck']
     59            sage: L.null_coroot()
     60            e['deltacheck']
     61
     62        Therefore the scalar product of the null coroot with itself
     63        differs from the larger ambient space::
     64
     65            sage: L.null_coroot().scalar(L.null_coroot())
     66            1
     67
     68        In general, scalar products between two elements that do not
     69        live on "opposite sides" won't necessarily match.
     70
     71    EXAMPLES::
     72
     73        sage: R = RootSystem(["A",3,1])
     74        sage: e = R.ambient_space(); e
     75        Ambient space of the Root system of type ['A', 3, 1]
     76        sage: TestSuite(e).run()
     77
     78    Systematic checks on all affine types::
     79
     80        sage: for ct in CartanType.samples(affine=True, crystalographic=True):
     81        ...       if ct.classical().root_system().ambient_space() is not None:
     82        ...           print ct
     83        ...           L = ct.root_system().ambient_space()
     84        ...           assert L
     85        ...           TestSuite(L).run()
     86        ['A', 1, 1]
     87        ['A', 5, 1]
     88        ['B', 1, 1]
     89        ['B', 5, 1]
     90        ['C', 1, 1]
     91        ['C', 5, 1]
     92        ['D', 3, 1]
     93        ['D', 5, 1]
     94        ['E', 6, 1]
     95        ['E', 7, 1]
     96        ['E', 8, 1]
     97        ['F', 4, 1]
     98        ['G', 2, 1]
     99        ['BC', 1, 2]
     100        ['BC', 5, 2]
     101        ['B', 5, 1]^*
     102        ['C', 4, 1]^*
     103        ['F', 4, 1]^*
     104        ['G', 2, 1]^*
     105        ['BC', 1, 2]^*
     106        ['BC', 5, 2]^*
     107    """
     108    @classmethod
     109    def smallest_base_ring(cls, cartan_type):
     110        r"""
     111        Return the smallest base ring the ambient space can be defined on.
     112
     113        This is the smallest base ring for the associated classical
     114        ambient space.
     115
     116        .. SEEALSO:: :meth:`~sage.combinat.root_system.ambient_space.AmbientSpace.smallest_base_ring`
     117
     118        EXAMPLES::
     119
     120            sage: cartan_type = CartanType(["A",3,1])
     121            sage: cartan_type.AmbientSpace.smallest_base_ring(cartan_type)
     122            Integer Ring
     123            sage: cartan_type = CartanType(["B",3,1])
     124            sage: cartan_type.AmbientSpace.smallest_base_ring(cartan_type)
     125            Rational Field
     126        """
     127        classical = cartan_type.classical()
     128        return cartan_type.classical().root_system().ambient_space().smallest_base_ring(classical)
     129
     130    def __init__(self, root_system, base_ring):
     131        r"""
     132        EXAMPLES::
     133
     134            sage: R = RootSystem(["A",3,1])
     135            sage: R.cartan_type().AmbientSpace
     136            <class 'sage.combinat.root_system.type_affine.AmbientSpace'>
     137            sage: e = R.ambient_space(); e
     138            Ambient space of the Root system of type ['A', 3, 1]
     139            sage: TestSuite(R.ambient_space()).run()
     140
     141            sage: L = RootSystem(['A',3]).coroot_lattice()
     142            sage: e.has_coerce_map_from(L)
     143            True
     144            sage: e(L.simple_root(1))
     145            e[0] - e[1]
     146        """
     147        self.root_system = root_system
     148        classical = root_system.cartan_type().classical().root_system().ambient_space(base_ring)
     149        basis_keys = tuple(classical.basis().keys()) + ("delta","deltacheck")
     150        CombinatorialFreeModule.__init__(self, base_ring,
     151                                         basis_keys,
     152                                         prefix = "e",
     153                                         latex_prefix = "e",
     154                                         category = WeightLatticeRealizations(base_ring))
     155        self._weight_space = self.root_system.weight_space(base_ring=base_ring,extended=True)
     156        self.classical().module_morphism(self.monomial, codomain=self).register_as_coercion()
     157        # Duplicated from ambient_space.AmbientSpace
     158        coroot_lattice = self.root_system.coroot_lattice()
     159        coroot_lattice.module_morphism(self.simple_coroot, codomain=self).register_as_coercion()
     160
     161    def _name_string(self, capitalize=True, base_ring=False, type=True):
     162        r"""
     163        Utility to implement _repr_
     164
     165        EXAMPLES::
     166
     167            sage: RootSystem(['A',4,1]).ambient_lattice()
     168            Ambient lattice of the Root system of type ['A', 4, 1]
     169            sage: RootSystem(['A',4,1]).ambient_space()
     170            Ambient space of the Root system of type ['A', 4, 1]
     171            sage: RootSystem(['A',4,1]).dual.ambient_lattice()
     172            Coambient lattice of the Root system of type ['A', 4, 1]
     173
     174            sage: RootSystem(['A',4,1]).ambient_lattice()._repr_()
     175            "Ambient lattice of the Root system of type ['A', 4, 1]"
     176            sage: RootSystem(['A',4,1]).ambient_lattice()._name_string()
     177            "Ambient lattice of the Root system of type ['A', 4, 1]"
     178        """
     179        return self._name_string_helper("ambient", capitalize=capitalize, base_ring=base_ring, type=type)
     180
     181    _repr_ = _name_string
     182
     183    @cached_method
     184    def _to_classical_on_basis(self, i):
     185        r"""
     186        Implement the projection onto the corresponding classical space or lattice, on the basis.
     187
     188        INPUT:
     189
     190        - ``i`` -- the index of an element of the basis of ``self``,
     191          namely 0, 1, 2, ..., "delta", or "deltacheck"
     192
     193        EXAMPLES::
     194
     195            sage: L = RootSystem(["A",2,1]).ambient_space()
     196            sage: L._to_classical_on_basis("delta")
     197            (0, 0, 0)
     198            sage: L._to_classical_on_basis("deltacheck")
     199            (0, 0, 0)
     200            sage: L._to_classical_on_basis(0)
     201            (1, 0, 0)
     202            sage: L._to_classical_on_basis(1)
     203            (0, 1, 0)
     204            sage: L._to_classical_on_basis(2)
     205            (0, 0, 1)
     206        """
     207        if i=="delta" or i=="deltacheck":
     208            return self.classical().zero()
     209        else:
     210            return self.classical().monomial(i)
     211
     212    def is_extended(self):
     213        r"""
     214        Return whether this is a realization of the extended weight lattice: yes!
     215
     216        .. SEEALSO::
     217
     218            - :class:`sage.combinat.root_system.weight_space.WeightSpace`
     219            - :meth:`sage.combinat.root_sytem.weight_lattice_realizations.WeightLatticeRealizations.ParentMethods.is_extended`
     220
     221        EXAMPLES::
     222
     223            sage: RootSystem(['A',3,1]).ambient_space().is_extended()
     224            True
     225        """
     226        return True
     227
     228    @cached_method
     229    def fundamental_weight(self, i):
     230        r"""
     231        Return the fundamental weight `\Lambda_i` in this ambient space.
     232
     233        It is constructed by taking the corresponding fundamental
     234        weight of the classical ambient space (or `0` for `\Lambda_0`)
     235        and raising it to the appropriate level by adding a suitable
     236        multiple of `\delta^\vee`.
     237
     238        EXAMPLES::
     239
     240            sage: RootSystem(['A',3,1]).ambient_space().fundamental_weight(2)
     241            e[0] + e[1] + e['deltacheck']
     242            sage: RootSystem(['A',3,1]).ambient_space().fundamental_weights()
     243            Finite family {0: e['deltacheck'], 1: e[0] + e['deltacheck'],
     244                           2: e[0] + e[1] + e['deltacheck'], 3: e[0] + e[1] + e[2] + e['deltacheck']}
     245            sage: RootSystem(['A',3]).ambient_space().fundamental_weights()
     246            Finite family {1: (1, 0, 0, 0), 2: (1, 1, 0, 0), 3: (1, 1, 1, 0)}
     247            sage: RootSystem(['A',3,1]).weight_lattice().fundamental_weights().map(attrcall("level"))
     248            Finite family {0: 1, 1: 1, 2: 1, 3: 1}
     249
     250            sage: RootSystem(['B',3,1]).ambient_space().fundamental_weights()
     251            Finite family {0: e['deltacheck'], 1: e[0] + e['deltacheck'],
     252                           2: e[0] + e[1] + 2*e['deltacheck'], 3: 1/2*e[0] + 1/2*e[1] + 1/2*e[2] + e['deltacheck']}
     253            sage: RootSystem(['B',3]).ambient_space().fundamental_weights()
     254            Finite family {1: (1, 0, 0), 2: (1, 1, 0), 3: (1/2, 1/2, 1/2)}
     255            sage: RootSystem(['B',3,1]).weight_lattice().fundamental_weights().map(attrcall("level"))
     256            Finite family {0: 1, 1: 1, 2: 2, 3: 1}
     257
     258       In type `BC` dual, the coefficient of '\delta^\vee' is the level
     259       divided by `2` to take into account that the null coroot is
     260       `2\delta^\vee`::
     261
     262            sage: R = CartanType(['BC',3,2]).dual().root_system()
     263            sage: R.ambient_space().fundamental_weights()
     264            Finite family {0: e['deltacheck'], 1: e[0] + e['deltacheck'],
     265                           2: e[0] + e[1] + e['deltacheck'],
     266                           3: 1/2*e[0] + 1/2*e[1] + 1/2*e[2] + 1/2*e['deltacheck']}
     267            sage: R.weight_lattice().fundamental_weights().map(attrcall("level"))
     268            Finite family {0: 2, 1: 2, 2: 2, 3: 1}
     269            sage: R.ambient_space().null_coroot()
     270            2*e['deltacheck']
     271
     272        By a slight naming abuse this function also accepts "delta" as
     273        input so that it can be used to implement the embedding from
     274        the extended weight lattice::
     275
     276            sage: RootSystem(['A',3,1]).ambient_space().fundamental_weight("delta")
     277            e['delta']
     278        """
     279        if i == "delta":
     280            return self.monomial("delta")
     281        deltacheck = self.monomial("deltacheck")
     282        result = deltacheck * self._weight_space.fundamental_weight(i).level() / deltacheck.level()
     283        if i != self.cartan_type().special_node():
     284            result += self(self.classical().fundamental_weight(i))
     285        return result
     286
     287    @cached_method
     288    def simple_root(self, i):
     289        r"""
     290        Return the `i`-th simple root of this affine ambient space.
     291
     292        EXAMPLES:
     293
     294        It is built straightforwardly from the corresponding simple
     295        root `\alpha_i` in the classical ambient space::
     296
     297            sage: RootSystem(["A",3,1]).ambient_space().simple_root(1)
     298            e[0] - e[1]
     299
     300        For the special node (typically `i=0`), `\alpha_0` is built
     301        from the other simple roots using the column annihilator of
     302        the Cartan matrix and adding `\delta`, where `\delta` is the
     303        null root::
     304
     305            sage: RootSystem(["A",3]).ambient_space().simple_roots()
     306            Finite family {1: (1, -1, 0, 0), 2: (0, 1, -1, 0), 3: (0, 0, 1, -1)}
     307            sage: RootSystem(["A",3,1]).ambient_space().simple_roots()
     308            Finite family {0: -e[0] + e[3] + e['delta'], 1: e[0] - e[1], 2: e[1] - e[2], 3: e[2] - e[3]}
     309
     310        Here is a twisted affine example::
     311
     312            sage: RootSystem(CartanType(["B",3,1]).dual()).ambient_space().simple_roots()
     313            Finite family {0: -e[0] - e[1] + e['delta'], 1: e[0] - e[1], 2: e[1] - e[2], 3: 2*e[2]}
     314
     315        In fact `\delta` is really `1/a_0` times the null root (see
     316        the discussion in :class:`~sage.combinat.root_system.weight_space.WeightSpace`)
     317        but this only makes a difference in type `BC`::
     318
     319            sage: L = RootSystem(CartanType(["BC",3,2])).ambient_space()
     320            sage: L.simple_roots()
     321            Finite family {0: -e[0] + e['delta'], 1: e[0] - e[1], 2: e[1] - e[2], 3: 2*e[2]}
     322            sage: L.null_root()
     323            2*e['delta']
     324
     325        .. NOTE::
     326
     327            An alternative would have been to use the default
     328            implementation of the simple roots as linear combinations
     329            of the fundamental weights. However, as in type `A_n` it is
     330            preferable to take a slight variant to avoid rational
     331            coefficient (the usual `GL_n` vs `SL_n` issue).
     332
     333        .. SEEALSO::
     334
     335            - :meth:`~sage.combinat.root_system.weight_space.WeightSpace.simple_root`
     336            - :class:`~sage.combinat.root_system.weight_space.WeightSpace`
     337            - :meth:`CartanType.col_annihilator`
     338            - :meth:`null_root`
     339        """
     340        cartan_type  = self.cartan_type()
     341        special_node = cartan_type.special_node()
     342        if i == special_node:
     343            return self(self._classical_alpha_0()) + self.monomial("delta")
     344        else:
     345            return self(self.classical().simple_root(i))
     346
     347    @cached_method
     348    def simple_coroot(self, i):
     349        r"""
     350        Return the `i`-th simple coroot `\alpha_i^\vee` of this affine ambient space.
     351
     352        EXAMPLES::
     353
     354            sage: RootSystem(["A",3,1]).ambient_space().simple_coroot(1)
     355            e[0] - e[1]
     356
     357        It is built as the coroot associated to the simple root
     358        `\alpha_i`::
     359
     360            sage: RootSystem(["B",3,1]).ambient_space().simple_roots()
     361            Finite family {0: -e[0] - e[1] + e['delta'], 1: e[0] - e[1], 2: e[1] - e[2], 3: e[2]}
     362            sage: RootSystem(["B",3,1]).ambient_space().simple_coroots()
     363            Finite family {0: -e[0] - e[1] + e['deltacheck'], 1: e[0] - e[1], 2: e[1] - e[2], 3: 2*e[2]}
     364
     365        .. TODO:: Factor out this code with the classical ambient space.
     366        """
     367        return self.simple_root(i).associated_coroot()
     368
     369    class Element(CombinatorialFreeModule.Element):
     370
     371        def inner_product(self, other):
     372            r"""
     373            Implement the canonical inner product of ``self`` with ``other``.
     374
     375            EXAMPLES::
     376
     377                sage: e = RootSystem(['B',3,1]).ambient_space()
     378                sage: B = e.basis()
     379                sage: matrix([[x.inner_product(y) for x in B] for y in B])
     380                [1 0 0 0 0]
     381                [0 1 0 0 0]
     382                [0 0 1 0 0]
     383                [0 0 0 1 0]
     384                [0 0 0 0 1]
     385                sage: x = e.an_element(); x
     386                2*e[0] + 2*e[1] + 3*e[2]
     387                sage: x.inner_product(x)
     388                17
     389
     390            :meth:`scalar` is an alias for this method::
     391
     392                sage: x.scalar(x)
     393                17
     394
     395            .. TODO:: Lift to CombinatorialFreeModule.Element as canonical_inner_product
     396            """
     397            return self.base_ring().sum( self[i] * c for (i,c) in other )
     398
     399        scalar = inner_product
     400
     401        def associated_coroot(self):
     402            r"""
     403            Return the coroot associated to ``self``.
     404
     405            INPUT:
     406
     407            - ``self`` -- a root
     408
     409            EXAMPLES::
     410
     411                sage: alpha = RootSystem(['C',2,1]).ambient_space().simple_roots()
     412                sage: alpha
     413                Finite family {0: -2*e[0] + e['delta'], 1: e[0] - e[1], 2: 2*e[1]}
     414                sage: alpha[0].associated_coroot()
     415                -e[0] + e['deltacheck']
     416                sage: alpha[1].associated_coroot()
     417                e[0] - e[1]
     418                sage: alpha[2].associated_coroot()
     419                e[1]
     420            """
     421            # CHECKME: does it make any sense to not rescale the delta term?
     422            L = self.parent()
     423            c = self["delta"]
     424            self = self - L.term("delta", c)
     425            return (2*self) / self.inner_product(self) + L.term("deltacheck", c)
  • 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 Root system data for dual Cartan types 
    33"""
    44#*****************************************************************************
    55#       Copyright (C) 2008-2009 Anne Schilling <anne at math.ucdavis.edu>
    6 #       Copyright (C) 2008-2009 Nicolas M. Thiery <nthiery at users.sf.net>,
     6#       Copyright (C) 2008-2013 Nicolas M. Thiery <nthiery at users.sf.net>
    77#
    88#  Distributed under the terms of the GNU General Public License (GPL)
    99#                  http://www.gnu.org/licenses/
    1010#*****************************************************************************
     11from sage.misc.misc import attrcall
     12from sage.misc.cachefunc import cached_method
     13from sage.structure.unique_representation import UniqueRepresentation
    1114from sage.structure.sage_object import SageObject
    12 from sage.misc.misc import attrcall
    13 from sage.structure.unique_representation import UniqueRepresentation
    14 from sage.combinat.root_system.cartan_type import CartanType_crystalographic
     15from sage.combinat.root_system.cartan_type import CartanType_crystalographic, CartanType_finite, CartanType_affine, CartanType_simple
    1516import sage
     17import ambient_space
    1618
    1719class CartanType(UniqueRepresentation, SageObject, CartanType_crystalographic):
    1820    r"""
    class CartanType(UniqueRepresentation, S 
    2426    of properties in common with its dual. In particular, the Weyl
    2527    group is isomorphic to that of the dual as a Coxeter group.
    2628
    27     Note: ``CartanType(['BC',4,2]).dual()`` is implemented by
    28     relabelling, not duality!
     29    EXAMPLES:
    2930
     31    For most finite Cartan types, and in particular the simply laced
     32    ones, the dual Cartan type is given by another preexisting Cartan
     33    type::
     34
     35        sage: CartanType(['A',4]).dual()
     36        ['A', 4]
     37        sage: CartanType(['B',4]).dual()
     38        ['C', 4]
     39        sage: CartanType(['C',4]).dual()
     40        ['B', 4]
     41
     42    So to exercise this class we need to consider the non simply laced
     43    exceptionnal or affine Cartan types::
     44
     45        sage: F4d = CartanType(['F', 4]).dual(); F4d
     46        ['F', 4]^*
     47        sage: G21d = CartanType(['G',2,1]).dual(); G21d
     48        ['G', 2, 1]^*
     49        sage: B41d = CartanType(['B',4,1]).dual(); B41d
     50        ['B', 4, 1]^*
     51
     52    They share many properties with their original Cartan types::
     53
     54        sage: F4d.is_irreducible()
     55        True
     56        sage: F4d.is_crystalographic()
     57        True
     58        sage: F4d.is_simply_laced()
     59        False
     60        sage: F4d.is_finite()
     61        True
     62        sage: G21d.is_finite()
     63        False
     64        sage: F4d.is_affine()
     65        False
     66        sage: G21d.is_affine()
     67        True
     68
     69    TESTS::
     70
     71        sage: TestSuite(F4d).run()
    3072    """
    3173    def __init__(self, type):
    3274        """
    class CartanType(UniqueRepresentation, S 
    3779        EXAMPLES::
    3880
    3981           sage: ct = CartanType(['F',4]).dual()
    40            sage: ct == loads(dumps(ct))
    41            True
     82           sage: TestSuite(ct).run()
    4283
    4384        TESTS::
    4485
    class CartanType(UniqueRepresentation, S 
    5394        """
    5495        assert type.is_crystalographic()
    5596        self._dual = type
    56         if type.is_affine():
     97        # TODO: design an appropriate infrastructure to handle this
     98        # automatically? Maybe using categories and axioms?
     99        if type.is_finite():
     100            self._add_abstract_superclass(CartanType_finite)
     101        elif type.is_affine():
    57102            self._add_abstract_superclass(CartanType_affine)
     103        if type.is_irreducible():
     104            self._add_abstract_superclass(CartanType_simple)
     105        # No need to check non crystalographic types (they have no dual)
     106        # or simply laced types (they are self-dual)
    58107
    59108    def _repr_(self, compact = False):
    60109        """
    class CartanType(UniqueRepresentation, S 
    80129
    81130    def ascii_art(self, label = lambda x: x):
    82131        """
    83         Returns an ascii art representation of this Cartan type
     132        Return an ascii art representation of this Cartan type
    84133
    85134        (by hacking the ascii art representation of the dual cartan type)
    86135
    class CartanType(UniqueRepresentation, S 
    156205        """
    157206        return self._dual
    158207
    159     def is_irreducible(self):
    160         """
    161         EXAMPLES::
    162 
    163            sage: ct = CartanType(['F', 4]).dual()
    164            sage: ct.is_irreducible()
    165            True
    166         """
    167         return self._dual.is_irreducible()
    168        
    169     def is_finite(self):
    170         """
    171         EXAMPLES::
    172 
    173            sage: ct = CartanType(['F', 4]).dual()
    174            sage: ct.is_finite()
    175            True
    176         """
    177         return self._dual.is_finite()
    178 
    179     def is_crystalographic(self):
    180         """
    181         EXAMPLES::
    182 
    183            sage: ct = CartanType(['F', 4]).dual()
    184            sage: ct.is_crystalographic()
    185            True
    186         """
    187         return self._dual.is_crystalographic()
    188 
    189     def is_affine(self):
    190         """
    191         EXAMPLES::
    192 
    193            sage: ct = CartanType(['F', 4]).dual()
    194            sage: ct.is_affine()
    195            False
    196         """
    197         return self._dual.is_affine()
    198 
    199208    def rank(self):
    200209        """
    201210        EXAMPLES::
    class CartanType(UniqueRepresentation, S 
    230239
    231240
    232241###########################################################################
    233 from cartan_type import CartanType_affine
    234 class CartanType_affine(CartanType_affine):
     242
     243class AmbientSpace(ambient_space.AmbientSpace):
     244    """
     245    Ambient space for a dual finite Cartan type.
     246
     247    It is constructed in the canonical way from the ambient space of
     248    the original Cartan type by switching the roles of simple roots,
     249    fundamental weights, etc.
     250
     251    EXAMPLES::
     252
     253        sage: F4 = CartanType(["F",4])
     254        sage: L = F4.dual().root_system().ambient_space(); L
     255        Ambient space of the Root system of type ['F', 4]^*
     256        sage: TestSuite(L).run()
     257    """
     258
     259    def dimension(self):
     260        """
     261        Return the dimension of this ambient space.
     262
     263        .. SEEALSO:: :meth:`sage.combinat.root_system.ambient_space.AmbientSpace.dimension`
     264
     265        EXAMPLES::
     266
     267            sage: F4 = CartanType(["F",4])
     268            sage: F4.dual().root_system().ambient_space().simple_root(1)
     269            (0, 1, -1, 0)
     270        """
     271        return self.root_system.dual.ambient_space().dimension()
     272
     273    @cached_method
     274    def simple_root(self, i):
     275        """
     276        Return the ``i``-th simple root.
     277
     278        It is constructed by looking up the corresponding simple
     279        coroot in the ambient space for the dual Cartan type.
     280
     281        EXAMPLES::
     282
     283            sage: F4 = CartanType(["F",4])
     284            sage: F4.dual().root_system().ambient_space().simple_root(1)
     285            (0, 1, -1, 0)
     286
     287            sage: F4.dual().root_system().ambient_space().simple_roots()
     288            Finite family {1: (0, 1, -1, 0), 2: (0, 0, 1, -1), 3: (0, 0, 0, 2), 4: (1, -1, -1, -1)}
     289
     290            sage: F4.root_system().ambient_space().simple_coroots()
     291            Finite family {1: (0, 1, -1, 0), 2: (0, 0, 1, -1), 3: (0, 0, 0, 2), 4: (1, -1, -1, -1)}
     292        """
     293        K = self.base_ring()
     294        dual_coroot = self.cartan_type().dual().root_system().ambient_space(K).simple_coroot(i)
     295        return self.sum_of_terms(dual_coroot)
     296
     297    @cached_method
     298    def fundamental_weights(self):
     299        """
     300        Return the fundamental weights.
     301
     302        They are computed from the simple roots by inverting the
     303        Cartan matrix. This is acceptable since this is only about
     304        ambient spaces for finite Cartan types. Also, we do not have
     305        to worry about the usual `GL_n` vs `SL_n` catch because type
     306        `A` is self dual.
     307
     308        An alternative would have been to start from the fundamental
     309        coweights in the dual ambient space, but those are not yet
     310        implemented.
     311
     312        EXAMPLES::
     313
     314            sage: L = CartanType(["F",4]).dual().root_system().ambient_space()
     315            sage: L.fundamental_weights()
     316            Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3, 1, 1, 1), 4: (2, 0, 0, 0)}
     317        """
     318        return self.fundamental_weights_from_simple_roots()
     319
     320class CartanType_finite(sage.combinat.root_system.cartan_type.CartanType_finite):
     321    AmbientSpace = AmbientSpace
     322
     323###########################################################################
     324class CartanType_affine(sage.combinat.root_system.cartan_type.CartanType_affine):
    235325    def classical(self):
    236326        """
    237327        Returns the classical Cartan type associated with self (which should be affine)
    238328
    239329        EXAMPLES::
    240        
     330
    241331            sage: CartanType(['A',3,1]).dual().classical()
    242332            ['A', 3]
    243333            sage: CartanType(['B',3,1]).dual().classical()
    class CartanType_affine(CartanType_affin 
    251341
    252342    def special_node(self):
    253343        """
    254         Implements :meth:`CartanType_affine.special_node`
     344        Implement :meth:`CartanType_affine.special_node`
    255345
    256346        The special node of the dual of an affine type `T` is the
    257347        special node of `T`.
    258348
    259349        EXAMPLES::
    260        
     350
    261351            sage: CartanType(['A',3,1]).dual().special_node()
    262352            0
    263353            sage: CartanType(['B',3,1]).dual().special_node()
    class CartanType_affine(CartanType_affin 
    268358            0
    269359        """
    270360        return self.dual().special_node()
    271 
    272 #class ambient_space(AmbientSpace):
    273 # todo?
  • sage/combinat/root_system/weight_lattice_realizations.py

    diff --git a/sage/combinat/root_system/weight_lattice_realizations.py b/sage/combinat/root_system/weight_lattice_realizations.py
    a b class WeightLatticeRealizations(Category 
    272272                    tester.assertEqual(self(domain.fundamental_weight(i)), Lambda[i])
    273273                if self.cartan_type().is_affine():
    274274                    tester.assertEqual(self(domain.null_root()), self.null_root())
     275                    if self.is_extended():
     276                        a = self.cartan_type().col_annihilator()
     277                        # This could be an over specification; we
     278                        # could imagine realizations of the extended
     279                        # weight lattice where the null root would not
     280                        # be a (multiple of) basis element.
     281                        tester.assertEqual(self.null_root(), self.term("delta", a[0]))
     282                    for i in self.index_set():
     283                        # The level of the fundamental weights is consistent
     284                        tester.assertEqual(domain.fundamental_weight(i).level(), Lambda[i].level())
    275285
    276286            # Check that the fundamental weights form the dual basis of the simple coroots
    277287            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 class WeightSpace(CombinatorialFreeModul 
    8686        sage: Q.null_root()
    8787        delta
    8888
    89     .. warning::
     89    .. WARNING::
    9090
    9191        By a slight notational abuse, the extra basis element used to
    9292        extend the fundamental weights is called ``\delta`` in the
    class WeightSpace(CombinatorialFreeModul 
    301301        """
    302302        Returns the `j^{th}` simple root
    303303
    304         TESTS::
     304        EXAMPLES::
    305305
    306306            sage: L = RootSystem(["C",4]).weight_lattice()
    307307            sage: L.simple_root(3)
    class WeightSpace(CombinatorialFreeModul 
    316316            [ 2]
    317317            [-1]
    318318
     319        Here are all simple roots::
     320
    319321            sage: L.simple_roots()
    320             Finite family {1: 2*Lambda[1] - Lambda[2],
    321                            2: -Lambda[1] + 2*Lambda[2] - Lambda[3],
    322                            3: -Lambda[2] + 2*Lambda[3] - Lambda[4],
    323                            4: -2*Lambda[3] + 2*Lambda[4]}
     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]}
    324326
    325327        For the extended weight lattice of an affine type, the simple
    326         root associated to the special node is deformed by `\delta`::
     328        root associated to the special node is deformed by adding
     329        `\delta`, where `\delta` is the null root::
    327330
    328331            sage: L = RootSystem(["C",4,1]).weight_lattice(extended=True)
    329332            sage: L.simple_root(0)
    330333            2*Lambda[0] - 2*Lambda[1] + delta
     334
     335        In fact `\delta` is really `1/a_0` times the null root (see
     336        the discussion in :class:`~sage.combinat.root_system.weight_space.WeightSpace`)
     337        but this only makes a difference in type `BC`::
     338
     339            sage: L = RootSystem(CartanType(["BC",4,2])).weight_lattice(extended=True)
     340            sage: L.simple_root(0)
     341            2*Lambda[0] - Lambda[1] + delta
     342            sage: L.null_root()
     343            2*delta
     344
     345        .. SEEALSO::
     346
     347            - :meth:`~sage.combinat.root_system.type_affine.AmbientSpace.simple_root`
     348            - :meth:`CartanType.col_annihilator`
    331349        """
    332350        assert(j in self.index_set())
    333351        result = self.sum_of_terms(self.root_system.dynkin_diagram().column(j))
    class WeightSpace(CombinatorialFreeModul 
    373391        else:
    374392            return super(WeightSpace, self)._latex_term(m)
    375393
     394    @cached_method
     395    def _to_classical_on_basis(self, i):
     396        r"""
     397        Implement the projection onto the corresponding classical space or lattice, on the basis.
     398
     399        INPUT:
     400
     401        - ``i`` -- a vertex of the Dynkin diagram or "delta"
     402
     403        EXAMPLES::
     404
     405            sage: L = RootSystem(["A",2,1]).weight_space()
     406            sage: L._to_classical_on_basis("delta")
     407            0
     408            sage: L._to_classical_on_basis(0)
     409            0
     410            sage: L._to_classical_on_basis(1)
     411            Lambda[1]
     412            sage: L._to_classical_on_basis(2)
     413            Lambda[2]
     414        """
     415        if i == "delta" or i == self.cartan_type().special_node():
     416            return self.classical().zero()
     417        else:
     418            return self.classical().monomial(i)
     419
    376420
    377421class WeightSpaceElement(CombinatorialFreeModuleElement):
    378422