def __classcall_private__(cls, cartan_type, P=None): r""" Normalize input to ensure a unique representation. EXAMPLES:: sage: C = crystals.elementary.Component("A2") sage: D = crystals.elementary.Component(CartanType(['A',2])) sage: C is D True sage: AS = RootSystem(['A',2]).ambient_space() sage: E = crystals.elementary.Component(AS) sage: F = crystals.elementary.Component(CartanType(['A',2]), AS) sage: C is E and C is F True """ if cartan_type in RootLatticeRealizations: P = cartan_type cartan_type = P.cartan_type() elif P is None: cartan_type = CartanType(cartan_type) P = cartan_type.root_system().ambient_space() if P is None: P = cartan_type.root_system().weight_lattice() return super(ComponentCrystal, cls).__classcall__(cls, cartan_type, P)
def _element_constructor_(self, cartan_type, **kwds): """ The element constructor. This method is called internally when we try to convert something into an element. In this case, the only thing that can be converted into an associahedron is the Cartan type. EXAMPLES:: sage: from sage.combinat.root_system.associahedron import Associahedra sage: parent = Associahedra(QQ,2) sage: parent(['A',2]) Generalized associahedron of type ['A', 2] with 5 vertices sage: parent._element_constructor_(['A',2]) Generalized associahedron of type ['A', 2] with 5 vertices """ cartan_type = CartanType(cartan_type) assert cartan_type.is_finite() root_space = cartan_type.root_system().root_space() # TODO: generalize this as a method of root lattice realization rhocheck = sum(beta.associated_coroot() for beta in root_space.positive_roots()) / 2 I = root_space.index_set() inequalities = [] for orbit in root_space.almost_positive_roots_decomposition(): c = rhocheck.coefficient(orbit[0].leading_support()) for beta in orbit: inequalities.append([c] + [beta.coefficient(i) for i in I]) associahedron = super(Associahedra, self)._element_constructor_( None, [inequalities, []]) associahedron._cartan_type = cartan_type return associahedron
def __classcall_private__(cls, cartan_type, wt=None): r""" Normalize the input arguments to ensure unique representation. EXAMPLES:: sage: La = RootSystem(['A', 2]).weight_lattice().fundamental_weights() sage: RC = crystals.RiggedConfigurations(La[1]) sage: RC2 = crystals.RiggedConfigurations(['A', 2], La[1]) sage: RC is RC2 True """ if wt is None: wt = cartan_type cartan_type = wt.parent().cartan_type() else: cartan_type = CartanType(cartan_type) wt_lattice = cartan_type.root_system().weight_lattice() wt = wt_lattice(wt) if not cartan_type.is_simply_laced(): vct = cartan_type.as_folding() return CrystalOfNonSimplyLacedRC(vct, wt) return super(CrystalOfRiggedConfigurations, cls).__classcall__(cls, wt)
def _element_constructor_(self, cartan_type, **kwds): """ The element constructor. This method is called internally when we try to convert something into an element. In this case, the only thing that can be converted into an associahedron is the Cartan type. EXAMPLES:: sage: from sage.combinat.root_system.associahedron import Associahedra sage: parent = Associahedra(QQ,2) sage: parent(['A',2]) Generalized associahedron of type ['A', 2] with 5 vertices sage: parent._element_constructor_(['A',2]) Generalized associahedron of type ['A', 2] with 5 vertices """ cartan_type = CartanType(cartan_type) if not cartan_type.is_finite(): raise ValueError("the Cartan type must be finite") root_space = cartan_type.root_system().root_space() # TODO: generalize this as a method of root lattice realization rhocheck = sum(beta.associated_coroot() for beta in root_space.positive_roots()) / 2 I = root_space.index_set() inequalities = [] for orbit in root_space.almost_positive_roots_decomposition(): c = rhocheck.coefficient(orbit[0].leading_support()) for beta in orbit: inequalities.append([c] + [beta.coefficient(i) for i in I]) associahedron = super(Associahedra, self)._element_constructor_(None, [inequalities, []]) associahedron._cartan_type = cartan_type return associahedron
def __classcall_private__(cls, cartan_type, P=None): r""" Normalize input to ensure a unique representation. EXAMPLES:: sage: C = crystals.elementary.Component("A2") sage: D = crystals.elementary.Component(CartanType(['A',2])) sage: C is D True sage: AS = RootSystem(['A',2]).ambient_space() sage: E = crystals.elementary.Component(AS) sage: F = crystals.elementary.Component(CartanType(['A',2]), AS) sage: C is E and C is F True """ if cartan_type in RootLatticeRealizations: P = cartan_type elif P is None: cartan_type = CartanType(cartan_type) P = cartan_type.root_system().ambient_space() if P is None: P = cartan_type.root_system().weight_lattice() return super(ComponentCrystal, cls).__classcall__(cls, P)
class InfinityCrystalOfMultisegments(Parent, UniqueRepresentation): r""" The type `A_n^{(1)}` crystal `B(\infty)` realized using Bernstein-Zelevinsky (BZ) multisegments. Using (a modified version of the) notation from [JL2009]_, for `\ell \in \ZZ_{>0}` and `i \in \ZZ / (n+1)\ZZ`, a segment of length `\ell` and head `i` is the sequence of consecutive residues `[i,i+1,\dots,i+\ell-1]`. The notation for a segment of length `\ell` and head `i` is simplified to `[i; \ell)`. Similarly, a segment of length `\ell` and tail `i` is the sequence of consecutive residues `[i-\ell+1, \ldots, i-1, i]`. The latter is denoted simply by `(\ell;i]`. Finally, a multisegment is a formal linear combination of segments, usually written in the form .. MATH:: \psi = \sum_{\substack{i \in \ZZ/(n+1)\ZZ \\ \ell \in \ZZ_{>0}}} m_{(\ell;i]} (\ell; i]. Such a multisegment is called aperiodic if, for every `\ell > 0`, there exists some `i \in \ZZ / (n+1)\ZZ` such that `(\ell; i]` does not appear in `\psi`. Denote the set of all periodic multisegments, together with the empty multisegment `\varnothing`, by `\Psi`. We define a crystal structure on multisegments as follows. Set `S_{\ell,i} = \sum_{k \ge \ell} (m_{(k;i-1]} - m_{(k;i]})` and let `\ell_f` be the minimal `\ell` that attains the value `\min_{\ell > 0} S_{\ell,i}`. Then we have .. MATH:: f_i \psi = \begin{cases} \psi + (1;i] & \text{ if } \ell_f = 1,\\ \psi + (\ell_f;i] - (\ell_f-1;i-1] & \text{ if } \ell_f > 1. \end{cases} Similarly, let `\ell_e` be the maximal `\ell` that attains the value `\min_{\ell > 0} S_{\ell,i}`. Then we have .. MATH:: e_i \psi = \begin{cases} 0 & \text{ if } \min_{\ell > 0} S_{\ell,i} = 0, \\ \psi + (1; i] & \text{ if } \ell_e = 1,\\ \psi - (\ell_e; i] + (\ell_e-1; i-1] & \text{ if } \ell_e > 1. \end{cases} Alternatively, the crystal operators may be defined using a signature rule, as detailed in Section 4 of [JL2009]_ (following [AJL2011]_). For `\psi \in \Psi` and `i \in \ZZ/(n+1)\ZZ`, encode all segments in `\psi` with tail `i` by the symbol `R` and all segments in `\psi` with tail `i-1` by `A`. For `\ell > 0`, set `w_{i,\ell} = R^{m_{(\ell;i]}} A^{m_{(\ell;i-1]}}` and `w_i = \prod_{\ell\ge 1} w_{i,\ell}`. By successively canceling out as many `RA` factors as possible, set `\widetilde{w}_i = A^{a_i(\psi)} R^{r_i(\psi)}`. If `a_i(\psi) > 0`, denote by `\ell_f > 0` the length of the rightmost segment `A` in `\widetilde{w}_i`. If `a_i(\psi) = 0`, set `\ell_f = 0`. Then .. MATH:: f_i \psi = \begin{cases} \psi + (1; i] & \text{ if } a_i(\psi) = 0,\\ \psi + (\ell_f; i] - (\ell_f-1; i-1] & \text{ if } a_i(\psi) > 0. \end{cases} The rule for computing `e_i \psi` is similar. INPUT: - ``n`` -- for type `A_n^{(1)}` EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: x = B([(8,1),(6,0),(5,1),(5,0),(4,0),(4,1),(4,1),(3,0),(3,0),(3,1),(3,1),(1,0),(1,2),(1,2)]); x (8; 1] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1] + 2 * (3; 0] + 2 * (3; 1] + (1; 0] + 2 * (1; 2] sage: x.f(1) (8; 1] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1] + 2 * (3; 0] + 2 * (3; 1] + (2; 1] + 2 * (1; 2] sage: x.f(1).f(1) (8; 1] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1] + 2 * (3; 0] + 2 * (3; 1] + (2; 1] + (1; 1] + 2 * (1; 2] sage: x.e(1) (7; 0] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1] + 2 * (3; 0] + 2 * (3; 1] + (1; 0] + 2 * (1; 2] sage: x.e(1).e(1) sage: x.f(0) (8; 1] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1] + 2 * (3; 0] + 2 * (3; 1] + (2; 0] + (1; 0] + (1; 2] We check an `\widehat{\mathfrak{sl}}_2` example against the generalized Young walls:: sage: B = crystals.infinity.Multisegments(1) sage: G = B.subcrystal(max_depth=4).digraph() sage: C = crystals.infinity.GeneralizedYoungWalls(1) sage: GC = C.subcrystal(max_depth=4).digraph() sage: G.is_isomorphic(GC, edge_labels=True) True REFERENCES: - [AJL2011]_ - [JL2009]_ - [LTV1999]_ """ def __init__(self, n): """ Initialize ``self``. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: TestSuite(B).run() """ self._cartan_type = CartanType(['A', n, 1]) self._Zn = IntegerModRing(n + 1) Parent.__init__(self, category=(HighestWeightCrystals(), InfiniteEnumeratedSets())) self.module_generators = (self.highest_weight_vector(), ) def _repr_(self): """ Return a string representation of ``self``. EXAMPLES:: sage: crystals.infinity.Multisegments(2) Infinity crystal of multisegments of type ['A', 2, 1] """ return "Infinity crystal of multisegments of type {}".format( self._cartan_type) @cached_method def highest_weight_vector(self): """ Return the highest weight vector of ``self``. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: B.highest_weight_vector() 0 """ return self.element_class(self, ()) def weight_lattice_realization(self): """ Return a realization of the weight lattice of ``self``. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: B.weight_lattice_realization() Extended weight lattice of the Root system of type ['A', 2, 1] """ return self._cartan_type.root_system().weight_lattice(extended=True) class Element(ElementWrapper): """ An element in a BZ multisegments crystal. """ def __init__(self, parent, value): """ Initialize ``self``. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: mg = B.highest_weight_vector() sage: TestSuite(mg).run() """ def sort_key(x): return (-x[0], ZZ(x[1])) ZM = parent._Zn value = [(k, ZM(i)) for k, i in value] ElementWrapper.__init__(self, parent, tuple(sorted(value, key=sort_key))) def _repr_(self): r""" Return a string representation of ``self``. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: B.highest_weight_vector() 0 sage: B([(4,2), (3,0), (3,1), (3,1), (1,1), (1,0)]) (4; 2] + (3; 0] + 2 * (3; 1] + (1; 0] + (1; 1] """ if not self.value: return '0' def sort_key(mc): x = mc[0] return (-x[0], ZZ(x[1])) def seg(x): m, c = x if c != 1: return "{} * ({}; {}]".format(c, m[0], m[1]) return "({}; {}]".format(m[0], m[1]) d = {} for x in self.value: d[x] = d.get(x, 0) + 1 return " + ".join(seg(x) for x in sorted(d.items(), key=sort_key)) def _latex_(self): r""" Return a LaTeX representation of ``self``. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: latex(B.highest_weight_vector()) 0 sage: latex(B([(4,2), (3,0), (3,1), (3,1), (1,1), (1,0)])) (4; 2] + (3; 0] + 2 (3; 1] + (1; 0] + (1; 1] """ if not self.value: return "0" def sort_key(mc): x = mc[0] return (-x[0], ZZ(x[1])) def seg(x): m, c = x if c != 1: return "{} ({}; {}]".format(c, m[0], m[1]) return "({}; {}]".format(m[0], m[1]) d = {} for x in self.value: d[x] = d.get(x, 0) + 1 return " + ".join(seg(x) for x in sorted(d.items(), key=sort_key)) def _sig(self, i): r""" Return an `i`-signature of ``self``. INPUT: - ``i`` -- an element of the indexing set OUTPUT: A pair ``(m, p, ep)`` where ``m`` and ``p`` correspond to the block length of the unmatched `-` and `+` respectively or ``None`` if there is no such block and ``ep`` is the number of unmatched `-`. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)]) sage: b._sig(0) (1, None, 1) sage: b._sig(1) (None, None, 0) """ if not self.value: return (None, None) pos = [] block = self.value[0][0] cur = 0 for k, j in self.value: if k != block: if cur != 0: pos.append((block, cur)) cur = 0 block = k if j + 1 == i: # + or ( cur += 1 elif j == i: # - or ) cur -= 1 if cur != 0: pos.append((block, cur)) # Now cancel all +- pairs cur = 0 m = None p = None ep = 0 for k, c in pos: old = cur cur += c if cur < 0: m = k p = None ep -= cur cur = 0 elif not cur: p = None elif cur > 0 and old <= 0: p = k return (m, p, ep) def e(self, i): r""" Return the action of `e_i` on ``self``. INPUT: - ``i`` -- an element of the index set EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)]) sage: b.e(0) (4; 2] + (3; 0] + (3; 1] + (1; 1] sage: b.e(1) sage: b.e(2) (3; 0] + 2 * (3; 1] + (1; 0] + (1; 1] """ i = self.parent()._Zn(i) m = self._sig(i)[0] if m is None: return None M = self.value a = M.index((m, i)) k = M[a][0] if k == 1: return self.__class__(self.parent(), M[:a] + M[a + 1:]) return self.__class__(self.parent(), M[:a] + ((k - 1, i - 1), ) + M[a + 1:]) def f(self, i): r""" Return the action of `f_i` on ``self``. INPUT: - ``i`` -- an element of the index set EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)]) sage: b.f(0) (4; 2] + (3; 0] + (3; 1] + 2 * (1; 0] + (1; 1] sage: b.f(1) (4; 2] + (3; 0] + (3; 1] + (1; 0] + 2 * (1; 1] sage: b.f(2) 2 * (4; 2] + (3; 0] + (1; 0] + (1; 1] """ i = self.parent()._Zn(i) p = self._sig(i)[1] M = self.value if p is None: return self.__class__(self.parent(), ((1, i), ) + M) a = M.index((p, i - 1)) return self.__class__(self.parent(), M[:a] + ((M[a][0] + 1, i), ) + M[a + 1:]) def epsilon(self, i): r""" Return `\varepsilon_i` of ``self``. INPUT: - ``i`` -- an element of the index set EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)]) sage: b.epsilon(0) 1 sage: b.epsilon(1) 0 sage: b.epsilon(2) 1 """ i = self.parent()._Zn(i) return self._sig(i)[2] def phi(self, i): r""" Return `\varphi_i` of ``self``. Let `\psi \in \Psi`. Define `\varphi_i(\psi) := \varepsilon_i(\psi) + \langle h_i, \mathrm{wt}(\psi) \rangle`, where `h_i` is the `i`-th simple coroot and `\mathrm{wt}(\psi)` is the :meth:`weight` of `\psi`. INPUT: - ``i`` -- an element of the index set EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)]) sage: b.phi(0) 1 sage: b.phi(1) 0 sage: mg = B.highest_weight_vector() sage: mg.f(1).phi(0) 1 """ h = self.parent().weight_lattice_realization().simple_coroots() return self.epsilon(i) + self.weight().scalar(h[i]) def weight(self): """ Return the weight of ``self``. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)]) sage: b.weight() -4*delta """ WLR = self.parent().weight_lattice_realization() alpha = WLR.simple_roots() n = self.parent()._cartan_type.rank() return WLR.sum(-1 * alpha[j % n] for k, i in self.value for j in range(ZZ(i), ZZ(i) + k))
class Associahedron(Polyhedron): r""" The generalized associahedron is a polytopal complex with vertices in one-to-one correspondence with clusters in the cluster complex, and with edges between two vertices if and only if the associated two clusters intersect in codimension 1. The associahedron of type `A_n` is one way to realize the classical associahedron as defined in http://en.wikipedia.org/wiki/Associahedron. A polytopal realization of the associahedron can be found in [CFZ]. The implementation is based on [CFZ, Theorem 1.5, Remark 1.6, and Corollary 1.9.]. EXAMPLES:: sage: Asso = Associahedron(['A',2]); Asso Generalized associahedron of type ['A', 2] with 5 vertices sage: sorted(Asso.Hrepresentation(), key=repr) [An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0, An inequality (1, 0) x + 1 >= 0, An inequality (1, 1) x + 1 >= 0] sage: Asso.Vrepresentation() [A vertex at (-1, 1), A vertex at (1, 1), A vertex at (1, -1), A vertex at (0, -1), A vertex at (-1, 0)] sage: Associahedron(['B',2]) Generalized associahedron of type ['B', 2] with 6 vertices The two pictures of [CFZ] can be recovered with:: sage: Asso = Associahedron(['A',3]); Asso Generalized associahedron of type ['A', 3] with 14 vertices sage: Asso.plot() sage: Asso = Associahedron(['B',3]); Asso Generalized associahedron of type ['B', 3] with 20 vertices sage: Asso.plot() TESTS:: sage: sorted(Associahedron(['A',3]).vertices()) [[-3/2, 0, -1/2], [-3/2, 0, 3/2], [-3/2, 1, -3/2], [-3/2, 2, -3/2], [-3/2, 2, 3/2], [-1/2, -1, -1/2], [-1/2, 0, -3/2], [1/2, -2, 1/2], [1/2, -2, 3/2], [3/2, -2, 1/2], [3/2, -2, 3/2], [3/2, 0, -3/2], [3/2, 2, -3/2], [3/2, 2, 3/2]] sage: sorted(Associahedron(['B',3]).vertices()) [[-3, 0, 0], [-3, 0, 3], [-3, 2, -2], [-3, 4, -3], [-3, 5, -3], [-3, 5, 3], [-2, 1, -2], [-2, 3, -3], [-1, -2, 0], [-1, -1, -1], [1, -4, 1], [1, -3, 0], [2, -5, 2], [2, -5, 3], [3, -5, 2], [3, -5, 3], [3, -3, 0], [3, 3, -3], [3, 5, -3], [3, 5, 3]] sage: Associahedron(['A',4]).f_vector() (1, 42, 84, 56, 14, 1) sage: Associahedron(['B',4]).f_vector() (1, 70, 140, 90, 20, 1) REFERENCES: - [CFZ] Chapoton, Fomin, Zelevinsky - Polytopal realizations of generalized associahedra, arXiv:0202004. """ def __init__(self, cartan_type): """ TESTS:: sage: Asso = Associahedron(['A',2]); Asso Generalized associahedron of type ['A', 2] with 5 vertices sage: TestSuite(Asso).run() """ self._cartan_type = CartanType( cartan_type ) assert self._cartan_type.is_finite() root_space = self._cartan_type.root_system().root_space() # TODO: generalize this as a method of root lattice realization rhocheck = sum( beta.associated_coroot() for beta in root_space.positive_roots() )/2 I = root_space.index_set() inequalities = [] for orbit in root_space.almost_positive_roots_decomposition(): c = rhocheck.coefficient(orbit[0].leading_support()) for beta in orbit: inequalities.append( [c] + [ beta.coefficient(i) for i in I ] ) Polyhedron.__init__(self,ieqs=inequalities) # check that there are non non trivial facets assert self.n_facets() == len(inequalities) def _repr_(self): r""" Returns a string representation of self. EXAMPLES:: sage: Associahedron(['A',3])._repr_() "Generalized associahedron of type ['A', 3] with 14 vertices" """ return 'Generalized associahedron of type %s with %s vertices'%(self._cartan_type,self.n_vertices()) def cartan_type(self): r""" Returns the Cartan type of self. EXAMPLES:: sage: Associahedron(['A',3]).cartan_type() ['A', 3] """ return self._cartan_type def vertices_in_root_space(self): r""" Returns the vertices of ``self`` as elements in the root space EXAMPLES:: sage: Asso = Associahedron(['A',2]) sage: Asso.vertices() [[-1, 1], [1, 1], [1, -1], [0, -1], [-1, 0]] sage: Asso.vertices_in_root_space() [-alpha[1] + alpha[2], alpha[1] + alpha[2], alpha[1] - alpha[2], -alpha[2], -alpha[1]] """ root_space = self._cartan_type.root_system().root_space() return [ root_space.from_vector(vector(V)) for V in self.vertex_generator() ]
def WeylGroup(x, prefix=None): """ Returns the Weyl group of type ct. INPUT: - ``ct`` - a Cartan Type. OPTIONAL: - ``prefix`` - changes the representation of elements from matrices to products of simple reflections EXAMPLES: The following constructions yield the same result, namely a weight lattice and its corresponding Weyl group:: sage: G = WeylGroup(['F',4]) sage: L = G.domain() or alternatively and equivalently:: sage: L = RootSystem(['F',4]).ambient_space() sage: G = L.weyl_group() Either produces a weight lattice, with access to its roots and weights. :: sage: G = WeylGroup(['F',4]) sage: G.order() 1152 sage: [s1,s2,s3,s4] = G.simple_reflections() sage: w = s1*s2*s3*s4; w [ 1/2 1/2 1/2 1/2] [-1/2 1/2 1/2 -1/2] [ 1/2 1/2 -1/2 -1/2] [ 1/2 -1/2 1/2 -1/2] sage: type(w) == G.element_class True sage: w.order() 12 sage: w.length() # length function on Weyl group 4 The default representation of Weyl group elements is as matrices. If you prefer, you may specify a prefix, in which case the elements are represented as products of simple reflections. :: sage: W=WeylGroup("C3",prefix="s") sage: [s1,s2,s3]=W.simple_reflections() # lets Sage parse its own output sage: s2*s1*s2*s3 s1*s2*s3*s1 sage: s2*s1*s2*s3 == s1*s2*s3*s1 True sage: (s2*s3)^2==(s3*s2)^2 True sage: (s1*s2*s3*s1).matrix() [ 0 0 -1] [ 0 1 0] [ 1 0 0] :: sage: L = G.domain() sage: fw = L.fundamental_weights(); fw Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3/2, 1/2, 1/2, 1/2), 4: (1, 0, 0, 0)} sage: rho = sum(fw); rho (11/2, 5/2, 3/2, 1/2) sage: w.action(rho) # action of G on weight lattice (5, -1, 3, 2) TESTS:: sage: TestSuite(WeylGroup(["A",3])).run() sage: TestSuite(WeylGroup(["A",3, 1])).run() sage: W=WeylGroup(['A',3,1]) sage: s=W.simple_reflections() sage: w=s[0]*s[1]*s[2] sage: w.reduced_word() [0, 1, 2] sage: w=s[0]*s[2] sage: w.reduced_word() [2, 0] """ if x in RootLatticeRealizations: return WeylGroup_gens(x, prefix=prefix) ct = CartanType(x) if ct.is_affine(): return WeylGroup_gens(ct.root_system().root_space(), prefix=prefix) else: return WeylGroup_gens(ct.root_system().ambient_space(), prefix=prefix)
def WeylGroup(x, prefix=None, implementation='matrix'): """ Returns the Weyl group of the root system defined by the Cartan type (or matrix) ``ct``. INPUT: - ``x`` - a root system or a Cartan type (or matrix) OPTIONAL: - ``prefix`` -- changes the representation of elements from matrices to products of simple reflections - ``implementation`` -- one of the following: * ``'matrix'`` - as matrices acting on a root system * ``"permutation"`` - as a permutation group acting on the roots EXAMPLES: The following constructions yield the same result, namely a weight lattice and its corresponding Weyl group:: sage: G = WeylGroup(['F',4]) sage: L = G.domain() or alternatively and equivalently:: sage: L = RootSystem(['F',4]).ambient_space() sage: G = L.weyl_group() sage: W = WeylGroup(L) Either produces a weight lattice, with access to its roots and weights. :: sage: G = WeylGroup(['F',4]) sage: G.order() 1152 sage: [s1,s2,s3,s4] = G.simple_reflections() sage: w = s1*s2*s3*s4; w [ 1/2 1/2 1/2 1/2] [-1/2 1/2 1/2 -1/2] [ 1/2 1/2 -1/2 -1/2] [ 1/2 -1/2 1/2 -1/2] sage: type(w) == G.element_class True sage: w.order() 12 sage: w.length() # length function on Weyl group 4 The default representation of Weyl group elements is as matrices. If you prefer, you may specify a prefix, in which case the elements are represented as products of simple reflections. :: sage: W=WeylGroup("C3",prefix="s") sage: [s1,s2,s3]=W.simple_reflections() # lets Sage parse its own output sage: s2*s1*s2*s3 s1*s2*s3*s1 sage: s2*s1*s2*s3 == s1*s2*s3*s1 True sage: (s2*s3)^2==(s3*s2)^2 True sage: (s1*s2*s3*s1).matrix() [ 0 0 -1] [ 0 1 0] [ 1 0 0] :: sage: L = G.domain() sage: fw = L.fundamental_weights(); fw Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3/2, 1/2, 1/2, 1/2), 4: (1, 0, 0, 0)} sage: rho = sum(fw); rho (11/2, 5/2, 3/2, 1/2) sage: w.action(rho) # action of G on weight lattice (5, -1, 3, 2) We can also do the same for arbitrary Cartan matrices:: sage: cm = CartanMatrix([[2,-5,0],[-2,2,-1],[0,-1,2]]) sage: W = WeylGroup(cm) sage: W.gens() ( [-1 5 0] [ 1 0 0] [ 1 0 0] [ 0 1 0] [ 2 -1 1] [ 0 1 0] [ 0 0 1], [ 0 0 1], [ 0 1 -1] ) sage: s0,s1,s2 = W.gens() sage: s1*s2*s1 [ 1 0 0] [ 2 0 -1] [ 2 -1 0] sage: s2*s1*s2 [ 1 0 0] [ 2 0 -1] [ 2 -1 0] sage: s0*s1*s0*s2*s0 [ 9 0 -5] [ 2 0 -1] [ 0 1 -1] Same Cartan matrix, but with a prefix to display using simple reflections:: sage: W = WeylGroup(cm, prefix='s') sage: s0,s1,s2 = W.gens() sage: s0*s2*s1 s2*s0*s1 sage: (s1*s2)^3 1 sage: (s0*s1)^5 s0*s1*s0*s1*s0*s1*s0*s1*s0*s1 sage: s0*s1*s2*s1*s2 s2*s0*s1 sage: s0*s1*s2*s0*s2 s0*s1*s0 TESTS:: sage: TestSuite(WeylGroup(["A",3])).run() sage: TestSuite(WeylGroup(["A",3,1])).run() # long time sage: W = WeylGroup(['A',3,1]) sage: s = W.simple_reflections() sage: w = s[0]*s[1]*s[2] sage: w.reduced_word() [0, 1, 2] sage: w = s[0]*s[2] sage: w.reduced_word() [2, 0] sage: W = groups.misc.WeylGroup(['A',3,1]) """ if implementation == "permutation": return WeylGroup_permutation(x, prefix) elif implementation != "matrix": raise ValueError("invalid implementation") if x in RootLatticeRealizations: return WeylGroup_gens(x, prefix=prefix) try: ct = CartanType(x) except TypeError: ct = CartanMatrix(x) # See if it is a Cartan matrix if ct.is_finite(): return WeylGroup_gens(ct.root_system().ambient_space(), prefix=prefix) return WeylGroup_gens(ct.root_system().root_space(), prefix=prefix)
def WeylGroup(x, prefix=None, implementation='matrix'): """ Returns the Weyl group of the root system defined by the Cartan type (or matrix) ``ct``. INPUT: - ``x`` - a root system or a Cartan type (or matrix) OPTIONAL: - ``prefix`` -- changes the representation of elements from matrices to products of simple reflections - ``implementation`` -- one of the following: * ``'matrix'`` - as matrices acting on a root system * ``"permutation"`` - as a permutation group acting on the roots EXAMPLES: The following constructions yield the same result, namely a weight lattice and its corresponding Weyl group:: sage: G = WeylGroup(['F',4]) sage: L = G.domain() or alternatively and equivalently:: sage: L = RootSystem(['F',4]).ambient_space() sage: G = L.weyl_group() sage: W = WeylGroup(L) Either produces a weight lattice, with access to its roots and weights. :: sage: G = WeylGroup(['F',4]) sage: G.order() 1152 sage: [s1,s2,s3,s4] = G.simple_reflections() sage: w = s1*s2*s3*s4; w [ 1/2 1/2 1/2 1/2] [-1/2 1/2 1/2 -1/2] [ 1/2 1/2 -1/2 -1/2] [ 1/2 -1/2 1/2 -1/2] sage: type(w) == G.element_class True sage: w.order() 12 sage: w.length() # length function on Weyl group 4 The default representation of Weyl group elements is as matrices. If you prefer, you may specify a prefix, in which case the elements are represented as products of simple reflections. :: sage: W=WeylGroup("C3",prefix="s") sage: [s1,s2,s3]=W.simple_reflections() # lets Sage parse its own output sage: s2*s1*s2*s3 s1*s2*s3*s1 sage: s2*s1*s2*s3 == s1*s2*s3*s1 True sage: (s2*s3)^2==(s3*s2)^2 True sage: (s1*s2*s3*s1).matrix() [ 0 0 -1] [ 0 1 0] [ 1 0 0] :: sage: L = G.domain() sage: fw = L.fundamental_weights(); fw Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3/2, 1/2, 1/2, 1/2), 4: (1, 0, 0, 0)} sage: rho = sum(fw); rho (11/2, 5/2, 3/2, 1/2) sage: w.action(rho) # action of G on weight lattice (5, -1, 3, 2) We can also do the same for arbitrary Cartan matrices:: sage: cm = CartanMatrix([[2,-5,0],[-2,2,-1],[0,-1,2]]) sage: W = WeylGroup(cm) sage: W.gens() ( [-1 5 0] [ 1 0 0] [ 1 0 0] [ 0 1 0] [ 2 -1 1] [ 0 1 0] [ 0 0 1], [ 0 0 1], [ 0 1 -1] ) sage: s0,s1,s2 = W.gens() sage: s1*s2*s1 [ 1 0 0] [ 2 0 -1] [ 2 -1 0] sage: s2*s1*s2 [ 1 0 0] [ 2 0 -1] [ 2 -1 0] sage: s0*s1*s0*s2*s0 [ 9 0 -5] [ 2 0 -1] [ 0 1 -1] Same Cartan matrix, but with a prefix to display using simple reflections:: sage: W = WeylGroup(cm, prefix='s') sage: s0,s1,s2 = W.gens() sage: s0*s2*s1 s2*s0*s1 sage: (s1*s2)^3 1 sage: (s0*s1)^5 s0*s1*s0*s1*s0*s1*s0*s1*s0*s1 sage: s0*s1*s2*s1*s2 s2*s0*s1 sage: s0*s1*s2*s0*s2 s0*s1*s0 TESTS:: sage: TestSuite(WeylGroup(["A",3])).run() sage: TestSuite(WeylGroup(["A",3,1])).run() # long time sage: W = WeylGroup(['A',3,1]) sage: s = W.simple_reflections() sage: w = s[0]*s[1]*s[2] sage: w.reduced_word() [0, 1, 2] sage: w = s[0]*s[2] sage: w.reduced_word() [2, 0] sage: W = groups.misc.WeylGroup(['A',3,1]) """ if implementation == "permutation": return WeylGroup_permutation(x, prefix) elif implementation != "matrix": raise ValueError("invalid implementation") if x in RootLatticeRealizations: return WeylGroup_gens(x, prefix=prefix) try: ct = CartanType(x) except TypeError: ct = CartanMatrix(x) # See if it is a Cartan matrix if ct.is_finite(): return WeylGroup_gens(ct.root_system().ambient_space(), prefix=prefix) return WeylGroup_gens(ct.root_system().root_space(), prefix=prefix)
def __classcall_private__(cls, cartan_type, La): ct = CartanType(cartan_type) La = ct.root_system().weight_lattice()(La) return super(HighestWeightCrystalOfGYW, cls).__classcall__(cls, ct, La)
class Associahedron(Polyhedron_QQ_ppl): r""" The generalized associahedron is a polytopal complex with vertices in one-to-one correspondence with clusters in the cluster complex, and with edges between two vertices if and only if the associated two clusters intersect in codimension 1. The associahedron of type `A_n` is one way to realize the classical associahedron as defined in http://en.wikipedia.org/wiki/Associahedron. A polytopal realization of the associahedron can be found in [CFZ]. The implementation is based on [CFZ, Theorem 1.5, Remark 1.6, and Corollary 1.9.]. EXAMPLES:: sage: Asso = Associahedron(['A',2]); Asso Generalized associahedron of type ['A', 2] with 5 vertices sage: sorted(Asso.Hrepresentation(), key=repr) [An inequality (-1, 0) x + 1 >= 0, An inequality (0, -1) x + 1 >= 0, An inequality (0, 1) x + 1 >= 0, An inequality (1, 0) x + 1 >= 0, An inequality (1, 1) x + 1 >= 0] sage: Asso.Vrepresentation() (A vertex at (1, -1), A vertex at (1, 1), A vertex at (-1, 1), A vertex at (-1, 0), A vertex at (0, -1)) sage: Associahedron(['B',2]) Generalized associahedron of type ['B', 2] with 6 vertices The two pictures of [CFZ] can be recovered with:: sage: Asso = Associahedron(['A',3]); Asso Generalized associahedron of type ['A', 3] with 14 vertices sage: Asso.plot() sage: Asso = Associahedron(['B',3]); Asso Generalized associahedron of type ['B', 3] with 20 vertices sage: Asso.plot() TESTS:: sage: sorted(Associahedron(['A',3]).vertices()) [[-3/2, 0, -1/2], [-3/2, 0, 3/2], [-3/2, 1, -3/2], [-3/2, 2, -3/2], [-3/2, 2, 3/2], [-1/2, -1, -1/2], [-1/2, 0, -3/2], [1/2, -2, 1/2], [1/2, -2, 3/2], [3/2, -2, 1/2], [3/2, -2, 3/2], [3/2, 0, -3/2], [3/2, 2, -3/2], [3/2, 2, 3/2]] sage: sorted(Associahedron(['B',3]).vertices()) [[-3, 0, 0], [-3, 0, 3], [-3, 2, -2], [-3, 4, -3], [-3, 5, -3], [-3, 5, 3], [-2, 1, -2], [-2, 3, -3], [-1, -2, 0], [-1, -1, -1], [1, -4, 1], [1, -3, 0], [2, -5, 2], [2, -5, 3], [3, -5, 2], [3, -5, 3], [3, -3, 0], [3, 3, -3], [3, 5, -3], [3, 5, 3]] sage: Associahedron(['A',4]).f_vector() (1, 42, 84, 56, 14, 1) sage: Associahedron(['B',4]).f_vector() (1, 70, 140, 90, 20, 1) REFERENCES: - [CFZ] Chapoton, Fomin, Zelevinsky - Polytopal realizations of generalized associahedra, arXiv:0202004. """ def __init__(self, cartan_type): """ TESTS:: sage: Asso = Associahedron(['A',2]); Asso Generalized associahedron of type ['A', 2] with 5 vertices sage: TestSuite(Asso).run() """ self._cartan_type = CartanType(cartan_type) assert self._cartan_type.is_finite() root_space = self._cartan_type.root_system().root_space() # TODO: generalize this as a method of root lattice realization rhocheck = sum(beta.associated_coroot() for beta in root_space.positive_roots()) / 2 I = root_space.index_set() inequalities = [] for orbit in root_space.almost_positive_roots_decomposition(): c = rhocheck.coefficient(orbit[0].leading_support()) for beta in orbit: inequalities.append([c] + [beta.coefficient(i) for i in I]) Polyhedron_QQ_ppl.__init__(self, len(I), None, [inequalities, []]) # check that there are non non trivial facets assert self.n_facets() == len(inequalities) def _repr_(self): r""" Returns a string representation of self. EXAMPLES:: sage: Associahedron(['A',3])._repr_() "Generalized associahedron of type ['A', 3] with 14 vertices" """ return 'Generalized associahedron of type %s with %s vertices' % ( self._cartan_type, self.n_vertices()) def cartan_type(self): r""" Returns the Cartan type of self. EXAMPLES:: sage: Associahedron(['A',3]).cartan_type() ['A', 3] """ return self._cartan_type def vertices_in_root_space(self): r""" Returns the vertices of ``self`` as elements in the root space EXAMPLES:: sage: Asso = Associahedron(['A',2]) sage: Asso.vertices() [[1, -1], [1, 1], [-1, 1], [-1, 0], [0, -1]] sage: Asso.vertices_in_root_space() (alpha[1] - alpha[2], alpha[1] + alpha[2], -alpha[1] + alpha[2], -alpha[1], -alpha[2]) """ root_space = self._cartan_type.root_system().root_space() return tuple( root_space.from_vector(vector(V)) for V in self.vertex_generator())
class InfinityCrystalOfMultisegments(Parent, UniqueRepresentation): r""" The type `A_n^{(1)}` crystal `B(\infty)` realized using Bernstein-Zelevinsky (BZ) multisegments. Using (a modified version of the) notation from [JL2009]_, for `\ell \in \ZZ_{>0}` and `i \in \ZZ / (n+1)\ZZ`, a segment of length `\ell` and head `i` is the sequence of consecutive residues `[i,i+1,\dots,i+\ell-1]`. The notation for a segment of length `\ell` and head `i` is simplified to `[i; \ell)`. Similarly, a segment of length `\ell` and tail `i` is the sequence of consecutive residues `[i-\ell+1, \ldots, i-1, i]`. The latter is denoted simply by `(\ell;i]`. Finally, a multisegment is a formal linear combination of segments, usually written in the form .. MATH:: \psi = \sum_{\substack{i \in \ZZ/(n+1)\ZZ \\ \ell \in \ZZ_{>0}}} m_{(\ell;i]} (\ell; i]. Such a multisegment is called aperiodic if, for every `\ell > 0`, there exists some `i \in \ZZ / (n+1)\ZZ` such that `(\ell; i]` does not appear in `\psi`. Denote the set of all periodic multisegments, together with the empty multisegment `\varnothing`, by `\Psi`. We define a crystal structure on multisegments as follows. Set `S_{\ell,i} = \sum_{k \ge \ell} (m_{(k;i-1]} - m_{(k;i]})` and let `\ell_f` be the minimal `\ell` that attains the value `\min_{\ell > 0} S_{\ell,i}`. Then we have .. MATH:: f_i \psi = \begin{cases} \psi + (1;i] & \text{ if } \ell_f = 1,\\ \psi + (\ell_f;i] - (\ell_f-1;i-1] & \text{ if } \ell_f > 1. \end{cases} Similarly, let `\ell_e` be the maximal `\ell` that attains the value `\min_{\ell > 0} S_{\ell,i}`. Then we have .. MATH:: e_i \psi = \begin{cases} 0 & \text{ if } \min_{\ell > 0} S_{\ell,i} = 0, \\ \psi + (1; i] & \text{ if } \ell_e = 1,\\ \psi - (\ell_e; i] + (\ell_e-1; i-1] & \text{ if } \ell_e > 1. \end{cases} Alternatively, the crystal operators may be defined using a signature rule, as detailed in Section 4 of [JL2009]_ (following [AJL2011]_). For `\psi \in \Psi` and `i \in \ZZ/(n+1)\ZZ`, encode all segments in `\psi` with tail `i` by the symbol `R` and all segments in `\psi` with tail `i-1` by `A`. For `\ell > 0`, set `w_{i,\ell} = R^{m_{(\ell;i]}} A^{m_{(\ell;i-1]}}` and `w_i = \prod_{\ell\ge 1} w_{i,\ell}`. By successively canceling out as many `RA` factors as possible, set `\widetilde{w}_i = A^{a_i(\psi)} R^{r_i(\psi)}`. If `a_i(\psi) > 0`, denote by `\ell_f > 0` the length of the rightmost segment `A` in `\widetilde{w}_i`. If `a_i(\psi) = 0`, set `\ell_f = 0`. Then .. MATH:: f_i \psi = \begin{cases} \psi + (1; i] & \text{ if } a_i(\psi) = 0,\\ \psi + (\ell_f; i] - (\ell_f-1; i-1] & \text{ if } a_i(\psi) > 0. \end{cases} The rule for computing `e_i \psi` is similar. INPUT: - ``n`` -- for type `A_n^{(1)}` EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: x = B([(8,1),(6,0),(5,1),(5,0),(4,0),(4,1),(4,1),(3,0),(3,0),(3,1),(3,1),(1,0),(1,2),(1,2)]); x (8; 1] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1] + 2 * (3; 0] + 2 * (3; 1] + (1; 0] + 2 * (1; 2] sage: x.f(1) (8; 1] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1] + 2 * (3; 0] + 2 * (3; 1] + (2; 1] + 2 * (1; 2] sage: x.f(1).f(1) (8; 1] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1] + 2 * (3; 0] + 2 * (3; 1] + (2; 1] + (1; 1] + 2 * (1; 2] sage: x.e(1) (7; 0] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1] + 2 * (3; 0] + 2 * (3; 1] + (1; 0] + 2 * (1; 2] sage: x.e(1).e(1) sage: x.f(0) (8; 1] + (6; 0] + (5; 0] + (5; 1] + (4; 0] + 2 * (4; 1] + 2 * (3; 0] + 2 * (3; 1] + (2; 0] + (1; 0] + (1; 2] We check an `\widehat{\mathfrak{sl}}_2` example against the generalized Young walls:: sage: B = crystals.infinity.Multisegments(1) sage: G = B.subcrystal(max_depth=4).digraph() sage: C = crystals.infinity.GeneralizedYoungWalls(1) sage: GC = C.subcrystal(max_depth=4).digraph() sage: G.is_isomorphic(GC, edge_labels=True) True REFERENCES: - [AJL2011]_ - [JL2009]_ - [LTV1999]_ """ def __init__(self, n): """ Initialize ``self``. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: TestSuite(B).run() """ self._cartan_type = CartanType(['A', n, 1]) self._Zn = IntegerModRing(n+1) Parent.__init__(self, category=(HighestWeightCrystals(), InfiniteEnumeratedSets())) self.module_generators = (self.highest_weight_vector(),) def _repr_(self): """ Return a string representation of ``self``. EXAMPLES:: sage: crystals.infinity.Multisegments(2) Infinity crystal of multisegments of type ['A', 2, 1] """ return "Infinity crystal of multisegments of type {}".format(self._cartan_type) @cached_method def highest_weight_vector(self): """ Return the highest weight vector of ``self``. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: B.highest_weight_vector() 0 """ return self.element_class(self, ()) def weight_lattice_realization(self): """ Return a realization of the weight lattice of ``self``. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: B.weight_lattice_realization() Extended weight lattice of the Root system of type ['A', 2, 1] """ return self._cartan_type.root_system().weight_lattice(extended=True) class Element(ElementWrapper): """ An element in a BZ multisegments crystal. """ def __init__(self, parent, value): """ Initialize ``self``. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: mg = B.highest_weight_vector() sage: TestSuite(mg).run() """ def sort_key(x): return (-x[0], ZZ(x[1])) ZM = parent._Zn value = [(k, ZM(i)) for k,i in value] ElementWrapper.__init__(self, parent, tuple(sorted(value, key=sort_key))) def _repr_(self): r""" Return a string representation of ``self``. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: B.highest_weight_vector() 0 sage: B([(4,2), (3,0), (3,1), (3,1), (1,1), (1,0)]) (4; 2] + (3; 0] + 2 * (3; 1] + (1; 0] + (1; 1] """ if not self.value: return '0' def sort_key(mc): x = mc[0] return (-x[0], ZZ(x[1])) def seg(x): m, c = x if c != 1: return "{} * ({}; {}]".format(c, m[0], m[1]) return "({}; {}]".format(m[0], m[1]) d = {} for x in self.value: d[x] = d.get(x, 0) + 1 return " + ".join(seg(x) for x in sorted(d.items(), key=sort_key)) def _latex_(self): r""" Return a LaTeX representation of ``self``. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: latex(B.highest_weight_vector()) 0 sage: latex(B([(4,2), (3,0), (3,1), (3,1), (1,1), (1,0)])) (4; 2] + (3; 0] + 2 (3; 1] + (1; 0] + (1; 1] """ if not self.value: return "0" def sort_key(mc): x = mc[0] return (-x[0], ZZ(x[1])) def seg(x): m, c = x if c != 1: return "{} ({}; {}]".format(c, m[0], m[1]) return "({}; {}]".format(m[0], m[1]) d = {} for x in self.value: d[x] = d.get(x, 0) + 1 return " + ".join(seg(x) for x in sorted(d.items(), key=sort_key)) def _sig(self, i): r""" Return an `i`-signature of ``self``. INPUT: - ``i`` -- an element of the indexing set OUTPUT: A pair ``(m, p, ep)`` where ``m`` and ``p`` correspond to the block length of the unmatched `-` and `+` respectively or ``None`` if there is no such block and ``ep`` is the number of unmatched `-`. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)]) sage: b._sig(0) (1, None, 1) sage: b._sig(1) (None, None, 0) TESTS: Check that :trac:`23439` is fixed:: sage: B = crystals.infinity.Multisegments(2) sage: b = B.highest_weight_vector() sage: b._sig(1) (None, None, 0) sage: b.epsilon(1) 0 """ if not self.value: return (None, None, 0) pos = [] block = self.value[0][0] cur = 0 for k,j in self.value: if k != block: if cur != 0: pos.append((block, cur)) cur = 0 block = k if j + 1 == i: # + or ( cur += 1 elif j == i: # - or ) cur -= 1 if cur != 0: pos.append((block, cur)) # Now cancel all +- pairs cur = 0 m = None p = None ep = 0 for k,c in pos: old = cur cur += c if cur < 0: m = k p = None ep -= cur cur = 0 elif not cur: p = None elif cur > 0 and old <= 0: p = k return (m, p, ep) def e(self, i): r""" Return the action of `e_i` on ``self``. INPUT: - ``i`` -- an element of the index set EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)]) sage: b.e(0) (4; 2] + (3; 0] + (3; 1] + (1; 1] sage: b.e(1) sage: b.e(2) (3; 0] + 2 * (3; 1] + (1; 0] + (1; 1] """ i = self.parent()._Zn(i) m = self._sig(i)[0] if m is None: return None M = self.value a = M.index((m, i)) k = M[a][0] if k == 1: return self.__class__(self.parent(), M[:a] + M[a+1:]) return self.__class__(self.parent(), M[:a] + ((k-1,i-1),) + M[a+1:]) def f(self, i): r""" Return the action of `f_i` on ``self``. INPUT: - ``i`` -- an element of the index set EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)]) sage: b.f(0) (4; 2] + (3; 0] + (3; 1] + 2 * (1; 0] + (1; 1] sage: b.f(1) (4; 2] + (3; 0] + (3; 1] + (1; 0] + 2 * (1; 1] sage: b.f(2) 2 * (4; 2] + (3; 0] + (1; 0] + (1; 1] """ i = self.parent()._Zn(i) p = self._sig(i)[1] M = self.value if p is None: return self.__class__(self.parent(), ((1, i),) + M) a = M.index((p, i-1)) return self.__class__(self.parent(), M[:a] + ((M[a][0]+1,i),) + M[a+1:]) def epsilon(self, i): r""" Return `\varepsilon_i` of ``self``. INPUT: - ``i`` -- an element of the index set EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)]) sage: b.epsilon(0) 1 sage: b.epsilon(1) 0 sage: b.epsilon(2) 1 """ i = self.parent()._Zn(i) return self._sig(i)[2] def phi(self, i): r""" Return `\varphi_i` of ``self``. Let `\psi \in \Psi`. Define `\varphi_i(\psi) := \varepsilon_i(\psi) + \langle h_i, \mathrm{wt}(\psi) \rangle`, where `h_i` is the `i`-th simple coroot and `\mathrm{wt}(\psi)` is the :meth:`weight` of `\psi`. INPUT: - ``i`` -- an element of the index set EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)]) sage: b.phi(0) 1 sage: b.phi(1) 0 sage: mg = B.highest_weight_vector() sage: mg.f(1).phi(0) 1 """ h = self.parent().weight_lattice_realization().simple_coroots() return self.epsilon(i) + self.weight().scalar(h[i]) def weight(self): """ Return the weight of ``self``. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: b = B([(4,2), (3,0), (3,1), (1,1), (1,0)]) sage: b.weight() -4*delta """ WLR = self.parent().weight_lattice_realization() alpha = WLR.simple_roots() n = self.parent()._cartan_type.rank() return WLR.sum(-1*alpha[j % n] for k,i in self.value for j in range(ZZ(i),ZZ(i)+k))
def WeylGroup(x, prefix=None): """ Returns the Weyl group of type ct. INPUT: - ``ct`` - a Cartan Type. OPTIONAL: - ``prefix`` - changes the representation of elements from matrices to products of simple reflections EXAMPLES: The following constructions yield the same result, namely a weight lattice and its corresponding Weyl group:: sage: G = WeylGroup(['F',4]) sage: L = G.domain() or alternatively and equivalently:: sage: L = RootSystem(['F',4]).ambient_space() sage: G = L.weyl_group() Either produces a weight lattice, with access to its roots and weights. :: sage: G = WeylGroup(['F',4]) sage: G.order() 1152 sage: [s1,s2,s3,s4] = G.simple_reflections() sage: w = s1*s2*s3*s4; w [ 1/2 1/2 1/2 1/2] [-1/2 1/2 1/2 -1/2] [ 1/2 1/2 -1/2 -1/2] [ 1/2 -1/2 1/2 -1/2] sage: type(w) == G.element_class True sage: w.order() 12 sage: w.length() # length function on Weyl group 4 The default representation of Weyl group elements is as matrices. If you prefer, you may specify a prefix, in which case the elements are represented as products of simple reflections. :: sage: W=WeylGroup("C3",prefix="s") sage: [s1,s2,s3]=W.simple_reflections() # lets Sage parse its own output sage: s2*s1*s2*s3 s1*s2*s3*s1 sage: s2*s1*s2*s3 == s1*s2*s3*s1 True sage: (s2*s3)^2==(s3*s2)^2 True sage: (s1*s2*s3*s1).matrix() [ 0 0 -1] [ 0 1 0] [ 1 0 0] :: sage: L = G.domain() sage: fw = L.fundamental_weights(); fw Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3/2, 1/2, 1/2, 1/2), 4: (1, 0, 0, 0)} sage: rho = sum(fw); rho (11/2, 5/2, 3/2, 1/2) sage: w.action(rho) # action of G on weight lattice (5, -1, 3, 2) TESTS:: sage: TestSuite(WeylGroup(["A",3])).run() sage: TestSuite(WeylGroup(["A",3, 1])).run() sage: W=WeylGroup(['A',3,1]) sage: s=W.simple_reflections() sage: w=s[0]*s[1]*s[2] sage: w.reduced_word() [0, 1, 2] sage: w=s[0]*s[2] sage: w.reduced_word() [2, 0] """ if x in RootLatticeRealizations: return WeylGroup_gens(x, prefix=prefix) ct = CartanType(x) if ct.is_affine(): return WeylGroup_gens(ct.root_system().root_space(), prefix=prefix) else: return WeylGroup_gens(ct.root_system().ambient_space(), prefix=prefix)