def __classcall_private__(cls, cartan_type, r, s): """ Normalize the input arguments to ensure unique representation. EXAMPLES:: sage: KRT1 = KirillovReshetikhinTableaux(CartanType(['A',3,1]), 2, 3) sage: KRT2 = KirillovReshetikhinTableaux(['A',3,1], 2, 3) sage: KRT1 is KRT2 True """ ct = CartanType(cartan_type) assert ct.is_affine() if ct.is_untwisted_affine(): if ct.letter == 'D': if r == ct.n or r == ct.n - 1: return KRTableauxSpin(ct, r, s) return KRTableauxTypeVertical(ct, r, s) if ct.letter == 'B': if r == ct.n: return KRTableauxBn(ct, r, s) return KRTypeVertical(ct, r, s) if ct.letter == 'A' or (ct.letter == 'C' and r == ct.n): return KRTableauxRectangle(ct, r, s) else: if ct.dual().letter == 'B': return KRTableauxTypeVertical(ct, r, s) raise NotImplementedError
def __classcall_private__(cls, arg0, cartan_type=None, kac_moody=True): """ Parse input to ensure a unique representation. INPUT: - ``arg0`` -- a simple Lie algebra or a base ring - ``cartan_type`` -- a Cartan type EXAMPLES:: sage: L1 = lie_algebras.Affine(QQ, ['A',4,1]) sage: cl = lie_algebras.sl(QQ, 5) sage: L2 = lie_algebras.Affine(cl) sage: L1 is L2 True sage: cl.affine() is L1 True """ if isinstance(arg0, LieAlgebra): ct = arg0.cartan_type() if not ct.is_finite(): raise ValueError("the base Lie algebra is not simple") cartan_type = ct.affine() g = arg0 else: # arg0 is the base ring cartan_type = CartanType(cartan_type) if not cartan_type.is_affine(): raise ValueError("the Cartan type must be affine") g = LieAlgebra(arg0, cartan_type=cartan_type.classical()) if not cartan_type.is_untwisted_affine(): raise NotImplementedError("only currently implemented for untwisted affine types") return super(AffineLieAlgebra, cls).__classcall__(cls, g, kac_moody)
def __classcall_private__(cls, starting_weight, cartan_type = None, starting_weight_parent = None): """ Classcall to mend the input. Internally, the :class:`~sage.combinat.crystals.littlemann_path.CrystalOfLSPaths` code works with a ``starting_weight`` that is in the weight space associated to the crystal. The user can, however, also input a ``cartan_type`` and the coefficients of the fundamental weights as ``starting_weight``. This code transforms the input into the right format (also necessary for UniqueRepresentation). TESTS:: sage: crystals.LSPaths(['A',2,1],[-1,0,1]) The crystal of LS paths of type ['A', 2, 1] and weight -Lambda[0] + Lambda[2] sage: R = RootSystem(['B',2,1]) sage: La = R.weight_space(extended=True).basis() sage: C = crystals.LSPaths(['B',2,1],[0,0,1]) sage: B = crystals.LSPaths(La[2]) sage: B is C True """ if cartan_type is not None: cartan_type, starting_weight = CartanType(starting_weight), cartan_type if cartan_type.is_affine(): extended = True else: extended = False R = RootSystem(cartan_type) P = R.weight_space(extended = extended) Lambda = P.basis() offset = R.index_set()[Integer(0)] starting_weight = P.sum(starting_weight[j-offset]*Lambda[j] for j in R.index_set()) if starting_weight_parent is None: starting_weight_parent = starting_weight.parent() else: # Both the weight and the parent of the weight are passed as arguments of init to be able # to distinguish between crystals with the extended and non-extended weight lattice! if starting_weight.parent() != starting_weight_parent: raise ValueError("The passed parent is not equal to parent of the inputted weight!") return super(CrystalOfLSPaths, cls).__classcall__(cls, starting_weight, starting_weight_parent = starting_weight_parent)
def __classcall_private__(cls, cartan_type, La): r""" Normalize input to ensure a unique representation. EXAMPLES:: sage: La = RootSystem(['E',8,1]).weight_lattice(extended=True).fundamental_weights() sage: M = crystals.NakajimaMonomials(['E',8,1],La[0]+La[8]) sage: M1 = crystals.NakajimaMonomials(CartanType(['E',8,1]),La[0]+La[8]) sage: M2 = crystals.NakajimaMonomials(['E',8,1],M.Lambda()[0] + M.Lambda()[8]) sage: M is M1 is M2 True """ cartan_type = CartanType(cartan_type) if cartan_type.is_affine(): La = RootSystem(cartan_type).weight_lattice(extended=True)(La) else: La = RootSystem(cartan_type).weight_lattice()(La) return super(CrystalOfNakajimaMonomials, cls).__classcall__(cls, cartan_type, La)
def __classcall_private__(cls, cartan_type, B): """ Normalize the input arguments to ensure unique representation. EXAMPLES:: sage: T1 = crystals.TensorProductOfKirillovReshetikhinTableaux(CartanType(['A',3,1]), [[2,2]]) sage: T2 = crystals.TensorProductOfKirillovReshetikhinTableaux(['A',3,1], [(2,2)]) sage: T3 = crystals.TensorProductOfKirillovReshetikhinTableaux(['A',3,1], ((2,2),)) sage: T2 is T1, T3 is T1 (True, True) """ cartan_type = CartanType(cartan_type) if not cartan_type.is_affine(): raise ValueError("The Cartan type must be affine") # Standardize B input into a tuple of tuples B = tuple(tuple(dim) for dim in B) return super(TensorProductOfKirillovReshetikhinTableaux, cls).__classcall__(cls, cartan_type, B)
def __classcall_private__(cls, cartan_type, La): r""" Normalize input to ensure a unique representation. EXAMPLES:: sage: La = RootSystem(['E',8,1]).weight_lattice(extended=True).fundamental_weights() sage: M = crystals.NakajimaMonomials(['E',8,1],La[0]+La[8]) sage: M1 = crystals.NakajimaMonomials(CartanType(['E',8,1]),La[0]+La[8]) sage: M2 = crystals.NakajimaMonomials(['E',8,1],M.Lambda()[0] + M.Lambda()[8]) sage: M is M1 is M2 True """ cartan_type = CartanType(cartan_type) if cartan_type.is_affine(): La = RootSystem(cartan_type).weight_lattice(extended=True)(La) else: La = RootSystem(cartan_type).weight_lattice()(La) return super(CrystalOfNakajimaMonomials, cls).__classcall__(cls, cartan_type, La)
def __classcall_private__(cls, starting_weight, cartan_type = None): """ Classcall to mend the input. Internally, the CrystalOfLSPaths code works with a ``starting_weight`` that is in the ``weight_space`` associated to the crystal. The user can, however, also input a ``cartan_type`` and the coefficients of the fundamental weights as ``starting_weight``. This code transforms the input into the right format (also necessary for UniqueRepresentation). TESTS:: sage: CrystalOfLSPaths(['A',2,1],[-1,0,1]) The crystal of LS paths of type ['A', 2, 1] and weight -Lambda[0] + Lambda[2] sage: R = RootSystem(['B',2,1]) sage: La = R.weight_space().basis() sage: C = CrystalOfLSPaths(['B',2,1],[0,0,1]) sage: B = CrystalOfLSPaths(La[2]) sage: B is C True """ if cartan_type is not None: cartan_type, starting_weight = CartanType(starting_weight), cartan_type if cartan_type.is_affine(): extended = True else: extended = False R = RootSystem(cartan_type) P = R.weight_space(extended = extended) Lambda = P.basis() offset = R.index_set()[Integer(0)] starting_weight = P.sum(starting_weight[j-offset]*Lambda[j] for j in R.index_set()) return super(CrystalOfLSPaths, cls).__classcall__(cls, starting_weight)
def __classcall_private__(cls, cartan_type, La=None, c=None): r""" Normalize input to ensure a unique representation. EXAMPLES:: sage: La = RootSystem(['E',8,1]).weight_lattice(extended=True).fundamental_weights() sage: M = crystals.NakajimaMonomials(['E',8,1],La[0]+La[8]) sage: M1 = crystals.NakajimaMonomials(CartanType(['E',8,1]),La[0]+La[8]) sage: M2 = crystals.NakajimaMonomials(['E',8,1],M.Lambda()[0] + M.Lambda()[8]) sage: M is M1 is M2 True """ if La is None: La = cartan_type cartan_type = La.parent().cartan_type() cartan_type = CartanType(cartan_type) if cartan_type.is_affine(): La = RootSystem(cartan_type).weight_lattice(extended=True)(La) else: La = RootSystem(cartan_type).weight_lattice()(La) n = len(cartan_type.index_set()) c = InfinityCrystalOfNakajimaMonomials._normalize_c(c, n) return super(CrystalOfNakajimaMonomials, cls).__classcall__(cls, cartan_type, La, c)
def __classcall__(cls, base_ring, cartan_type, level=None, twisted=False): """ Normalize arguments to ensure a unique representation. EXAMPLES:: sage: Q1 = QSystem(QQ, ['A',4]) sage: Q2 = QSystem(QQ, 'A4') sage: Q1 is Q2 True Twisted Q-systems are different from untwisted Q-systems:: sage: Q1 = QSystem(QQ, ['E',6,2], twisted=True) sage: Q2 = QSystem(QQ, ['E',6,2]) sage: Q1 is Q2 False """ cartan_type = CartanType(cartan_type) if not is_tamely_laced(cartan_type): raise ValueError("the Cartan type is not tamely-laced") if twisted and not cartan_type.is_affine() and not cartan_type.is_untwisted_affine(): raise ValueError("the Cartan type must be of twisted type") return super(QSystem, cls).__classcall__(cls, base_ring, cartan_type, level, twisted)
class CrystalOfLSPaths(UniqueRepresentation, Parent): r""" Crystal graph of LS paths generated from the straight-line path to a given weight. INPUT: - ``cartan_type`` -- the Cartan type of a finite or affine root system - ``starting_weight`` -- a weight given as a list of coefficients of the fundamental weights The crystal class of piecewise linear paths in the weight space, generated from a straight-line path from the origin to a given element of the weight lattice. OUTPUT: - a tuple of weights defining the directions of the piecewise linear segments EXAMPLES:: sage: C = CrystalOfLSPaths(['A',2,1],[-1,0,1]); C The crystal of LS paths of type ['A', 2, 1] and weight (-1, 0, 1) sage: c = C.module_generators[0]; c (-Lambda[0] + Lambda[2],) sage: [c.f(i) for i in C.index_set()] [None, None, (Lambda[1] - Lambda[2],)] sage: R = C.R; R Root system of type ['A', 2, 1] sage: Lambda = R.weight_space().basis(); Lambda Finite family {0: Lambda[0], 1: Lambda[1], 2: Lambda[2]} sage: b=C(tuple([-Lambda[0]+Lambda[2]])) sage: b==c True sage: b.f(2) (Lambda[1] - Lambda[2],) For classical highest weight crystals we can also compare the results with the tableaux implementation:: sage: C = CrystalOfLSPaths(['A',2],[1,1]) sage: list(set(C.list())) [(-Lambda[1] - Lambda[2],), (-Lambda[1] + 1/2*Lambda[2], Lambda[1] - 1/2*Lambda[2]), (-Lambda[1] + 2*Lambda[2],), (1/2*Lambda[1] - Lambda[2], -1/2*Lambda[1] + Lambda[2]), (Lambda[1] - 2*Lambda[2],), (-2*Lambda[1] + Lambda[2],), (2*Lambda[1] - Lambda[2],), (Lambda[1] + Lambda[2],)] sage: C.cardinality() 8 sage: B = CrystalOfTableaux(['A',2],shape=[2,1]) sage: B.cardinality() 8 sage: B.digraph().is_isomorphic(C.digraph()) True TESTS:: sage: C = CrystalOfLSPaths(['A',2,1],[-1,0,1]) sage: TestSuite(C).run(skip=['_test_elements', '_test_elements_eq', '_test_enumerated_set_contains', '_test_some_elements']) sage: C = CrystalOfLSPaths(['E',6],[1,0,0,0,0,0]) sage: TestSuite(C).run() REFERENCES:: .. [L] P. Littelmann, Paths and root operators in representation theory. Ann. of Math. (2) 142 (1995), no. 3, 499-525. """ @staticmethod def __classcall__(cls, cartan_type, starting_weight): """ cartan_type and starting_weight are lists, which are mutable. The class UniqueRepresentation requires immutable inputs. The following code fixes this problem. TESTS:: sage: CrystalOfLSPaths.__classcall__(CrystalOfLSPaths,['A',2,1],[-1,0,1]) The crystal of LS paths of type ['A', 2, 1] and weight (-1, 0, 1) """ cartan_type = CartanType(cartan_type) starting_weight = tuple(starting_weight) return super(CrystalOfLSPaths, cls).__classcall__(cls, cartan_type, starting_weight) def __init__(self, cartan_type, starting_weight): """ EXAMPLES:: sage: C = CrystalOfLSPaths(['A',2,1],[-1,0,1]); C The crystal of LS paths of type ['A', 2, 1] and weight (-1, 0, 1) sage: C.R Root system of type ['A', 2, 1] sage: C.weight -Lambda[0] + Lambda[2] sage: C.weight.parent() Extended weight space over the Rational Field of the Root system of type ['A', 2, 1] sage: C.module_generators [(-Lambda[0] + Lambda[2],)] """ self._cartan_type = CartanType(cartan_type) self.R = RootSystem(cartan_type) self._name = "The crystal of LS paths of type %s and weight %s"%(cartan_type,starting_weight) if self._cartan_type.is_affine(): self.extended = True if all(i>=0 for i in starting_weight): Parent.__init__(self, category = HighestWeightCrystals()) else: Parent.__init__(self, category = Crystals()) else: self.extended = False Parent.__init__(self, category = FiniteCrystals()) Lambda = self.R.weight_space(extended = self.extended).basis() offset = self.R.index_set()[Integer(0)] zero_weight = self.R.weight_space(extended = self.extended).zero() self.weight = sum([zero_weight]+[starting_weight[j-offset]*Lambda[j] for j in self.R.index_set()]) if self.weight == zero_weight: initial_element = self(tuple([])) else: initial_element = self(tuple([self.weight])) self.module_generators = [initial_element] def _repr_(self): """ EXAMPLES:: sage: CrystalOfLSPaths(['B',3],[1,1,0]) # indirect doctest The crystal of LS paths of type ['B', 3] and weight (1, 1, 0) """ return self._name class Element(ElementWrapper): """ TESTS:: sage: C = CrystalOfLSPaths(['E',6],[1,0,0,0,0,0]) sage: c=C.an_element() sage: TestSuite(c).run() """ def endpoint(self): r""" Computes the endpoint of the path. EXAMPLES:: sage: C = CrystalOfLSPaths(['A',2],[1,1]) sage: b = C.module_generators[0] sage: b.endpoint() Lambda[1] + Lambda[2] sage: b.f_string([1,2,2,1]) (-Lambda[1] - Lambda[2],) sage: b.f_string([1,2,2,1]).endpoint() -Lambda[1] - Lambda[2] sage: b.f_string([1,2]) (1/2*Lambda[1] - Lambda[2], -1/2*Lambda[1] + Lambda[2]) sage: b.f_string([1,2]).endpoint() 0 sage: b = C([]) sage: b.endpoint() 0 """ if len(self.value) > 0: return sum(self.value) return self.parent().R.weight_space(extended = self.parent().extended).zero() def compress(self): r""" Merges consecutive positively parallel steps present in the path. EXAMPLES:: sage: C = CrystalOfLSPaths(['A',2],[1,1]) sage: Lambda = C.R.weight_space().fundamental_weights(); Lambda Finite family {1: Lambda[1], 2: Lambda[2]} sage: c = C(tuple([1/2*Lambda[1]+1/2*Lambda[2], 1/2*Lambda[1]+1/2*Lambda[2]])) sage: c.compress() (Lambda[1] + Lambda[2],) """ def positively_parallel_weights(v, w): """ Checks whether the vectors ``v`` and ``w`` are positive scalar multiples of each other. """ supp = v.support() if len(supp) > 0: i = supp[0] if v[i]*w[i] > 0 and v[i]*w == w[i]*v: return True return False if len(self.value) == 0: return self q = [] curr = self.value[0] for i in range(1,len(self.value)): if positively_parallel_weights(curr,self.value[i]): curr = curr + self.value[i] else: q.append(curr) curr = self.value[i] q.append(curr) return self.parent()(tuple(q)) def split_step(self, which_step, r): r""" Splits indicated step into two parallel steps of relative lengths `r` and `1-r`. INPUT: - ``which_step`` -- a position in the tuple ``self`` - ``r`` -- a rational number between 0 and 1 EXAMPLES:: sage: C = CrystalOfLSPaths(['A',2],[1,1]) sage: b = C.module_generators[0] sage: b.split_step(0,1/3) (1/3*Lambda[1] + 1/3*Lambda[2], 2/3*Lambda[1] + 2/3*Lambda[2]) """ assert which_step in range(len(self.value)) v = self.value[which_step] return self.parent()(self.value[:which_step]+tuple([r*v,(1-r)*v])+self.value[which_step+1:]) def reflect_step(self, which_step, i): r""" Apply the `i`-th simple reflection to the indicated step in ``self``. EXAMPLES:: sage: C = CrystalOfLSPaths(['A',2],[1,1]) sage: b = C.module_generators[0] sage: b.reflect_step(0,1) (-Lambda[1] + 2*Lambda[2],) sage: b.reflect_step(0,2) (2*Lambda[1] - Lambda[2],) """ assert i in self.index_set() assert which_step in range(len(self.value)) return self.parent()(self.value[:which_step]+tuple([self.value[which_step].simple_reflection(i)])+self.value[which_step+1:]) def _string_data(self, i): r""" Computes the `i`-string data of ``self``. TESTS:: sage: C = CrystalOfLSPaths(['A',2],[1,1]) sage: b = C.module_generators[0] sage: b._string_data(1) () sage: b._string_data(2) () sage: b.f(1)._string_data(1) ((0, -1, -1),) sage: b.f(1).f(2)._string_data(2) ((0, -1, -1),) """ if len(self.value) == 0: return () # get the i-th simple coroot alv = self.value[0].parent().alphacheck()[i] # Compute the i-heights of the steps of vs steps = [v.scalar(alv) for v in self.value] # Get the wet step data minima_pos = [] ps = 0 psmin = 0 for ix in range(len(steps)): ps = ps + steps[ix] if ps < psmin: minima_pos.append((ix,ps,steps[ix])) psmin = ps return tuple(minima_pos) def epsilon(self, i): r""" Returns the distance to the beginning of the `i`-string. This method overrides the generic implementation in the category of crystals since this computation is more efficient. EXAMPLES:: sage: C = CrystalOfLSPaths(['A',2],[1,1]) sage: [c.epsilon(1) for c in C] [0, 1, 0, 0, 1, 0, 1, 2] sage: [c.epsilon(2) for c in C] [0, 0, 1, 2, 1, 1, 0, 0] """ return self.e(i,length_only=True) def phi(self, i): r""" Returns the distance to the end of the `i`-string. This method overrides the generic implementation in the category of crystals since this computation is more efficient. EXAMPLES:: sage: C = CrystalOfLSPaths(['A',2],[1,1]) sage: [c.phi(1) for c in C] [1, 0, 0, 1, 0, 2, 1, 0] sage: [c.phi(2) for c in C] [1, 2, 1, 0, 0, 0, 0, 1] """ return self.f(i,length_only=True) def e(self, i, power=1, to_string_end=False, length_only=False): r""" Returns the `i`-th crystal raising operator on ``self``. INPUT: - ``i`` -- element of the index set of the underlying root system - ``power`` -- positive integer; specifies the power of the raising operator to be applied (default: 1) - ``to_string_end`` -- boolean; if set to True, returns the dominant end of the `i`-string of ``self``. (default: False) - ``length_only`` -- boolean; if set to True, returns the distance to the dominant end of the `i`-string of ``self``. EXAMPLES:: sage: C = CrystalOfLSPaths(['A',2],[1,1]) sage: c = C[2]; c (1/2*Lambda[1] - Lambda[2], -1/2*Lambda[1] + Lambda[2]) sage: c.e(1) sage: c.e(2) (-Lambda[1] + 2*Lambda[2],) sage: c.e(2,to_string_end=True) (-Lambda[1] + 2*Lambda[2],) sage: c.e(1,to_string_end=True) (1/2*Lambda[1] - Lambda[2], -1/2*Lambda[1] + Lambda[2]) sage: c.e(1,length_only=True) 0 """ assert i in self.index_set() data = self._string_data(i) # compute the minimum i-height M on the path if len(data) == 0: M = 0 else: M = data[-1][1] max_raisings = floor(-M) if length_only: return max_raisings # set the power of e_i to apply if to_string_end: p = max_raisings else: p = power if p > max_raisings: return None # copy the vector sequence into a working vector sequence ws #!!! ws only needs to be the actual vector sequence, not some #!!! fancy crystal graph element ws = self.parent()(self.value) ix = len(data)-1 while ix >= 0 and data[ix][1] < M + p: # get the index of the current step to be processed j = data[ix][0] # find the i-height where the current step might need to be split if ix == 0: prev_ht = M + p else: prev_ht = min(data[ix-1][1],M+p) # if necessary split the step. Then reflect the wet part. if data[ix][1] - data[ix][2] > prev_ht: ws = ws.split_step(j,1-(prev_ht-data[ix][1])/(-data[ix][2])) ws = ws.reflect_step(j+1,i) else: ws = ws.reflect_step(j,i) ix = ix - 1 #!!! at this point we should return the fancy crystal graph element #!!! corresponding to the humble vector sequence ws return self.parent()(ws.compress()) def dualize(self): r""" Returns dualized path. EXAMPLES:: sage: C = CrystalOfLSPaths(['A',2],[1,1]) sage: for c in C: ... print c, c.dualize() ... (Lambda[1] + Lambda[2],) (-Lambda[1] - Lambda[2],) (-Lambda[1] + 2*Lambda[2],) (Lambda[1] - 2*Lambda[2],) (1/2*Lambda[1] - Lambda[2], -1/2*Lambda[1] + Lambda[2]) (1/2*Lambda[1] - Lambda[2], -1/2*Lambda[1] + Lambda[2]) (Lambda[1] - 2*Lambda[2],) (-Lambda[1] + 2*Lambda[2],) (-Lambda[1] - Lambda[2],) (Lambda[1] + Lambda[2],) (2*Lambda[1] - Lambda[2],) (-2*Lambda[1] + Lambda[2],) (-Lambda[1] + 1/2*Lambda[2], Lambda[1] - 1/2*Lambda[2]) (-Lambda[1] + 1/2*Lambda[2], Lambda[1] - 1/2*Lambda[2]) (-2*Lambda[1] + Lambda[2],) (2*Lambda[1] - Lambda[2],) """ if len(self.value) == 0: return self dual_path = [-v for v in self.value] dual_path.reverse() return self.parent()(tuple(dual_path)) def f(self, i, power=1, to_string_end=False, length_only=False): r""" Returns the `i`-th crystal lowering operator on ``self``. INPUT: - ``i`` -- element of the index set of the underlying root system - ``power`` -- positive integer; specifies the power of the lowering operator to be applied (default: 1) - ``to_string_end`` -- boolean; if set to True, returns the anti-dominant end of the `i`-string of ``self``. (default: False) - ``length_only`` -- boolean; if set to True, returns the distance to the anti-dominant end of the `i`-string of ``self``. EXAMPLES:: sage: C = CrystalOfLSPaths(['A',2],[1,1]) sage: c = C.module_generators[0] sage: c.f(1) (-Lambda[1] + 2*Lambda[2],) sage: c.f(1,power=2) sage: c.f(2) (2*Lambda[1] - Lambda[2],) sage: c.f(2,to_string_end=True) (2*Lambda[1] - Lambda[2],) sage: c.f(2,length_only=True) 1 sage: C = CrystalOfLSPaths(['A',2,1],[-1,-1,2]) sage: c = C.module_generators[0] sage: c.f(2,power=2) (Lambda[0] + Lambda[1] - 2*Lambda[2],) """ dual_path = self.dualize() dual_path = dual_path.e(i, power, to_string_end, length_only) if length_only: return dual_path if dual_path == None: return None return dual_path.dualize() def s(self, i): r""" Computes the reflection of ``self`` along the `i`-string. This method is more efficient than the generic implementation since it uses powers of `e` and `f` in the Littelmann model directly. EXAMPLES:: sage: C = CrystalOfLSPaths(['A',2],[1,1]) sage: c = C.module_generators[0] sage: c.s(1) (-Lambda[1] + 2*Lambda[2],) sage: c.s(2) (2*Lambda[1] - Lambda[2],) sage: C = CrystalOfLSPaths(['A',2,1],[-1,0,1]) sage: c = C.module_generators[0]; c (-Lambda[0] + Lambda[2],) sage: c.s(2) (Lambda[1] - Lambda[2],) sage: c.s(1) (-Lambda[0] + Lambda[2],) sage: c.f(2).s(1) (Lambda[0] - Lambda[1],) """ ph = self.phi(i) ep = self.epsilon(i) diff = ph - ep if diff >= 0: return self.f(i, power=diff) else: return self.e(i, power=-diff) def _latex_(self): r""" Latex method for ``self``. EXAMPLES:: sage: C = CrystalOfLSPaths(['A',2],[1,1]) sage: c = C.module_generators[0] sage: c._latex_() [\Lambda_{1} + \Lambda_{2}] """ return [latex(p) for p in self.value]
def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, index_set=None, abelian=False, **kwds): """ Select the correct parent based upon input. TESTS:: sage: LieAlgebra(QQ, abelian=True, names='x,y,z') Abelian Lie algebra on 3 generators (x, y, z) over Rational Field sage: LieAlgebra(QQ, {('e','h'): {'e':-2}, ('f','h'): {'f':2}, ....: ('e','f'): {'h':1}}, names='e,f,h') Lie algebra on 3 generators (e, f, h) over Rational Field """ # Parse associative algebra input # ----- assoc = kwds.get("associative", None) if assoc is not None: return LieAlgebraFromAssociative(assoc, names=names, index_set=index_set) # Parse input as a Cartan type # ----- ct = kwds.get("cartan_type", None) if ct is not None: from sage.combinat.root_system.cartan_type import CartanType ct = CartanType(ct) if ct.is_affine(): from sage.algebras.lie_algebras.affine_lie_algebra import AffineLieAlgebra return AffineLieAlgebra(R, cartan_type=ct, kac_moody=kwds.get("kac_moody", True)) if not ct.is_finite(): raise NotImplementedError("non-finite types are not implemented yet, see trac #14901 for details") rep = kwds.get("representation", "bracket") if rep == 'bracket': from sage.algebras.lie_algebras.classical_lie_algebra import LieAlgebraChevalleyBasis return LieAlgebraChevalleyBasis(R, ct) if rep == 'matrix': from sage.algebras.lie_algebras.classical_lie_algebra import ClassicalMatrixLieAlgebra return ClassicalMatrixLieAlgebra(R, ct) raise ValueError("invalid representation") # Parse the remaining arguments # ----- if R is None: raise ValueError("invalid arguments") check_assoc = lambda A: (isinstance(A, (Ring, MatrixSpace)) or A in Rings() or A in Algebras(R).Associative()) if arg0 in ZZ or check_assoc(arg1): # Check if we need to swap the arguments arg0, arg1 = arg1, arg0 # Parse the first argument # ----- if isinstance(arg0, dict): if not arg0: from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra return AbelianLieAlgebra(R, names, index_set) elif isinstance(next(iter(arg0.keys())), (list, tuple)): # We assume it is some structure coefficients arg1, arg0 = arg0, arg1 if isinstance(arg0, (list, tuple)): if all(isinstance(x, str) for x in arg0): # If they are all strings, then it is a list of variables names = tuple(arg0) if isinstance(arg0, str): names = tuple(arg0.split(',')) elif isinstance(names, str): names = tuple(names.split(',')) # Parse the second argument if isinstance(arg1, dict): # Assume it is some structure coefficients from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients return LieAlgebraWithStructureCoefficients(R, arg1, names, index_set, **kwds) # Otherwise it must be either a free or abelian Lie algebra if arg1 in ZZ: if isinstance(arg0, str): names = arg0 if names is None: index_set = list(range(arg1)) else: if isinstance(names, str): names = tuple(names.split(',')) if arg1 != 1 and len(names) == 1: names = tuple('{}{}'.format(names[0], i) for i in range(arg1)) if arg1 != len(names): raise ValueError("the number of names must equal the" " number of generators") if abelian: from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra return AbelianLieAlgebra(R, names, index_set) # Otherwise it is the free Lie algebra rep = kwds.get("representation", "bracket") if rep == "polynomial": # Construct the free Lie algebra from polynomials in the # free (associative unital) algebra # TODO: Change this to accept an index set once FreeAlgebra accepts one from sage.algebras.free_algebra import FreeAlgebra F = FreeAlgebra(R, names) if index_set is None: index_set = F.variable_names() # TODO: As part of #16823, this should instead construct a # subclass with specialized methods for the free Lie algebra return LieAlgebraFromAssociative(F, F.gens(), names=names, index_set=index_set) raise NotImplementedError("the free Lie algebra has only been" " implemented using polynomials in the" " free algebra, see trac ticket #16823")
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 FundamentalGroupOfExtendedAffineWeylGroup(cartan_type, prefix='pi', general_linear=None): r""" Factory for the fundamental group of an extended affine Weyl group. INPUT: - ``cartan_type`` -- a Cartan type that is either affine or finite, with the latter being a shorthand for the untwisted affinization - ``prefix`` (default: 'pi') -- string that labels the elements of the group - ``general_linear`` -- (default: None, meaning False) In untwisted type A, if True, use the universal central extension .. RUBRIC:: Fundamental group Associated to each affine Cartan type `\tilde{X}` is an extended affine Weyl group `E`. Its subgroup of length-zero elements is called the fundamental group `F`. The group `F` can be identified with a subgroup of the group of automorphisms of the affine Dynkin diagram. As such, every element of `F` can be viewed as a permutation of the set `I` of affine Dynkin nodes. Let `0 \in I` be the distinguished affine node; it is the one whose removal produces the associated finite Cartan type (call it `X`). A node `i \in I` is called *special* if some automorphism of the affine Dynkin diagram, sends `0` to `i`. The node `0` is always special due to the identity automorphism. There is a bijection of the set of special nodes with the fundamental group. We denote the image of `i` by `\pi_i`. The structure of `F` is determined as follows. - `\tilde{X}` is untwisted -- `F` is isomorphic to `P^\vee/Q^\vee` where `P^\vee` and `Q^\vee` are the coweight and coroot lattices of type `X`. The group `P^\vee/Q^\vee` consists of the cosets `\omega_i^\vee + Q^\vee` for special nodes `i`, where `\omega_0^\vee = 0` by convention. In this case the special nodes `i` are the *cominuscule* nodes, the ones such that `\omega_i^\vee(\alpha_j)` is `0` or `1` for all `j\in I_0 = I \setminus \{0\}`. For `i` special, addition by `\omega_i^\vee+Q^\vee` permutes `P^\vee/Q^\vee` and therefore permutes the set of special nodes. This permutation extends uniquely to an automorphism of the affine Dynkin diagram. - `\tilde{X}` is dual untwisted -- (that is, the dual of `\tilde{X}` is untwisted) `F` is isomorphic to `P/Q` where `P` and `Q` are the weight and root lattices of type `X`. The group `P/Q` consists of the cosets `\omega_i + Q` for special nodes `i`, where `\omega_0 = 0` by convention. In this case the special nodes `i` are the *minuscule* nodes, the ones such that `\alpha_j^\vee(\omega_i)` is `0` or `1` for all `j \in I_0`. For `i` special, addition by `\omega_i+Q` permutes `P/Q` and therefore permutes the set of special nodes. This permutation extends uniquely to an automorphism of the affine Dynkin diagram. - `\tilde{X}` is mixed -- (that is, not of the above two types) `F` is the trivial group. EXAMPLES:: sage: from sage.combinat.root_system.fundamental_group import FundamentalGroupOfExtendedAffineWeylGroup sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',3,1]); F Fundamental group of type ['A', 3, 1] sage: F.cartan_type().dynkin_diagram() 0 O-------+ | | | | O---O---O 1 2 3 A3~ sage: F.special_nodes() (0, 1, 2, 3) sage: F(1)^2 pi[2] sage: F(1)*F(2) pi[3] sage: F(3)^(-1) pi[1] sage: F = FundamentalGroupOfExtendedAffineWeylGroup("B3"); F Fundamental group of type ['B', 3, 1] sage: F.cartan_type().dynkin_diagram() O 0 | | O---O=>=O 1 2 3 B3~ sage: F.special_nodes() (0, 1) sage: F = FundamentalGroupOfExtendedAffineWeylGroup("C2"); F Fundamental group of type ['C', 2, 1] sage: F.cartan_type().dynkin_diagram() O=>=O=<=O 0 1 2 C2~ sage: F.special_nodes() (0, 2) sage: F = FundamentalGroupOfExtendedAffineWeylGroup("D4"); F Fundamental group of type ['D', 4, 1] sage: F.cartan_type().dynkin_diagram() O 4 | | O---O---O 1 |2 3 | O 0 D4~ sage: F.special_nodes() (0, 1, 3, 4) sage: (F(4), F(4)^2) (pi[4], pi[0]) sage: F = FundamentalGroupOfExtendedAffineWeylGroup("D5"); F Fundamental group of type ['D', 5, 1] sage: F.cartan_type().dynkin_diagram() 0 O O 5 | | | | O---O---O---O 1 2 3 4 D5~ sage: F.special_nodes() (0, 1, 4, 5) sage: (F(5), F(5)^2, F(5)^3, F(5)^4) (pi[5], pi[1], pi[4], pi[0]) sage: F = FundamentalGroupOfExtendedAffineWeylGroup("E6"); F Fundamental group of type ['E', 6, 1] sage: F.cartan_type().dynkin_diagram() O 0 | | O 2 | | O---O---O---O---O 1 3 4 5 6 E6~ sage: F.special_nodes() (0, 1, 6) sage: F(1)^2 pi[6] sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['D',4,2]); F Fundamental group of type ['C', 3, 1]^* sage: F.cartan_type().dynkin_diagram() O=<=O---O=>=O 0 1 2 3 C3~* sage: F.special_nodes() (0, 3) We also implement a fundamental group for `GL_n`. It is defined to be the group of integers, which is the covering group of the fundamental group Z/nZ for affine `SL_n`:: sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',2,1], general_linear=True); F Fundamental group of GL(3) sage: x = F.an_element(); x pi[5] sage: x*x pi[10] sage: x.inverse() pi[-5] sage: wt = F.cartan_type().classical().root_system().ambient_space().an_element(); wt (2, 2, 3) sage: x.act_on_classical_ambient(wt) (2, 3, 2) sage: w = WeylGroup(F.cartan_type(),prefix="s").an_element(); w s0*s1*s2 sage: x.act_on_affine_weyl(w) s2*s0*s1 """ cartan_type = CartanType(cartan_type) if cartan_type.is_finite(): cartan_type = cartan_type.affine() if not cartan_type.is_affine(): raise NotImplementedError("Cartan type is not affine") if general_linear is True: if cartan_type.is_untwisted_affine() and cartan_type.type() == "A": return FundamentalGroupGL(cartan_type, prefix) else: raise ValueError("General Linear Fundamental group is untwisted type A") return FundamentalGroupOfExtendedAffineWeylGroup_Class(cartan_type,prefix,finite=True)
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)