Weight lattices and weight spaces - Combinatorics

Skip to content
Back to top
View this page
Edit this page

# Weight lattices and weight spaces

class sage.combinat.root_system.weight_space.WeightSpace(root_system, base_ring, extended)

  Bases: `CombinatorialFreeModule`

  INPUT:

  - `root_system` – a root system

  - `base_ring` – a ring \(R\)

  - `extended` – boolean (default: `False`)

  The weight space (or lattice if `base_ring` is \(\ZZ\)) of a root system is the formal free module \(\bigoplus_i R \Lambda_i\) generated by the fundamental weights \((\Lambda_i)_{i\in I}\) of the root system.

  This class is also used for coweight spaces (or lattices).

  See also

  - `RootSystem()`

  - `RootSystem.weight_lattice()` and `RootSystem.weight_space()`

  - `WeightLatticeRealizations()`

  EXAMPLES:

  Sage

      sage: Q = RootSystem(['A', 3]).weight_lattice(); Q
      Weight lattice of the Root system of type ['A', 3]
      sage: Q.simple_roots()                                                          # needs sage.graphs
      Finite family {1: 2*Lambda[1] -   Lambda[2],
                     2:  -Lambda[1] + 2*Lambda[2] -   Lambda[3],
                     3:                -Lambda[2] + 2*Lambda[3]}

      sage: Q = RootSystem(['A', 3, 1]).weight_lattice(); Q
      Weight lattice of the Root system of type ['A', 3, 1]
      sage: Q.simple_roots()                                                          # needs sage.graphs
      Finite family {0: 2*Lambda[0] -   Lambda[1]               -   Lambda[3],
                     1:  -Lambda[0] + 2*Lambda[1] -   Lambda[2],
                     2:                -Lambda[1] + 2*Lambda[2] -   Lambda[3],
                     3:  -Lambda[0]               -   Lambda[2] + 2*Lambda[3]}

  Python

      >>> from sage.all import *
      >>> Q = RootSystem(['A', Integer(3)]).weight_lattice(); Q
      Weight lattice of the Root system of type ['A', 3]
      >>> Q.simple_roots()                                                          # needs sage.graphs
      Finite family {1: 2*Lambda[1] -   Lambda[2],
                     2:  -Lambda[1] + 2*Lambda[2] -   Lambda[3],
                     3:                -Lambda[2] + 2*Lambda[3]}

      >>> Q = RootSystem(['A', Integer(3), Integer(1)]).weight_lattice(); Q
      Weight lattice of the Root system of type ['A', 3, 1]
      >>> Q.simple_roots()                                                          # needs sage.graphs
      Finite family {0: 2*Lambda[0] -   Lambda[1]               -   Lambda[3],
                     1:  -Lambda[0] + 2*Lambda[1] -   Lambda[2],
                     2:                -Lambda[1] + 2*Lambda[2] -   Lambda[3],
                     3:  -Lambda[0]               -   Lambda[2] + 2*Lambda[3]}

  For infinite types, the Cartan matrix is singular, and therefore the embedding of the root lattice is not faithful:

  Sage

      sage: sum(Q.simple_roots())                                                     # needs sage.graphs
      0

  [Python]

      >>> from sage.all import *
      >>> sum(Q.simple_roots())                                                     # needs sage.graphs
      0

  In particular, the null root is zero:

  Sage

      sage: Q.null_root()                                                             # needs sage.graphs
      0

  Python

      >>> from sage.all import *
      >>> Q.null_root()                                                             # needs sage.graphs
      0

  This can be compensated by extending the basis of the weight space and slightly deforming the simple roots to make them linearly independent, without affecting the scalar product with the coroots. This feature is currently only implemented for affine types. In that case, if `extended` is set, then the basis of the weight space is extended by an element \(\delta\):

  Sage

      sage: Q = RootSystem(['A', 3, 1]).weight_lattice(extended=True); Q
      Extended weight lattice of the Root system of type ['A', 3, 1]
      sage: Q.basis().keys()
      {0, 1, 2, 3, 'delta'}

  [Python]

      >>> from sage.all import *
      >>> Q = RootSystem(['A', Integer(3), Integer(1)]).weight_lattice(extended=True); Q
      Extended weight lattice of the Root system of type ['A', 3, 1]
      >>> Q.basis().keys()
      {0, 1, 2, 3, 'delta'}

  And the simple root \(\alpha_0\) associated to the special node is deformed as follows:

  Sage

      sage: Q.simple_roots()                                                          # needs sage.graphs
      Finite family {0: 2*Lambda[0] -   Lambda[1]               -   Lambda[3] + delta,
                     1:  -Lambda[0] + 2*Lambda[1] -   Lambda[2],
                     2:                -Lambda[1] + 2*Lambda[2] -   Lambda[3],
                     3:  -Lambda[0]               -   Lambda[2] + 2*Lambda[3]}

  Python

      >>> from sage.all import *
      >>> Q.simple_roots()                                                          # needs sage.graphs
      Finite family {0: 2*Lambda[0] -   Lambda[1]               -   Lambda[3] + delta,
                     1:  -Lambda[0] + 2*Lambda[1] -   Lambda[2],
                     2:                -Lambda[1] + 2*Lambda[2] -   Lambda[3],
                     3:  -Lambda[0]               -   Lambda[2] + 2*Lambda[3]}

  Now, the null root is nonzero:

  Sage

      sage: Q.null_root()                                                             # needs sage.graphs
      delta

  [Python]

      >>> from sage.all import *
      >>> Q.null_root()                                                             # needs sage.graphs
      delta

  Warning

  By a slight notational abuse, the extra basis element used to extend the fundamental weights is called `\delta` in the current implementation. However, in the literature, `\delta` usually denotes instead the null root. Most of the time, those two objects coincide, but not for type \(BC\) (aka. \(A_{2n}^{(2)}\)). Therefore we currently have:

  Sage

      sage: Q = RootSystem(["A",4,2]).weight_lattice(extended=True)
      sage: Q.simple_root(0)                                                      # needs sage.graphs
      2*Lambda[0] - Lambda[1] + delta
      sage: Q.null_root()                                                         # needs sage.graphs
      2*delta

  Python

      >>> from sage.all import *
      >>> Q = RootSystem(["A",Integer(4),Integer(2)]).weight_lattice(extended=True)
      >>> Q.simple_root(Integer(0))                                                      # needs sage.graphs
      2*Lambda[0] - Lambda[1] + delta
      >>> Q.null_root()                                                         # needs sage.graphs
      2*delta

  whereas, with the standard notations from the literature, one would expect to get respectively \(2\Lambda_0 -\Lambda_1 +1/2 \delta\) and \(\delta\).

  Other than this notational glitch, the implementation remains correct for type \(BC\).

  The notations may get improved in a subsequent version, which might require changing the index of the extra basis element. To guarantee backward compatibility in code not included in Sage, it is recommended to use the following idiom to get that index:

  Sage

      sage: F = Q.basis_extension(); F
      Finite family {'delta': delta}
      sage: index = F.keys()[0]; index
      'delta'

  [Python]

      >>> from sage.all import *
      >>> F = Q.basis_extension(); F
      Finite family {'delta': delta}
      >>> index = F.keys()[Integer(0)]; index
      'delta'

  Then, for example, the coefficient of an element of the extended weight lattice on that basis element can be recovered with:

  Sage

      sage: Q.null_root()[index]                                                  # needs sage.graphs
      2

  Python

      >>> from sage.all import *
      >>> Q.null_root()[index]                                                  # needs sage.graphs
      2

  Element

    alias of `WeightSpaceElement`

  basis_extension()

    Return the basis elements used to extend the fundamental weights.

    EXAMPLES:

    Sage

        sage: Q = RootSystem(["A",3,1]).weight_lattice()
        sage: Q.basis_extension()
        Family ()

        sage: Q = RootSystem(["A",3,1]).weight_lattice(extended=True)
        sage: Q.basis_extension()
        Finite family {'delta': delta}

    Python

        >>> from sage.all import *
        >>> Q = RootSystem(["A",Integer(3),Integer(1)]).weight_lattice()
        >>> Q.basis_extension()
        Family ()

        >>> Q = RootSystem(["A",Integer(3),Integer(1)]).weight_lattice(extended=True)
        >>> Q.basis_extension()
        Finite family {'delta': delta}

    This method is irrelevant for finite types:

    Sage

        sage: Q = RootSystem(["A",3]).weight_lattice()
        sage: Q.basis_extension()
        Family ()

    [Python]

        >>> from sage.all import *
        >>> Q = RootSystem(["A",Integer(3)]).weight_lattice()
        >>> Q.basis_extension()
        Family ()

  fundamental_weight(i)

    Return the \(i\)-th fundamental weight.

    INPUT:

    - `i` – an element of the index set or `'delta'`

    By a slight notational abuse, for an affine type this method also accepts `'delta'` as input, and returns the image of \(\delta\) of the extended weight lattice in this realization.

    See also

    `fundamental_weight()`

    EXAMPLES:

    Sage

        sage: Q = RootSystem(["A",3]).weight_lattice()
        sage: Q.fundamental_weight(1)
        Lambda[1]

        sage: Q = RootSystem(["A",3,1]).weight_lattice(extended=True)
        sage: Q.fundamental_weight(1)
        Lambda[1]
        sage: Q.fundamental_weight("delta")
        delta

    Python

        >>> from sage.all import *
        >>> Q = RootSystem(["A",Integer(3)]).weight_lattice()
        >>> Q.fundamental_weight(Integer(1))
        Lambda[1]

        >>> Q = RootSystem(["A",Integer(3),Integer(1)]).weight_lattice(extended=True)
        >>> Q.fundamental_weight(Integer(1))
        Lambda[1]
        >>> Q.fundamental_weight("delta")
        delta

  is_extended()

    Return whether this is an extended weight lattice.

    See also

    `is_extended()`

    EXAMPLES:

    Sage

        sage: RootSystem(["A",3,1]).weight_lattice().is_extended()
        False
        sage: RootSystem(["A",3,1]).weight_lattice(extended=True).is_extended()
        True

    Python

        >>> from sage.all import *
        >>> RootSystem(["A",Integer(3),Integer(1)]).weight_lattice().is_extended()
        False
        >>> RootSystem(["A",Integer(3),Integer(1)]).weight_lattice(extended=True).is_extended()
        True

  simple_root(j)

    Return the \(j\)-th simple root.

    EXAMPLES:

    Sage

        sage: L = RootSystem(["C",4]).weight_lattice()
        sage: L.simple_root(3)                                                      # needs sage.graphs
        -Lambda[2] + 2*Lambda[3] - Lambda[4]

    Python

        >>> from sage.all import *
        >>> L = RootSystem(["C",Integer(4)]).weight_lattice()
        >>> L.simple_root(Integer(3))                                                      # needs sage.graphs
        -Lambda[2] + 2*Lambda[3] - Lambda[4]

    Its coefficients are given by the corresponding column of the Cartan matrix:

    Sage

        sage: L.cartan_type().cartan_matrix()[:,2]                                  # needs sage.graphs
        [ 0]
        [-1]
        [ 2]
        [-1]

    [Python]

        >>> from sage.all import *
        >>> L.cartan_type().cartan_matrix()[:,Integer(2)]                                  # needs sage.graphs
        [ 0]
        [-1]
        [ 2]
        [-1]

    Here are all simple roots:

    Sage

        sage: L.simple_roots()                                                      # needs sage.graphs
        Finite family {1:  2*Lambda[1]   - Lambda[2],
                       2:   -Lambda[1] + 2*Lambda[2]   - Lambda[3],
                       3:   -Lambda[2] + 2*Lambda[3]   - Lambda[4],
                       4:               -2*Lambda[3] + 2*Lambda[4]}

    Python

        >>> from sage.all import *
        >>> L.simple_roots()                                                      # needs sage.graphs
        Finite family {1:  2*Lambda[1]   - Lambda[2],
                       2:   -Lambda[1] + 2*Lambda[2]   - Lambda[3],
                       3:   -Lambda[2] + 2*Lambda[3]   - Lambda[4],
                       4:               -2*Lambda[3] + 2*Lambda[4]}

    For the extended weight lattice of an affine type, the simple root associated to the special node is deformed by adding \(\delta\), where \(\delta\) is the null root:

    Sage

        sage: L = RootSystem(["C",4,1]).weight_lattice(extended=True)
        sage: L.simple_root(0)                                                      # needs sage.graphs
        2*Lambda[0] - 2*Lambda[1] + delta

    [Python]

        >>> from sage.all import *
        >>> L = RootSystem(["C",Integer(4),Integer(1)]).weight_lattice(extended=True)
        >>> L.simple_root(Integer(0))                                                      # needs sage.graphs
        2*Lambda[0] - 2*Lambda[1] + delta

    In fact \(\delta\) is really \(1/a_0\) times the null root (see the discussion in `WeightSpace`) but this only makes a difference in type \(BC\):

    Sage

        sage: L = RootSystem(CartanType(["BC",4,2])).weight_lattice(extended=True)
        sage: L.simple_root(0)                                                      # needs sage.graphs
        2*Lambda[0] - Lambda[1] + delta
        sage: L.null_root()                                                         # needs sage.graphs
        2*delta

    Python

        >>> from sage.all import *
        >>> L = RootSystem(CartanType(["BC",Integer(4),Integer(2)])).weight_lattice(extended=True)
        >>> L.simple_root(Integer(0))                                                      # needs sage.graphs
        2*Lambda[0] - Lambda[1] + delta
        >>> L.null_root()                                                         # needs sage.graphs
        2*delta

    See also

    - `simple_root()`

    - `CartanType.col_annihilator()`

  to_ambient_space_morphism()

    The morphism from `self` to its associated ambient space.

    EXAMPLES:

    Sage

        sage: CartanType(['A',2]).root_system().weight_lattice().to_ambient_space_morphism()
        Generic morphism:
        From: Weight lattice of the Root system of type ['A', 2]
        To:   Ambient space of the Root system of type ['A', 2]

    Python

        >>> from sage.all import *
        >>> CartanType(['A',Integer(2)]).root_system().weight_lattice().to_ambient_space_morphism()
        Generic morphism:
        From: Weight lattice of the Root system of type ['A', 2]
        To:   Ambient space of the Root system of type ['A', 2]

    Warning

    Implemented only for finite Cartan type.

