Crystals

Let T be a CartanType with index set I, and W be a realization of the type T weight lattice.

A type T crystal C is a colored oriented graph equipped with a weight function from the nodes to some realization of the type T weight lattice such that:

  • Each edge is colored with a label in i \in I.

  • For each i\in I, each node x has:

    • at most one i-successor f_i(x);
    • at most one i-predecessor e_i(x).

    Furthermore, when they exist,

    • f_i(x).weight() = x.weight() - \alpha_i;
    • e_i(x).weight() = x.weight() + \alpha_i.

This crystal actually models a representation of a Lie algebra if it satisfies some further local conditions due to Stembridge, see J. Stembridge, A local characterization of simply-laced crystals, Trans. Amer. Math. Soc. 355 (2003), no. 12, 4807-4823.

EXAMPLES:

We construct the type A_5 crystal on letters (or in representation theoretic terms, the highest weight crystal of type A_5 corresponding to the highest weight \Lambda_1)

sage: C = CrystalOfLetters(['A',5]); C
The crystal of letters for type ['A', 5]

It has a single highest weight element:

sage: C.highest_weight_vectors()
[1]

A crystal is an enumerated set (see EnumeratedSets); and we can count and list its elements in the usual way:

sage: C.cardinality()
6
sage: C.list()
[1, 2, 3, 4, 5, 6]

as well as use it in for loops:

sage: [x for x in C]
[1, 2, 3, 4, 5, 6]

Here are some more elaborate crystals (see their respective documentations):

sage: Tens = TensorProductOfCrystals(C, C)
sage: Spin = CrystalOfSpins(['B', 3])
sage: Tab  = CrystalOfTableaux(['A', 3], shape = [2,1,1])
sage: Fast = FastCrystal(['B', 2], shape = [3/2, 1/2])
sage: KR = KirillovReshetikhinCrystal(['A',2,1],1,1)

One can get (currently) crude plotting via:

sage: Tab.plot()

For rank two crystals, there is an alternative method of getting metapost pictures. For more information see C.metapost?

Caveat: this crystal library, although relatively featureful for classical crystals, is still in an early development stage, and the syntax details may be subject to changes.

TODO:

  • Vocabulary and conventions:
    • elements or vectors of a crystal?
    • For a classical crystal: connected / highest weight / irreducible
    • ...
  • More introductory doc explaining the mathematical background
  • Layout instructions for plot() for rank 2 types
  • Streamlining the latex output
  • Littelmann paths and/or alcove paths (this would give us the exceptional types)
  • RestrictionOfCrystal / DirectSumOfCrystals

Most of the above features (except Littelmann/alcove paths) are in MuPAD-Combinat (see lib/COMBINAT/crystals.mu), which could provide inspiration.

class sage.combinat.crystals.crystals.ClassicalCrystal

Bases: sage.combinat.crystals.crystals.Crystal

The abstract class of classical crystals

cardinality()

Returns the number of elements of the crystal, using Weyl’s dimension formula on each connected component

EXAMPLES:

sage: from sage.combinat.crystals.crystals import ClassicalCrystal
sage: C = CrystalOfLetters(['A', 5])
sage: ClassicalCrystal.cardinality(C)
6
highest_weight_vector()

Returns the highest weight vector if there is a single one; otherwise, raises an error.

EXAMPLES:

sage: C = CrystalOfLetters(['A',5])
sage: C.highest_weight_vector()
1
highest_weight_vectors()

Returns a list of the highest weight vectors of self.

EXAMPLES:

sage: C = CrystalOfLetters(['A',5])
sage: C.highest_weight_vectors()
[1]
sage: C = CrystalOfLetters(['A',2])
sage: T = TensorProductOfCrystals(C,C,C,generators=[[C(2),C(1),C(1)],[C(1),C(2),C(1)]])
sage: T.highest_weight_vectors()
[[2, 1, 1], [1, 2, 1]]
list()

Returns the list of the elements of self, as per FiniteEnumeratedSets.ParentMethods.list()

EXAMPLES:

