Affine Root System Basics¶
Among infinite-dimensional Lie algebras, Kac-Moody Lie algebras are generalizations of finite-dimensional simple Lie algebras. They include finite-dimensional simple Lie algebras as special cases but are usually infinite-dimensional. Many concepts and results from the representation theory of finite-dimensional Lie groups and Lie algebras extend to Kac-Moody Lie algebras. This includes the root system, Weyl group, weight lattice, the parametrization of important representations (the integrable highest weight ones) by dominant weights and the Weyl character formula for these representations.
Among Kac-Moody Lie algebras, affine Lie algebras are an important infinite-dimensional class, and their infinite-dimensional integrable highest-weight representations are an important class among their representations. In this section many of the concepts are applicable to general Kac-Moody Lie algebras. However the code that we will discuss is mainly for the affine case. This is sufficiently different from the general case (and important) to merit special attention.
In this section we will review some of the Kac-Moody theory, taking [Kac] as our primary reference. We also recommend [KMPS]. This two volume set contains tables (in Volume 2) of quantities such as string functions and modular characteristics that you can now compute in Sage. Volume 1 contains an introduction to affine Lie algebras and their representations, including a valuable discussion of how they arise in string theory.
In this section and the next, we will also explain what facilities there are in Sage for computing with these. We will often restrict ourselves to the case of affine Lie algebras.
Cartan Matrix¶
See [Kac] Chapter 1 for this topic.
The basic data defining a Kac-Moody Lie algebra is a (generalized) Cartan matrix. This is a square matrix \(A = (a_{ij})\) with diagonal entries equal to 2 and nonpositive off diagonal entries such that \(a_{ij} = 0\) if and only if \(a_{ji} = 0\). It is useful to assume that it is indecomposable and symmetrizable. Indecomposable means that it cannot be arranged into two diagonal blocks by permuting the rows and columns; and symmetrizable means that \(DA\) is symmetric for some invertible diagonal matrix \(D\).
Given a generalized Cartan matrix there is a vector space \(\mathfrak{h}\) containing vectors \(\alpha_i^\vee\) (called simple coroots) and vectors \(\alpha_i \in \mathfrak{h}^*\) (called simple roots) such that \(\langle \alpha_i^\vee, \alpha_j \rangle = \alpha_i^\vee(\alpha_j) = a_{ij}\). Moreover there exists a Kac-Moody Lie algebra \(\mathfrak{g}\) containing \(\mathfrak{h}\) as an abelian subalgebra that is generated by \(\mathfrak{h}\) and elements \(e_i\) and \(f_i\) such that
(These conditions do not quite characterize \(\mathfrak{g}\), but they do if supplemented by the Serre relations, which we will not need or state.)
The significance of the diagonalizability assumption is that \(\mathfrak{g}\) admits an invariant symmetric bilinear form, and hence has a Casimir operator and a good representation theory.
The transpose of \(A\) is also a symmetrizable indecomposable generalized Cartan matrix, so there is a dual Cartan type in which the roots and coroots are interchanged.
In Sage, we may recover the Cartan matrix as follows:
sage: RootSystem(['B',2]).cartan_matrix()
[ 2 -1]
[-2 2]
sage: RootSystem(['B',2,1]).cartan_matrix()
[ 2 0 -1]
[ 0 2 -1]
[-2 -2 2]
>>> from sage.all import *
>>> RootSystem(['B',Integer(2)]).cartan_matrix()
[ 2 -1]
[-2 2]
>>> RootSystem(['B',Integer(2),Integer(1)]).cartan_matrix()
[ 2 0 -1]
[ 0 2 -1]
[-2 -2 2]
RootSystem(['B',2]).cartan_matrix() RootSystem(['B',2,1]).cartan_matrix()
If \(\det(A) = 0\) and its nullspace is one-dimensional, then \(\mathfrak{g}\) is an affine Lie algebra, as in the second example above.
Untwisted Affine Kac-Moody Lie Algebras¶
One realization of affine Lie algebras, described in Chapter 7
of [Kac] begins with a finite-dimensional simple Lie algebra
\(\mathfrak{g}^\circ\), with Cartan type \(X_\ell\) (['X',l]
in Sage).
Tensoring with the Laurent polynomial ring gives the loop Lie algebra
\(\mathfrak{g}^\circ \otimes \CC[t,t^{-1}]\). This is the Lie algebra of
vector fields in \(\mathfrak{g}^\circ\) on the circle. Then one may make
a central extension:
After that, it is convenient to adjoin another basis element, which acts on \(\mathfrak{g}'\) as a derivation \(d\). If \(\mathfrak{h}^\circ\) is a Cartan subalgebra of \(\mathfrak{g}^\circ\), then we obtain a Cartan subalgebra \(\mathfrak{h}'\) of \(\mathfrak{g}'\) by adjoining the central element \(K\), and then a Cartan subalgebra \(\mathfrak{h}\) by further adjoining the derivation \(d\).
The resulting Lie algebra \(\mathfrak{g}\) is the untwisted affine
Lie algebra. The Cartan type is designated to be \(X_\ell^{(1)}\)
in Kac’ notation, which is rendered as ['X',l,1]
or "Xl~"
in Sage. The Dynkin diagram of this Cartan type is the
extended Dynkin-diagram of \(\mathfrak{g}^\circ\):
sage: CartanType("E6~").dynkin_diagram()
O 0
|
|
O 2
|
|
O---O---O---O---O
1 3 4 5 6
E6~
>>> from sage.all import *
>>> CartanType("E6~").dynkin_diagram()
O 0
|
|
O 2
|
|
O---O---O---O---O
1 3 4 5 6
E6~
CartanType("E6~").dynkin_diagram()
From the Dynkin diagram, we can read off generators and relations for the affine Weyl group, which is a Coxeter group with generators \(s_i\) of order 2, that commute if \(i\) and \(j\) are not adjacent in the Dynkin diagram, and otherwise are subject to a braid relation. We can infer some Levi subalgebras of \(\mathfrak{g}\), obtained by omitting one node from the Dynkin diagram; particularly omitting the “affine node” \(0\) gives \(E_6\), that is \(\mathfrak{g}^\circ\).
The index set for the finite-dimensional Lie algebra \(\mathfrak{g}^\circ\) is \(I = \{1, 2, \ldots, \ell\}\). This means we label the roots, coroots etc. by \(i \in I\). The index set for the affine Lie algebra \(\mathfrak{g}\) adds one index \(0\) for the affine root \(\alpha_0\).
The subset of \(\lambda \in \mathfrak{h}^*\) characterized by \(\lambda(\alpha_i^\vee) \in \ZZ\) for the coroots \(\alpha_i^\vee\) is called the weight lattice \(P\). There are two versions of the weight lattice, depending on whether we are working with \(\mathfrak{g}\) or \(\mathfrak{g}'\). The weight lattice of \(\mathfrak{g}\) is called the extended weight lattice. We may create these as follows:
sage: RootSystem("A2~").weight_lattice()
Weight lattice of the Root system of type ['A', 2, 1]
sage: RootSystem("A2~").weight_lattice(extended=True)
Extended weight lattice of the Root system of type ['A', 2, 1]
>>> from sage.all import *
>>> RootSystem("A2~").weight_lattice()
Weight lattice of the Root system of type ['A', 2, 1]
>>> RootSystem("A2~").weight_lattice(extended=True)
Extended weight lattice of the Root system of type ['A', 2, 1]
RootSystem("A2~").weight_lattice() RootSystem("A2~").weight_lattice(extended=True)
Referring to the extended lattice, the term lattice is a slight misnomer because \(P\) is not discrete; it contains all complex multiples of \(\delta\), which is orthogonal to the coroots. However the image of \(P\) in \(\mathfrak{h}^* / \CC\delta\) is a bona fide lattice. Indeed, the fundamental weights are vectors \(\Lambda_i \in \mathfrak{h}^*\) such that \(\Lambda_i(\alpha_j^\vee) = \delta_{ij}\), and then
The Weyl vector \(\rho\) is the sum of the fundamental weights. This plays the role as does the classical Weyl vector, which also equals half the sum of the positive roots, in the theory of finite semisimple Lie algebras. The weight lattice \(P\) contains the root lattice \(Q\), which is the lattice spanned by \(\alpha_0, \alpha_1, \ldots, \alpha_\ell\).
Usually there is an advantage to working with \(\mathfrak{g}\) instead of \(\mathfrak{g}'\). (Thus we prefer the extended weight lattice, though this is not the default.) The reason for this is as follows. If \(V\) is a representation of \(\mathfrak{g}\) then usually the weight spaces \(V_\lambda\), in a decomposition with respect to characters (weights) of \(\mathfrak{h}\) are finite-dimensional; but the corresponding weight spaces for \(\mathfrak{h}'\) would not be.
There are exceptions to this rule of preferring the extended weight lattice. In particular, we can construct non-trivial irreducible finite-dimensional representations of \(\mathfrak{g}'\), and these cannot be lifted to \(\mathfrak{g}\) (although they do have infinite-dimensional analogs). These certain finite-dimensional representations have crystal bases, which include Kirillov-Reshetikhin crystals. Thus, for Kirillov-Reshetikhin crystals we prefer to use the non-extended weight lattice. See Affine Finite Crystals.
Twisted Types¶
There are also twisted types with Cartan type \(X_\ell^{(m)}\)
or ['X',l,m]
where \(m\) is the order of an automorphism of
the Dynkin diagram of \(\mathfrak{g}^\circ\). These are described
in [Kac] Chapter 8. Alternative descriptions of the twisted
types may be found in [Macdonald2003]. Examining the tables
Aff1, Aff2 and Aff3 in Chapter 4 of Kac, you will see that
each twisted type is dual to an untwisted type (except
\(A_{2\ell}^{(2)}\)). For example the twisted type ['E',6,2]
(or \(E_6^{(2)}\)) in Aff2 is dual to the untwisted type
['F',4,1]
(or \(F_4^{(1)}\)).
Referring to the above Dynkin diagram for ['E',6,1]
, if
we collapse the nodes 1 and 6 together, and the nodes 3 and 5,
we obtain the Dynkin diagram for ['E',6,2]
:
sage: CartanType(['E',6,2]).dynkin_diagram()
O---O---O=<=O---O
0 1 2 3 4
F4~*
>>> from sage.all import *
>>> CartanType(['E',Integer(6),Integer(2)]).dynkin_diagram()
O---O---O=<=O---O
0 1 2 3 4
F4~*
CartanType(['E',6,2]).dynkin_diagram()
We must explain why Sage calls this Cartan type F4~*
.
The Cartan type ['F',4,1]
is obtained by adding one
Dynkin node to the Cartan type “F4”:
sage: CartanType(['F',4,1]).dynkin_diagram()
O---O---O=>=O---O
0 1 2 3 4
F4~
>>> from sage.all import *
>>> CartanType(['F',Integer(4),Integer(1)]).dynkin_diagram()
O---O---O=>=O---O
0 1 2 3 4
F4~
CartanType(['F',4,1]).dynkin_diagram()
The Cartan types ['E',6,2]
and ['F',4,1]
(abbreviated F4~
)
are dual in the sense that long roots of one correspond to short roots
of the other. (Thus \(\alpha_0\), \(\alpha_1\) and \(\alpha_2\) are short
roots of ['E',6,2]
, they are long roots of ['F',4,1]
.)
More generally, every twisted affine type is dual to a unique untwisted
type, and the Macdonald convention is to refer to the Cartan type as
the dual of the corresponding untwisted type:
sage: CartanType(['F',4,1]).dual() == CartanType(['E',6,2])
True
>>> from sage.all import *
>>> CartanType(['F',Integer(4),Integer(1)]).dual() == CartanType(['E',Integer(6),Integer(2)])
True
CartanType(['F',4,1]).dual() == CartanType(['E',6,2])
Roots and Weights¶
A Kac-Moody Lie algebra \(\mathfrak{g}\) has a triangular decomposition
where \(\mathfrak{n}_-\) and \(\mathfrak{n}_+\) are locally nilpotent Lie algebras.
If \(V\) is a \(\mathfrak{g}\)-module then we often have a weight space decomposition
where \(V_\lambda\) is finite-dimensional, and where \(\mathfrak{h}\) acts by \(X\,v = \lambda(X) v\) for \(X \in \mathfrak{h}\), \(v \in V_\lambda\). When \(V_\lambda \neq 0\), the linear functional \(\lambda\) is called a weight. The space \(V_\lambda\) is called the weight space and its dimension is the multiplicity of the weight \(\lambda\).
As a special case, \(\mathfrak{g}\) is a module over itself under the adjoint representation, and it has a weight space decomposition.
The roots are the nonzero weights in the adjoint representation of \(\mathfrak{g}\) on itself. In contrast with the finite-dimensional case, if \(\mathcal{g}\) is an infinite Kac-Moody Lie algebra there are two types of roots, called real and imaginary. The real roots have multiplicity 1, while the imaginary roots can have multiplicity \(> 1\). In the case of the affine Kac-Moody Lie algebra the imaginary roots have bounded multiplicity, while in non-affine cases the multiplicities of the imaginary roots is somewhat mysterious.
The roots may be divided into those in the adjoint representation of \(\mathfrak{h}\) on \(\mathfrak{n}_+\), called positive, and those on \(\mathfrak{n}_-\), called negative.
Returning to the general module \(V\) with a weight space decomposition, a vector in the module \(V\) that is annihilated by \(\mathfrak{n}_+\) is called a highest weight vector. If the space of highest weight vectors is one-dimensional, and if \(V\) is generated by a highest weight vector \(v\) then \(\CC\,v = V_\lambda\) for a weight \(\lambda\), called the highest weight, and \(V\) is called a highest weight representation.
If \(\lambda\) is any linear functional on \(\mathfrak{h}\), then there is a universal highest weight module \(M(\lambda)\) such that any highest weight module with highest weight \(\lambda\) is a quotient of \(M(\lambda)\). In particular \(M(\lambda)\) (which is also called a Verma module) has a unique irreducible quotient denoted \(L(\lambda)\). Looking ahead to crystal bases, the infinity crystal \(\mathcal{B}(\infty)\) is a crystal base of the Verma module \(M(0)\).
A weight \(\lambda \in P\) is called dominant if
for all simple coroots \(\alpha_i^\vee\). Let \(P^+\) be the set of dominant weights.
A weight has a level which can be defined as its inner product with the canonical central element \(c\). Each weight knows its level:
sage: L = RootSystem(['E',6,1]).weight_lattice(extended=True)
sage: Lambda = L.fundamental_weights()
sage: [Lambda[i].level() for i in L.index_set()]
[1, 1, 2, 2, 3, 2, 1]
>>> from sage.all import *
>>> L = RootSystem(['E',Integer(6),Integer(1)]).weight_lattice(extended=True)
>>> Lambda = L.fundamental_weights()
>>> [Lambda[i].level() for i in L.index_set()]
[1, 1, 2, 2, 3, 2, 1]
L = RootSystem(['E',6,1]).weight_lattice(extended=True) Lambda = L.fundamental_weights() [Lambda[i].level() for i in L.index_set()]
Affine Root System and Weyl Group¶
We now specialize to affine Kac-Moody Lie algebras and their root systems. The basic reference for the affine root system and Weyl group is [Kac] Chapter 6.
In the untwisted affine case, the root system \(\Delta\) contains a copy of the root system \(\Delta^\circ\) of \(\mathfrak{g}^\circ\). The real roots consist of \(\alpha + n \delta\) with \(\alpha \in \Delta^\circ\), and \(n \in \ZZ\). The root is positive if either \(n = 0\) and \(\alpha \in \Delta^\circ_+\) or \(n > 0\). The imaginary roots consist of \(n \delta\) with \(n \in \ZZ\) nonzero. See [Kac], Proposition 6.3 for a description of the root system in the twisted affine case.
The multiplicity \(m(\alpha)\) is the dimension of \(\mathfrak{g}_\alpha\). It is 1 if \(\alpha\) is a real root. For the untwisted affine Lie algebras, the multiplicity of an imaginary root is the rank \(\ell\) of \(\mathfrak{g}^\circ\). (For the twisted cases, see [Kac] Corollary 8.3.)
In most cases we recommend creating the weight lattice with the
option extended=True
:
sage: WL = RootSystem(['A',2,1]).weight_lattice(extended=True); WL
Extended weight lattice of the Root system of type ['A', 2, 1]
sage: WL.positive_roots()
Disjoint union of Family (Positive real roots of type ['A', 2, 1], Positive imaginary roots of type ['A', 2, 1])
sage: WL.simple_roots()
Finite family {0: 2*Lambda[0] - Lambda[1] - Lambda[2] + delta, 1: -Lambda[0] + 2*Lambda[1] - Lambda[2], 2: -Lambda[0] - Lambda[1] + 2*Lambda[2]}
sage: WL.weyl_group()
Weyl Group of type ['A', 2, 1] (as a matrix group acting on the extended weight lattice)
sage: WL.basic_imaginary_roots()[0]
delta
>>> from sage.all import *
>>> WL = RootSystem(['A',Integer(2),Integer(1)]).weight_lattice(extended=True); WL
Extended weight lattice of the Root system of type ['A', 2, 1]
>>> WL.positive_roots()
Disjoint union of Family (Positive real roots of type ['A', 2, 1], Positive imaginary roots of type ['A', 2, 1])
>>> WL.simple_roots()
Finite family {0: 2*Lambda[0] - Lambda[1] - Lambda[2] + delta, 1: -Lambda[0] + 2*Lambda[1] - Lambda[2], 2: -Lambda[0] - Lambda[1] + 2*Lambda[2]}
>>> WL.weyl_group()
Weyl Group of type ['A', 2, 1] (as a matrix group acting on the extended weight lattice)
>>> WL.basic_imaginary_roots()[Integer(0)]
delta
WL = RootSystem(['A',2,1]).weight_lattice(extended=True); WL WL.positive_roots() WL.simple_roots() WL.weyl_group() WL.basic_imaginary_roots()[0]
Be aware that for the exceptional groups, the ordering of the indices are different from those in [Kac]. This is because Sage uses the Bourbaki ordering of the roots, and Kac does not. Thus in Bourbaki (and in Sage) the \(G_2\) short root is \(\alpha_1\):
sage: CartanType(['G',2,1]).dynkin_diagram()
3
O=<=O---O
1 2 0
G2~
>>> from sage.all import *
>>> CartanType(['G',Integer(2),Integer(1)]).dynkin_diagram()
3
O=<=O---O
1 2 0
G2~
CartanType(['G',2,1]).dynkin_diagram()
By contrast in Kac, \(\alpha_2\) is the short root.
Labels and Coxeter Number¶
Certain constants \(a_i\) label the vertices \(i = 0, \ldots, \ell\) in the tables Aff1, Aff2 and Aff3 in [Kac] Chapter 4. They are called labels by Kac and marks in [KMPS]. They play an important role in the theory. In Sage they are available as follows:
sage: CartanType(['B',5,1]).a()
Finite family {0: 1, 1: 1, 2: 2, 3: 2, 4: 2, 5: 2}
>>> from sage.all import *
>>> CartanType(['B',Integer(5),Integer(1)]).a()
Finite family {0: 1, 1: 1, 2: 2, 3: 2, 4: 2, 5: 2}
CartanType(['B',5,1]).a()
The column vector \(a\) with these entries spans the nullspace of \(A\):
sage: RS = RootSystem(['E',6,2]); RS
Root system of type ['F', 4, 1]^*
sage: A = RS.cartan_matrix(); A
[ 2 -1 0 0 0]
[-1 2 -1 0 0]
[ 0 -1 2 -2 0]
[ 0 0 -1 2 -1]
[ 0 0 0 -1 2]
sage: ann = Matrix([[v] for v in RS.cartan_type().a()]); ann
[1]
[2]
[3]
[2]
[1]
sage: A*ann
[0]
[0]
[0]
[0]
[0]
>>> from sage.all import *
>>> RS = RootSystem(['E',Integer(6),Integer(2)]); RS
Root system of type ['F', 4, 1]^*
>>> A = RS.cartan_matrix(); A
[ 2 -1 0 0 0]
[-1 2 -1 0 0]
[ 0 -1 2 -2 0]
[ 0 0 -1 2 -1]
[ 0 0 0 -1 2]
>>> ann = Matrix([[v] for v in RS.cartan_type().a()]); ann
[1]
[2]
[3]
[2]
[1]
>>> A*ann
[0]
[0]
[0]
[0]
[0]
RS = RootSystem(['E',6,2]); RS A = RS.cartan_matrix(); A ann = Matrix([[v] for v in RS.cartan_type().a()]); ann A*ann
The nullroot \(\delta = \sum_{i\in I} a_i \alpha_i\):
sage: WL = RootSystem('C3~').weight_lattice(extended=True); WL
Extended weight lattice of the Root system of type ['C', 3, 1]
sage: sum(WL.cartan_type().a()[i]*WL.simple_root(i) for i in WL.cartan_type().index_set())
delta
>>> from sage.all import *
>>> WL = RootSystem('C3~').weight_lattice(extended=True); WL
Extended weight lattice of the Root system of type ['C', 3, 1]
>>> sum(WL.cartan_type().a()[i]*WL.simple_root(i) for i in WL.cartan_type().index_set())
delta
WL = RootSystem('C3~').weight_lattice(extended=True); WL sum(WL.cartan_type().a()[i]*WL.simple_root(i) for i in WL.cartan_type().index_set())
The number \(h = \sum_{i\in I} a_i\) is called the Coxeter number. In the untwisted case it is the order of a Coxeter element of the finite Weyl group of \(\mathfrak{g}^\circ\). The dual Coxeter number \(h^\vee\) is the Coxeter number of the dual root system. It appears frequently in representation theory. The Coxeter number and dual Coxeter number may be computed as follow:
sage: sum(CartanType(['F',4,1]).a()) # Coxeter number
12
sage: sum(CartanType(['F',4,1]).dual().a()) # Dual Coxeter number
9
>>> from sage.all import *
>>> sum(CartanType(['F',Integer(4),Integer(1)]).a()) # Coxeter number
12
>>> sum(CartanType(['F',Integer(4),Integer(1)]).dual().a()) # Dual Coxeter number
9
sum(CartanType(['F',4,1]).a()) # Coxeter number sum(CartanType(['F',4,1]).dual().a()) # Dual Coxeter number
The Weyl Group¶
The ambient space of the root system comes with an (indefinite) inner product. The real roots have nonzero length but the imaginary roots are isotropic. If \(\alpha\) is a real root we may define a reflection \(r_\alpha\) in the hyperplane orthogonal to \(\alpha\). In particular the \(\ell+1\) reflections \(s_i\) with respect to the simple positive roots \(\alpha_i\) (\(i = 0, 1, 2, \ldots, \ell\)) generate a Coxeter group. This is the Weyl group \(W\).
Illustrating how to use Sage to compute the action of \(W\) on the weight lattice:
sage: L = RootSystem("A2~").weight_lattice(extended=True)
sage: Lambda = L.fundamental_weights()
sage: delta = L.null_root()
sage: W = L.weyl_group(prefix="s")
sage: s0,s1,s2 = W.simple_reflections()
sage: [(s0*s1*s2*s1).action(x) - x for x in Lambda]
[-2*Lambda[0] + Lambda[1] + Lambda[2] - delta,
-2*Lambda[0] + Lambda[1] + Lambda[2] - 2*delta,
-2*Lambda[0] + Lambda[1] + Lambda[2] - 2*delta]
sage: [s0.action(x) for x in Lambda]
[-Lambda[0] + Lambda[1] + Lambda[2] - delta, Lambda[1], Lambda[2]]
sage: s0.action(delta)
delta
>>> from sage.all import *
>>> L = RootSystem("A2~").weight_lattice(extended=True)
>>> Lambda = L.fundamental_weights()
>>> delta = L.null_root()
>>> W = L.weyl_group(prefix="s")
>>> s0,s1,s2 = W.simple_reflections()
>>> [(s0*s1*s2*s1).action(x) - x for x in Lambda]
[-2*Lambda[0] + Lambda[1] + Lambda[2] - delta,
-2*Lambda[0] + Lambda[1] + Lambda[2] - 2*delta,
-2*Lambda[0] + Lambda[1] + Lambda[2] - 2*delta]
>>> [s0.action(x) for x in Lambda]
[-Lambda[0] + Lambda[1] + Lambda[2] - delta, Lambda[1], Lambda[2]]
>>> s0.action(delta)
delta
L = RootSystem("A2~").weight_lattice(extended=True) Lambda = L.fundamental_weights() delta = L.null_root() W = L.weyl_group(prefix="s") s0,s1,s2 = W.simple_reflections() [(s0*s1*s2*s1).action(x) - x for x in Lambda] [s0.action(x) for x in Lambda] s0.action(delta)
The extended affine Weyl Group¶
The subgroup \(W^\circ\) generated by \(s_1, \ldots, s_\ell\) is a finite Coxeter group that may be identified with the Weyl group of the finite-dimensional simple Lie algebra \(\mathfrak{g}^\circ\).
Geometrically, \(W\) may be interpreted as the semidirect product of the finite Weyl group \(W^\circ\) by a discrete group of translations \(Q^\vee\) isomorphic to the coroot lattice. A larger extended affine Weyl group is the semidirect product of \(W^\circ\) by the coweight lattice \(P^\vee\). If \(P^\vee\) is strictly larger than \(Q^\vee\) this is not a Coxeter group but arises naturally in many problems. It may be constructed in Sage as follows:
sage: E = ExtendedAffineWeylGroup(["A",2,1]); E
Extended affine Weyl group of type ['A', 2, 1]
>>> from sage.all import *
>>> E = ExtendedAffineWeylGroup(["A",Integer(2),Integer(1)]); E
Extended affine Weyl group of type ['A', 2, 1]
E = ExtendedAffineWeylGroup(["A",2,1]); E
See the documentation in
extended_affine_weyl_group
if you need this.