class sage.combinat.root_system.weight_space.WeightSpaceElement

  Bases: `IndexedFreeModuleElement`

  is_dominant()

    Check whether an element in the weight space lies in the positive cone spanned by the basis elements (fundamental weights).

    EXAMPLES:

    Sage

        sage: W = RootSystem(['A',3]).weight_space()
        sage: Lambda = W.basis()
        sage: w = Lambda[1] + Lambda[3]
        sage: w.is_dominant()
        True
        sage: w = Lambda[1] - Lambda[2]
        sage: w.is_dominant()
        False

    Python

        >>> from sage.all import *
        >>> W = RootSystem(['A',Integer(3)]).weight_space()
        >>> Lambda = W.basis()
        >>> w = Lambda[Integer(1)] + Lambda[Integer(3)]
        >>> w.is_dominant()
        True
        >>> w = Lambda[Integer(1)] - Lambda[Integer(2)]
        >>> w.is_dominant()
        False

    In the extended affine weight lattice, `'delta'` is orthogonal to the positive coroots, so adding or subtracting it should not affect dominance:

    Sage

        sage: P = RootSystem(['A',2,1]).weight_lattice(extended=true)
        sage: Lambda = P.fundamental_weights()
        sage: delta = P.null_root()                                                 # needs sage.graphs
        sage: w = Lambda[1] - delta                                                 # needs sage.graphs
        sage: w.is_dominant()                                                       # needs sage.graphs
        True

    [Python]

        >>> from sage.all import *
        >>> P = RootSystem(['A',Integer(2),Integer(1)]).weight_lattice(extended=true)
        >>> Lambda = P.fundamental_weights()
        >>> delta = P.null_root()                                                 # needs sage.graphs
        >>> w = Lambda[Integer(1)] - delta                                                 # needs sage.graphs
        >>> w.is_dominant()                                                       # needs sage.graphs
        True

  is_dominant_weight()

    Check whether an element in the weight space lies in the positive \(\ZZ\)-lattice cone spanned by the basis elements (fundamental weights).

    EXAMPLES:

    Sage

        sage: W = RootSystem(['A',3]).weight_space()
        sage: Lambda = W.basis()
        sage: w = Lambda[1] + Lambda[3]
        sage: w.is_dominant_weight()
        True
        sage: w = Lambda[1] + 2/3*Lambda[3]
        sage: w.is_dominant_weight()
        False
        sage: w = Lambda[1] - Lambda[2]
        sage: w.is_dominant_weight()
        False

    Python

        >>> from sage.all import *
        >>> W = RootSystem(['A',Integer(3)]).weight_space()
        >>> Lambda = W.basis()
        >>> w = Lambda[Integer(1)] + Lambda[Integer(3)]
        >>> w.is_dominant_weight()
        True
        >>> w = Lambda[Integer(1)] + Integer(2)/Integer(3)*Lambda[Integer(3)]
        >>> w.is_dominant_weight()
        False
        >>> w = Lambda[Integer(1)] - Lambda[Integer(2)]
        >>> w.is_dominant_weight()
        False

    In the extended affine weight lattice, `'delta'` is orthogonal to the positive coroots, so adding or subtracting it should not affect dominance:

    Sage

        sage: P = RootSystem(['A',2,1]).weight_lattice(extended=true)
        sage: Lambda = P.fundamental_weights()
        sage: delta = P.null_root()                                                 # needs sage.graphs
        sage: w = Lambda[1] - delta                                                 # needs sage.graphs
        sage: w.is_dominant_weight()                                                # needs sage.graphs
        True

    [Python]

        >>> from sage.all import *
        >>> P = RootSystem(['A',Integer(2),Integer(1)]).weight_lattice(extended=true)
        >>> Lambda = P.fundamental_weights()
        >>> delta = P.null_root()                                                 # needs sage.graphs
        >>> w = Lambda[Integer(1)] - delta                                                 # needs sage.graphs
        >>> w.is_dominant_weight()                                                # needs sage.graphs
        True

  scalar(lambdacheck)

    The canonical scalar product between the weight lattice and the coroot lattice.

    Todo

    - merge with_apply_multi_module_morphism

    - allow for any root space / lattice

    - define properly the return type (depends on the base rings of the two spaces)

    - make this robust for extended weight lattices (\(i\) might be “delta”)

    EXAMPLES:

    Sage

        sage: L = RootSystem(["C",4,1]).weight_lattice()
        sage: Lambda     = L.fundamental_weights()
        sage: alphacheck = L.simple_coroots()
        sage: Lambda[1].scalar(alphacheck[1])
        1
        sage: Lambda[1].scalar(alphacheck[2])
        0

    Python

        >>> from sage.all import *
        >>> L = RootSystem(["C",Integer(4),Integer(1)]).weight_lattice()
        >>> Lambda     = L.fundamental_weights()
        >>> alphacheck = L.simple_coroots()
        >>> Lambda[Integer(1)].scalar(alphacheck[Integer(1)])
        1
        >>> Lambda[Integer(1)].scalar(alphacheck[Integer(2)])
        0

    The fundamental weights and the simple coroots are dual bases:

    Sage

        sage: matrix([ [ Lambda[i].scalar(alphacheck[j])
        ....:            for i in L.index_set() ]
        ....:          for j in L.index_set() ])
        [1 0 0 0 0]
        [0 1 0 0 0]
        [0 0 1 0 0]
        [0 0 0 1 0]
        [0 0 0 0 1]

    [Python]

        >>> from sage.all import *
        >>> matrix([ [ Lambda[i].scalar(alphacheck[j])
        ...            for i in L.index_set() ]
        ...          for j in L.index_set() ])
        [1 0 0 0 0]
        [0 1 0 0 0]
        [0 0 1 0 0]
        [0 0 0 1 0]
        [0 0 0 0 1]

    Note that the scalar product is not yet implemented between the weight space and the coweight space; in any cases, that won’t be the job of this method:

    Sage

        sage: R = RootSystem(["A",3])
        sage: alpha = R.weight_space().roots()                                      # needs sage.graphs
        sage: alphacheck = R.coweight_space().roots()                               # needs sage.graphs
        sage: alpha[1].scalar(alphacheck[1])                                        # needs sage.graphs
        Traceback (most recent call last):
        ...
        ValueError: -Lambdacheck[1] + 2*Lambdacheck[2] - Lambdacheck[3]
        is not in the coroot space

    Python

        >>> from sage.all import *
        >>> R = RootSystem(["A",Integer(3)])
        >>> alpha = R.weight_space().roots()                                      # needs sage.graphs
        >>> alphacheck = R.coweight_space().roots()                               # needs sage.graphs
        >>> alpha[Integer(1)].scalar(alphacheck[Integer(1)])                                        # needs sage.graphs
        Traceback (most recent call last):
        ...
        ValueError: -Lambdacheck[1] + 2*Lambdacheck[2] - Lambdacheck[3]
        is not in the coroot space

  to_ambient()

    Map `self` to the ambient space.

    EXAMPLES:

    Sage

        sage: mu = CartanType(['B',2]).root_system().weight_lattice().an_element(); mu
        2*Lambda[1] + 2*Lambda[2]
        sage: mu.to_ambient()
        (3, 1)

    Python

        >>> from sage.all import *
        >>> mu = CartanType(['B',Integer(2)]).root_system().weight_lattice().an_element(); mu
        2*Lambda[1] + 2*Lambda[2]
        >>> mu.to_ambient()
        (3, 1)

    Warning

    Only implemented in finite Cartan type. Does not work for coweight lattices because there is no implemented map from the coweight lattice to the ambient space.

  to_weight_space()

    Map `self` to the weight space.

    Since \(self.parent()\) is the weight space, this map just returns `self`. This overrides the generic method in \(WeightSpaceRealizations\).

    EXAMPLES:

    Sage

        sage: mu = CartanType(['A',2]).root_system().weight_lattice().an_element(); mu
        2*Lambda[1] + 2*Lambda[2]
        sage: mu.to_weight_space()
        2*Lambda[1] + 2*Lambda[2]

    Python

        >>> from sage.all import *
        >>> mu = CartanType(['A',Integer(2)]).root_system().weight_lattice().an_element(); mu
        2*Lambda[1] + 2*Lambda[2]
        >>> mu.to_weight_space()
        2*Lambda[1] + 2*Lambda[2]