sage: C = CrystalOfLetters(['D',4])
sage: C.list()
[1, 2, 3, 4, -4, -3, -2, -1]

FIXME: this is just there to reinstate the default implementation of list which is overriden in Crystals.

class sage.combinat.crystals.crystals.Crystal

Bases: sage.structure.unique_representation.UniqueRepresentation, sage.structure.parent.Parent

The abstract class of crystals

Derived subclasses should implement the following:

  • either a method cartan_type or an attribute _cartan_type
  • module_generators: a list (or container) of distinct elements which generate the crystal using f_i
Lambda()

Returns the fundamentals weights in the weight lattice realization for the root system associated to self.

EXAMPLES:

sage: C = CrystalOfLetters(['A', 5])
sage: C.Lambda()
Finite family {1: (1, 0, 0, 0, 0, 0), 2: (1, 1, 0, 0, 0, 0), 3: (1, 1, 1, 0, 0, 0), 4: (1, 1, 1, 1, 0, 0), 5: (1, 1, 1, 1, 1, 0)}
cartan_type()

Returns the Cartan type of the associated crystal

EXAMPLES::
sage: C = CrystalOfLetters([‘A’,2]) sage: C.cartan_type() [‘A’, 2]
character(R)

INPUT: R, a WeylCharacterRing. Produces the character of the crystal.

EXAMPLES:

sage: C = CrystalOfLetters(['A',2])
sage: T = TensorProductOfCrystals(C, C)
sage: A2 = WeylCharacterRing(C.cartan_type()); A2
The Weyl Character Ring of Type ['A', 2] with Integer Ring coefficients
sage: chi = T.character(A2); chi
A2(1,1,0) + A2(2,0,0)
sage: chi.check(verbose = true)
[9, 9]
check()

Runs sanity checks on the crystal:

  • Checks that count, list, and __iter__ are consistent. For a ClassicalCrystal, this in particular checks that the number of elements returned by the brute force listing and the iterator __iter__ are consistent with the Weyl dimension formula.
  • Should check Stembridge’s rules, etc.

EXAMPLES:

sage: C = CrystalOfLetters(['A', 5])
sage: C.check()
True
crystal_morphism(g, index_set=None, automorphism=<function <lambda> at 0x3eda0c8>, direction='down', direction_image='down', similarity_factor=None, similarity_factor_domain=None, cached=False, acyclic=True)

Constructs a morphism from the crystal self to another crystal. The input g can either be a function of a (sub)set of elements of self to element in another crystal or a dictionary between certain elements. Usually one would map highest weight elements or crystal generators to each other using g. Specifying index_set gives the opportunity to define the morphism as I-crystals where I = index_set. If index_set is not specified, the index set of self is used. It is also possible to define twisted-morphisms by specifying an automorphism on the nodes in te Dynkin diagram (or the index_set). The option direction and direction_image indicate whether to use f_i or e_i in self or the image crystal to construct the morphism, depending on whether the direction is set to ‘down’ or ‘up’. It is also possible to set a similarity_factor. This should be a dictionary between the elements in the index set and positive integers. The crystal operator f_i then gets mapped to f_i^{m_i} where m_i = similarity_factor[i]. Setting similarity_factor_domain to a dictionary between the index set and positive integers has the effect that f_i^{m_i} gets mapped to f_i where m_i = similarity_factor_domain[i]. Finally, it is possible to set the option acyclic = False. This calculates an isomorphism for cyclic crystals (for example finite affine crystals). In this case the input function g is supposed to be given as a dictionary.

EXAMPLES:

