def __contains__(self, x): """ Check if ``x`` is in ``self``. EXAMPLES:: sage: B = crystals.Tableaux(['A',4], shape=[2,1]) sage: S = B.subcrystal(generators=(B(2,1,1), B(5,2,4)), index_set=[1,2]) sage: B(5,2,4) in S True sage: mg = B.module_generators[0] sage: mg in S True sage: mg.f(2).f(3) in S False """ if isinstance(x, Subcrystal.Element) and x.parent() == self: return True if x in self._ambient: if not self._containing(x): return False x = self.element_class(self, x) if self in FiniteCrystals(): return x in self.list() # TODO: make this work for infinite crystals import warnings warnings.warn("Testing containment in an infinite crystal" " defaults to returning True") return True
def cardinality(self): """ Return the cardinality of ``self``. EXAMPLES:: sage: B = crystals.Tableaux(['A',4], shape=[2,1]) sage: S = B.subcrystal(generators=[B(2,1,1)], index_set=[1,2]) sage: S.cardinality() 8 sage: B = crystals.infinity.Tableaux(['A',2]) sage: S = B.subcrystal(max_depth=4) sage: S.cardinality() 22 """ if self._cardinality is not None: return self._cardinality try: card = Integer(len(self._list)) self._cardinality = card return self._cardinality except AttributeError: if self in FiniteCrystals(): return Integer(len(self.list())) card = super(Subcrystal, self).cardinality() if card == infinity: self._cardinality = card return card self._cardinality = Integer(len(self.list())) return self._cardinality
def __contains__(self, x): """ Check if ``x`` is in ``self``. EXAMPLES:: sage: B = crystals.Tableaux(['B',3], shape=[1]) sage: C = crystals.Tableaux(['D',4], shape=[2]) sage: psi = B.crystal_morphism(C.module_generators) sage: V = psi.image() sage: mg = C.module_generators[0] sage: mg in V True sage: mg.f(1) in V False sage: mg.f(1).f(1) in V True """ if not Subcrystal.__contains__(self, x): return False if self in FiniteCrystals(): if isinstance(x, self._ambient.element_class): if x.parent() == self: x = self.element_class(self, self._ambient(x)) elif x.parent() == self._ambient: x = self.element_class(self, self._ambient(x)) elif isinstance(x, self.element_class) and x.parent() != self: x = self.element_class(self, x.value) return x in self.list() return True
def __init__(self, cartan_type, classical_crystal, category=None): """ Input is an affine Cartan type 'cartan_type', a classical crystal 'classical_crystal', and automorphism and its inverse 'automorphism' and 'inverse_automorphism', and the Dynkin node 'dynkin_node' EXAMPLES:: sage: n = 1 sage: C = CrystalOfTableaux(['A',n],shape=[1]) sage: pr = attrcall("promotion") sage: pr_inverse = attrcall("promotion_inverse") sage: A = AffineCrystalFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1) # indirect doctest sage: A.list() [[[1]], [[2]]] sage: A.cartan_type() ['A', 1, 1] sage: A.index_set() [0, 1] Note: AffineCrystalFromClassical is an abstract class, so we can't test it directly. TESTS:: sage: TestSuite(A).run() """ if category is None: category = FiniteCrystals() self._cartan_type = cartan_type Parent.__init__(self, category=category) self.classical_crystal = classical_crystal self.module_generators = map(self.retract, self.classical_crystal.module_generators) self.element_class._latex_ = lambda x: x.lift()._latex_()
def __init__(self, cartan_type, r, s): r""" Initialize the KirillovReshetikhinTableaux class. INPUT: - ``cartan_type`` -- The Cartan type - ``r`` -- The number of rows - ``s`` -- The number of columns EXAMPLES:: sage: KRT = KirillovReshetikhinTableaux(['A', 4, 1], 2, 3); KRT Kirillov-Reshetikhin tableaux of type ['A', 4, 1] and shape (2, 3) sage: TestSuite(KRT).run() # long time (4s on sage.math, 2013) sage: KRT = KirillovReshetikhinTableaux(['D', 4, 1], 2, 3); KRT Kirillov-Reshetikhin tableaux of type ['D', 4, 1] and shape (2, 3) sage: TestSuite(KRT).run() # long time (53s on sage.math, 2013) sage: KRT = KirillovReshetikhinTableaux(['D', 4, 1], 4, 1); KRT Kirillov-Reshetikhin tableaux of type ['D', 4, 1] and shape (4, 1) sage: TestSuite(KRT).run() """ self._r = r self._s = s Parent.__init__(self, category=FiniteCrystals()) self.rename( "Kirillov-Reshetikhin tableaux of type %s and shape (%d, %d)" % (cartan_type, r, s)) self._cartan_type = cartan_type.classical() self.letters = CrystalOfLetters(self._cartan_type) self.module_generators = self._build_module_generators()
def __init__(self, cartan_type, B, biject_class): r""" Initialize all common elements for rigged configurations. INPUT: - ``cartan_type`` -- The Cartan type - ``B`` -- A list of dimensions `[r,s]` for rectangles of height `r` and width `s` - ``biject_class`` -- The class the bijection creates TESTS:: sage: RC = HighestWeightRiggedConfigurations(['A', 3, 1], [[3, 2], [1, 2], [1, 1]]) # indirect doctest sage: RC Highest weight rigged configurations of type ['A', 3, 1] and factors ((3, 2), (1, 2), (1, 1)) sage: RC = RiggedConfigurations(['A', 3, 1], [[3, 2], [1, 2], [1, 1]]) # indirect doctest sage: RC Rigged configurations of type ['A', 3, 1] and factors ((3, 2), (1, 2), (1, 1)) """ assert cartan_type.is_affine() self._affine_ct = cartan_type # Force to classical since we do not have e_0 and f_0 yet self._cartan_type = cartan_type.classical() self.dims = B self._bijection_class = biject_class self.rename("Rigged configurations of type %s and factors %s" % (cartan_type, B)) Parent.__init__(self, category=FiniteCrystals())
def __classcall_private__(cls, ambient, contained=None, generators=None, virtualization=None, scaling_factors=None, cartan_type=None, index_set=None, category=None): """ Normalize arguments to ensure a (relatively) unique representation. EXAMPLES:: sage: B = crystals.Tableaux(['A',4], shape=[2,1]) sage: S1 = B.subcrystal(generators=(B(2,1,1), B(5,2,4)), index_set=[1,2]) sage: S2 = B.subcrystal(generators=[B(2,1,1), B(5,2,4)], cartan_type=['A',4], index_set=(1,2)) sage: S1 is S2 True """ if isinstance(contained, (list, tuple, set, frozenset)): contained = frozenset(contained) #elif contained in Sets(): if cartan_type is None: cartan_type = ambient.cartan_type() else: cartan_type = CartanType(cartan_type) if index_set is None: index_set = cartan_type.index_set if generators is None: generators = ambient.module_generators category = Crystals().or_subcategory(category) if ambient in FiniteCrystals() or isinstance(contained, frozenset): category = category.Finite() if virtualization is not None: if scaling_factors is None: scaling_factors = {i: 1 for i in index_set} from sage.combinat.crystals.virtual_crystal import VirtualCrystal return VirtualCrystal(ambient, virtualization, scaling_factors, contained, generators, cartan_type, index_set, category) if scaling_factors is not None: # virtualization must be None virtualization = {i: (i, ) for i in index_set} from sage.combinat.crystals.virtual_crystal import VirtualCrystal return VirtualCrystal(ambient, virtualization, scaling_factors, contained, generators, cartan_type, index_set, category) # We need to give these as optional arguments so it unpickles correctly return super(Subcrystal, cls).__classcall__(cls, ambient, contained, tuple(generators), cartan_type=cartan_type, index_set=tuple(index_set), category=category)
def super_categories(self): r""" EXAMPLES:: sage: ClassicalCrystals().super_categories() [Category of finite crystals, Category of highest weight crystals] """ return [FiniteCrystals(), HighestWeightCrystals()]
def __init__(self, starting_weight): """ 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() """ 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]
def __classcall_private__(cls, ambient, virtualization, scaling_factors, contained=None, generators=None, cartan_type=None, index_set=None, category=None): """ Normalize arguments to ensure a unique representation. EXAMPLES:: sage: B = crystals.Tableaux(['B',3], shape=[1]) sage: C = crystals.Tableaux(['D',4], shape=[2]) sage: psi1 = B.crystal_morphism(C.module_generators) sage: V1 = psi1.image() sage: psi2 = B.crystal_morphism(C.module_generators, index_set=[1,2,3]) sage: V2 = psi2.image() sage: V1 is V2 True TESTS: Check that :trac:`19481` is fixed:: sage: from sage.combinat.crystals.virtual_crystal import VirtualCrystal sage: A = crystals.Tableaux(['A',3], shape=[2,1,1]) sage: V = VirtualCrystal(A, {1:(1,3), 2:(2,)}, {1:1, 2:2}, cartan_type=['C',2]) sage: V.category() Category of finite crystals """ if cartan_type is None: cartan_type = ambient.cartan_type() else: cartan_type = CartanType(cartan_type) if index_set is None: index_set = cartan_type.index_set() if generators is None: generators = ambient.module_generators virtualization = Family(virtualization) scaling_factors = Family(scaling_factors) category = Crystals().or_subcategory(category) if ambient in FiniteCrystals() or isinstance(contained, frozenset): category = category.Finite() return super(Subcrystal, cls).__classcall__(cls, ambient, virtualization, scaling_factors, contained, tuple(generators), cartan_type, tuple(index_set), category)
def __init__(self, cartan_type, weight): r""" Initialize ``self``. EXAMPLES:: sage: la = RootSystem("A2").weight_lattice().fundamental_weights() sage: B = crystals.elementary.R("A2",5*la[2]) sage: TestSuite(B).run() """ Parent.__init__(self, category = (FiniteCrystals(),HighestWeightCrystals())) self._weight = weight self._cartan_type = cartan_type self.module_generators = (self.element_class(self),)
def cardinality(self): """ Return the cardinality of ``self``. EXAMPLES:: sage: B = crystals.Tableaux(['A',4], shape=[2,1]) sage: S = B.subcrystal(generators=[B(2,1,1)], index_set=[1,2]) sage: S.cardinality() 8 sage: B = crystals.infinity.Tableaux(['A',2]) sage: S = B.subcrystal(max_depth=4) sage: S.cardinality() 22 TESTS: Check that :trac:`19481` is fixed:: sage: from sage.combinat.crystals.virtual_crystal import VirtualCrystal sage: A = crystals.infinity.Tableaux(['A',3]) sage: V = VirtualCrystal(A, {1:(1,3), 2:(2,)}, {1:1, 2:2}, cartan_type=['C',2]) sage: V.cardinality() Traceback (most recent call last): ... NotImplementedError: unknown cardinality """ if self._cardinality is not None: return self._cardinality try: card = Integer(len(self._list)) self._cardinality = card return self._cardinality except AttributeError: if self in FiniteCrystals(): return Integer(len(self.list())) try: card = super(Subcrystal, self).cardinality() except AttributeError: raise NotImplementedError("unknown cardinality") if card == infinity: self._cardinality = card return card self._cardinality = Integer(len(self.list())) return self._cardinality
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 __init__(self, cartan_type, classical_crystal, category=None): """ Input is an affine Cartan type ``cartan_type``, a classical crystal ``classical_crystal``, and automorphism and its inverse ``automorphism`` and ``inverse_automorphism``, and the Dynkin node ``dynkin_node``. EXAMPLES:: sage: n = 1 sage: C = crystals.Tableaux(['A',n],shape=[1]) sage: pr = attrcall("promotion") sage: pr_inverse = attrcall("promotion_inverse") sage: A = crystals.AffineFromClassicalAndPromotion(['A',n,1],C,pr,pr_inverse,1) # indirect doctest sage: A.list() [[[1]], [[2]]] sage: A.cartan_type() ['A', 1, 1] sage: A.index_set() (0, 1) .. NOTE:: :class:`~sage.combinat.crystals.affine.AffineCrystalFromClassical` is an abstract class, so we can't test it directly. TESTS:: sage: TestSuite(A).run() """ if category is None: category = (RegularCrystals(), FiniteCrystals()) self._cartan_type = cartan_type Parent.__init__(self, category=category) self.classical_crystal = classical_crystal self.module_generators = [ self.retract(_) for _ in self.classical_crystal.module_generators ] self.element_class._latex_ = lambda x: x.lift()._latex_()
def q_dimension(self, q=None, prec=None, use_product=False): r""" Return the `q`-dimension of ``self``. Let `B(\lambda)` denote a highest weight crystal. Recall that the degree of the `\mu`-weight space of `B(\lambda)` (under the principal gradation) is equal to `\langle \rho^{\vee}, \lambda - \mu \rangle` where `\langle \rho^{\vee}, \alpha_i \rangle = 1` for all `i \in I` (in particular, take `\rho^{\vee} = \sum_{i \in I} h_i`). The `q`-dimension of a highest weight crystal `B(\lambda)` is defined as .. MATH:: \dim_q B(\lambda) := \sum_{j \geq 0} \dim(B_j) q^j, where `B_j` denotes the degree `j` portion of `B(\lambda)`. This can be expressed as the product .. MATH:: \dim_q B(\lambda) = \prod_{\alpha^{\vee} \in \Delta_+^{\vee}} \left( \frac{1 - q^{\langle \lambda + \rho, \alpha^{\vee} \rangle}}{1 - q^{\langle \rho, \alpha^{\vee} \rangle}} \right)^{\mathrm{mult}\, \alpha}, where `\Delta_+^{\vee}` denotes the set of positive coroots. Taking the limit as `q \to 1` gives the dimension of `B(\lambda)`. For more information, see [Ka1990]_ Section 10.10. INPUT: - ``q`` -- the (generic) parameter `q` - ``prec`` -- (default: ``None``) The precision of the power series ring to use if the crystal is not known to be finite (i.e. the number of terms returned). If ``None``, then the result is returned as a lazy power series. - ``use_product`` -- (default: ``False``) if we have a finite crystal and ``True``, use the product formula EXAMPLES:: sage: C = crystals.Tableaux(['A',2], shape=[2,1]) sage: qdim = C.q_dimension(); qdim q^4 + 2*q^3 + 2*q^2 + 2*q + 1 sage: qdim(1) 8 sage: len(C) == qdim(1) True sage: C.q_dimension(use_product=True) == qdim True sage: C.q_dimension(prec=20) q^4 + 2*q^3 + 2*q^2 + 2*q + 1 sage: C.q_dimension(prec=2) 2*q + 1 sage: R.<t> = QQ[] sage: C.q_dimension(q=t^2) t^8 + 2*t^6 + 2*t^4 + 2*t^2 + 1 sage: C = crystals.Tableaux(['A',2], shape=[5,2]) sage: C.q_dimension() q^10 + 2*q^9 + 4*q^8 + 5*q^7 + 6*q^6 + 6*q^5 + 6*q^4 + 5*q^3 + 4*q^2 + 2*q + 1 sage: C = crystals.Tableaux(['B',2], shape=[2,1]) sage: qdim = C.q_dimension(); qdim q^10 + 2*q^9 + 3*q^8 + 4*q^7 + 5*q^6 + 5*q^5 + 5*q^4 + 4*q^3 + 3*q^2 + 2*q + 1 sage: qdim == C.q_dimension(use_product=True) True sage: C = crystals.Tableaux(['D',4], shape=[2,1]) sage: C.q_dimension() q^16 + 2*q^15 + 4*q^14 + 7*q^13 + 10*q^12 + 13*q^11 + 16*q^10 + 18*q^9 + 18*q^8 + 18*q^7 + 16*q^6 + 13*q^5 + 10*q^4 + 7*q^3 + 4*q^2 + 2*q + 1 We check with a finite tensor product:: sage: TP = crystals.TensorProduct(C, C) sage: TP.cardinality() 25600 sage: qdim = TP.q_dimension(use_product=True); qdim # long time q^32 + 2*q^31 + 8*q^30 + 15*q^29 + 34*q^28 + 63*q^27 + 110*q^26 + 175*q^25 + 276*q^24 + 389*q^23 + 550*q^22 + 725*q^21 + 930*q^20 + 1131*q^19 + 1362*q^18 + 1548*q^17 + 1736*q^16 + 1858*q^15 + 1947*q^14 + 1944*q^13 + 1918*q^12 + 1777*q^11 + 1628*q^10 + 1407*q^9 + 1186*q^8 + 928*q^7 + 720*q^6 + 498*q^5 + 342*q^4 + 201*q^3 + 117*q^2 + 48*q + 26 sage: qdim(1) # long time 25600 sage: TP.q_dimension() == qdim # long time True The `q`-dimensions of infinite crystals are returned as formal power series:: sage: C = crystals.LSPaths(['A',2,1], [1,0,0]) sage: C.q_dimension(prec=5) 1 + q + 2*q^2 + 2*q^3 + 4*q^4 + O(q^5) sage: C.q_dimension(prec=10) 1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6 + 9*q^7 + 13*q^8 + 16*q^9 + O(q^10) sage: qdim = C.q_dimension(); qdim 1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6 + 9*q^7 + 13*q^8 + 16*q^9 + 22*q^10 + O(x^11) sage: qdim.compute_coefficients(15) sage: qdim 1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6 + 9*q^7 + 13*q^8 + 16*q^9 + 22*q^10 + 27*q^11 + 36*q^12 + 44*q^13 + 57*q^14 + 70*q^15 + O(x^16) """ from sage.rings.all import ZZ WLR = self.weight_lattice_realization() I = self.index_set() mg = self.highest_weight_vectors() max_deg = float('inf') if prec is None else prec - 1 def iter_by_deg(gens): next = set(gens) deg = -1 while next and deg < max_deg: deg += 1 yield len(next) todo = next next = set([]) while todo: x = todo.pop() for i in I: y = x.f(i) if y is not None: next.add(y) # def iter_by_deg from sage.categories.finite_crystals import FiniteCrystals if self in FiniteCrystals(): if q is None: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing q = PolynomialRing(ZZ, 'q').gen(0) if use_product: # Since we are in the classical case, all roots occur with multiplicity 1 pos_coroots = [ x.associated_coroot() for x in WLR.positive_roots() ] rho = WLR.rho() P = q.parent() ret = P.zero() for v in self.highest_weight_vectors(): hw = v.weight() ret += P.prod((1 - q**(rho + hw).scalar(ac)) / (1 - q**rho.scalar(ac)) for ac in pos_coroots) # We do a cast since the result would otherwise live in the fraction field return P(ret) elif prec is None: # If we're here, we may not be a finite crystal. # In fact, we're probably infinite. from sage.combinat.species.series import LazyPowerSeriesRing if q is None: P = LazyPowerSeriesRing(ZZ, names='q') else: P = q.parent() if not isinstance(P, LazyPowerSeriesRing): raise TypeError( "the parent of q must be a lazy power series ring") ret = P(iter_by_deg(mg)) ret.compute_coefficients(10) return ret from sage.rings.power_series_ring import PowerSeriesRing, PowerSeriesRing_generic if q is None: q = PowerSeriesRing(ZZ, 'q', default_prec=prec).gen(0) P = q.parent() ret = P.sum(c * q**deg for deg, c in enumerate(iter_by_deg(mg))) if ret.degree() == max_deg and isinstance(P, PowerSeriesRing_generic): ret = P(ret, prec) return ret