Path: blob/master/sage/combinat/crystals/fast_crystals.py
4096 views
r"""1Fast Rank Two Crystals2"""3#*****************************************************************************4# Copyright (C) 2007 Anne Schilling <anne at math.ucdavis.edu>5# Nicolas Thiery <nthiery at users.sf.net>6# Ben Brubaker <brubaker at math.mit.edu>7# Daniel Bump <bump at match.stanford.edu>8# Justin Walker <justin at mac.com>9#10# Distributed under the terms of the GNU General Public License (GPL)11#12# This code is distributed in the hope that it will be useful,13# but WITHOUT ANY WARRANTY; without even the implied warranty of14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU15# General Public License for more details.16#17# The full text of the GPL is available at:18#19# http://www.gnu.org/licenses/20#****************************************************************************2122from sage.structure.unique_representation import UniqueRepresentation23from sage.structure.parent import Parent24from sage.categories.classical_crystals import ClassicalCrystals25from sage.structure.element import Element, parent26from sage.combinat.root_system.cartan_type import CartanType272829class FastCrystal(UniqueRepresentation, Parent):30"""31An alternative implementation of rank 2 crystals. The root32operators are implemented in memory by table lookup. This means33that in comparison with the CrystalsOfTableaux, these crystals34are slow to instantiate but faster for computation. Implemented for35types A2, B2 and C2.3637Input: CartanType and a shape. The CartanType is ['A',2], ['B',2]38or ['C',2]. The shape is of the form [l1,l2] where l1 and l2 are39either integers or (in type B) half integers such that l1-l2 is40integral. It is assumed that l1 >= l2 >= 0. If l1 and l2 are41integers, this will produce the a crystal isomorphic to the one42obtained by CrystalOfTableaux(type, shape=[l1,l2]). Furthermore43FastCrystal(['B', 2], l1+1/2, l2+1/2) produces a crystal isomorphic44to the following crystal T::4546C = CrystalOfTableaux(['B',2], shape=[l1,l2])47D = CrystalOfSpins(['B',2])48T = TensorProductOfCrystals(C,D,C.list()[0],D.list()[0])4950The representation of elements is in term of the51Berenstein-Zelevinsky-Littelmann strings [a1, a2, ...] described52under metapost in crystals.py. Alternative representations may be53obtained by the options format="dual_string" or format="simple".54In the simple format, the element is represented by and integer,55and in the dual_string format, it is represented by the56Berenstein-Zelevinsky-Littelmann string, but the underlying57decomposition of the long Weyl group element into simple58reflections is changed.5960TESTS::6162sage: C = FastCrystal(['A',2],shape=[4,1])63sage: C.cardinality()642465sage: C.cartan_type()66['A', 2]67sage: TestSuite(C).run()68sage: C = FastCrystal(['B',2],shape=[4,1])69sage: C.cardinality()7015471sage: TestSuite(C).run()72sage: C = FastCrystal(['B',2],shape=[3/2,1/2])73sage: C.cardinality()741675sage: TestSuite(C).run()76sage: C = FastCrystal(['C',2],shape=[2,1])77sage: C.cardinality()781679sage: C = FastCrystal(['C',2],shape=[3,1])80sage: C.cardinality()813582sage: TestSuite(C).run()83"""8485@staticmethod86def __classcall__(cls, cartan_type, shape, format = "string"):87"""88Normalizes the input arguments to ensure unique representation8990EXAMPLES::9192sage: C1 = FastCrystal(['A',2], shape=(4,1))93sage: C2 = FastCrystal(CartanType(['A',2]),shape=[4,1])94sage: C1 is C295True96"""97cartan_type = CartanType(cartan_type)98shape = tuple(shape)99if len(shape) > 2:100raise ValueError, "The shape must have length <=2"101shape = shape + (0,)*(2-len(shape))102return super(FastCrystal, cls).__classcall__(cls, cartan_type, shape, format)103104def __init__(self, ct, shape, format):105"""106EXAMPLES::107108sage: C = FastCrystal(['A',2],shape=[4,1]); C109The fast crystal for A2 with shape [4,1]110sage: TestSuite(C).run()111"""112Parent.__init__(self, category = ClassicalCrystals())113# super(FastCrystal, self).__init__(category = FiniteEnumeratedSets())114self._cartan_type = ct115if ct[1] != 2:116raise NotImplementedError117118l1 = shape[0]119l2 = shape[1]120121# For safety, delpat and gampat should be immutable122123self.delpat = []124self.gampat = []125126if ct[0] == 'A':127self._type_a_init(l1, l2)128elif ct[0] == 'B' or ct[0] == 'C':129self._type_bc_init(l1, l2)130else:131raise NotImplementedError132133self.format = format134self.size = len(self.delpat)135self._rootoperators = []136self.shape = shape137138for i in range(self.size):139target = [x for x in self.delpat[i]]140141target[0] = target[0]-1142e1 = None if target not in self.delpat else self.delpat.index(target)143target[0] = target[0]+1+1144f1 = None if target not in self.delpat else self.delpat.index(target)145146target = [x for x in self.gampat[i]]147target[0] = target[0]-1148e2 = None if target not in self.gampat else self.gampat.index(target)149target[0] = target[0]+1+1150f2 = None if target not in self.gampat else self.gampat.index(target)151152self._rootoperators.append([e1,f1,e2,f2])153154if int(2*l1)%2 == 0:155l1_str = "%d"%l1156l2_str = "%d"%l2157else:158assert self._cartan_type[0] == 'B' and int(2*l2)%2 == 1159l1_str = "%d/2"%int(2*l1)160l2_str = "%d/2"%int(2*l2)161self.rename("The fast crystal for %s2 with shape [%s,%s]"%(ct[0],l1_str,l2_str))162self.module_generators = [self(0)]163# self._list = ClassicalCrystal.list(self)164self._list = super(FastCrystal, self).list()165# self._digraph = ClassicalCrystal.digraph(self)166self._digraph = super(FastCrystal, self).digraph()167self._digraph_closure = self.digraph().transitive_closure()168169def _type_a_init(self, l1, l2):170"""171EXAMPLES::172173sage: C = FastCrystal(['A',2],shape=[1,1])174sage: C.delpat # indirect doctest175[[0, 0, 0], [0, 1, 0], [1, 1, 0]]176sage: C.gampat177[[0, 0, 0], [1, 0, 0], [0, 1, 1]]178"""179for b in range(l2,-1,-1):180for a in range(l1,l2-1,-1):181for c in range(a,b-1,-1):182a3 = l1-a183a2 = l1+l2-a-b184a1 = a-c185b1 = max(a3,a2-a1)186b2 = a1+a3187b3 = min(a2-a3,a1)188self.delpat.append([a1,a2,a3])189self.gampat.append([b1,b2,b3])190191def _type_bc_init(self, l1, l2):192"""193EXAMPLES::194195sage: C = FastCrystal(['B',2],shape=[1])196sage: len(C.delpat) # indirect doctest1975198sage: len(C.gampat)1995200sage: C = FastCrystal(['C',2],shape=[1])201sage: len(C.delpat)2024203sage: len(C.gampat)2044205"""206if self._cartan_type[0] == 'B':207[m1, m2] = [l1+l2, l1-l2]208else:209[m1, m2] = [l1, l2]210for b in range(m2,-1,-1):211for a in range(m1,m2-1,-1):212for c in range(b,a+1):213for d in range(c,-1,-1):214a1 = c-d215a2 = m1+m2+c-a-2*b216a3 = m1+m2-a-b217a4 = m1-a218b1 = max(a4,2*a3-a2,a2-2*a1)219b2 = max(a3, a1+a4, a1+2*a3-a2)220b3 = min(a2, 2*a2-2*a3+a4, 2*a1+a4)221b4 = min(a1, a2-a3, a3-a4)222if self._cartan_type[0] == 'B':223self.delpat.append([a1,a2,a3,a4])224self.gampat.append([b1,b2,b3,b4])225else:226self.gampat.append([a1,a2,a3,a4])227self.delpat.append([b1,b2,b3,b4])228229def __call__(self, value):230"""231EXAMPLES::232233sage: C = FastCrystal(['A',2],shape=[2,1])234sage: C(0)235[0, 0, 0]236sage: C(1)237[1, 0, 0]238sage: x = C(0)239sage: C(x) is x240True241"""242if parent(value) is self: return value243return self.element_class(self, value, self.format)244245def list(self):246"""247Returns a list of the elements of self.248249EXAMPLES::250251sage: C = FastCrystal(['A',2],shape=[2,1])252sage: C.list()253[[0, 0, 0],254[1, 0, 0],255[0, 1, 1],256[0, 2, 1],257[1, 2, 1],258[0, 1, 0],259[1, 1, 0],260[2, 1, 0]]261"""262return self._list263264def digraph(self):265"""266Returns the digraph associated to self.267268EXAMPLES::269270sage: C = FastCrystal(['A',2],shape=[2,1])271sage: C.digraph()272Digraph on 8 vertices273"""274return self._digraph275276def cmp_elements(self, x,y):277r"""278Returns True if and only if there is a path from x to y in the279crystal graph.280281Because the crystal graph is classical, it is a directed acyclic282graph which can be interpreted as a poset. This function implements283the comparison function of this poset.284285EXAMPLES::286287sage: C = FastCrystal(['A',2],shape=[2,1])288sage: x = C(0)289sage: y = C(1)290sage: C.cmp_elements(x,y)291-1292sage: C.cmp_elements(y,x)2931294sage: C.cmp_elements(x,x)2950296"""297assert x.parent() == self and y.parent() == self298if self._digraph_closure.has_edge(x,y):299return -1300elif self._digraph_closure.has_edge(y,x):301return 1302else:303return 0304305class Element(Element):306def __init__(self, parent, value, format):307"""308EXAMPLES::309310sage: C = FastCrystal(['A',2],shape=[2,1])311sage: c = C(0); c312[0, 0, 0]313sage: C[0].parent()314The fast crystal for A2 with shape [2,1]315sage: TestSuite(c).run()316"""317Element.__init__(self, parent)318self.value = value319self.format = format320321def weight(self):322"""323Returns the weight of self.324325EXAMPLES::326327sage: [v.weight() for v in FastCrystal(['A',2], shape=[2,1])]328[(2, 1, 0), (1, 2, 0), (1, 1, 1), (1, 0, 2), (0, 1, 2), (2, 0, 1), (1, 1, 1), (0, 2, 1)]329sage: [v.weight() for v in FastCrystal(['B',2], shape=[1,0])]330[(1, 0), (0, 1), (0, 0), (0, -1), (-1, 0)]331sage: [v.weight() for v in FastCrystal(['B',2], shape=[1/2,1/2])]332[(1/2, 1/2), (1/2, -1/2), (-1/2, 1/2), (-1/2, -1/2)]333sage: [v.weight() for v in FastCrystal(['C',2], shape=[1,0])]334[(1, 0), (0, 1), (0, -1), (-1, 0)]335sage: [v.weight() for v in FastCrystal(['C',2], shape=[1,1])]336[(1, 1), (1, -1), (0, 0), (-1, 1), (-1, -1)]337"""338delpat = self.parent().delpat[self.value]339if self.parent()._cartan_type[0] == 'A':340delpat = delpat + [0,]341[alpha1, alpha2] = self.parent().weight_lattice_realization().simple_roots()342hwv = sum(self.parent().shape[i]*self.parent().weight_lattice_realization().monomial(i) for i in range(2))343return hwv - (delpat[0]+delpat[2])*alpha1 - (delpat[1]+delpat[3])*alpha2344345def _repr_(self):346"""347EXAMPLES::348349sage: C = FastCrystal(['A',2],shape=[2,1])350sage: C[0]._repr_()351'[0, 0, 0]'352"""353if self.format == "string":354return repr(self.parent().delpat[self.value])355elif self.format == "dual_string":356return repr(self.parent().gampat[self.value])357elif self.format == "simple":358return repr(self.value)359else:360raise NotImplementedError361362def __eq__(self, other):363"""364EXAMPLES::365366sage: C = FastCrystal(['A',2],shape=[2,1])367sage: D = FastCrystal(['B',2],shape=[2,1])368sage: C(0) == C(0)369True370sage: C(1) == C(0)371False372sage: C(0) == D(0)373False374"""375return self.__class__ is other.__class__ and \376self.parent() == other.parent() and \377self.value == other.value378379def __ne__(self, other):380"""381EXAMPLES::382383sage: C = FastCrystal(['A',2],shape=[2,1])384sage: D = FastCrystal(['B',2],shape=[2,1])385sage: C(0) != C(0)386False387sage: C(1) != C(0)388True389sage: C(0) != D(0)390True391"""392return not self == other393394395def __cmp__(self, other):396"""397EXAMPLES::398399sage: C = FastCrystal(['A',2],shape=[2,1])400sage: C(1) < C(2)401True402sage: C(2) < C(1)403False404sage: C(2) > C(1)405True406sage: C(1) <= C(1)407True408"""409if type(self) is not type(other):410return cmp(type(self), type(other))411if self.parent() != other.parent():412return cmp(self.parent(), other.parent())413return self.parent().cmp_elements(self, other)414415def e(self, i):416"""417Returns the action of `e_i` on self.418419EXAMPLES::420421sage: C = FastCrystal(['A',2],shape=[2,1])422sage: C(1).e(1)423[0, 0, 0]424sage: C(0).e(1) is None425True426"""427assert i in self.index_set()428if i == 1:429r = self.parent()._rootoperators[self.value][0]430else:431r = self.parent()._rootoperators[self.value][2]432return self.parent()(r) if r is not None else None433434435def f(self, i):436"""437Returns the action of `f_i` on self.438439EXAMPLES::440441sage: C = FastCrystal(['A',2],shape=[2,1])442sage: C(6).f(1)443[1, 2, 1]444sage: C(7).f(1) is None445True446"""447assert i in self.index_set()448if i == 1:449r = self.parent()._rootoperators[self.value][1]450else:451r = self.parent()._rootoperators[self.value][3]452return self.parent()(r) if r is not None else None453454455#FastCrystal.Element = FastCrystalElement456457458