sage: C2 = CrystalOfLetters(['A',2])
sage: C3 = CrystalOfLetters(['A',3])
sage: g = {C2.module_generators[0] : C3.module_generators[0]}
sage: g_full = C2.crystal_morphism(g)
sage: g_full(C2(1))
1
sage: g_full(C2(2))
2
sage: g = {C2(1) : C2(3)}
sage: g_full = C2.crystal_morphism(g, automorphism = lambda i : 3-i, direction_image = 'up')
sage: [g_full(b) for b in C2]
[3, 2, 1]
sage: T = CrystalOfTableaux(['A',2], shape = [2])
sage: g = {C2(1) : T(rows=[[1,1]])}
sage: g_full = C2.crystal_morphism(g, similarity_factor = {1:2, 2:2})
sage: [g_full(b) for b in C2]
[[[1, 1]], [[2, 2]], [[3, 3]]]
sage: g = {T(rows=[[1,1]]) : C2(1)}
sage: g_full = T.crystal_morphism(g, similarity_factor_domain = {1:2, 2:2})
sage: g_full(T(rows=[[2,2]]))
2

sage: B1=KirillovReshetikhinCrystal(['A',2,1],1,1)
sage: B2=KirillovReshetikhinCrystal(['A',2,1],1,2)
sage: T=TensorProductOfCrystals(B1,B2)
sage: T1=TensorProductOfCrystals(B2,B1)
sage: La = T.weight_lattice_realization().fundamental_weights()
sage: t = [b for b in T if b.weight() == -3*La[0] + 3*La[1]][0]
sage: t1 = [b for b in T1 if b.weight() == -3*La[0] + 3*La[1]][0]
sage: g={t:t1}
sage: f=T.crystal_morphism(g,acyclic = False)
sage: [[b,f(b)] for b in T]
[[[[[1]], [[1, 1]]], [[[1, 1]], [[1]]]],
[[[[1]], [[1, 2]]], [[[1, 1]], [[2]]]],
[[[[1]], [[2, 2]]], [[[1, 2]], [[2]]]],
[[[[1]], [[1, 3]]], [[[1, 1]], [[3]]]],
[[[[1]], [[2, 3]]], [[[1, 2]], [[3]]]],
[[[[1]], [[3, 3]]], [[[1, 3]], [[3]]]],
[[[[2]], [[1, 1]]], [[[1, 2]], [[1]]]],
[[[[2]], [[1, 2]]], [[[2, 2]], [[1]]]],
[[[[2]], [[2, 2]]], [[[2, 2]], [[2]]]],
[[[[2]], [[1, 3]]], [[[2, 3]], [[1]]]],
[[[[2]], [[2, 3]]], [[[2, 2]], [[3]]]],
[[[[2]], [[3, 3]]], [[[2, 3]], [[3]]]],
[[[[3]], [[1, 1]]], [[[1, 3]], [[1]]]],
[[[[3]], [[1, 2]]], [[[1, 3]], [[2]]]],
[[[[3]], [[2, 2]]], [[[2, 3]], [[2]]]],
[[[[3]], [[1, 3]]], [[[3, 3]], [[1]]]],
[[[[3]], [[2, 3]]], [[[3, 3]], [[2]]]],
[[[[3]], [[3, 3]]], [[[3, 3]], [[3]]]]]
demazure_character(weight, reduced_word=False)

Calculates the Demazure character associated to the specified weight in the ambient weight lattice.

INPUT:
  • weight in the weight lattice realization of the crystal (default input)
  • when the option reduced_word is set to True, a reduced word can be inputted

This is currently only supported for crystals whose underlying weight space is the ambient space.

References:

M. Demazure, “Desingularisation des varietes de Schubert”, Ann. E. N. S., Vol. 6, (1974), p. 163-172

Sarah Mason, “An Explicit Construction of Type A Demazure Atoms”, Journal of Algebraic Combinatorics, Vol. 29, (2009), No. 3, p.295-313 (arXiv:0707.4267)

EXAMPLES:

sage: T = CrystalOfTableaux(['A',2], shape = [2,1])
sage: e = T.weight_lattice_realization().basis()
sage: weight = e[0] + 2*e[2]
sage: weight.reduced_word()
[2, 1]
sage: T.demazure_character(weight)
x1^2*x2 + x1^2*x3 + x1*x2^2 + x1*x2*x3 + x1*x3^2

sage: T = CrystalOfTableaux(['A',3],shape=[2,1])
sage: T.demazure_character([1,2,3], reduced_word = True)
x1^2*x2 + x1^2*x3 + x1*x2^2 + x1*x2*x3 + x2^2*x3

