# HG changeset patch # User Niles Johnson # Date 1313503325 14400 # Node ID 1a8d235888828d46d4b98e725f71ef6b8a99baa6 # Parent ce324e28c3334398d3552640e2cb1520d22465a3 Kleshchev-Sheth Composition Factors diff -r ce324e28c333 -r 1a8d23588882 doc/en/reference/combinat/index.rst --- a/doc/en/reference/combinat/index.rst Mon May 23 13:36:51 2011 +0000 +++ b/doc/en/reference/combinat/index.rst Tue Aug 16 10:02:05 2011 -0400 @@ -44,6 +44,7 @@ root_systems ../sage/combinat/kazhdan_lusztig + ../sage/combinat/kleshchev_sheth crystals posets diff -r ce324e28c333 -r 1a8d23588882 sage/combinat/all.py --- a/sage/combinat/all.py Mon May 23 13:36:51 2011 +0000 +++ b/sage/combinat/all.py Tue Aug 16 10:02:05 2011 -0400 @@ -108,3 +108,5 @@ from multichoose_nk import MultichooseNK from kazhdan_lusztig import KazhdanLusztigPolynomial + +from kleshchev_sheth import KleshchevShethGroup diff -r ce324e28c333 -r 1a8d23588882 sage/combinat/kleshchev_sheth.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sage/combinat/kleshchev_sheth.py Tue Aug 16 10:02:05 2011 -0400 @@ -0,0 +1,1562 @@ +r""" +Kleshchev-Sheth Composition Factors of Weyl Modules + +Composition factors of Weyl modules for types `GL_n`, `SL_n`, `\Sigma_n`, and `SP_{2n}` +----------------------------------------------------------------------------------------- + +AUTHORS: + +- Niles Johnson (07/2011): initial version + +DESCRIPTION: + +We provide tools to calculate composition factors of some +Weyl modules over certain algebraic and symmetric groups. +These tools are based on the papers of Kleshchev-Sheth [KS99]_ and +[KS01]_, including some results of Adamovich [Ada86]_ reprinted therein. + +The tools are implemented in four classes: + +- :class:`KleshchevShethGroup`: Determines the group with which we work, + including rank and characteristic of ground field. + +- :class:`KleshchevShethWeight`: Weights and related data, including methods + for returning the relevant sets `B^+`, `B^-`, and + `\widehat{A}_\lambda`. + +- :class:`KleshchevShethIntervals`: A class for storing and manipulating the + integer intervals used to determine composition factors. + +- :class:`KleshchevShethFactors`: The composition factors of a Weyl + module. Includes methods for returning the poset of composition + factors, or a diagram thereof. + + +The main functions are +:meth:`KleshchevShethWeight.composition_factors` and +:meth:`KleshchevShethGroup.draw_diagrams`. The first of these returns +the composition factors of a given weight, as a +:class:`KleshchevShethFactors` instance. The second of these +determines the composition factors for a range of weights and returns +a graphic showing the poset of composition factors for each. + +EXAMPLES:: + + sage: Sig = KleshchevShethGroup('Sigma',168,5) + sage: w = Sig.weight(38,130) + sage: w.composition_factors().weights().list() + [(6, 162), (3, 165), (31, 137), (36, 132), (28, 140), (38, 130)] + sage: w.composition_factors().show() # draw poset of composition factors + + sage: G = KleshchevShethGroup('GL',34,3) + sage: w = G.weight(22,25) + sage: w.composition_factors().weights().list() + [(17, 30), (16, 31), (20, 27), (22, 25)] + sage: w.composition_factors().show() # draw poset of composition factors + +Nodes are colored to indicate nontrivial ext1 with the trivial module. See :meth:`KleshchevShethFactors.vertex_colors`:: + + sage: G = KleshchevShethGroup('C',142,5) + sage: w = G.weight(0) + sage: w.nontrivial_ext1() + {(30, 142): 30, (6, 142): 6} + sage: w = G.weight(30) + sage: w.composition_factors().weights().list() + [6, 26, 0, 30] + sage: w.composition_factors().show() # draw poset of composition factors + + sage: w = Sig.weight(0) + sage: w.nontrivial_ext1() + {(4, 164): (4, 164), (25, 143): (25, 143), (15, 153): (15, 153)} + sage: w = Sig.weight(25) + sage: w.composition_factors().weights().list() + [(19, 149), (15, 153), (24, 144), (0, 168), (25, 143)] + sage: w.composition_factors().show() + + +REFERENCES: + +.. [Ada86] A. M. Adamovich, The submodule lattices of Weyl modules of symplectic groups with fundamental highest weights. Vestnik Moskov. Univ. Ser. I Mat. Mekh. (1986), no. 2. + +.. [KS99] A. S. Kleshchev and J. Sheth, On extensions of simple modules over symmetric and algebraic groups, J. Algebra 221 (1999). + +.. [KS01] A. S. Kleshchev and J. Sheth, Corrigendum, J. Algebra 238, (2001). +""" + +#***************************************************************************** +# Copyright (C) 2011 Niles Johnson , +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# http://www.gnu.org/licenses/ +#***************************************************************************** + +from sage.misc.misc import verbose +from sage.structure.sage_object import SageObject +from sage.sets.family import TrivialFamily +from sage.combinat.posets.posets import Poset +from sage.plot.plot import plot + + +class KleshchevShethGroup(SageObject): + """ + Class to hold basic group data (type, rank, prime). + + INPUTS: + + - type - The type of the group; one of ``'GL'``, ``'SL'``, ``'C'``, ``'Sigma'``. + - rank - A positive integer. + - prime - Characteristic of the ground field (p > 0). + + EXAMPLES:: + + sage: G = KleshchevShethGroup('GL',10,5); G + Group GL_10 over algebraically closed field of characteristic 5 + + sage: S = KleshchevShethGroup('SL',10,3); S + Group SL_10 over algebraically closed field of characteristic 3 + + sage: C = KleshchevShethGroup('C',20,7); C + Group C_20 over algebraically closed field of characteristic 7 + + sage: Sig = KleshchevShethGroup('Sigma',35,3); Sig + Group Sigma_35 over algebraically closed field of characteristic 3 + """ + def __init__(self,type,rank,char): + """ + Initialize the class. + + EXAMPLES:: + + sage: G = KleshchevShethGroup('GL',10,5); G + Group GL_10 over algebraically closed field of characteristic 5 + + sage: S = KleshchevShethGroup('SL',10,3); S + Group SL_10 over algebraically closed field of characteristic 3 + + sage: C = KleshchevShethGroup('C',20,7); C + Group C_20 over algebraically closed field of characteristic 7 + + sage: Sig = KleshchevShethGroup('Sigma',35,3); Sig + Group Sigma_35 over algebraically closed field of characteristic 3 + """ + from sage.rings.integer_ring import ZZ + from sage.rings.arith import is_prime + if type not in ['GL','SL','C','Sigma']: + raise ValueError('input type must be one of GL, SL, C, or Sigma') + if rank not in ZZ or rank < 1: + raise ValueError('rank must be a positive integer') + if not is_prime(char): + raise ValueError('input characteristic must be prime') + self.type = type + self.rank = rank + self.prime = char + def _repr_(self): + """ + String representation. + + TESTS:: + + sage: G = KleshchevShethGroup('GL',10,5); G + Group GL_10 over algebraically closed field of characteristic 5 + """ + return "Group {0}_{1} over algebraically closed field of characteristic {2}".format(self.type,self.rank,self.prime) + def __eq__(self,other): + """ + Test equality. + + TESTS:: + + sage: G = KleshchevShethGroup('GL',10,5) + sage: H = KleshchevShethGroup('GL',10,3) + sage: K = KleshchevShethGroup('SL',10,3) + sage: L = KleshchevShethGroup('GL',10,5) + + sage: G == H + False + sage: G == K + False + sage: H == K + False + sage: G == L + True + sage: K == L + False + """ + return (self.type,self.rank,self.prime) == (other.type, other.rank, other.prime) + def weight(self,u,v=None): + """ + Returns a :class:`KleshchevShethWeight`. Two arguments are + required except for types ``C`` and ``Sigma``, where ``v`` can + be determined from ``u``. + + EXAMPLES:: + + sage: G = KleshchevShethGroup('GL',34,5) + sage: w = G.weight(12,15) + + sage: C = KleshchevShethGroup('C',12,3) + sage: w = G.weight(12) + """ + if v is None: + if self.type == 'Sigma': + v = self.rank - u + elif self.type == 'C': + v = self.rank + else: + v = u + return KleshchevShethWeight(self,(u,v)) + def allowable_weights(self): + """ + Return dict whose values are all weights of this group for + which the Kleshchev-Sheth combinatorics apply. Keys of the + dict are indices for the weights. + + TESTS:: + + sage: G = KleshchevShethGroup('GL',10,5) + sage: sorted(G.allowable_weights().keys()) + [(0, 0), (0, 1), (0, 2), ... + sage: len(G.allowable_weights().keys()) == (G.rank+1)*(G.rank+2)/2 + True + + sage: H = KleshchevShethGroup('SL',10,5) + sage: sorted(G.allowable_weights().keys()) == sorted(H.allowable_weights().keys()) + True + + sage: G = KleshchevShethGroup('C',20,5) + sage: sorted(G.allowable_weights().keys()) + [(0, 20), (1, 20), (2, 20), (3, 20)...] + sage: len(G.allowable_weights().keys()) == (G.rank+1) + True + + sage: G = KleshchevShethGroup('Sigma',10,5) + sage: sorted(G.allowable_weights().keys()) + [(0, 10), (1, 9), (2, 8), (3, 7), (4, 6), (5, 5)] + sage: G = KleshchevShethGroup('Sigma',11,5) + sage: sorted(G.allowable_weights().keys()) + [(0, 11), (1, 10), (2, 9), (3, 8), (4, 7), (5, 6)] + """ + allowable = dict() + if self.type == 'GL' or self.type == 'SL': + for v in range(self.rank+1): + for u in range(v+1): + allowable[(u,v)] = self.weight(u,v) + elif self.type == 'C': + for u in range(self.rank+1): + allowable[(u,self.rank)] = self.weight(u) + elif self.type == 'Sigma': + for u in range(int(self.rank/2)+1): + allowable[(u,self.rank-u)] = self.weight(u) + return allowable + + def draw_diagrams(self, each_width=None, each_height=None, return_graphic=False, specific_weights=None, min_factors=2, num_cols=6, **kwds): + """ + Draw composition factor diagrams for Weyl modules of this + group. Only modules whose number of composition factors is at + least ``min_factors`` will be drawn. The arguments + ``each_width`` and ``each_height`` specify the width and + height of each diagram. Due to limitations of poset plotting + and graphics array, it is often necessary to test and modify + the width and height settings. + + The keyword ``return_graphic`` can be used to store this graphic + in another variable for saving. + + EXAMPLES:: + + sage: C = KleshchevShethGroup('C',12,3) + sage: C.draw_diagrams(each_height=4) + + Draw only specific Weyl modules by using the keyword + ``specific_weights``:: + + sage: G = KleshchevShethGroup('Sigma',168,5) + sage: s = [x.indices for x in G.allowable_weights().values() if len(x.interval_set()) >= 5] + sage: G.draw_diagrams(specific_weights=s, each_width=20,each_height=10) # not tested + """ + from sage.plot.plot import text, graphics_array + from sage.functions.other import ceil + + weights = self.allowable_weights() + if specific_weights is None: + weights_keys = [] + M = 0 + for k in sorted(weights.keys()): + l = len(weights[k].interval_set()) + M = max(M,l) + if l >= min_factors: + weights_keys.append(k) + else: + weights_keys = specific_weights + M = max(len(weights[k].interval_set()) for k in weights_keys) + + if each_height is None: + if self.type == 'C': + f = 16 + else: + f = 6 + each_height = (M**(1/2))*f + if each_width is None: + each_width = each_height*2 + + A = [weights[w].composition_factors().graphics_object() for w in weights_keys] + info_args = {'rgbcolor':(0,0,0), + 'fontsize':11, + 'vertical_alignment':'bottom'} + info_image = plot(.8*each_height,(-2.5,2), rgbcolor=(0,0,0)) \ + + plot(0,(-2.5,2), rgbcolor=(0,0,0)) \ + + text('Type {0}_{1}'.format(self.type,self.rank),(0,.5*each_height), **info_args) \ + + text('p = %s'%self.prime,(0,.2*each_height), **info_args) + + A = [info_image] + A + num_rows=ceil((len(weights_keys)+1)/num_cols) + if num_rows > 0: + g = graphics_array(A,num_rows,num_cols) + else: + g = graphics_array(A) + g.show(figsize=[each_width,each_height], axes=False, **kwds) + if return_graphic: + return g + else: + return None + + + +class KleshchevShethWeight(SageObject): + r""" + Class to hold basic weight data. + + INPUTS: + + - G -- a :class:`KleshchevShethGroup` instance + - uv -- a tuple ``(u,v)`` representing a weight `\lambda` + + * For `GL_n`, `\lambda = (2^u, 1^{v-u})`, with `0 \leq u \leq v \leq n` + * For `SL_n`, `\lambda = \omega_u + \omega_v`, with `0 \leq u \leq v \leq n` + * For `C_n = Sp_{2n}`, `\lambda = \omega_u`, with `0 \leq u \leq n` (`v = n`) + * for `\Sigma_n`, `\lambda = (v,u)`, with `0 \leq u \leq v \leq n` and `u + v = n` + + EXAMPLES:: + + sage: G = KleshchevShethGroup('SL',14,5) + sage: w = G.weight(2,6); w + (2, 6) + sage: G = KleshchevShethGroup('SL',14,5) + sage: w = G.weight(4,5) + sage: F = w.composition_factors() + sage: F.weights() + Finite poset containing 2 elements + sage: F.intervals().list() + [[0,1), [0,0)] + sage: F.graphics_object() # draw poset of composition factors + + sage: C = KleshchevShethGroup('C',16,3) + sage: la = C.weight(12); la + 12 + sage: la = C.weight(12) + sage: F = la.composition_factors() + sage: F.weights().list() + [4, 0, 10, 12] + sage: F.graphics_object() # draw poset of composition factors + + sage: Sig = KleshchevShethGroup('Sigma',30,5) + sage: w = Sig.weight(6,24) + sage: F = w.composition_factors() + sage: F.weights().list() + [(0, 30), (5, 25), (6, 24)] + """ + def __init__(self,G,uv): + """ + Initialize the class. + + TESTS:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethWeight + + sage: G = KleshchevShethGroup('SL',14,5) + sage: KleshchevShethWeight(G,(2,6)) + (2, 6) + + sage: C = KleshchevShethGroup('C',16,3) + sage: KleshchevShethWeight(C,12) + 12 + """ + from sage.rings.integer import Integer + self.group = G + if self.group.type == 'C' and isinstance(uv,(int,Integer)): + u = uv + v = self.group.rank + else: + u = Integer(uv[0]) + v = Integer(uv[1]) + if v < u: + u,v = v,u + if self.group.rank < v: + raise ValueError("must have u <= v <= rank") + if self.group.type == 'C': + v = self.group.rank + if self.group.type == 'Sigma' and u + v != self.group.rank: + raise ValueError("For type Sigma, must have u + v = rank") + self.indices = u,v + + self.prime = self.group.prime + self.type = self.group.type + #self.weight = self.indices + + + def _repr_(self): + """ + String representation. + + TESTS:: + + sage: G = KleshchevShethGroup('SL',14,5) + sage: G.weight(2,6) # indirect doctest + (2, 6) + + sage: C = KleshchevShethGroup('C',16,3) + sage: C.weight(12) # indirect doctest + 12 + """ + if self.group.type == 'C': + wt_str = str(self[0]) + # elif self.group.type == 'Sigma': + # wt_str = str((self[1],self[0])) + else: + wt_str = str(self.indices) + return wt_str + + def __getitem__(self,i): + return self.indices[i] + + def __eq__(self,other): + return self.group == other.group and self.indices == other.indices + + def a(self): + """ + a = v - u + 1. For type `C_n = Sp_{2n}`, `v = n`. + + EXAMPLES:: + + sage: G = KleshchevShethGroup('GL',34,5) + sage: w = G.weight(7,12) + sage: w.a() + 6 + """ + return self[1] - self[0] + 1 + def a_digits(self): + """ + Base-`p` digits of ``self.a()``. + + EXAMPLES:: + + sage: G = KleshchevShethGroup('GL',34,5) + sage: w = G.weight(7,12) + sage: w.a_digits() + [1, 1] + + sage: C = KleshchevShethGroup('C',12,3) + sage: w = C.weight(6) + sage: w.a_digits() + [1, 2] + + sage: Sig = KleshchevShethGroup('Sigma',30,5) + sage: w = Sig.weight(6,24) + sage: w.a_digits() + [4, 3] + """ + return self.a().digits(self.group.prime) + + def b_minus_plus(self): + """ + Return sets of integers `B^-` and `B^+` for this weight. Note + that `B^+` implicitly contains all k > number of base-`p` digits + of v - u + 1; that is, all k > max(`B^-`). + + EXAMPLES:: + + sage: G = KleshchevShethGroup('GL',34,5) + sage: w = G.weight(7,12) + sage: w.a_digits() + [1, 1] + sage: w.b_minus_plus() == {'plus': [0, 1], 'minus': [0, 1]} + True + + + sage: C = KleshchevShethGroup('C',12,3) + sage: w = C.weight(6) + sage: w.a_digits() + [1, 2] + sage: w.b_minus_plus() == {'plus': [0], 'minus': [0, 1]} + True + + sage: Sig = KleshchevShethGroup('Sigma',30,5) + sage: w = Sig.weight(6,24) + sage: w.a_digits() + [4, 3] + sage: w.b_minus_plus() == {'plus': [1], 'minus': [0, 1]} + True + """ + L = self.a_digits() + verbose("base-"+str(self.prime)+" digits of i-j+1="+str(self[1]-self[0]+1)+" "+str(L)) + Bminus = [] + Bplus = [] + for k in range(len(L)): + if L[k] != 0: + Bminus.append(k) + if L[k] != self.prime-1: + Bplus.append(k) + B = {'minus':Bminus, 'plus':Bplus} + verbose("B is "+str(B)) + return B + + def a_hat_endpoints(self): + r""" + `\widehat{A}_{\lambda}` is a collection of unions of intervals whose + left-hand-endpoints are elements of `B^-` and whose right-hand-endpoints + are elements of `B^+`, subject to a few other restrictions. + + Note that the single intervals of `\widehat{A}_{\lambda}` + divide into a finite 'exceptional' family, and an infinite + 'generic' family. The finite family consists of those + intervals [a,b) for which b is smaller than the index of the + last non-zero digit (base `p`) of `v - u + 1`. The infinite + family consists of those intervals [a,b) for which b is larger + than this last index, which is to say b > max(`B^-`). + + This function returns pairs of endpoints corresponding to the + exceptional intervals. We deal with the infinite generic family when + computing `A_{\lambda}` (see :meth:`interval_set`). + + EXAMPLES:: + + sage: G = KleshchevShethGroup('GL',34,5) + sage: wG = G.weight(7,12) + sage: wG.a_digits() + [1, 1] + sage: wG.a_hat_endpoints() + [(0, 1)] + + sage: C30 = KleshchevShethGroup('C',30,5) + sage: wC30 = C30.weight(25) + sage: wC30.a_hat_endpoints() + [(0, 1)] + + sage: Sig = KleshchevShethGroup('Sigma',30,5) + sage: w = Sig.weight(6,24) + sage: w.a_hat_endpoints() + [(0, 1)] + """ + B = self.b_minus_plus() + + ends = [] + + for l in B['minus']: + verbose("Bminus: checking "+str(l), level=2) + for r in B['plus']: + verbose("Bplus: checking "+str(r), level=2) + if r > l: + ends.append((l,r)) + return ends + + def take_valid_unions_KS(self,L): + """ + Given a list of Kleshchev-Sheth intervals, return a new list of + Kleshchev-Sheth intervals which adds all valid unions. + + EXAMPLES:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethIntervals + sage: C = KleshchevShethGroup('C',196,5) + sage: w = C.weight(104) + sage: P = [KleshchevShethIntervals(C,w,[J]) for J in [(0,3),(1,3),(0,1),(2,3),(0,2),(1,2)]] + sage: w.take_valid_unions_KS(P) + [[0,3), [1,3), [0,1), [2,3), [0,2), [1,2), [0,1) + [2,3)] + """ + verbose("checking for valid unions..") + from sage.misc.mrange import cartesian_product_iterator + CPI = cartesian_product_iterator((L,L)) + for I1,I2 in CPI: + verbose("I1,I2 = "+str(I1)+","+str(I2), level=2) + if I1.less_than(I2): + I_new = I1 + I2 + if I_new.in_A(): + verbose("appending "+str(I_new)) + L.append(I_new) # note that new items are included in the CPI + if I2.less_than(I1): + I_new = I2 + I1 + if I_new.in_A() and I_new not in L: # don't add duplicates + verbose("appending "+str(I_new)) + L.append(I_new) # note that new items are included in the CPI + return L + + + def in_interval_set(self,I): + """ + Given Kleshchev-Sheth interval ``I``, determine whether ``I`` + is in the interval set of self. + + EXAMPLES:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethIntervals + sage: C = KleshchevShethGroup('C',196,5) + sage: w = C.weight(104) + sage: P = [KleshchevShethIntervals(C,w,[J]) for J in [(0,3),(1,3),(0,1),(2,3),(0,2),(1,2)]] + sage: w.in_interval_set(P[0]) + True + sage: w.in_interval_set(P[2]) + True + sage: w.interval_set() + [[0,1), [0,2), [1,2), [0,3), [1,3), [2,3), [0,1) + [2,3), [0,0)] + """ + if self.group.type == 'C': + return 2*I.delta() <= self[0] + else: + return (I.delta() <= self[0] and I.delta() <= self.group.rank-self[1]) + + + def interval_set(self): + """ + Return set of intervals, `A_lambda`. + + The function :meth:`a_hat_endpoints` returns the endpoints of the + finite family of 'exceptional' intervals, this function + additionally determines how many elements from the infinite + 'generic' family of intervals which are in + `\widehat{A}_{\lambda}` should be included in `A_{\lambda}` + (note that this is necessarily a finite number). + + EXAMPLES:: + + + sage: G = KleshchevShethGroup('GL',34,5) + sage: w = G.weight(4,5) + sage: w.interval_set() + [[0,1), [0,0)] + sage: w = G.weight(10,27) + sage: w.interval_set() + [[0,1), [0,2), [0,0)] + + + sage: C = KleshchevShethGroup('C',30,3) + sage: w = C.weight(6) + sage: w.interval_set() + [[0,3), [1,3), [0,0)] + + sage: Sig = KleshchevShethGroup('Sigma',30,5) + sage: w = Sig.weight(6,24) + sage: w.interval_set() + [[0,1), [0,2), [0,0)] + """ + # shorthand function + KSI = lambda I: KleshchevShethIntervals(self.group, + self, + [I]) + B = self.b_minus_plus() + M = max(B['minus']) + Ahat = [KSI(t) for t in self.a_hat_endpoints()] + + output = [] + + # first, check all the intervals in Ahat + for I in Ahat: + # d = I.delta() + # verbose("delta_"+str(I)+" = "+str(d)) + if self.in_interval_set(I): + output.append(I) + + # second, determine which intervals of the form [a,m) should be + # included, with a in B['minus'] and m > M. + verbose("now checking generic family..") + for a in B['minus']: + m = M+1 + I = KSI((a,m)) + # d = I.delta() + while self.in_interval_set(I): + verbose("appending {0}".format(I)) + output.append(I) + m += 1 + I = KSI((a,m)) + + # finally, determine which finite unions should be included + output = self.take_valid_unions_KS(output) + + output.append(KSI((0,0))) # include the empty set + return output + + def to_cf(self,I): + """ + Convert ``I`` to composition factor: return weight of + composition factor corresponding to this interval (or union of + intervals). + + EXAMPLES:: + + sage: G = KleshchevShethGroup('GL',34,5) + sage: w = G.weight(10,27) + sage: P = w.interval_set() + sage: P[0].delta() + 2 + sage: w.to_cf(P[0]) + (8, 29) + sage: P[1].delta() + 7 + sage: w.to_cf(P[1]) + (3, 34) + + sage: C = KleshchevShethGroup('C',12,3) + sage: w = C.weight(6) + sage: P = w.interval_set(); P + [[0,2), [1,2), [0,0)] + sage: P[1].delta() + 3 + sage: w.to_cf(P[1]) + 0 + + sage: Sig = KleshchevShethGroup('Sigma',30,5) + sage: w = Sig.weight(6,24) + sage: P = w.interval_set(); P + [[0,1), [0,2), [0,0)] + sage: P[1].delta() + 6 + sage: w.to_cf(P[1]) + (0, 30) + """ + if self.type == 'C': + cf_weight = (self[0] - 2*I.delta(), self.group.rank) + else: + cf_weight = (self[0] - I.delta(), self[1] + I.delta()) + return self.group.weight(*cf_weight) + + def composition_factors(self): + """ + Return composition factors of self. This is an instance of + :class:`KleshchevShethFactors`. + + EXAMPLES:: + + sage: G = KleshchevShethGroup('GL',34,5) + sage: w = G.weight(10,27) + sage: w.composition_factors() + Composition factors for Weyl module with highest weight (10, 27) for Group GL_34 over algebraically closed field of characteristic 5 + sage: w.composition_factors().weights().list() + [(3, 34), (8, 29), (10, 27)] + sage: w.composition_factors().graphics_object() # draw poset of composition factors (not tested) + """ + return KleshchevShethFactors(self.group,self) + + def ext1(self,other): + r""" + Determine rank of `\text{Ext}^1_G(\text{self},\text{other})` = + `\text{Ext}^1_G(\text{other},\text{self})`. + + EXAMPLES:: + + sage: G = KleshchevShethGroup('GL',34,5) + sage: w = G.weight(10,27) + sage: w.ext1(G.weight(13,24)) + 1 + sage: w.ext1(G.weight(10,24)) + 0 + + sage: Sig = KleshchevShethGroup('Sigma',30,5) + sage: w = Sig.weight(6,24) + sage: w.ext1(Sig.weight(3,27)) + 0 + sage: w.ext1(Sig.weight(10,20)) + 1 + """ + if self.group != other.group: + raise ValueError("self and other must be weights for the same groups") + u,v = self.indices + r,s = other.indices + + # the algorithm below is only accurate for u >= r + if u < r: + return other.ext1(self) + + if self.type == 'GL' or self.type == 'SL': + if s-v != u-r: + return 0 + + if self.type == 'C': + c = 2 + m = u + else: + c = 1 + m = min(u,self.group.rank-v) + a = self.a_digits() + a.append(0) + # use erratta to Kleshchev-Sheth + for i in range(len(a)-1): + if a[i] > 0 and u-r == c*(self.prime - a[i])*self.prime**i: + if a[i+1] < self.prime - 1 or m < c*self.prime**(i+1): + return 1 + return 0 + + + def nontrivial_ext1(self): + """ + Return all allowable weights of self.group which have + nontrivial ext1 with self. Keys are tuples ``(u,v)``, values + are corresponding :class:`KleshchevShethWeight` instances. + + EXAMPLES:: + + sage: G = KleshchevShethGroup('GL',105,5) + sage: w = G.weight(15,33) + sage: w.a_digits() + [4, 3] + sage: sorted(w.nontrivial_ext1().keys()) + [(5, 43), (14, 34), (19, 29)] + + sage: G = KleshchevShethGroup('Sigma',23,5) + sage: w = G.weight(10) + sage: sorted(w.nontrivial_ext1().keys()) + [(9, 14)] + + sage: m = G.weight(3) + sage: sorted(m.nontrivial_ext1().keys()) + [(1, 22), (6, 17)] + + sage: G = KleshchevShethGroup('C',16,5) + sage: w = G.weight(4) + sage: sorted(w.nontrivial_ext1().keys()) + [(0, 16), (10, 16)] + + sage: G = KleshchevShethGroup('C',30,3) + sage: w = G.weight(18) + sage: sorted(w.nontrivial_ext1().keys()) + [(6, 30), (14, 30), (20, 30), (24, 30)] + + """ + wts = self.group.allowable_weights() + nontriv = dict() + for rs in wts.keys(): + if self.ext1(wts[rs]) != 0: + nontriv[rs] = wts[rs] + return nontriv + + def has_composition_factor(self,other=None): + """ + Return True if ``other`` weight is a composition factor of + Weyl module with highest weight ``self``. Default input + checks ``other`` = trivial module. + + EXAMPLES:: + + sage: G = KleshchevShethGroup('GL',105,5) + sage: w = G.weight(15,33) + sage: w.has_composition_factor(G.weight(5,43)) + True + sage: w.has_composition_factor(G.weight(19,29)) + False + sage: G.weight(19,29).has_composition_factor(w) + True + """ + if other is None: + other = self.group.weight(0) + for I in self.interval_set(): + if self.to_cf(I) == other: + return True + return False + + + + + + +from sage.sets.family import TrivialFamily +class KleshchevShethIntervals(TrivialFamily): + """ + A bookkeeping class for the index intervals in Kleshchev-Sheth. This + implements union of intervals as addition, checking to see that the + endpoint condition for unions is met. + + Each instance of this class represents a single element of `\widehat{A}`, + that is, it defines an interval or a union of intervals, but we do not + enforce restrictions on the value of ``delta``. + + EXAMPLES:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethIntervals + sage: G = KleshchevShethGroup('C',30,3) + sage: w = G.weight(6) + sage: I = KleshchevShethIntervals(G,w,[(0,3)]); I + [0,3) + sage: I.list() # list of the integers in this union of intervals + [0, 1, 2] + sage: I.is_valid() # is this a valid element of A? + True + + sage: J = KleshchevShethIntervals(G,w,[(0,3),(1,3)]); J + [0,3) + [1,3) + sage: J.list() + [0, 1, 2, 1, 2] + sage: J.is_valid() + False + + sage: J.contains(I) + True + sage: I.less_than(J) + False + + sage: K = KleshchevShethIntervals(G,w,[(7,9)]); K + [7,9) + sage: K.list() + [7, 8] + sage: K.is_valid() + False + + sage: I.less_than(K) + True + """ + def __init__(self,G,weight,endpoint_list=None): + """ + Initialize the class. + + TESTS:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethIntervals + sage: G = KleshchevShethGroup('C',30,3) + sage: w = G.weight(6) + sage: I = KleshchevShethIntervals(G,w,[(0,3)]); I + [0,3) + """ + elements = [] + for I in endpoint_list: + elements += range(I[0],I[1]) + TrivialFamily.__init__(self,elements) + self.group = G + self.type = self.group.type + self.rank = self.group.rank + self._rank = self.rank + self.weight = weight + self._weight = self.weight + self.j = self.weight[0] + self.i = self.weight[1] + self.prime = self.group.prime + self._prime = self.prime + self.endpoint_list = endpoint_list + self._endpoint_list = self.endpoint_list + self._delta = None + def _repr_(self): + """ + String representation. + + TESTS:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethIntervals + sage: G = KleshchevShethGroup('C',30,3) + sage: w = G.weight(6) + sage: I = KleshchevShethIntervals(G,w,[(0,3)]); I # indirect doctest + [0,3) + """ + intervals = ["[%s,%s)"%(I[0],I[1]) for I in self._endpoint_list] + return " + ".join(intervals) + def _cmp_check_(self,other): + """ + For comparisons and arithmetic, check that self and other are both + instances of KleshchevShethIntervals and have the same rank, weight, + prime. + + TESTS:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethIntervals + sage: G = KleshchevShethGroup('C',30,3) + sage: w = G.weight(6) + sage: I = KleshchevShethIntervals(G,w,[(0,3)]); I + [0,3) + sage: J = KleshchevShethIntervals(G,w,[(5,7)]); J + [5,7) + sage: I.less_than(J) # indirect doctest + True + """ + #if not isinstance(other,KleshchevShethIntervals): + # raise TypeError("self and other must each be instances of KleshchevShethIntervals") + if not (self.rank == other.rank and \ + self.weight == other.weight and \ + self.prime == other.prime): + raise ValueError("peripheral data of self and other do not match") + return True + def __eq__(self,other): + """ + Test equality of self and other. + + TESTS:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethIntervals + sage: G = KleshchevShethGroup('C',30,3) + sage: w = G.weight(6) + sage: I = KleshchevShethIntervals(G,w,[(0,3)]); I + [0,3) + sage: J = KleshchevShethIntervals(G,w,[(0,3),(5,7)]); J + [0,3) + [5,7) + sage: I == J # indirect doctest + False + """ + try: + if self._cmp_check_(other): + return self.endpoint_list == other.endpoint_list + else: + return False + except (TypeError,ValueError): + return False + + def __add__(self,other): + """ + Union of Kleshchev-Sheth intervals. + + TESTS:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethIntervals + sage: G = KleshchevShethGroup('GL',30,7) + sage: w = G.weight(6,15) + sage: I = KleshchevShethIntervals(G,w,[(1,3)]); I + [1,3) + sage: J = KleshchevShethIntervals(G,w,[(4,7)]); J + [4,7) + sage: I+J # indirect doctest + [1,3) + [4,7) + """ + if not self._cmp_check_(other): + raise("problem with addition") + + if not max(self)+1 < min(other): + raise ValueError("not a valid union of Kleshchev-Sheth intervals") + + return KleshchevShethIntervals(self.group, \ + self.weight, \ + self.endpoint_list + other.endpoint_list) + + def less_than(self,other): + """ + Comparison by ordering on the integers; for s + t to be a valid sum of + Kleshchev-Sheth intervals, ``s.less_than(t)`` must return ``True``. + + EXAMPLES:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethIntervals + sage: G = KleshchevShethGroup('Sigma',30,3) + sage: w = G.weight(6,24) + sage: I = KleshchevShethIntervals(G,w,[(0,2)]) + sage: J = KleshchevShethIntervals(G,w,[(2,4)]) + sage: K = KleshchevShethIntervals(G,w,[(3,4)]) + sage: I.less_than(J) + False + sage: I.less_than(K) + True + """ + if not self._cmp_check_(other): + raise("problem determining comparison") + return max(self)+1 < min(other) + + def contains(self,other): + """ + True iff self contains other + + EXAMPLES:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethIntervals + sage: G = KleshchevShethGroup('Sigma',30,3) + sage: w = G.weight(6,24) + sage: I = KleshchevShethIntervals(G,w,[(0,2)]) + sage: J = KleshchevShethIntervals(G,w,[(1,4)]) + sage: K = KleshchevShethIntervals(G,w,[(0,4)]) + sage: K.contains(I) + True + sage: J.contains(I) + False + """ + if not self._cmp_check_(other): + raise("problem determining containment") + return all(i in self for i in other) + + def contained_in(self,other): + """ + True iff self is contained in other + + EXAMPLES:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethIntervals + sage: G = KleshchevShethGroup('Sigma',30,3) + sage: w = G.weight(6,24) + sage: I = KleshchevShethIntervals(G,w,[(0,2)]) + sage: J = KleshchevShethIntervals(G,w,[(1,4)]) + sage: K = KleshchevShethIntervals(G,w,[(0,4)]) + sage: K.contained_in(I) + False + sage: J.contained_in(K) + True + """ + return other.contains(self) + + def subintervals(self): + """ + Return list of subintervals + + EXAMPLES:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethIntervals + sage: G = KleshchevShethGroup('GL',55,7) + sage: w = G.weight(6,34) + sage: J = KleshchevShethIntervals(G,w,[(0,2),(3,5)]); J + [0,2) + [3,5) + sage: J.subintervals() + [[0,2), [3,5)] + """ + return [KleshchevShethIntervals(self.group, \ + self.weight, \ + [I]) + for I in self._endpoint_list] + + def is_valid(self): + """ + Return True iff self is in the set `A_{\lambda}`, not just + `\widehat{A}_{\lambda}`. + + + EXAMPLES:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethIntervals + sage: G = KleshchevShethGroup('C',30,5) + sage: w = G.weight(10) + sage: I = KleshchevShethIntervals(G,w,[(0,2)]); I + [0,2) + sage: I.is_valid() + True + sage: I = KleshchevShethIntervals(G,w,[(0,3)]); I + [0,3) + sage: I.is_valid() + False + """ + L = self.weight.a_digits() + verbose("i-j+1 = "+str(L)) + for (a,b) in self._endpoint_list: + verbose("checking (a,b) = (%s,%s)"%(a,b)) + if a >= len(L) or L[a] == 0: + return False + if b < len(L) and L[b] == self._prime - 1: + return False + if not self.in_A(): + return False + return True + + def in_A(self): + """ + Determine if self is a member of the set `A_\lambda`. + + EXAMPLES:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethIntervals + sage: G = KleshchevShethGroup('C',30,5) + sage: w = G.weight(10) + sage: I = KleshchevShethIntervals(G,w,[(0,2)]); I + [0,2) + sage: I.in_A() + True + + sage: I = KleshchevShethIntervals(G,w,[(0,3)]); I + [0,3) + sage: I.in_A() + False + """ + if self.type == 'C': + return 2*self.delta() <= self.weight[0] + else: + return (self.delta() <= self.weight[0] and self.delta() <= self.rank-self.weight[1]) + + def delta(self): + """ + Return value of `\delta_I` on self. + + EXAMPLES:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethIntervals + sage: G = KleshchevShethGroup('Sigma',30,5) + sage: w = G.weight(6,24) + sage: I = KleshchevShethIntervals(G,w,[(0,2)]); I + [0,2) + sage: I.delta() + 6 + """ + if len(self._endpoint_list) > 1: + return sum(I.delta() for I in self.subintervals()) + + else: + l = self._endpoint_list[0][0] + r = self._endpoint_list[0][1] + coeff = list(self.delta_coefficients(l,r)) + de = sum(coeff[i]*self.prime**(l+i) for i in range(len(coeff))) + verbose("delta_[{0},{1}) = {2}; coefficients are: {3}".format(l,r,de,coeff)) + return de + + + def delta_coefficients(self,l,r): + """ + This function generates a list of coefficients for delta_interval_sum. + Given left- and right-hand endpoints l and r, it returns coefficients + for `\delta_{[l,r)}`. + + EXAMPLES:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethIntervals + sage: G = KleshchevShethGroup('Sigma',30,3) + sage: w = G.weight(6,24) + sage: w.a_digits() + [1, 0, 2] + sage: I = KleshchevShethIntervals(G,w,[(0,2)]) + sage: I.delta_coefficients(0,2) + [2, 2] + sage: I.delta_coefficients(0,4) + [2, 2, 0, 2] + """ + #(n,j,p) = (self._rank, self._weight, self._prime) + L = self.weight.a_digits() + i = l + + too_big = (l >= len(L)) + + dcoeffs = [] + + while i < r: + verbose("checking i = "+str(i)) + if i == l and i < len(L): + dcoeffs.append(self.prime - 1 - L[i] + 1) + elif i < len(L): + dcoeffs.append(self.prime - 1 - L[i]) + else: + dcoeffs.append(self.prime - 1) + i += 1 + return dcoeffs + + + +class KleshchevShethFactors(SageObject): + """ + Class to hold data for Kleshchev-Sheth composition factors of a + particular Weyl module, and produce convenient output (posets or + diagrams). + + INPUTS: + + - G -- A :class:`KleshchevShethGroup` instance + - uv -- A :class:`KleshchevShethWeight` instance + + EXAMPLES:: + + sage: S = KleshchevShethGroup('SL',18,3) + sage: w = S.weight(7,11) + sage: F = w.composition_factors(); F + Composition factors for Weyl module with highest weight (7, 11) for Group SL_18 over algebraically closed field of characteristic 3 + sage: F.weights() + Finite poset containing 4 elements + sage: F.weights().list() + [(3, 15), (6, 12), (1, 17), (7, 11)] + sage: F.graphics_object() # draws poset of composition factors (not tested) + """ + + def __init__(self,G, uv): + """ + INPUTS: + + - G -- A :class:`KleshchevShethGroup` instance + - uv -- A :class:`KleshchevShethWeight` instance + + TESTS:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethFactors + sage: S = KleshchevShethGroup('SL',18,3) + sage: w = S.weight(7,11) + sage: KleshchevShethFactors(S,w) + Composition factors for Weyl module with highest weight (7, 11) for Group SL_18 over algebraically closed field of characteristic 3 + + """ + self.group = G + self.type = self.group.type + self._type = self.type + self.rank = self.group.rank + self._rank = self.rank + self.prime = self.group.prime + self._prime = self.prime + + self.weight = uv + self._weight = self.weight + self._interval_set = self.weight.interval_set() + + # self.i = i + # if self.type == "C": + # verbose("type C: i = n = {0}".format(self.rank)) + # self.i = self.rank + + + + self.default_vertex_color = '#ffffcc' # trivial ext^1 with trivial module + self._default_vertex_color = '#ffffcc' # trivial ext^1 with trivial module + self.nontriv_ext_one_vertex_color = '#ffccff' # nontrivial ext^1 with trivial module + self._nontriv_ext_one_vertex_color = '#ffccff' # nontrivial ext^1 with trivial module + self.trivial_composition_factor_vertex_color = '#ccffcc' # trivial module as a composition factor (but trivial ext^1) + self._trivial_composition_factor_vertex_color = '#ccffcc' # trivial module as a composition factor (but trivial ext^1) + + #verbose('Computing KleshchevShethFactors({0},{1},{2},{3},{4})'.format(G,n,p,j,i)) + #self._intervals = self.interval_set() + + def _repr_(self): + """ + String representation. + + TESTS:: + + sage: from sage.combinat.kleshchev_sheth import KleshchevShethFactors + sage: S = KleshchevShethGroup('SL',18,3) + sage: w = S.weight(7,11) + sage: KleshchevShethFactors(S,w) + Composition factors for Weyl module with highest weight (7, 11) for Group SL_18 over algebraically closed field of characteristic 3 + """ + return "Composition factors for Weyl module with highest weight " + \ + str(self.weight) + " for " + str(self.group) + + def intervals(self): + """ + Return poset of intervals. + + EXAMPLES:: + + sage: S = KleshchevShethGroup('SL',18,3) + sage: w = S.weight(7,11) + sage: F = w.composition_factors() + sage: F.intervals().list() + [[0,2), [1,2), [0,1), [0,0)] + + sage: G = KleshchevShethGroup('C',30,3) + sage: w = G.weight(6) + sage: F = w.composition_factors() + sage: F.intervals().list() + [[0,3), [1,3), [0,0)] + """ + intervals = self._interval_set + relations = [(str(x),str(y)) + for x in intervals + for y in intervals + if x.contains(y)] + return Poset(([str(x) for x in intervals],relations)) + + def weights(self, dual=False): + """ + Return poset of weights of composition factors. Use the + optional argument ``dual`` to return the dual poset. + + EXAMPLES:: + + sage: S = KleshchevShethGroup('SL',18,3) + sage: w = S.weight(7,11) + sage: F = w.composition_factors() + sage: F.weights().list() + [(3, 15), (6, 12), (1, 17), (7, 11)] + + sage: G = KleshchevShethGroup('C',30,3) + sage: w = G.weight(6) + sage: F = w.composition_factors() + sage: F.weights().list() + [2, 0, 6] + + + NOTES: + + As an intermediate step, we build a dictionary of composition + factor weights and their corresponding intervals -- this depends on + the fact that delta is injective. + """ + outdict = dict([(self.weight.to_cf(x),x) for x in self._interval_set]) + elements = outdict.keys() + if dual: + relations = [(y,x) for x in elements for y in elements if outdict[x].contains(outdict[y])] + else: + relations = [(x,y) for x in elements for y in elements if outdict[x].contains(outdict[y])] + + return Poset((elements,relations)) + + + def vertex_colors(self,marked_weight=None): + """ + Return vertex coloring for use with graphing composition + factors. Colors track interaction with marked weight + (default: the trivial weight). + + - nontrivial Ext^1: pink + - composition factor (but trivial ext1): green + - otherwise: yellow + + EXAMPLES:: + + sage: G = KleshchevShethGroup('C',34,3) + sage: w = G.weight(12) + sage: w.composition_factors().graphics_object() # indirect doctest + + sage: Sig = KleshchevShethGroup('Sigma',168,5) + sage: v = Sig.weight(40) + sage: v.composition_factors().show(marked_weight=v) # indirect doctest + sage: w = Sig.weight(39) + sage: w.composition_factors().show(marked_weight=v) # indirect doctest + + TESTS:: + + sage: vc = v.composition_factors().vertex_colors(marked_weight=v) + sage: [(k,vc[k]) for k in sorted(vc)] + [('#ccffcc', [(40, 128)]), ('#ffccff', [(39, 129), (25, 143)]), ('#ffffcc', [(4, 164), (29, 139), (0, 168)])] + + sage: wc = w.composition_factors().vertex_colors(marked_weight=v) + sage: [(k,wc[k]) for k in sorted(wc)] + [('#ccffcc', []), ('#ffccff', [(39, 129)]), ('#ffffcc', [(5, 163), (30, 138), (35, 133), (4, 164), (29, 139)])] + """ + if marked_weight is None: + marked_weight = self.group.weight(0) + W = self.weights() + T = self._default_vertex_color # trivial ext^1 with marked weight + N = self._nontriv_ext_one_vertex_color # nontrivial ext^1 with marked weight + F = self._trivial_composition_factor_vertex_color # marked weight as a composition factor (but trivial ext^1) + #nontriv = nontrivial_ext1(self._rank,self._prime) + #verbose("nontrivial ext1 with weights "+str(nontriv)) + colors = {T:[], N:[], F:[]} + + for v in W: + v_wt = v.element + #w = int(str(v)) # convert to python int for color dict + if v_wt.ext1(marked_weight): + colors[N].append(v_wt) + elif v_wt.has_composition_factor(marked_weight): + colors[F].append(v_wt) + else: + colors[T].append(v_wt) + return colors + + def graphics_object(self, labels="weights", color=None, dual=False, marked_weight=None, **kwds): + """ + Return the graphics object for self, for use with generic + graphics manipulations such as graphics_array. This is a + Hasse diagram for the poset of composition factors determined + by the Kleshchev-Sheth algorithm. + + The optional argument ``dual`` is passed to the + :meth:`weights` method. By default, nodes are labeled with + :meth:`vertex_colors`. Setting ``labels='intervals'`` can be + used to label with :class:`KleshchevShethIntervals` instead -- in + this case all nodes are given default color. + + EXAMPLES:: + + sage: G = KleshchevShethGroup('C',34,3) + sage: G.draw_diagrams() + sage: w = G.weight(12) + sage: w.composition_factors().graphics_object() # draw poset of composition factors (not tested) + """ + if labels == "intervals": + if color is None: + color = '#ffffcc' + base = self.intervals() + #self.intervals().show(vertex_colors = color, **kwds) + else: + if color is None: + color = self.vertex_colors(marked_weight=marked_weight) + verbose('color dict is '+str(color)) + base = self.weights(dual=dual) + #self.weights().show(vertex_colors = color, **kwds) + verbose("color: "+str(color)) + p = base.plot(vertex_colors = color, axes=False, **kwds) + if self.type == 'C': + xpad, ypad = 0.6, 0.2 + else: + xpad, ypad = 0.6, 0.2 + verbose("xmin: %s; xmax: %s"%(p.xmin(),p.xmax())) + p.set_axes_range(p.xmin()-xpad,p.xmax()+xpad,p.ymin()-ypad,p.ymax()+ypad) + # Labels on each diagram: + # p += text('$H^0(%s)$'%self._weight, + # (.5*p.xmin() + .5*p.xmax() + .5,p.ymin()+.4), + # axes=False,color=(0,0,0) + # ) \ + # + text('n=%s, p=%s'%(self._rank,self._prime), + # (.5*p.xmin() + .5*p.xmax() + .5,p.ymin()+.25), + # axes=False,color=(0,0,0)) + + return p + + def show(self, **kwds): + """ + Show graph of self. Use :meth:`save` to save the image in the current + directory. See :meth:`graphics_object` for a description of the graphic. + + EXAMPLES:: + + sage: G = KleshchevShethGroup('C',34,3) + sage: G.draw_diagrams() + sage: w = G.weight(12) + sage: w.composition_factors().show(dual=True) # draw poset of composition factors (not tested) + + """ + self.graphics_object(**kwds).show(axes=False) + + def save(self, filename=None, dirname=None, **kwds): + """ + Save png file in current directory -- this is the same graphic + returned by :meth:`graphics_object` and :meth:`show`. If ``filename`` + is omitted, a default name of the form 'poset_Gn_p_u-v.png' + is used and, if present, ``dirname`` is prepended to the + default filename. + + EXAMPLES:: + + sage: G = KleshchevShethGroup('C',34,3) + sage: w = G.weight(12) + sage: F = w.composition_factors() + sage: F.save(filename='tmp.png',labels='intervals',dual=True) # not tested + """ + p = self.graphics_object(**kwds) + if filename is None: + filename = "comp_factors_{0}{1}_{2}_{3}-{4}.png".format(self.group.type,self.rank,self.prime,self.weight.indices[0],self.weight.indices[1]) + if dirname is not None: + filename = dirname + "/" + filename + verbose("saving file '%s'"%(filename)) + p.save(filename=filename, axes=False) + + +def ext1_tests(group_type,rank,prime,return_lists=False): + """ + Test algorithms by calculating Ext^1 in two different ways. + Returns ``True`` if the two calculations agree, ``False`` if not. + + EXAMPLES:: + + sage: from sage.combinat.kleshchev_sheth import ext1_tests + sage: ext1_tests('GL',20,5) + True + + sage: ext1_tests('SL',20,3) + True + + sage: ext1_tests('C',162,5) + True + + sage: ext1_tests('Sigma',83,7) + True + + """ + G = KleshchevShethGroup(group_type,rank,prime) + ext_in_weyl_modules = [] + ext_by_calc = [] + for w in G.allowable_weights().values(): + P = w.composition_factors().weights() + for x in P.lower_covers(P.maximal_elements()[0]): + ext_in_weyl_modules.append((x.element.indices,w.indices)) + for x in w.nontrivial_ext1().values(): + if x.indices < w.indices: + ext_by_calc.append((x.indices,w.indices)) + d,c = sorted(ext_in_weyl_modules), sorted(ext_by_calc) + if return_lists: + print d == c + return d,c + else: + return d == c + + +