Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Project: SageDays78
Views: 431
In order to look at crystals, we first start with the Lie algebra sl2={Mtr(M)=0}\mathfrak{sl}_2 = \{ M \mid \operatorname{tr}(M) = 0 \}. This has a natural basis of E=[0100]F=[0010]H=[1001] E = \begin{bmatrix} 0 & 1 \\ 0 & 0 \end{bmatrix} \qquad F = \begin{bmatrix} 0 & 0 \\ 1 & 0 \end{bmatrix} \qquad H = \begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}
%auto from sage.structure.element_wrapper import ElementWrapper from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.categories.modules import Modules class sl2(Parent, UniqueRepresentation): def __init__(self, R): Parent.__init__(self, R, category=Modules(R).WithBasis().FiniteDimensional()) def _repr_(self): return "sl2 over {}".format(self.base_ring()) @cached_method def basis(self): MS = MatrixSpace(self.base_ring(), 2) return Family({'E': self.element_class(self, MS([[0,1],[0,0]])), 'F': self.element_class(self, MS([[0,0],[1,0]])), 'H': self.element_class(self, MS([[1,0],[0,-1]]))}) class Element(ElementWrapper): def _add_(self, rhs): return type(self)(self.parent(), self.value + rhs.value) def _sub_(self, rhs): return type(self)(self.parent(), self.value - rhs.value) def _neg_(self): return type(self)(self.parent(), -self.value) def _acted_upon_(self, scalar, self_on_left=True): return type(self)(self.parent(), scalar * self.value) def bracket(self, rhs): return type(self)(self.parent(), self.value * rhs.value - rhs.value * self.value)
L = sl2(QQ) L
sl2 over Rational Field
L.basis()
Finite family {'H': [ 1 0] [ 0 -1], 'E': [0 1] [0 0], 'F': [0 0] [1 0]}
B = L.basis() E,F,H = B['E'], B['F'], B['H'] E
[0 1] [0 0]
H
[ 1 0] [ 0 -1]
E + H
[ 1 1] [ 0 -1]
H.bracket(E)
[0 2] [0 0]
H.bracket(F)
[ 0 0] [-2 0]
E.bracket(F)
[ 1 0] [ 0 -1]
E * 2
[0 2] [0 0]
3/2 * H
[ 3/2 0] [ 0 -3/2]
F - E
[ 0 -1] [ 1 0]
More generally, for sln\mathfrak{sl}_n, there are three types of basis elements: upper triangular, lower triangular, and diagonal matrices. These are generated, as a Lie algebra, by EiE_i, FiF_i, and HiH_i respectively. The upper and lower half are "eigenvectors" for the Cartan subalgebra h:=H1,,Hn1\mathfrak{h} := \langle H_1, \dots, H_{n-1} \rangle, i.e., [H,Ei]=αi(H)Ei[H, E_i] = \alpha_i(H) E_i and [H,Fi]=αi(H)Fi[H, F_i] = -\alpha_i(H) F_i. The eigenvalues, considered as elements in h\mathfrak{h}^*, are called roots and form a root system with {αi}iI\{\alpha_i\}_{i \in I} being the simple roots.
A = RootSystem(['A',2]).ambient_space() A.plot(roots='all')
RootSystem(['B',2]).ambient_space().plot(roots='all')
RootSystem(['C',2]).ambient_space().plot(roots='all')
RootSystem(['G',2]).ambient_space().plot(roots='all')
We construct representations of sln\mathfrak{sl}_n by restricting to copies of sl2\mathfrak{sl}_2, where we understand the irreducible finite-dimensional representations, and piecing them together. Specifically, the irreducible representations VmV_m for mZ>0m \in \ZZ_{>0} have a basis {vm,vm+2,,vm2,vm}\{v_{-m}, v_{-m+2}, \dotsc, v_{m-2}, v_{m}\} with actions Evk=(k+m2+1)vk+2,Fvk=(mk2+1)vk2,Hvk=kvk.\begin{align*} E v_k & = \left(\frac{k+m}{2} + 1\right) v_{k+2}, \\ F v_k & = \left(\frac{m-k}{2} + 1\right) v_{k-2}, \\ H v_k & = k v_k. \end{align*}
class sl2IrreducibleRepresentation(CombinatorialFreeModule): def __init__(self, R, m): self._m = m CombinatorialFreeModule.__init__(self, R, range(-m, m+1, 2), prefix='v') def _repr_(self): return "Irreducible representation of highest weight {} of sl2 over {}".format(self._m, self.base_ring()) def highest_weight_vector(self): return self.basis()[self._m] class Element(CombinatorialFreeModule.Element): def E(self): P = self.parent() d = self.monomial_coefficients(copy=False) return P._from_dict({k+2: c * (k+P._m+2) // 2 for k,c in d.items() if k < P._m}) def F(self): P = self.parent() d = self.monomial_coefficients(copy=False) return P._from_dict({k-2: c * (P._m-k+2) // 2 for k,c in d.items() if k > -P._m}) def H(self): d = self.monomial_coefficients(copy=False) return self.parent()._from_dict({k: c*k for k,c in d.items()})
V = sl2IrreducibleRepresentation(QQ, 1) v = V.highest_weight_vector() v
v[1]
v.E()
0
vm = v.F() vm
v[-1]
vm.F()
0
vm.E()
v[1]
v.H()
v[1]
vm.H()
-v[-1]
vm.F().E() - vm.E().F()
-v[-1]
V = sl2IrreducibleRepresentation(QQ, 3) V.basis()
Finite family {1: v[1], 3: v[3], -3: v[-3], -1: v[-1]}
all(v.F().E() - v.E().F() == v.H() for v in V.basis())
True

By ignoring these constants for the action of EiE_i and FiF_i, we can encode representation in an edge colored, weighted directed graph as follows. We write Fib=αbF_i b = \alpha b' as an arrow bibb \xrightarrow[\hspace{20pt}]{i} b', where we must have Eib=αbE_i b' = \alpha' b by the Lie algebra relations. We encode the action of HiH_i by the weight. The resulting graph is called a crystal graph. Specifically, the weight must satisfy wt(fib)=wt(b)αi\operatorname{wt}(f_i b) = \operatorname{wt}(b) - \alpha_i.

For sln\mathfrak{sl}_n, the irreducible representations are indexed by partitions λ\lambda (of height at most nn), and the basis is given by semistandard tableaux. To determine the action of eie_i and fif_i, we read a tableau top-to-bottom, right-to-left and

  • add any ii as a ++;
  • add any i+1i+1 as a -;
  • cancel any ++- pair (in that order);
  • change the ii corresponding to the leftmost remaining ++ to an i+1i+1.
A slight generalization of this is the tensor product rule, where we essentially only care about the dominant term. (Formally, we take a qq-deformation of the universal enveloping algebra, then look at a Kazhdan-Lusztig like basis and take q0q \to 0.)

Warning: Due to Sage's tensor product convention, we reverse the order of the reading word and pairing.

C = crystals.Tableaux(['A',2], shape=[1]) latex.eval(latex(C))
''
T = tensor([C, C, C]) latex.eval(latex(T))
''
mg = C.highest_weight_vector() x = T(mg.f(1), mg, mg) x
[[[2]], [[1]], [[1]]]
S = x.subcrystal() S
Subcrystal of Full tensor product of the crystals [The crystal of tableaux of type ['A', 2] and shape(s) [[1]], The crystal of tableaux of type ['A', 2] and shape(s) [[1]], The crystal of tableaux of type ['A', 2] and shape(s) [[1]]]
T21 = crystals.Tableaux(['A',2], shape=[2,1]) D = crystals.DirectSum([T21, S]) latex.eval(latex(D))
''
The weight is given by ϵi\epsilon_i coefficient counts the number of ii's in the tableaux. This is exactly analogous to the definition of Schur functions (which are the characters of the irreducible highest weight representations of sln\mathfrak{sl}_n). To connect this back to the action of h\mathfrak{h}, ϵi\epsilon_i gives the coefficient on the ii-diagonal entry. Hence, we can plot the crystal in the ambient space.
A = RootSystem(['A',2,1]).ambient_space() p = A.plot_alcoves() + A.plot_crystal(T21, plot_labels='circles') p.axes(False) p
A = RootSystem(['B',3]).ambient_space() B = crystals.Tableaux(['B',3], shape=[1,1]) A.plot_fundamental_weights() + A.plot_crystal(B, edge_labels=True, plot_labels='circles')
3D rendering not yet implemented

While tableaux are nice, they don't work well beyond the classical types (A,B,C,DA, B, C, D) and G2G_2. This is because it requires knowledge of the representation of B(Λ1)B(\Lambda_1), and it uses the semi-simplicity of g\mathfrak{g}. However, we want something that works for Kac-Moody Lie algebras, the generalization of sln\mathfrak{sl}_n, so2n+1\mathfrak{so}_{2n+1}, sp2n\mathfrak{sp}_{2n}, so2n\mathfrak{so}_{2n} which includes all of the affine Lie algebras. Moreover, we want a model that is uniform, that is only depends on the underlying root system which defines g\mathfrak{g}.

The first known such model is the Littelmann path model. The elements (vertices) are given by paths π ⁣:[0,1]h\pi \colon [0,1] \to \mathfrak{h}^* in the weight space, and the crystal operators are given by partial reflections of the path.

La = RootSystem(['C',2]).weight_space().fundamental_weights() B = crystals.LSPaths(3*La[1]+La[2]) mg = B.highest_weight_vector() A = RootSystem(['C',2,1]).ambient_space() elts = [mg, mg.f(1), mg.f(1).f(1), mg.f_string([1,1,1]), mg.f(2), mg.f(2).f(1)] p = A.plot(reflection_hyperplanes=False, bounding_box=4) + A.plot_ls_paths(elts) p.axes(False) p
There is a discrete counterpart to the Littelmann path model called the alcove path model. In this model, elements are given by alcove walks, reflect the Bruhat graph, and are related to the equivariant K-theory of flag varities. The crystal operators are given by folding the alcove walk.
B = crystals.AlcovePaths(['C',2], [3,1]) mg = B.module_generators[0] A = RootSystem(['C',2,1]).ambient_space() mg.plot()
mg.f(1).plot()
mg.f(2).plot(bounding_box=4)
mg.f(2).f(1).plot()
Another model for crystals is given by Nakajima monomials, whsoe elements are Laurent monomials in {Yi,kiI,kZ}\{Y_{i,k} \mid i \in I, k \in \ZZ\} and the crystal operators are multiplication by certain monomials Ai,kA_{i,k}. In particular, the weight of Yi,kY_{i,k} is Λi\Lambda_i, and so the Ai,kA_{i,k} are a modification of the simple root αi\alpha_i.
La = RootSystem(['A',2,1]).weight_lattice(extended=True).fundamental_weights() M = crystals.NakajimaMonomials(['A',2,1], La[0]) S = M.subcrystal(max_depth=4) G = S.digraph() G.set_latex_options(edge_options=None) latex.eval(latex(G))
''
Note that highest weight crystals/representations are indexed by elements in the dominant weight lattice ParseError: KaTeX parse error: Undefined control sequence: \span at position 8: P^+ := \̲s̲p̲a̲n̲_{\ZZ_{>0}} \{\…. We demonstrate one last model, rigged configurations, which was given by Salisbury and S. generalizing the work of Schilling. Elements are given by partitions with integers (called riggings) attached to each row, one for each node of the Dynkin diagram. The crystal operators fif_i (resp. eie_i) adds (resp. removes) a box from the partition ν(i)\nu^{(i)}.
D = DynkinDiagram() for i in range(4): for j in range(i+1,4): D.add_edge(i,j) La = RootSystem(D.cartan_matrix()).weight_lattice().fundamental_weights() RC = crystals.RiggedConfigurations(La[0]) S = RC.subcrystal(max_depth=2) G = S.digraph() G.set_latex_options(edge_options=None) latex.eval(latex(G))
''

Open problem: Find an (explicit) combinatorial bijection between LS/Littelmann paths, Nakajima monomials, and rigged configurations.

One particular aspect is that B(λ)B(\lambda), for any fixed λP+\lambda \in P^+, is unique, and there is a unique crystal isomorphism by mapping the highest weight element to the highest weight element.

La = RootSystem(['C',2]).weight_lattice().fundamental_weights() M = crystals.NakajimaMonomials(['C',2], La[1]+La[2]) RC = crystals.RiggedConfigurations(La[1]+La[2]) phi = M.crystal_morphism({M.highest_weight_vector(): RC.highest_weight_vector()}) for m in M: A = ascii_art(phi(m)) A._baseline = 0 A = ascii_art(m) + ascii_art(' |--> ') + A print(A) print("")
Y(1,0) Y(2,0) |--> (/) (/) Y(1,1)^-1 Y(2,0)^2 |--> -1[ ]-1 (/) Y(1,1) Y(2,0) Y(2,1)^-1 |--> 0[ ]0 0[ ]-1 Y(1,2)^-1 Y(2,0) |--> -1[ ][ ]-1 1[ ]0 Y(1,1)^3 Y(2,1)^-2 |--> 0[ ]0 -2[ ][ ]-2 Y(1,1)^2 Y(1,2)^-1 Y(2,1)^-1 |--> -1[ ][ ]-1 -1[ ][ ]-1 Y(1,1) Y(1,2)^-2 |--> -2[ ][ ][ ]-2 0[ ][ ]0 Y(1,2)^-3 Y(2,1) |--> -3[ ][ ][ ][ ]-3 1[ ][ ]1 Y(1,0) Y(1,1)^2 Y(2,1)^-1 |--> (/) -1[ ]-1 Y(1,0) Y(1,1) Y(1,2)^-1 |--> 0[ ]-1 0[ ]0 Y(1,0) Y(1,2)^-2 Y(2,1) |--> -1[ ][ ]-2 1[ ]1 Y(1,1)^-1 Y(1,2)^-2 Y(2,0) Y(2,1) |--> -3[ ][ ][ ]-3 1[ ]1 1[ ][ ]0 -1[ ]-1 Y(1,0) Y(2,2)^-1 |--> -1[ ]-1 -1[ ][ ][ ]-1 -1[ ]-1 Y(1,1)^-1 Y(2,0) Y(2,2)^-1 |--> -1[ ]-1 0[ ][ ][ ]0 -2[ ][ ]-2 Y(1,1) Y(2,1)^-1 Y(2,2)^-1 |--> -1[ ]-1 -1[ ][ ][ ][ ]-1 -1[ ][ ]-1 Y(1,2)^-1 Y(2,2)^-1 |--> -1[ ]-1
One particularly nice property of rigged configurations is that they all "nest" inside each other, i.e., B(λ)B(μ)B(\lambda) \subseteq B(\mu) if λμ\lambda \leq \mu. This allows us to construct the direct limit B()B(\infty), which is the crystal for the lower half of the quantum group (or equivalently, the universal enveloping algebra).
La = RootSystem(['C',2]).weight_lattice().fundamental_weights() RC1 = crystals.RiggedConfigurations(['C',2], La[1]) RC2 = crystals.RiggedConfigurations(['C',2], La[2]) latex.eval(latex(RC1 + RC2))
''
RC = crystals.RiggedConfigurations(['C',2], La[1]+La[2]) latex.eval(latex(RC))
''
RC = crystals.infinity.RiggedConfigurations(['C',2]) S = RC.subcrystal(max_depth=2) latex.eval(latex(S))
''

There are also models for B()B(\infty) using (modified) Nakajima monomials, LS paths, and the polyhedral realization. There are also a number of more specialized models: (marginally large) tableaux (classical types), or those only for (affine) type AA.

More generally, we can recover B(λ)B(\lambda) by tensoring with a specific one element crystal, denoted by RλR_{\lambda}. Note: the order of the tensor factors is important.

La = RootSystem(['E',6]).weight_lattice().fundamental_weights() B = crystals.infinity.NakajimaMonomials(['E',6]) R = crystals.elementary.R(['E',6], La[1]) T = tensor([R, B]) C = crystals.RiggedConfigurations(['E',6], La[1]) hw = T(R.module_generators[0], B.highest_weight_vector()) G = hw.subcrystal().digraph() G.is_isomorphic(C.digraph(), edge_labels=True)
True

There is also one other special class of crystals for affine types called Kirillov-Reshetikhin (KR) crystals, which are finite crystals denoted by Br,sB^{r,s} with rIr \in I and sZ>0s \in \ZZ_{>0}. While there exists general (and uniform) theories for highest weight crystals, there is very little general and/or uniform understanding of KR crystals. The only known uniform constructions are for i=1NBri,1\bigotimes_{i=1}^N B^{r_i, 1}. Depsite this, KR crystals are known to have many wonderful properties, such as tensor products of KR crystals are connected. Moreover, (tensor products of) KR crystals are strongly related to multiple aspects of mathematical physics, such as box-ball systems (or soliton cellular automata), spin chains, and 2d solvable lattice models.

Open problem: Construct a uniform model for Br,sB^{r,s}.

K = crystals.KirillovReshetikhin(['A',2,1], 2,2) latex.eval(latex(K))
''
K2 = crystals.KirillovReshetikhin(['A',2,1], 2,1) latex.eval(latex(K2))
''
T = tensor([K2, K2]) latex.eval(latex(T))
''
K1 = crystals.KirillovReshetikhin(['A',2,1], 1,1) T = tensor([K1,K1]) latex.eval(latex(T))
''
K = crystals.KirillovReshetikhin(['A',2,1], 1,2) latex.eval(latex(K))
''

There are two important properties that characters of tensor products of KR crystals have. The first is that their characters (resp. qq-characters) solve Q-systems (resp. T-systems). Morever, there is that there is a statistic called energy, such that the graded character is a specalization of Macdonald polynomials and allows one to compute Kostka polynomials. We utilize here an equivalence with a slightly different version of rigged configurations than what is used by highest weight crystals.

Open problem: Show such a bijection exists in all (affine) types. Bonus points for stating and/or proving it uniformly.

RC = RiggedConfigurations(['A',7,1], [[3,1],[1,1],[1,1]]) RC.fermionic_formula(only_highest_weight=True)
(q^2+q)*B[Lambda[1] + Lambda[4]] + B[2*Lambda[1] + Lambda[3]] + q*B[Lambda[2] + Lambda[3]] + q^3*B[Lambda[5]]
t = FractionField(ZZ['t']).gen() Sym = SymmetricFunctions(t.parent()) s = Sym.s() h = Sym.h() P = Sym.hall_littlewood(t).P()
P(s[4,1])
(t^9+t^8+t^7+t^6)*HLP[1, 1, 1, 1, 1] + (t^5+t^4+t^3)*HLP[2, 1, 1, 1] + (t^3+t^2)*HLP[2, 2, 1] + (t^2+t)*HLP[3, 1, 1] + t*HLP[3, 2] + HLP[4, 1]
P(s[3,1,1])
(t^7+t^6+2*t^5+t^4+t^3)*HLP[1, 1, 1, 1, 1] + (t^3+t^2+t)*HLP[2, 1, 1, 1] + t*HLP[2, 2, 1] + HLP[3, 1, 1]
P(s[3,2])
(t^8+t^7+t^6+t^5+t^4)*HLP[1, 1, 1, 1, 1] + (t^4+t^3+t^2)*HLP[2, 1, 1, 1] + (t^2+t)*HLP[2, 2, 1] + t*HLP[3, 1, 1] + HLP[3, 2]
P(s[5])
t^10*HLP[1, 1, 1, 1, 1] + t^6*HLP[2, 1, 1, 1] + t^4*HLP[2, 2, 1] + t^3*HLP[3, 1, 1] + t^2*HLP[3, 2] + t*HLP[4, 1] + HLP[5]
HL = Sym.hall_littlewood(t)
Qp = HL.Qp()
s(Qp[3,1,1])
s[3, 1, 1] + t*s[3, 2] + (t^2+t)*s[4, 1] + t^3*s[5]