| 1 | |
| 2 | r""" |
| 3 | Schur algebras for `GL_n` |
| 4 | |
| 5 | This file implements: |
| 6 | |
| 7 | - Schur algebras for `GL_n` over an arbitrary field, |
| 8 | |
| 9 | - The canonical action of the Schur algebra on a tensor power of the standard representation, |
| 10 | |
| 11 | - Using the above to calculate the characters of irreducible `GL_n` modules. |
| 12 | |
| 13 | AUTHORS: |
| 14 | |
| 15 | - Eric Webster (2010-07-01): implement Schur algebra |
| 16 | |
| 17 | - Hugh Thomas (2011-05-08): implement action of Schur algebra and characters of irreducible modules |
| 18 | |
| 19 | REFERENCES: |
| 20 | |
| 21 | J. Green, Polynomial representations of `GL_n`, Springer Verlag. |
| 22 | |
| 23 | """ |
| 24 | |
| 25 | #***************************************************************************** |
| 26 | # Copyright (C) 2010 Eric Webster |
| 27 | # Copyright (C) 2011 Hugh Thomas (hugh.ross.thomas@gmail.com) |
| 28 | # |
| 29 | # Distributed under the terms of the GNU General Public License (GPL) |
| 30 | # http://www.gnu.org/licenses/ |
| 31 | #***************************************************************************** |
| 32 | |
| 33 | |
| 34 | from sage.categories.all import AlgebrasWithBasis |
| 35 | from sage.combinat.free_module import CombinatorialFreeModule |
| 36 | from sage.combinat.permutation import Permutations |
| 37 | from copy import copy |
| 38 | from sage.rings.ring import CommutativeRing |
| 39 | from sage.rings.integer import Integer |
| 40 | from sage.misc.cachefunc import cached_method |
| 41 | from sage.combinat.sf.sfa import SymmetricFunctionAlgebra |
| 42 | from sage.rings.rational_field import QQ |
| 43 | from sage.combinat.words.word import Word |
| 44 | from sage.combinat.words.words import Words |
| 45 | from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra |
| 46 | from sage.groups.perm_gps.permgroup_named import SymmetricGroup |
| 47 | from sage.combinat.tableau import SemistandardTableaux |
| 48 | from sage.misc.flatten import flatten |
| 49 | from sage.combinat.partition import Partitions, Partition |
| 50 | from sage.matrix.constructor import Matrix |
| 51 | |
| 52 | def SchurAlgebra(n,r,R): |
| 53 | |
| 54 | """ |
| 55 | The Schur algebra for `GL_n` with rank `r` over the |
| 56 | ring `R`. |
| 57 | """ |
| 58 | |
| 59 | if not isinstance(n,(int,Integer)) or n <= 0: |
| 60 | raise ValueError, "n must be a positive integer (n=%s)"%(n) |
| 61 | if not isinstance(r,(int,Integer)) or r < 0: |
| 62 | raise ValueError, "r must be a non-negative integer (r=%s)"%(r) |
| 63 | if not isinstance(R,CommutativeRing): |
| 64 | raise ValueError, "R must be a commutative Ring (R=%s)"%(R) |
| 65 | |
| 66 | return SchurAlgebra_nrR(n,r,R) |
| 67 | |
| 68 | def _schur_I_nr_representatives(n, r, element, index): |
| 69 | |
| 70 | """ |
| 71 | This is an internal function called by schur_representation_indices below. |
| 72 | """ |
| 73 | |
| 74 | if r == 0: |
| 75 | return index |
| 76 | |
| 77 | if len(element) == r: |
| 78 | index.append(copy(element)) |
| 79 | return |
| 80 | |
| 81 | if len(element) == 0: |
| 82 | for i in range(1,n+1): |
| 83 | element.append(i) |
| 84 | _schur_I_nr_representatives(n,r,element,index) |
| 85 | element.pop() |
| 86 | else: |
| 87 | for i in range(element[-1],n+1): |
| 88 | element.append(i) |
| 89 | _schur_I_nr_representatives(n,r,element,index) |
| 90 | element.pop() |
| 91 | |
| 92 | return index |
| 93 | |
| 94 | |
| 95 | |
| 96 | def schur_representative_indices(n, r): |
| 97 | |
| 98 | r""" |
| 99 | This function returns a set which functions as a basis of `S_K(n,r)`. |
| 100 | |
| 101 | More specifically, the basis for `S_K(n,r)` consists of equivalence classes of pairs words of length ``r`` on the alphabet `1\dots n`, |
| 102 | where the equivalence relation is simultaneous permutation of the two words. |
| 103 | We can therefore fix a representative for each equivalence class |
| 104 | in which the entries of the first word |
| 105 | weakly increase, and the entries of the second word |
| 106 | whose corresponding values |
| 107 | in the first word are equal, also weakly increase. |
| 108 | |
| 109 | EXAMPLES:: |
| 110 | |
| 111 | sage: sage.algebras.schur_algebra.schur_representative_indices(2,2) |
| 112 | [(word: 11, word: 11), (word: 11, word: 12), (word: 11, word: 22), (word: 12, word: 11), (word: 12, word: 12), (word: 12, word: 21), (word: 12, word: 22), (word: 22, word: 11), (word: 22, word: 12), (word: 22, word: 22)] |
| 113 | |
| 114 | |
| 115 | """ |
| 116 | |
| 117 | basis = [] |
| 118 | I_nr_repr = _schur_I_nr_representatives(n, r, [], []) |
| 119 | for e in I_nr_repr: |
| 120 | j = 0 |
| 121 | k = 0 |
| 122 | I1 = [] |
| 123 | l = len(e) |
| 124 | while k < l: |
| 125 | if e[k] != e[j]: |
| 126 | I2 = [] |
| 127 | if j == 0: |
| 128 | I1 = _schur_I_nr_representatives(n,k-j,[],[]) |
| 129 | else: |
| 130 | I2 = _schur_I_nr_representatives(n,k-j,[],[]) |
| 131 | I = [] |
| 132 | for m1 in range(0,len(I1)): |
| 133 | for m2 in range(0,len(I2)): |
| 134 | I.append(I1[m1]+I2[m2]) |
| 135 | I1 = I |
| 136 | j = k |
| 137 | elif k == l-1: |
| 138 | I2 = [] |
| 139 | k += 1 |
| 140 | if j == 0: |
| 141 | I1 = _schur_I_nr_representatives(n,k-j,[],[]) |
| 142 | else: |
| 143 | I2 = _schur_I_nr_representatives(n,k-j,[],[]) |
| 144 | I = [] |
| 145 | for m1 in range(0,len(I1)): |
| 146 | for m2 in range(0,len(I2)): |
| 147 | I.append(I1[m1]+I2[m2]) |
| 148 | I1 = I |
| 149 | else: |
| 150 | k += 1 |
| 151 | |
| 152 | for v in I1: |
| 153 | basis.append((Word(e),Word(v))) |
| 154 | |
| 155 | return basis |
| 156 | |
| 157 | def schur_representative_from_index(index): |
| 158 | """ |
| 159 | This function simultaneously reorders a pair of words to obtain the |
| 160 | equivalent element |
| 161 | of the distinguished basis of the Schur algebra. |
| 162 | seealso:: :func:`schur_representative_indices` |
| 163 | |
| 164 | INPUT: |
| 165 | |
| 166 | - A 2-ple of words from `Words (range(1,n+1),r)` |
| 167 | |
| 168 | OUTPUT: |
| 169 | |
| 170 | - The corresponding pair of words ordered correctly. |
| 171 | |
| 172 | EXAMPLES:: |
| 173 | |
| 174 | sage: sage.algebras.schur_algebra.schur_representative_from_index((Word([2,1,2,2]),Word([1,3,0,0]))) |
| 175 | (word: 1222, word: 3001) |
| 176 | |
| 177 | |
| 178 | """ |
| 179 | |
| 180 | w = [] |
| 181 | for i in range(0,len(index[0])): |
| 182 | w.append((index[0][i], index[1][i])) |
| 183 | w.sort() |
| 184 | index = [[], []] |
| 185 | for i in range(0, len(w)): |
| 186 | index[0].append(w[i][0]) |
| 187 | index[1].append(w[i][1]) |
| 188 | return tuple(map(Word, index)) |
| 189 | |
| 190 | |
| 191 | class SchurAlgebra_nrR(CombinatorialFreeModule): |
| 192 | |
| 193 | """ |
| 194 | This is the class that implements Schur algebras. |
| 195 | |
| 196 | EXAMPLES:: |
| 197 | |
| 198 | sage: S = sage.algebras.schur_algebra.SchurAlgebra_nrR(2, 2, ZZ); S |
| 199 | Schur Algebra (2,2) over Integer Ring |
| 200 | |
| 201 | """ |
| 202 | |
| 203 | def __init__(self, n, r, R): |
| 204 | |
| 205 | self._n = n |
| 206 | self._r = r |
| 207 | |
| 208 | CombinatorialFreeModule.__init__(self, R, schur_representative_indices(n,r), category = AlgebrasWithBasis(R)) |
| 209 | |
| 210 | def _repr_(self): |
| 211 | """ |
| 212 | EXAMPLES:: |
| 213 | |
| 214 | sage: S = sage.algebras.schur_algebra.SchurAlgebra_nrR(4, 4, ZZ) |
| 215 | sage: repr(S) |
| 216 | 'Schur Algebra (4,4) over Integer Ring' |
| 217 | """ |
| 218 | return "Schur Algebra (%s,%s) over %s"%(self._n, self._r, self.base_ring()) |
| 219 | |
| 220 | @cached_method |
| 221 | def one_basis(self): |
| 222 | return None |
| 223 | |
| 224 | def product_on_basis(self, e_ij, e_kl): |
| 225 | r""" |
| 226 | Product of basis elements, as per :meth:`AlgebrasWithBasis.ParentMethods.product_on_basis`. |
| 227 | |
| 228 | EXAMPLES:: |
| 229 | |
| 230 | sage: S=sage.algebras.schur_algebra.SchurAlgebra(2, 3, QQ) |
| 231 | sage: B=S.basis() |
| 232 | |
| 233 | If we multiply two basis elements `x` and `y`, such that `x[1]` and `y[0]` are not |
| 234 | permutations of each other, the result is zero |
| 235 | |
| 236 | .. link:: |
| 237 | |
| 238 | :: |
| 239 | |
| 240 | sage: B[(Word((1, 1, 1)), Word((1, 1, 2)))]*B[(Word((1, 2, 2)),Word((1, 1, 2)))] |
| 241 | 0 |
| 242 | |
| 243 | If we multiply a basis element `x` by a basis element which consists of the same tuple repeated twice (on either side), |
| 244 | the result |
| 245 | is either zero (if the previous case applies) or `x` |
| 246 | |
| 247 | .. link:: |
| 248 | |
| 249 | :: |
| 250 | |
| 251 | sage: B[(Word((1, 2, 2)), Word((1, 2, 2)))]*B[(Word((1, 2, 2)), Word((1, 1, 2)))] |
| 252 | B[(word: 122, word: 112)] |
| 253 | |
| 254 | |
| 255 | An arbitrary product, on the other hand, may have multiplicities |
| 256 | |
| 257 | .. link:: |
| 258 | |
| 259 | :: |
| 260 | |
| 261 | sage: B[(Word((1, 1, 1)), Word((1, 1, 2)))]*B[(Word((1, 1, 2)), Word((1, 2, 2)))] |
| 262 | 2*B[(word: 111, word: 122)] |
| 263 | |
| 264 | """ |
| 265 | |
| 266 | k = e_kl[0] |
| 267 | j = e_ij[1] |
| 268 | |
| 269 | i = e_ij[0] |
| 270 | l = e_kl[1] |
| 271 | |
| 272 | l = sorted(l) |
| 273 | |
| 274 | # Find basis elements (p,q) such that p ~ i and q ~ l |
| 275 | e_pq = [] |
| 276 | for v in self.basis().keys(): |
| 277 | if v[0] == i and sorted(v[1]) == l: |
| 278 | e_pq.append(v) |
| 279 | |
| 280 | b = self.basis() |
| 281 | product = self.zero() |
| 282 | |
| 283 | # Find s in I(n,r) such that (p,s) ~ (i,j) and (s,q) ~ (k,l) |
| 284 | for e in e_pq: |
| 285 | Z_ijklpq = self.base_ring()(0) |
| 286 | for s in Permutations([xx for xx in j]): |
| 287 | if schur_representative_from_index((e[0],s)) == e_ij and schur_representative_from_index((s,e[1])) == e_kl: |
| 288 | Z_ijklpq += self.base_ring()(1) |
| 289 | product += Z_ijklpq*b[e] |
| 290 | |
| 291 | return product |
| 292 | |
| 293 | class TensorSpace(CombinatorialFreeModule): |
| 294 | """ |
| 295 | This is the ``r``-fold tensor product of an ``n``-dimensional free module over ``R``, |
| 296 | equipped with an action of the Schur algebra `S(n,r)` and the |
| 297 | symmetric group `S_r`. |
| 298 | """ |
| 299 | |
| 300 | def __init__(self, n, r, R): |
| 301 | |
| 302 | self._n = n |
| 303 | self._r = r |
| 304 | self._R = R |
| 305 | CombinatorialFreeModule.__init__(self, R, Words(range(1,n+1), r)) |
| 306 | |
| 307 | def _repr_(self): |
| 308 | return "The %s-fold tensor product of a free module of dimension %s over %s"%(self._r, self._n, self.base_ring()) |
| 309 | |
| 310 | def _basis_elt_from_permuted_word(self, v, perm): |
| 311 | """ |
| 312 | return the basis element of self corresponding to applying the permutation perm to a word v |
| 313 | """ |
| 314 | return self.basis()[Word(v).apply_permutation_to_positions(perm)] |
| 315 | |
| 316 | def action_by_perm(self, t, perm): |
| 317 | """ |
| 318 | Apply a permutation to an element of self |
| 319 | |
| 320 | INPUT: |
| 321 | |
| 322 | - ``perm`` is an element of Permutations(self._r) |
| 323 | - ``t`` is an element of self |
| 324 | |
| 325 | OUTPUT: |
| 326 | |
| 327 | - the output is the result of acting by ``perm`` on ``t`` |
| 328 | """ |
| 329 | h=self.module_morphism(self._basis_elt_from_permuted_word, codomain=self) |
| 330 | return h(t, perm) |
| 331 | |
| 332 | def action_by_symmetric_group_algebra(self, t, z): |
| 333 | """ |
| 334 | INPUT: |
| 335 | |
| 336 | - ``t`` -- an element of ``self`` |
| 337 | - ``z`` -- an element of ``SymmetricGroupAlgebra(self._R,self._r)`` |
| 338 | |
| 339 | OUTPUT: |
| 340 | |
| 341 | result of action of ``z`` on ``t``. |
| 342 | """ |
| 343 | S=SymmetricGroupAlgebra(self._R,self._r) |
| 344 | assert z in S |
| 345 | sym_action=S.module_morphism(self.action_by_perm, codomain=self,position=1) |
| 346 | return sym_action(t, z) |
| 347 | |
| 348 | def _monomial_product(self,xi,v): |
| 349 | """ |
| 350 | Result of acting by the basis element ``xi`` of ``S`` on the basis element ``v`` of self. |
| 351 | """ |
| 352 | x=self.zero() |
| 353 | for i in Words(range(1,self._n+1),self._r): |
| 354 | if schur_representative_from_index((i,v))==xi: |
| 355 | x=x+self.basis()[i] |
| 356 | return x |
| 357 | |
| 358 | def action_by_Schur_alg(self,nu,v): |
| 359 | |
| 360 | r""" |
| 361 | returns action of ``nu`` in Schur algebra on ``v`` in ``self``. |
| 362 | """ |
| 363 | |
| 364 | A=SchurAlgebra(self._n,self._r,self._R) |
| 365 | assert nu in A |
| 366 | g=A.module_morphism(self._monomial_product, codomain=self) |
| 367 | action= self.module_morphism(g,codomain=self,position=1) |
| 368 | return action(nu,v) |
| 369 | |
| 370 | def bracket(r,X,S): |
| 371 | r""" |
| 372 | Given ``X`` a set of permutations of ``r`` in cycle notation, |
| 373 | return the sum in the symmetric group algebra |
| 374 | of those permutations, times their sign. |
| 375 | |
| 376 | This implements the notation `\{X\}` from just before (5.3a) of Green. |
| 377 | |
| 378 | EXAMPLES:: |
| 379 | |
| 380 | sage: sage.algebras.schur_algebra.bracket(2,[PermutationGroupElement(()),PermutationGroupElement((1,2))],SymmetricGroupAlgebra(QQ,2)) |
| 381 | () - (1,2) |
| 382 | |
| 383 | """ |
| 384 | t=S.zero() |
| 385 | SG=SymmetricGroup(r) |
| 386 | return sum([x.sign()*S.basis()[SG(x)] for x in X]) |
| 387 | |
| 388 | |
| 389 | def GL_n_irred_character(n,mu,KK): |
| 390 | r""" |
| 391 | This function calculates the character of the irreducible character indexed by ``mu`` of `GL(n)` over the field ``KK``. |
| 392 | |
| 393 | INPUT: |
| 394 | |
| 395 | - ``n`` is a positive integer. |
| 396 | - ``mu`` is a partition of at most ``n`` parts. |
| 397 | - ``KK`` is a field . |
| 398 | |
| 399 | OUTPUT: |
| 400 | |
| 401 | a symmetric function which should be interpreted in ``n`` variables to be meaningful as a character |
| 402 | |
| 403 | EXAMPLES: |
| 404 | |
| 405 | Over `\QQ`, the irreducible character for ``mu`` is the Schur function associated to ``mu``, |
| 406 | plus garbage terms (Schur functions associated to partitions with more than `n` parts) |
| 407 | |
| 408 | :: |
| 409 | |
| 410 | sage: from sage.algebras.schur_algebra import GL_n_irred_character |
| 411 | sage: z = GL_n_irred_character(2, [2], QQ) |
| 412 | sage: sbasis = SymmetricFunctionAlgebra(QQ, 'schur') |
| 413 | sage: sbasis(z) |
| 414 | s[2] |
| 415 | |
| 416 | |
| 417 | sage: from sage.algebras.schur_algebra import GL_n_irred_character |
| 418 | sage: z = GL_n_irred_character(4, [3, 2], QQ) # long time |
| 419 | sage: sbasis = SymmetricFunctionAlgebra(QQ, 'schur') # long time |
| 420 | sage: sbasis(z) #long time |
| 421 | -5*s[1, 1, 1, 1, 1] + s[3, 2] |
| 422 | |
| 423 | Over a Galois field, the irreducible character for `\mu` will in general |
| 424 | be smaller. |
| 425 | |
| 426 | In characteristic `p`, for a one-part partition `(r)`, where |
| 427 | `r= a_0 + p a_1 + p^2 a_2 + \dots`, the result is [Green, after 5.5d] |
| 428 | the product of `h[a_0], h[a_1]( pbasis[p]), h[a_2] ( pbasis[p^2]),\dots,` |
| 429 | which is consistent with the following |
| 430 | |
| 431 | :: |
| 432 | |
| 433 | sage: from sage.algebras.schur_algebra import GL_n_irred_character |
| 434 | sage: GL_n_irred_character(2, [7], GF(3)) # long time |
| 435 | m[4, 3] + m[6, 1] + m[7] |
| 436 | |
| 437 | |
| 438 | """ |
| 439 | mbasis = SymmetricFunctionAlgebra(QQ,basis='monomial') |
| 440 | r=sum(mu) |
| 441 | A=SchurAlgebra(n,r,KK) |
| 442 | M=TensorSpace(n,r,KK) |
| 443 | S=SymmetricGroupAlgebra(KK,r) |
| 444 | |
| 445 | #make ST the superstandard tableau of shape mu |
| 446 | from sage.combinat.tableau import from_shape_and_word |
| 447 | ST=from_shape_and_word(mu, range(1,r+1), order='English') |
| 448 | |
| 449 | #make ell the reading word of the highest weight tableau of shape mu |
| 450 | ell=[] |
| 451 | for i in range(0,len(mu)): |
| 452 | for j in range(0,mu[i]): |
| 453 | ell.append(i+1) |
| 454 | |
| 455 | e=M.basis()[Word(ell)]; #the element e_l |
| 456 | BracC=bracket(r,ST.column_stabilizer(),S) |
| 457 | f=M.action_by_symmetric_group_algebra(e,BracC) |
| 458 | |
| 459 | #[Green, Theorem 5.3b] says that a basis of the Carter-Lusztig module V_\mu is given by taking |
| 460 | #this f, and multiplying by |
| 461 | #all xi_{i,ell} with ell as above and i semistandard. |
| 462 | |
| 463 | carter_lusztig=[] |
| 464 | for i in [Word(flatten(T)) for T in SemistandardTableaux(mu,max_entry=n)]: |
| 465 | y=M.action_by_Schur_alg(A.basis()[schur_representative_from_index((i,Word(ell)))],e) |
| 466 | carter_lusztig.append(y.to_vector()) |
| 467 | |
| 468 | #Therefore, we now have carter_lusztig as a list giving the basis of `V_\mu` |
| 469 | |
| 470 | #We want to think of expressing this character as a sum of monomial |
| 471 | #symmetric functions. |
| 472 | |
| 473 | #We will determine a basis element for each m_\lambda in the |
| 474 | #character, and we want to keep track of them by \lambda. |
| 475 | |
| 476 | #That means that we only want to pick out the basis elements above for |
| 477 | #those semistandard words whose content is a partition. |
| 478 | |
| 479 | contents=Partitions(r,max_length=n).list() #all partitions of r, length at most n |
| 480 | |
| 481 | # JJ will consist of a list for each element of `contents`, |
| 482 | # recording the list |
| 483 | # of semistandard tableaux words with that content |
| 484 | |
| 485 | # graded_basis will consist of the a corresponding basis element |
| 486 | |
| 487 | |
| 488 | graded_basis=[] |
| 489 | JJ=[] |
| 490 | for i in range(0,len(contents)): |
| 491 | graded_basis.append([]) |
| 492 | JJ.append([]) |
| 493 | for i in [Word(flatten(T),range(1,n+1))for T in SemistandardTableaux(mu,max_entry=n)]: |
| 494 | con=i.evaluation() |
| 495 | if all([ con[j+1] <= con[j] for j in range(0,len(con)-1)]): |
| 496 | #don't test whether con is in Partitions, because con could |
| 497 | #have trailing zeros |
| 498 | JJ[contents.index(Partition(con))].append(i) |
| 499 | x=M.action_by_Schur_alg(A.basis()[schur_representative_from_index((i,Word(ell)))],f) |
| 500 | graded_basis[contents.index(Partition(con))].append(x.to_vector()) |
| 501 | |
| 502 | #There is an inner product on the Carter-Lusztig module V_\mu; its |
| 503 | #maximal submodule is exactly the kernel of the inner product. |
| 504 | |
| 505 | #Now, for each possible partition content, we look at the graded piece of |
| 506 | #that degree, and we record how these elements pair with each of the |
| 507 | #elements of carter_lusztig. |
| 508 | |
| 509 | #The kernel of this pairing is the part of this graded piece which is |
| 510 | #not in the irreducible module for \mu. |
| 511 | |
| 512 | length=len(carter_lusztig) |
| 513 | |
| 514 | Phi=mbasis.zero() |
| 515 | for aa in range(0,len(contents)): |
| 516 | Mat=[] |
| 517 | for kk in range(0,len(JJ[aa])): |
| 518 | temp=[] |
| 519 | for j in range(0,length): |
| 520 | temp.append(graded_basis[aa][kk].inner_product(carter_lusztig[j])) |
| 521 | Mat.append(temp) |
| 522 | Angle=Matrix(Mat) |
| 523 | Phi=Phi+(len(JJ[aa])-Angle.kernel().rank())*mbasis(contents[aa]) |
| 524 | return Phi |
| 525 | |