sage: T = CrystalOfTableaux(['B',2], shape = [2])
sage: e = T.weight_lattice_realization().basis()
sage: weight = -2*e[1]
sage: T.demazure_character(weight)
x1^2 + x1*x2 + x2^2 + x1 + x2 + x1/x2 + 1/x2 + 1/x2^2 + 1
digraph()

Returns the DiGraph associated to self.

EXAMPLES:

sage: from sage.combinat.crystals.crystals import Crystal
sage: C = CrystalOfLetters(['A', 5])
sage: Crystal.digraph(C)
Digraph on 6 vertices
dot_tex()

Returns a dot_tex version of self.

EXAMPLES:

sage: C = CrystalOfLetters(['A',2])
sage: C.dot_tex()
'digraph G { \n  node [ shape=plaintext ];\n  N_0 [ label = " ", texlbl = "$1$" ];\n  N_1 [ label = " ", texlbl = "$2$" ];\n  N_2 [ label = " ", texlbl = "$3$" ];\n  N_0 -> N_1 [ label = " ", texlbl = "1" ];\n  N_1 -> N_2 [ label = " ", texlbl = "2" ];\n}'
index_set()

Returns the index set of the Dynkin diagram underlying the given crystal

EXAMPLES:
sage: C = CrystalOfLetters([‘A’, 5]) sage: C.index_set() [1, 2, 3, 4, 5]
latex()

Returns the crystal graph as a bit of latex. This can be exported to a file with self.latex_file(‘filename’).

This requires the dot2tex spkg. Here some tips for installation:

  • Install graphviz = 2.14
  • Download dot2tex-0.?.spkg from http://wiki.sagemath.org/combinat/FPSAC09/projects
  • Install pgf-2.00 inside your latex tree. In short:
    • untaring in /usr/share/texmf/tex/generic
    • clean out remaining pgf files from older version
    • run texhash

In case LaTeX complains about tikzpicture not being defined, you may need to further run:

sage: sage.misc.latex.LATEX_HEADER+=r"\\usepackage{tikz}"

EXAMPLES:

sage: C = CrystalOfLetters(['A', 5])
sage: C.latex()         #optional requires dot2tex
...
sage: view(C, pdflatex = True, tightpage = True) # optional
latex_file(filename)

Exports a file, suitable for pdflatex, to ‘filename’. This requires a proper installation of dot2tex in sage-python. For more information see the documentation for self.latex().

EXAMPLES:

sage: C = CrystalOfLetters(['A', 5])
sage: C.latex_file('/tmp/test.tex') #optional requires dot2tex
list()

Returns a list of the elements of self obtained by continually apply the f_i operators to the module generators of self.

EXAMPLES:

sage: from sage.combinat.crystals.crystals import Crystal
sage: C = CrystalOfLetters(['A', 5])
sage: l = Crystal.list(C)
sage: l.sort(); l
[1, 2, 3, 4, 5, 6]
metapost(filename, thicklines=False, labels=True, scaling_factor=1.0, tallness=1.0)

Use C.metapost(“filename.mp”,[options]) where options can be:

thicklines = True (for thicker edges) labels = False (to suppress labeling of the vertices) scaling_factor=value, where value is a floating point number, 1.0 by default. Increasing or decreasing the scaling factor changes the size of the image. tallness=1.0. Increasing makes the image taller without increasing the width.

Root operators e(1) or f(1) move along red lines, e(2) or f(2) along green. The highest weight is in the lower left. Vertices with the same weight are kept close together. The concise labels on the nodes are strings introduced by Berenstein and Zelevinsky and Littelmann; see Littelmann’s paper Cones, Crystals, Patterns, sections 5 and 6.

For Cartan types B2 or C2, the pattern has the form

a2 a3 a4 a1

