def maximal_elements(self): r""" Return the maximal elements of ``self`` with respect to Bruhat order. The current implementation is via a conjectural type-free formula. Use maximal_elements_combinatorial() for proven type-specific implementations. To compare type-free and type-specific (combinatorial) implementations, use method :meth:`_test_maximal_elements`. EXAMPLES:: sage: W = WeylGroup(['A',4,1]) sage: PF = W.pieri_factors() sage: sorted([w.reduced_word() for w in PF.maximal_elements()], key=str) [[0, 4, 3, 2], [1, 0, 4, 3], [2, 1, 0, 4], [3, 2, 1, 0], [4, 3, 2, 1]] sage: W = WeylGroup(RootSystem(["C",3,1]).weight_space()) sage: PF = W.pieri_factors() sage: sorted([w.reduced_word() for w in PF.maximal_elements()], key=str) [[0, 1, 2, 3, 2, 1], [1, 0, 1, 2, 3, 2], [1, 2, 3, 2, 1, 0], [2, 1, 0, 1, 2, 3], [2, 3, 2, 1, 0, 1], [3, 2, 1, 0, 1, 2]] sage: W = WeylGroup(RootSystem(["B",3,1]).weight_space()) sage: PF = W.pieri_factors() sage: sorted([w.reduced_word() for w in PF.maximal_elements()], key=str) [[0, 2, 3, 2, 0], [1, 0, 2, 3, 2], [1, 2, 3, 2, 1], [2, 1, 0, 2, 3], [2, 3, 2, 1, 0], [3, 2, 1, 0, 2]] sage: W = WeylGroup(['D',4,1]) sage: PF = W.pieri_factors() sage: sorted([w.reduced_word() for w in PF.maximal_elements()], key=str) [[0, 2, 4, 3, 2, 0], [1, 0, 2, 4, 3, 2], [1, 2, 4, 3, 2, 1], [2, 1, 0, 2, 4, 3], [2, 4, 3, 2, 1, 0], [3, 2, 1, 0, 2, 3], [4, 2, 1, 0, 2, 4], [4, 3, 2, 1, 0, 2]] """ ct = self.W.cartan_type() s = ct.translation_factors()[1] R = RootSystem(ct).weight_space() Lambda = R.fundamental_weights() orbit = [ R.reduced_word_of_translation(x) for x in ( s * (Lambda[1] - Lambda[1].level() * Lambda[0]))._orbit_iter() ] return [self.W.from_reduced_word(x) for x in orbit]
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 weight_in_root_lattice(self): r""" Return the weight of ``self`` as an element of the root lattice. EXAMPLES:: sage: M = crystals.infinity.NakajimaMonomials(['F',4]) sage: m = M.module_generators[0].f_string([3,3,1,2,4]) sage: m.weight_in_root_lattice() -alpha[1] - alpha[2] - 2*alpha[3] - alpha[4] sage: M = crystals.infinity.NakajimaMonomials(['B',3,1]) sage: mg = M.module_generators[0] sage: m = mg.f_string([1,3,2,0,1,2,3,0,0,1]) sage: m.weight_in_root_lattice() -3*alpha[0] - 3*alpha[1] - 2*alpha[2] - 2*alpha[3] """ Q = RootSystem(self.parent().cartan_type()).root_lattice() alpha = Q.simple_roots() path = self.to_highest_weight() return Q(sum(-alpha[j] for j in path[1]))
def __classcall_private__(cls, starting_weight, cartan_type=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().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()) return super(CrystalOfLSPaths, cls).__classcall__(cls, starting_weight)
def __classcall_private__(cls, crystals, weight): """ Normalize input to ensure a unique representation. EXAMPLES:: sage: B = crystals.KirillovReshetikhin(['A',2,1], 1,1) sage: L = RootSystem(['A',2,1]).weight_lattice() sage: C = crystals.KyotoPathModel(B, L.fundamental_weight(0)) sage: C2 = crystals.KyotoPathModel((B,), L.fundamental_weight(0)) sage: C3 = crystals.KyotoPathModel([B], L.fundamental_weight(0)) sage: C is C2 and C2 is C3 True sage: L = RootSystem(['A',2,1]).weight_space() sage: C = KyotoPathModel(B, L.fundamental_weight(0)) Traceback (most recent call last): ... ValueError: Lambda[0] is not in the weight lattice """ if isinstance(crystals, list): crystals = tuple(crystals) elif not isinstance(crystals, tuple): crystals = (crystals, ) if any(not B.is_perfect() for B in crystals): raise ValueError("all crystals must be perfect") level = crystals[0].level() if any(B.level() != level for B in crystals[1:]): raise ValueError("all crystals must have the same level") ct = crystals[0].cartan_type() P = RootSystem(ct).weight_lattice() if weight.parent() is not P: raise ValueError("{} is not in the weight lattice".format(weight)) if sum(ct.dual().c()[i] * weight.scalar(h) for i, h in enumerate(P.simple_coroots())) != level: raise ValueError("{} is not a level {} weight".format( weight, level)) return super(KyotoPathModel, cls).__classcall__(cls, crystals, weight)
def __init__(self, cartan_type, highest_weight): """ EXAMPLES:: sage: C = ClassicalCrystalOfAlcovePaths(['A',3],[1,0,0]) sage: C.list() [[], [0], [0, 1], [0, 1, 2]] sage: TestSuite(C).run() """ Parent.__init__(self, category=ClassicalCrystals()) self._cartan_type = CartanType(cartan_type) self._name = "The crystal of alcove paths for type %s" % cartan_type self.chain_cache = {} self.endweight_cache = {} self.R = RootSystem(cartan_type) alpha = self.R.root_space().simple_roots() Lambda = self.R.weight_space().basis() self.positive_roots = sorted(self.R.root_space().positive_roots()) self.weight = Lambda[Integer(1)] - Lambda[Integer(1)] offset = self.R.index_set()[Integer(0)] for j in self.R.index_set(): self.weight = self.weight + highest_weight[j - offset] * Lambda[j] self.initial_element = self([]) self.initial_element.chain = self.get_initial_chain(self.weight) rho = (Integer(1) / Integer(2)) * sum(self.positive_roots) self.initial_element.endweight = rho self.chain_cache[str([])] = self.initial_element.chain self.endweight_cache[str([])] = self.initial_element.endweight self.module_generators = [self.initial_element] self._list = super(ClassicalCrystalOfAlcovePaths, self).list() self._digraph = super(ClassicalCrystalOfAlcovePaths, self).digraph() self._digraph_closure = self.digraph().transitive_closure()
def _reflections(self): """ A dictionary of reflections to a pair of the associated root and coroot. EXAMPLES:: sage: R = algebras.RationalCherednik(['B',2], [1,2], 1, QQ) sage: [R._reflections[k] for k in sorted(R._reflections, key=str)] [(alpha[1], alphacheck[1], 1), (alpha[1] + alpha[2], 2*alphacheck[1] + alphacheck[2], 2), (alpha[2], alphacheck[2], 2), (alpha[1] + 2*alpha[2], alphacheck[1] + alphacheck[2], 1)] """ d = {} for r in RootSystem(self._cartan_type).root_lattice().positive_roots(): s = self._weyl.from_reduced_word(r.associated_reflection()) if r.is_short_root(): c = self._c[1] else: c = self._c[0] d[s] = (r, r.associated_coroot(), c) return d
def __classcall_private__(cls, cartan_type, La): r""" Normalize input to ensure a unique representation. INPUT: - ``ct`` -- Cartan type - ``La`` -- an element of ``weight_lattice`` EXAMPLES:: sage: La = RootSystem(['E',8,1]).weight_lattice().fundamental_weights() sage: M = CrystalOfNakajimaMonomials(['E',8,1],La[0]+La[8]) sage: M1 = CrystalOfNakajimaMonomials(CartanType(['E',8,1]),La[0]+La[8]) sage: M2 = CrystalOfNakajimaMonomials(['E',8,1],M.Lambda()[0] + M.Lambda()[8]) sage: M is M1 is M2 True """ cartan_type = CartanType(cartan_type) La = RootSystem(cartan_type).weight_lattice()(La) return super(CrystalOfNakajimaMonomials, cls).__classcall__(cls, cartan_type, La)
def __init__(self, abstract_polynomial_ring, group_code, group_type, basis_name, basis_repr=None, extra_category=None): r""" TESTS:: sage: # Fix a nice test """ if (basis_repr is None): basis_repr = abstract_polynomial_ring._main_repr_var self._root_system = RootSystem(group_code) self._group_type = group_type self._basis_keys = MonomialKeyWrapper(self._root_system) FiniteRankPolynomialRingWithBasis.__init__( self, abstract_polynomial_ring, abstract_polynomial_ring.polynomial_ring_tower( ).monomial_basis_with_type(group_type), self._basis_keys, basis_name, basis_repr, extra_category=extra_category) monomial_basis = self.abstract_algebra().monomial_basis() self._to_monomial_morphism = self._module_morphism( self._to_monomial_on_basis, codomain=monomial_basis) self._from_monomial_morphism = monomial_basis._module_morphism( self._from_monomial_on_basis, codomain=self) #temp# self._to_monomial_morphism.register_as_coercion() self._from_monomial_morphism.register_as_coercion()
def __init__(self, cartan_type, prefix, finite=True): r""" EXAMPLES:: sage: from sage.combinat.root_system.fundamental_group import FundamentalGroupOfExtendedAffineWeylGroup sage: F = FundamentalGroupOfExtendedAffineWeylGroup(['A',3,1]) sage: F in Groups().Commutative().Finite() True sage: TestSuite(F).run() """ def leading_support(beta): r""" Given a dictionary with one key, return this key """ supp = beta.support() assert len(supp) == 1 return supp[0] self._cartan_type = cartan_type self._prefix = prefix special_node = cartan_type.special_node() self._special_nodes = cartan_type.special_nodes() # initialize dictionaries with the entries for the # distinguished special node # dictionary of inverse elements inverse_dict = {} inverse_dict[special_node] = special_node # dictionary for the action of special automorphisms by # permutations of the affine Dynkin nodes auto_dict = {} for i in cartan_type.index_set(): auto_dict[special_node, i] = i # dictionary for the finite Weyl component of the special automorphisms reduced_words_dict = {} reduced_words_dict[0] = tuple([]) if cartan_type.dual().is_untwisted_affine(): # this combines the computations for an untwisted affine # type and its affine dual cartan_type = cartan_type.dual() if cartan_type.is_untwisted_affine(): cartan_type_classical = cartan_type.classical() I = [i for i in cartan_type_classical.index_set()] Q = RootSystem(cartan_type_classical).root_lattice() alpha = Q.simple_roots() omega = RootSystem( cartan_type_classical).weight_lattice().fundamental_weights() W = Q.weyl_group(prefix="s") for i in self._special_nodes: if i == special_node: continue antidominant_weight, reduced_word = omega[ i].to_dominant_chamber(reduced_word=True, positive=False) reduced_words_dict[i] = tuple(reduced_word) w0i = W.from_reduced_word(reduced_word) idual = leading_support(-antidominant_weight) inverse_dict[i] = idual auto_dict[i, special_node] = i for j in I: if j == idual: auto_dict[i, j] = special_node else: auto_dict[i, j] = leading_support(w0i.action(alpha[j])) self._action = Family( self._special_nodes, lambda i: Family(cartan_type.index_set(), lambda j: auto_dict[i, j])) self._dual_node = Family(self._special_nodes, inverse_dict.__getitem__) self._reduced_words = Family(self._special_nodes, reduced_words_dict.__getitem__) if finite: cat = Category.join( (Groups().Commutative().Finite(), EnumeratedSets())) else: cat = Groups().Commutative().Infinite() Parent.__init__(self, category=cat)
def energy_function(self): r""" Return the energy function of ``self``. The energy function `D(\pi)` of the level zero LS path `\pi \in \mathbb{B}_\mathrm{cl}(\lambda)` requires a series of definitions; for simplicity the root system is assumed to be untwisted affine. The LS path `\pi` is a piecewise linear map from the unit interval `[0,1]` to the weight lattice. It is specified by "times" `0=\sigma_0<\sigma_1<\dotsm<\sigma_s=1` and "direction vectors" `x_u \lambda` where `x_u \in W/W_J` for `1\le u\le s`, and `W_J` is the stabilizer of `\lambda` in the finite Weyl group `W`. Precisely, .. MATH:: \pi(t)=\sum_{u'=1}^{u-1} (\sigma_{u'}-\sigma_{u'-1})x_{u'}\lambda+(t-\sigma_{u-1})x_{u}\lambda for `1\le u\le s` and `\sigma_{u-1} \le t \le \sigma_{u}`. For any `x,y\in W/W_J` let .. MATH:: d: x= w_{0} \stackrel{\beta_{1}}{\leftarrow} w_{1} \stackrel{\beta_{2}}{\leftarrow} \cdots \stackrel{\beta_{n}}{\leftarrow} w_{n}=y be a shortest directed path in the parabolic quantum Bruhat graph. Define .. MATH:: \mathrm{wt}(d):=\sum_{\substack{1\le k\le n \\ \ell(w_{k-1})<\ell(w_k)}} \beta_{k}^{\vee} It can be shown that `\mathrm{wt}(d)` depends only on `x,y`; call its value `\mathrm{wt}(x,y)`. The energy function `D(\pi)` is defined by .. MATH:: D(\pi)=-\sum_{u=1}^{s-1} (1-\sigma_{u}) \langle \lambda,\mathrm{wt}(x_u,x_{u+1}) \rangle For more information, see [LNSSS2013]_. REFERENCES: .. [LNSSS2013] C. Lenart, S. Naito, D. Sagaki, A. Schilling, M. Shimozono, A uniform model for Kirillov-Reshetikhin crystals. Extended abstract. DMTCS proc, to appear ( {{{:arXiv:`1211.6019`}}} ) .. NOTE:: In the dual-of-untwisted case the parabolic quantum Bruhat graph that is used is obtained by exchanging the roles of roots and coroots. Moreover, in the computation of the pairing the short roots must be doubled (or tripled for type `G`). This factor is determined by the translation factor of the corresponding root. Type `BC` is viewed as untwisted type, whereas the dual of `BC` is viewed as twisted. Except for the untwisted cases, these formulas are currently still conjectural. EXAMPLES:: sage: R = RootSystem(['C',3,1]) sage: La = R.weight_space().basis() sage: LS = CrystalOfProjectedLevelZeroLSPaths(La[1]+La[3]) sage: b = LS.module_generators[0] sage: c = b.f(1).f(3).f(2) sage: c.energy_function() 0 sage: c=b.e(0) sage: c.energy_function() 1 sage: R = RootSystem(['A',2,1]) sage: La = R.weight_space().basis() sage: LS = CrystalOfProjectedLevelZeroLSPaths(2*La[1]) sage: b = LS.module_generators[0] sage: c = b.e(0) sage: c.energy_function() 1 sage: [c.energy_function() for c in sorted(LS.list())] [0, 1, 0, 0, 0, 1, 0, 1, 0] The next test checks that the energy function is constant on classically connected components:: sage: R = RootSystem(['A',2,1]) sage: La = R.weight_space().basis() sage: LS = CrystalOfProjectedLevelZeroLSPaths(2*La[1]+La[2]) sage: G = LS.digraph(index_set=[1,2]) sage: C = G.connected_components() sage: [all(c[0].energy_function()==a.energy_function() for a in c) for c in C] [True, True, True, True] sage: R = RootSystem(['D',4,2]) sage: La = R.weight_space().basis() sage: LS = CrystalOfProjectedLevelZeroLSPaths(La[2]) sage: J = R.cartan_type().classical().index_set() sage: hw = [x for x in LS if x.is_highest_weight(J)] sage: [(x.weight(), x.energy_function()) for x in hw] [(-2*Lambda[0] + Lambda[2], 0), (-2*Lambda[0] + Lambda[1], 1), (0, 2)] sage: G = LS.digraph(index_set=J) sage: C = G.connected_components() sage: [all(c[0].energy_function()==a.energy_function() for a in c) for c in C] [True, True, True] sage: R = RootSystem(CartanType(['G',2,1]).dual()) sage: La = R.weight_space().basis() sage: LS = CrystalOfProjectedLevelZeroLSPaths(La[1]+La[2]) sage: G = LS.digraph(index_set=[1,2]) sage: C = G.connected_components() sage: [all(c[0].energy_function()==a.energy_function() for a in c) for c in C] [True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True] sage: ct = CartanType(['BC',2,2]).dual() sage: R = RootSystem(ct) sage: La = R.weight_space().basis() sage: LS = CrystalOfProjectedLevelZeroLSPaths(2*La[1]+La[2]) sage: G = LS.digraph(index_set=R.cartan_type().classical().index_set()) sage: C = G.connected_components() sage: [all(c[0].energy_function()==a.energy_function() for a in c) for c in C] [True, True, True, True, True, True, True, True, True, True, True] sage: R = RootSystem(['BC',2,2]) sage: La = R.weight_space().basis() sage: LS = CrystalOfProjectedLevelZeroLSPaths(2*La[1]+La[2]) sage: G = LS.digraph(index_set=R.cartan_type().classical().index_set()) sage: C = G.connected_components() sage: [all(c[0].energy_function()==a.energy_function() for a in c) for c in C] [True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True] """ weight = self.parent().weight P = weight.parent() c_weight = P.classical()(weight) ct = P.cartan_type() cartan = ct.classical() Qv = RootSystem(cartan).coroot_lattice() W = WeylGroup(cartan,prefix='s') J = tuple(weight.weyl_stabilizer()) L = self.weyl_group_representation() if ct.is_untwisted_affine() or ct.type() == 'BC': untwisted = True G = W.quantum_bruhat_graph(J) else: untwisted = False cartan_dual = cartan.dual() Wd = WeylGroup(cartan_dual, prefix='s') G = Wd.quantum_bruhat_graph(J) Qd = RootSystem(cartan_dual).root_lattice() dualize = lambda x: Qv.from_vector(x.to_vector()) L = [Wd.from_reduced_word(x.reduced_word()) for x in L] def stretch_short_root(a): # stretches roots by translation factor if ct.dual().type() == 'BC': return ct.c()[a.to_simple_root()]*a return ct.dual().c()[a.to_simple_root()]*a #if a.is_short_root(): # if cartan_dual.type() == 'G': # return 3*a # else: # return 2*a #return a paths = [G.shortest_path(L[i+1],L[i]) for i in range(len(L)-1)] paths_labels = [[G.edge_label(p[i],p[i+1]) for i in range(len(p)-1) if p[i].length()+1 != p[i+1].length()] for p in paths] scalars = self.scalar_factors() if untwisted: s = sum((1-scalars[i])*c_weight.scalar( Qv.sum(root.associated_coroot() for root in paths_labels[i]) ) for i in range(len(paths_labels))) if ct.type() == 'BC': return 2*s else: return s else: s = sum((1-scalars[i])*c_weight.scalar( dualize (Qd.sum(stretch_short_root(root) for root in paths_labels[i])) ) for i in range(len(paths_labels))) if ct.dual().type() == 'BC': return s/2 else: return s
def Shi(self, data, K=QQ, names=None, m=1): r""" Return the Shi arrangement. INPUT: - ``data`` -- either an integer or a Cartan type (or coercible into; see "CartanType") - ``K`` -- field (default:``QQ``) - ``names`` -- tuple of strings or ``None`` (default); the variable names for the ambient space - ``m`` -- integer (default: 1) OUTPUT: - If ``data`` is an integer `n`, return the Shi arrangement in dimension `n`, i.e. the set of `n(n-1)` hyperplanes: `\{ x_i - x_j = 0,1 : 1 \leq i \leq j \leq n \}`. This corresponds to the Shi arrangement of Cartan type `A_{n-1}`. - If ``data`` is a Cartan type, return the Shi arrangement of given type. - If `m > 1`, return the `m`-extended Shi arrangement of given type. The `m`-extended Shi arrangement of a given crystallographic Cartan type is defined by the inner product `\langle a,x \rangle = k` for `-m < k \leq m` and `a \in \Phi^+` is a positive root of the root system `\Phi`. EXAMPLES:: sage: hyperplane_arrangements.Shi(4) Arrangement of 12 hyperplanes of dimension 4 and rank 3 sage: hyperplane_arrangements.Shi("A3") Arrangement of 12 hyperplanes of dimension 4 and rank 3 sage: hyperplane_arrangements.Shi("A3",m=2) Arrangement of 24 hyperplanes of dimension 4 and rank 3 sage: hyperplane_arrangements.Shi("B4") Arrangement of 32 hyperplanes of dimension 4 and rank 4 sage: hyperplane_arrangements.Shi("B4",m=3) Arrangement of 96 hyperplanes of dimension 4 and rank 4 sage: hyperplane_arrangements.Shi("C3") Arrangement of 18 hyperplanes of dimension 3 and rank 3 sage: hyperplane_arrangements.Shi("D4",m=3) Arrangement of 72 hyperplanes of dimension 4 and rank 4 sage: hyperplane_arrangements.Shi("E6") Arrangement of 72 hyperplanes of dimension 8 and rank 6 sage: hyperplane_arrangements.Shi("E6",m=2) Arrangement of 144 hyperplanes of dimension 8 and rank 6 If the Cartan type is not crystallographic, the Shi arrangement is not defined:: sage: hyperplane_arrangements.Shi("H4") Traceback (most recent call last): ... NotImplementedError: Shi arrangements are not defined for non crystallographic Cartan types The characteristic polynomial is pre-computed using the results of [Ath1996]_:: sage: hyperplane_arrangements.Shi("A3").characteristic_polynomial() x^4 - 12*x^3 + 48*x^2 - 64*x sage: hyperplane_arrangements.Shi("A3",m=2).characteristic_polynomial() x^4 - 24*x^3 + 192*x^2 - 512*x sage: hyperplane_arrangements.Shi("C3").characteristic_polynomial() x^3 - 18*x^2 + 108*x - 216 sage: hyperplane_arrangements.Shi("E6").characteristic_polynomial() x^8 - 72*x^7 + 2160*x^6 - 34560*x^5 + 311040*x^4 - 1492992*x^3 + 2985984*x^2 sage: hyperplane_arrangements.Shi("B4",m=3).characteristic_polynomial() x^4 - 96*x^3 + 3456*x^2 - 55296*x + 331776 TESTS:: sage: h = hyperplane_arrangements.Shi(4) sage: h.characteristic_polynomial() x^4 - 12*x^3 + 48*x^2 - 64*x sage: h.characteristic_polynomial.clear_cache() # long time sage: h.characteristic_polynomial() # long time x^4 - 12*x^3 + 48*x^2 - 64*x sage: h = hyperplane_arrangements.Shi("A3",m=2) sage: h.characteristic_polynomial() x^4 - 24*x^3 + 192*x^2 - 512*x sage: h.characteristic_polynomial.clear_cache() sage: h.characteristic_polynomial() x^4 - 24*x^3 + 192*x^2 - 512*x sage: h = hyperplane_arrangements.Shi("B3",m=3) sage: h.characteristic_polynomial() x^3 - 54*x^2 + 972*x - 5832 sage: h.characteristic_polynomial.clear_cache() sage: h.characteristic_polynomial() x^3 - 54*x^2 + 972*x - 5832 """ if data in NN: cartan_type = CartanType(["A", data - 1]) else: cartan_type = CartanType(data) if not cartan_type.is_crystallographic(): raise NotImplementedError( "Shi arrangements are not defined for non crystallographic Cartan types" ) n = cartan_type.rank() h = cartan_type.coxeter_number() Ra = RootSystem(cartan_type).ambient_space() PR = Ra.positive_roots() d = Ra.dimension() H = make_parent(K, d, names) x = H.gens() hyperplanes = [] for a in PR: for const in range(-m + 1, m + 1): hyperplanes.append(sum(a[j] * x[j] for j in range(d)) - const) A = H(*hyperplanes) x = polygen(QQ, 'x') charpoly = x**(d - n) * (x - m * h)**n A.characteristic_polynomial.set_cache(charpoly) return A
def product_on_basis(self, left, right): r""" Return ``left`` multiplied by ``right`` in ``self``. EXAMPLES:: sage: R = algebras.RationalCherednik(['A',2], 1, 1, QQ) sage: a2 = R.algebra_generators()['a2'] sage: ac1 = R.algebra_generators()['ac1'] sage: a2 * ac1 # indirect doctest a2*ac1 sage: ac1 * a2 -I + a2*ac1 - s1 - s2 + 1/2*s1*s2*s1 sage: x = R.an_element() sage: [y * x for y in R.some_elements()] [0, 3*ac1 + 2*s1 + a1, 9*ac1^2 + 10*I + 6*a1*ac1 + 6*s1 + 3/2*s2 + 3/2*s1*s2*s1 + a1^2, 3*a1*ac1 + 2*a1*s1 + a1^2, 3*a2*ac1 + 2*a2*s1 + a1*a2, 3*s1*ac1 + 2*I - a1*s1, 3*s2*ac1 + 2*s2*s1 + a1*s2 + a2*s2, 3*ac1^2 - 2*s1*ac1 + 2*I + a1*ac1 + 2*s1 + 1/2*s2 + 1/2*s1*s2*s1, 3*ac1*ac2 + 2*s1*ac1 + 2*s1*ac2 - I + a1*ac2 - s1 - s2 + 1/2*s1*s2*s1] sage: [x * y for y in R.some_elements()] [0, 3*ac1 + 2*s1 + a1, 9*ac1^2 + 10*I + 6*a1*ac1 + 6*s1 + 3/2*s2 + 3/2*s1*s2*s1 + a1^2, 6*I + 3*a1*ac1 + 6*s1 + 3/2*s2 + 3/2*s1*s2*s1 - 2*a1*s1 + a1^2, -3*I + 3*a2*ac1 - 3*s1 - 3*s2 + 3/2*s1*s2*s1 + 2*a1*s1 + 2*a2*s1 + a1*a2, -3*s1*ac1 + 2*I + a1*s1, 3*s2*ac1 + 3*s2*ac2 + 2*s1*s2 + a1*s2, 3*ac1^2 + 2*s1*ac1 + a1*ac1, 3*ac1*ac2 + 2*s1*ac2 + a1*ac2] """ # Make copies of the internal dictionaries dl = dict(left[2]._monomial) dr = dict(right[0]._monomial) # If there is nothing to commute if not dl and not dr: return self.monomial((left[0], left[1] * right[1], right[2])) R = self.base_ring() I = self._cartan_type.index_set() P = PolynomialRing(R, 'x', len(I)) G = P.gens() gens_dict = {a: G[i] for i, a in enumerate(I)} Q = RootSystem(self._cartan_type).root_lattice() alpha = Q.simple_roots() alphacheck = Q.simple_coroots() def commute_w_hd(w, al): # al is given as a dictionary ret = P.one() for k in al: x = sum(c * gens_dict[i] for i, c in alpha[k].weyl_action(w)) ret *= x**al[k] ret = ret.dict() for k in ret: yield (self._hd({I[i]: e for i, e in enumerate(k) if e != 0}), ret[k]) # Do Lac Ra if they are both non-trivial if dl and dr: il = dl.keys()[0] ir = dr.keys()[0] # Compute the commutator terms = self._product_coroot_root(il, ir) # remove the generator from the elements dl[il] -= 1 if dl[il] == 0: del dl[il] dr[ir] -= 1 if dr[ir] == 0: del dr[ir] # We now commute right roots past the left reflections: s Ra = Ra' s cur = self._from_dict({(hd, s * right[1], right[2]): c * cc for s, c in terms for hd, cc in commute_w_hd(s, dr)}) cur = self.monomial((left[0], left[1], self._h(dl))) * cur # Add back in the commuted h and hd elements rem = self.monomial((left[0], left[1], self._h(dl))) rem = rem * self.monomial( (self._hd({ir: 1}), self._weyl.one(), self._h({il: 1}))) rem = rem * self.monomial((self._hd(dr), right[1], right[2])) return cur + rem if dl: # We have La Ls Lac Rs Rac, # so we must commute Lac Rs = Rs Lac' # and obtain La (Ls Rs) (Lac' Rac) ret = P.one() for k in dl: x = sum(c * gens_dict[i] for i, c in alphacheck[k].weyl_action( right[1].reduced_word(), inverse=True)) ret *= x**dl[k] ret = ret.dict() w = left[1] * right[1] return self._from_dict({ (left[0], w, self._h({I[i]: e for i, e in enumerate(k) if e != 0}) * right[2]): ret[k] for k in ret }) # Otherwise dr is non-trivial and we have La Ls Ra Rs Rac, # so we must commute Ls Ra = Ra' Ls w = left[1] * right[1] return self._from_dict({(left[0] * hd, w, right[2]): c for hd, c in commute_w_hd(left[1], dr)})
def one_dimensional_configuration_sum(self, q=None, group_components=True): r""" Compute the one-dimensional configuration sum. INPUT: - ``q`` -- (default: ``None``) a variable or ``None``; if ``None``, a variable ``q`` is set in the code - ``group_components`` -- (default: ``True``) boolean; if ``True``, then the terms are grouped by classical component The one-dimensional configuration sum is the sum of the weights of all elements in the crystal weighted by the energy function. For untwisted types it uses the parabolic quantum Bruhat graph, see [LNSSS2013]_. In the dual-of-untwisted case, the parabolic quantum Bruhat graph is defined by exchanging the roles of roots and coroots (which is still conjectural at this point). EXAMPLES:: sage: R = RootSystem(['A',2,1]) sage: La = R.weight_space().basis() sage: LS = crystals.ProjectedLevelZeroLSPaths(2*La[1]) sage: LS.one_dimensional_configuration_sum() # long time B[-2*Lambda[1] + 2*Lambda[2]] + (q+1)*B[-Lambda[1]] + (q+1)*B[Lambda[1] - Lambda[2]] + B[2*Lambda[1]] + B[-2*Lambda[2]] + (q+1)*B[Lambda[2]] sage: R.<t> = ZZ[] sage: LS.one_dimensional_configuration_sum(t, False) # long time B[-2*Lambda[1] + 2*Lambda[2]] + (t+1)*B[-Lambda[1]] + (t+1)*B[Lambda[1] - Lambda[2]] + B[2*Lambda[1]] + B[-2*Lambda[2]] + (t+1)*B[Lambda[2]] TESTS:: sage: R = RootSystem(['B',3,1]) sage: La = R.weight_space().basis() sage: LS = crystals.ProjectedLevelZeroLSPaths(La[1]+La[2]) sage: LS.one_dimensional_configuration_sum() == LS.one_dimensional_configuration_sum(group_components=False) # long time True sage: K1 = crystals.KirillovReshetikhin(['B',3,1],1,1) sage: K2 = crystals.KirillovReshetikhin(['B',3,1],2,1) sage: T = crystals.TensorProduct(K2,K1) sage: T.one_dimensional_configuration_sum() == LS.one_dimensional_configuration_sum() # long time True sage: R = RootSystem(['D',4,2]) sage: La = R.weight_space().basis() sage: LS = crystals.ProjectedLevelZeroLSPaths(La[1]+La[2]) sage: K1 = crystals.KirillovReshetikhin(['D',4,2],1,1) sage: K2 = crystals.KirillovReshetikhin(['D',4,2],2,1) sage: T = crystals.TensorProduct(K2,K1) sage: T.one_dimensional_configuration_sum() == LS.one_dimensional_configuration_sum() # long time True sage: R = RootSystem(['A',5,2]) sage: La = R.weight_space().basis() sage: LS = crystals.ProjectedLevelZeroLSPaths(3*La[1]) sage: K1 = crystals.KirillovReshetikhin(['A',5,2],1,1) sage: T = crystals.TensorProduct(K1,K1,K1) sage: T.one_dimensional_configuration_sum() == LS.one_dimensional_configuration_sum() # long time True """ if q is None: from sage.rings.all import QQ q = QQ['q'].gens()[0] #P0 = self.weight_lattice_realization().classical() P0 = RootSystem(self.cartan_type().classical()).weight_lattice() B = P0.algebra(q.parent()) def weight(x): w = x.weight() return P0.sum( int(c) * P0.basis()[i] for i, c in w if i in P0.index_set()) if group_components: G = self.digraph( index_set=self.cartan_type().classical().index_set()) C = G.connected_components() return sum(q**(c[0].energy_function()) * B.sum(B(weight(b)) for b in c) for c in C) return B.sum(q**(b.energy_function()) * B(weight(b)) for b in self)
def __init__(self, starting_weight, starting_weight_parent): """ EXAMPLES:: sage: C = crystals.LSPaths(['A',2,1],[-1,0,1]); C The crystal of LS paths of type ['A', 2, 1] and weight -Lambda[0] + Lambda[2] 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],)] TESTS:: sage: C = crystals.LSPaths(['A',2,1], [-1,0,1]) sage: TestSuite(C).run() # long time sage: C = crystals.LSPaths(['E',6], [1,0,0,0,0,0]) sage: TestSuite(C).run() sage: R = RootSystem(['C',3,1]) sage: La = R.weight_space().basis() sage: LaE = R.weight_space(extended=True).basis() sage: B = crystals.LSPaths(La[0]) sage: BE = crystals.LSPaths(LaE[0]) sage: B is BE False sage: B.weight_lattice_realization() Weight space over the Rational Field of the Root system of type ['C', 3, 1] sage: BE.weight_lattice_realization() Extended weight space over the Rational Field of the Root system of type ['C', 3, 1] """ cartan_type = starting_weight.parent().cartan_type() self.R = RootSystem(cartan_type) self.weight = starting_weight if not self.weight.parent().base_ring().has_coerce_map_from(QQ): raise ValueError( "Please use the weight space, rather than weight lattice for your weights" ) self._cartan_type = cartan_type self._name = "The crystal of LS paths of type %s and weight %s" % ( cartan_type, starting_weight) if cartan_type.is_affine(): if all(i >= 0 for i in starting_weight.coefficients()): Parent.__init__(self, category=(RegularCrystals(), HighestWeightCrystals(), InfiniteEnumeratedSets())) elif starting_weight.parent().is_extended(): Parent.__init__(self, category=(RegularCrystals(), InfiniteEnumeratedSets())) else: Parent.__init__(self, category=(RegularCrystals(), FiniteCrystals())) else: Parent.__init__(self, category=ClassicalCrystals()) if starting_weight == starting_weight.parent().zero(): initial_element = self(tuple([])) else: initial_element = self(tuple([starting_weight])) self.module_generators = [initial_element]