where c*a2 = a3 = 2*a4 =0 and a1=0, with c=2 for B2, c=1 for C2. Applying e(2) a1 times, e(1) a2 times, e(2) a3 times, e(1) a4 times returns to the highest weight. (Observe that Littelmann writes the roots in opposite of the usual order, so our e(1) is his e(2) for these Cartan types.) For type A2, the pattern has the form

a3 a2 a1

where applying e(1) a1 times, e(2) a2 times then e(3) a1 times returns to the highest weight. These data determine the vertex and may be translated into a Gelfand-Tsetlin pattern or tableau.

EXAMPLES:

sage: C = CrystalOfLetters(['A', 2])
sage: C.metapost('/tmp/test.mp') #optional
sage: C = CrystalOfLetters(['A', 5])
sage: C.metapost('/tmp/test.mp')
Traceback (most recent call last):
...
NotImplementedError
plot(**options)

Returns the plot of self as a directed graph.

EXAMPLES:

sage: C = CrystalOfLetters(['A', 5])
sage: show_default(False) #do not show the plot by default
sage: C.plot()
Graphics object consisting of 17 graphics primitives
weight_lattice_realization()

Returns the weight lattice realization for the root system associated to self. This default implementation uses the ambient space of the root system.

EXAMPLES:

sage: C = CrystalOfLetters(['A', 5])
sage: C.weight_lattice_realization()
Ambient space of the Root system of type ['A', 5]
sage: K = KirillovReshetikhinCrystal(['A',2,1], 1, 1)
sage: K.weight_lattice_realization()
Weight lattice of the Root system of type ['A', 2, 1]
class sage.combinat.crystals.crystals.CrystalBacktracker(crystal)
Bases: sage.combinat.backtrack.GenericBacktracker
class sage.combinat.crystals.crystals.CrystalElement

Bases: sage.structure.element.Element

The abstract class of crystal elements

Sub classes should implement at least:

  • x.e(i) (returning e_i(x))
  • x.f(i) (returning f_i(x))
  • x.weight()
Epsilon()

EXAMPLES:

sage: C = CrystalOfLetters(['A',5])
sage: C(0).Epsilon()
(0, 0, 0, 0, 0, 0)
sage: C(1).Epsilon()
(0, 0, 0, 0, 0, 0)
sage: C(2).Epsilon()
(1, 0, 0, 0, 0, 0)
Phi()

EXAMPLES:

sage: C = CrystalOfLetters(['A',5])
sage: C(0).Phi()
(0, 0, 0, 0, 0, 0)
sage: C(1).Phi()
(1, 0, 0, 0, 0, 0)
sage: C(2).Phi()
(1, 1, 0, 0, 0, 0)
cartan_type()

Returns the cartan type associated to self

EXAMPLES::
sage: C = CrystalOfLetters([‘A’, 5]) sage: C(1).cartan_type() [‘A’, 5]
demazure_operator(i, truncated=False)

Yields all elements one can obtain from self by application of f_i. If the option “truncated” is set to True, then self is not included in the list.

References:

Peter Littelmann, “Crystal graphs and Young tableaux”, J. Algebra 175 (1995), no. 1, 65–87.

Masaki Kashiwara, “The crystal base and Littelmann’s refined Demazure character formula”, Duke Math. J. 71 (1993), no. 3, 839–858.

EXAMPLES:

sage: T = CrystalOfTableaux(['A',2], shape=[2,1])
sage: t=T(rows=[[1,2],[2]])
sage: t.demazure_operator(2)
[[[1, 2], [2]], [[1, 3], [2]], [[1, 3], [3]]]
sage: t.demazure_operator(2, truncated = True)
[[[1, 3], [2]], [[1, 3], [3]]]
sage: t.demazure_operator(1, truncated = True)
[]
sage: t.demazure_operator(1)
[[[1, 2], [2]]]

sage: K = KirillovReshetikhinCrystal(['A',2,1],2,1)
sage: t = K(rows=[[3],[2]])
sage: t.demazure_operator(0)
[[[2, 3]], [[1, 2]]]
e(i)

Returns e_i(x) if it exists or None otherwise. This is to be implemented by subclasses of CrystalElement.

TESTS:

sage: from sage.combinat.crystals.crystals import CrystalElement
sage: C = CrystalOfLetters(['A',5])
sage: CrystalElement.e(C(1), 1)
Traceback (most recent call last):
...
NotImplementedError
e_string(list)

Applies e_{i_r} ... e_{i_1} to self for list = [i_1, ..., i_r]

EXAMPLES:

sage: C = CrystalOfLetters(['A',3])
sage: b = C(3)
sage: b.e_string([2,1])
1
sage: b.e_string([1,2])
epsilon(i)

EXAMPLES:

sage: C = CrystalOfLetters(['A',5])
sage: C(1).epsilon(1)
0
sage: C(2).epsilon(1)
1
f(i)

Returns f_i(x) if it exists or None otherwise. This is to be implemented by subclasses of CrystalElement.

TESTS:

sage: from sage.combinat.crystals.crystals import CrystalElement
sage: C = CrystalOfLetters(['A',5])
sage: CrystalElement.f(C(1), 1)
Traceback (most recent call last):
...
NotImplementedError
f_string(list)

Applies f_{i_r} ... f_{i_1} to self for list = [i_1, ..., i_r]

EXAMPLES:

sage: C = CrystalOfLetters(['A',3])
sage: b = C(1)
sage: b.f_string([1,2])
3
sage: b.f_string([2,1])
index_set()

EXAMPLES:

sage: C = CrystalOfLetters(['A',5])
sage: C(1).index_set()
[1, 2, 3, 4, 5]
is_highest_weight(index_set=None)

Returns True if self is a highest weight. Specifying the option index_set to be a subset I of the index set of the underlying crystal, finds all highest weight vectors for arrows in I.

EXAMPLES:

sage: C = CrystalOfLetters(['A',5])
sage: C(1).is_highest_weight()
True
sage: C(2).is_highest_weight()
False
sage: C(2).is_highest_weight(index_set = [2,3,4,5])
True
phi(i)

EXAMPLES:

sage: C = CrystalOfLetters(['A',5])
sage: C(1).phi(1)
1
sage: C(2).phi(1)
0
phi_minus_epsilon(i)

Returns \phi_i - \epsilon_i of self. There are sometimes better implementations using the weight for this. It is used for reflections along a string.

EXAMPLES:

sage: C = CrystalOfLetters(['A',5])
sage: C(1).phi_minus_epsilon(1)
1
s(i)

Returns the reflection of self along its i-string

EXAMPLES:

sage: C = CrystalOfTableaux(['A',2], shape=[2,1])
sage: b=C(rows=[[1,1],[3]])
sage: b.s(1)
[[2, 2], [3]]
sage: b=C(rows=[[1,2],[3]])
sage: b.s(2)
[[1, 2], [3]]
sage: T=CrystalOfTableaux(['A',2],shape=[4])
sage: t=T(rows=[[1,2,2,2]])
sage: t.s(1)
[[1, 1, 1, 2]]
to_highest_weight(list=[], index_set=None)

Yields the highest weight element u and list [i_1,...,i_k] such that self = f_{i_1} ... f_{i_k} u, where i_1,...,i_k are elements in index_set. By default the index set is assumed to be the full index set of self.

EXAMPLES:

sage: T = CrystalOfTableaux(['A',3], shape = [1])
sage: t = T(rows = [[3]])
sage: t.to_highest_weight()
[[[1]], [2, 1]]
sage: t.to_highest_weight()
[[[1]], [2, 1]]
sage: T = CrystalOfTableaux(['A',3], shape = [2,1])
sage: t = T(rows = [[1,2],[4]])
sage: t.to_highest_weight()
[[[1, 1], [2]], [1, 3, 2]]
sage: t.to_highest_weight(index_set = [3])
[[[1, 2], [3]], [3]]
weight()

EXAMPLES:

sage: C = CrystalOfLetters(['A',5])
sage: C(1).weight()
(1, 0, 0, 0, 0, 0)

Previous topic

Crystals

Next topic

Crystals of letters

This Page