Attachment 'lie_algebra_reprs.sage'

Download

   1 """
   2 Lie Algebra Representations
   3 
   4 EXAMPLES::
   5 
   6     sage: La = RootSystem(['E',6]).weight_lattice().fundamental_weights()
   7     sage: M = crystals.NakajimaMonomials(La[1])
   8     sage: VM = ReprMinuscule(M, QQ)
   9     sage: v = VM.maximal_vector()
  10     sage: x = (tensor([v, v.f(1), v.f(1).f(3)]) 
  11     ....:      - tensor([v.f(1), v, v.f(1).f(3)])
  12     ....:      - tensor([v, v.f(1).f(3), v.f(1)])
  13     ....:      + tensor([v.f(1), v.f(1).f(3), v])
  14     ....:      + tensor([v.f(1).f(3), v, v.f(1)])
  15     ....:      - tensor([v.f(1).f(3), v.f(1), v])
  16     ....:      )
  17     sage: all(x.e(i) == 0 for i in M.index_set())
  18     True
  19     sage: S = SubRepresentation(x, crystals.NakajimaMonomials(La[4]))
  20        initializing _build_basis
  21        building basis
  22        running checks
  23     sage: verify_representation(S)  # long time -- multiple minutes
  24 
  25     sage: B4 = S.basis().keys()
  26     sage: wt0 = [b for b in B4 if b.weight() == 0]
  27     sage: S0 = [S.basis()[b] for b in wt0]
  28     sage: def build_smat(i):
  29     ....:     ret = []
  30     ....:     for b in S0:
  31     ....:         bs = b.s(i)
  32     ....:         ret.append([bs[c] for c in wt0])
  33     ....:     return matrix(ret)
  34     sage: s_mats = [build_smat(i) for i in B4.index_set()]
  35 
  36     sage: [m.det() for m in s_mats]                                                           
  37     [-1, -1, -1, -1, -1, -1]
  38     sage: W = WeylGroup(['E',6], prefix='s')
  39     sage: W.cardinality()
  40     51840
  41     sage: MG = MatrixGroup(s_mats)
  42     sage: MG.cardinality()   # long time - few minutes computation
  43     51840
  44 """
  45 
  46 #from sage.combinat.dict_addition import dict_addition, dict_linear_combination
  47 from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModule_Tensor
  48 from sage.misc.lazy_attribute import lazy_attribute
  49 
  50 class ReprElement(CombinatorialFreeModule.Element):
  51     def e(self, i):
  52         F = self.parent()
  53         return F.linear_combination( (F.e_on_basis(i, m), c)
  54                                      for m,c in self.monomial_coefficients(copy=False).items() )
  55 
  56     def f(self, i):
  57         F = self.parent()
  58         return F.linear_combination( (F.f_on_basis(i, m), c)
  59                                      for m,c in self.monomial_coefficients(copy=False).items() )
  60 
  61     def h(self, i, power=1):
  62         """
  63         Return the action of `h_i` on ``self``.
  64 
  65         We assume everything is working in a weight basis, so we have
  66         :meth:`h_on_basis()` return the appropriate scalar.
  67         """
  68         F = self.parent()
  69         return F._from_dict({m: c * F.h_on_basis(i, m, power)
  70                              for m,c in self.monomial_coefficients(copy=False).items()})
  71 
  72     def exp(self, op):
  73         """
  74         Return the action of the exponential of the opeartor ``op``
  75         on ``self``.
  76 
  77         .. WARNING::
  78 
  79             This assumes ``op`` is locally nilpontent.
  80         """
  81         F = self.parent()
  82         ret = F.zero()
  83         n = 0
  84         temp = self
  85         while temp:
  86             ret += temp / factorial(n)
  87             temp = op(temp)
  88             n += 1
  89         return ret
  90 
  91     def s(self, i):
  92         """
  93         Return the action of `s_i` on ``self``.
  94         """
  95         fop = lambda x: x.f(i)
  96         eop = lambda x: -x.e(i)
  97         return self.exp(fop).exp(eop).exp(fop)
  98 
  99 # -----------------------------------------------------------------------------------------
 100 
 101 class ReprMinuscule(CombinatorialFreeModule):
 102     def __init__(self, C, R):
 103         CombinatorialFreeModule.__init__(self, R, C)
 104 
 105     def _repr_(self):
 106         return "V({})".format(self.basis().keys().highest_weight_vector().weight())
 107 
 108     def _latex_(self):
 109         from sage.misc.latex import latex
 110         return "V({})".format(latex(self.basis().keys().highest_weight_vector().weight()))
 111 
 112     def cartan_type(self):
 113         return self.basis().keys().cartan_type()
 114 
 115     def maximal_vector(self):
 116         return self.monomial(self.basis().keys().highest_weight_vector())
 117 
 118     def e_on_basis(self, i, b):
 119         C = self.basis().keys()
 120         x = b.e(i)
 121         if x is None:
 122             return self.zero()
 123         return self.monomial(x)
 124 
 125     def f_on_basis(self, i, b):
 126         C = self.basis().keys()
 127         x = b.f(i)
 128         if x is None:
 129             return self.zero()
 130         return self.monomial(x)
 131 
 132     def h_on_basis(self, i, b, power=1):
 133         C = self.basis().keys()
 134         WLR = C.weight_lattice_realization()
 135         alc = WLR.simple_coroots()
 136         return b.weight().scalar(alc[i]) * power
 137 
 138     Element = ReprElement
 139 
 140 # -----------------------------------------------------------------------------------------
 141 
 142 class ReprAdjoint(CombinatorialFreeModule):
 143     def __init__(self, C, R):
 144         self._d = C.cartan_type().symmetrizer()
 145         self._zero_elts = {}
 146         self._WLR_zero = C.weight_lattice_realization().zero()
 147         for x in C:
 148             if x.weight() == self._WLR_zero:
 149                 for i in C.index_set():
 150                     if x.epsilon(i) > 0:
 151                         self._zero_elts[i] = x
 152                         break
 153         CombinatorialFreeModule.__init__(self, R, C)
 154 
 155     def _repr_(self):
 156         return "V({})".format(self.basis().keys().highest_weight_vector().weight())
 157 
 158     def _latex_(self):
 159         from sage.misc.latex import latex
 160         return "V({})".format(latex(self.basis().keys().highest_weight_vector().weight()))
 161 
 162     def cartan_type(self):
 163         return self.basis().keys().cartan_type()
 164 
 165     def maximal_vector(self):
 166         return self.monomial(self.basis().keys().highest_weight_vector())
 167 
 168     def e_on_basis(self, i, b):
 169         C = self.basis().keys()
 170         x = b.e(i)
 171         if x is None:
 172             return self.zero()
 173         I = {j: pos for pos,j in enumerate(C.index_set())}
 174         if x.weight() == self._WLR_zero:
 175             A = C.cartan_type().cartan_matrix()
 176             return self.monomial(x) + sum(self.term(self._zero_elts[j], -A[I[i],I[j]] / 2)
 177                                           for j in C.index_set()
 178                                           if A[I[i],I[j]] < 0 and j in self._zero_elts)
 179         return self.term(x, x.phi(i))
 180 
 181     def f_on_basis(self, i, b):
 182         C = self.basis().keys()
 183         x = b.f(i)
 184         if x is None:
 185             return self.zero()
 186         I = {j:pos for pos,j in enumerate(C.index_set())}
 187         if x.weight() == self._WLR_zero:
 188             A = C.cartan_type().cartan_matrix()
 189             return self.monomial(x) + sum(self.term(self._zero_elts[j], -A[I[i],I[j]] / 2)
 190                                           for j in C.index_set()
 191                                           if A[I[i],I[j]] < 0 and j in self._zero_elts)
 192         return self.term(x, x.epsilon(i))
 193 
 194     def h_on_basis(self, i, b, power=1):
 195         C = self.basis().keys()
 196         WLR = C.weight_lattice_realization()
 197         alc = WLR.simple_coroots()
 198         return b.weight().scalar(alc[i]) * power
 199 
 200     Element = ReprElement
 201 
 202 # -----------------------------------------------------------------------------------------
 203 
 204 # This doesn't work!!!
 205 class ReprNiceEnough(CombinatorialFreeModule):
 206     def __init__(self, C, R):
 207         self._d = C.cartan_type().symmetrizer()
 208         self._middle_elts = {}
 209         for x in C:
 210             wt = x.weight()
 211             for i in C.index_set():
 212                 if x.epsilon(i) == x.phi(i) == 1:
 213                     if wt not in self._middle_elts:
 214                         self._middle_elts[wt] = {}
 215                     assert i not in self._middle_elts[wt], wt
 216                     self._middle_elts[wt][i] = x
 217         CombinatorialFreeModule.__init__(self, R, C)
 218 
 219     def _repr_(self):
 220         return "V({})".format(self.basis().keys().highest_weight_vector().weight())
 221 
 222     def _latex_(self):
 223         from sage.misc.latex import latex
 224         return "V({})".format(latex(self.basis().keys().highest_weight_vector().weight()))
 225 
 226     def cartan_type(self):
 227         return self.basis().keys().cartan_type()
 228 
 229     def maximal_vector(self):
 230         return self.monomial(self.basis().keys().highest_weight_vector())
 231 
 232     def e_on_basis(self, i, b):
 233         C = self.basis().keys()
 234         x = b.e(i)
 235         if x is None:
 236             return self.zero()
 237         ret = self.term(x, q_int(x.phi(i), self._q**self._d[i]))
 238         wt = x.weight()
 239         if wt in self._middle_elts:
 240             others = self._middle_elts[wt]
 241             A = C.cartan_type().cartan_matrix()
 242             return ret + sum(self.term(others[j], q_int(-A[i,j], self._q**self._d[i]) / q_int(2, self._q**self._d[j]))
 243                              for j in C.index_set() if A[i,j] < 0 and j in others)
 244         return ret
 245 
 246     def f_on_basis(self, i, b):
 247         C = self.basis().keys()
 248         x = b.f(i)
 249         if x is None:
 250             return self.zero()
 251         wt = x.weight()
 252         ret = self.term(x, q_int(x.epsilon(i), self._q**self._d[i]))
 253         if wt in self._middle_elts:
 254             others = self._middle_elts[wt]
 255             A = C.cartan_type().cartan_matrix()
 256             return ret + sum(self.term(others[j], q_int(-A[i,j], self._q**self._d[i]) / q_int(2, self._q**self._d[j]))
 257                              for j in C.index_set() if A[i,j] < 0 and j in others)
 258         return ret
 259 
 260     def h_on_basis(self, i, b, power=1):
 261         C = self.basis().keys()
 262         WLR = C.weight_lattice_realization()
 263         alc = WLR.simple_coroots()
 264         return self._q**(b.weight().scalar(alc[i]) * power)
 265 
 266     Element = ReprElement
 267 
 268 
 269 # -----------------------------------------------------------------------------------------
 270 
 271 def tensor_basis_wt(x):
 272     return sum((comp.weight() for comp in x), x[0].weight().parent().zero())
 273 
 274 class SubRepresentation(CombinatorialFreeModule):
 275     """
 276     INPUT:
 277 
 278     - ``gen`` -- the generator
 279     - ``C`` -- the KR crystal this is isomorphic to
 280     - ``check`` -- verify the basis constructed really is a basis
 281     - ``fast_basis`` -- if ``True``, then just use the first `f_i` action to
 282       construct a new basis element
 283 
 284     EXAMPLES::
 285 
 286         sage: La = RootSystem(['E',6]).weight_lattice().fundamental_weights()
 287         sage: M = crystals.NakajimaMonomials(La[1])
 288         sage: VM = ReprMinuscule(M, QQ)
 289         sage: v = VM.maximal_vector()
 290         sage: x = (tensor([v, v.f(1), v.f(1).f(3)]) 
 291         ....:      - tensor([v.f(1), v, v.f(1).f(3)])
 292         ....:      - tensor([v, v.f(1).f(3), v.f(1)])
 293         ....:      + tensor([v.f(1), v.f(1).f(3), v])
 294         ....:      + tensor([v.f(1).f(3), v, v.f(1)])
 295         ....:      - tensor([v.f(1).f(3), v.f(1), v])
 296         ....:      )
 297         sage: S = SubRepresentation(x, crystals.NakajimaMonomials(La[4]))
 298            initializing _build_basis
 299            building basis
 300            running checks
 301     """
 302     def __init__(self, gen, C, check=True, fast_basis=True):
 303         self._gen = gen
 304         self._ambient = gen.parent()
 305         self._d = C.cartan_type().symmetrizer()
 306         R = self._ambient.base_ring()
 307         CombinatorialFreeModule.__init__(self, R, C, prefix='s')
 308         self._build_basis(check=check, fast_basis=fast_basis)
 309 
 310     def _repr_(self):
 311         return "V({}) inside {}".format(self.basis().keys().highest_weight_vector().weight(), self._ambient)
 312 
 313     def _latex_(self):
 314         from sage.misc.latex import latex
 315         return "V({}) \\subseteq {}".format(latex(self.basis().keys().highest_weight_vector().weight()),
 316                                             latex(self._ambient))
 317 
 318     def _build_basis(self, check=True, fast_basis=True):
 319         # Data
 320         print("   initializing _build_basis")
 321         A = self._ambient
 322         R = A.base_ring()
 323         I = self.cartan_type().index_set()
 324         mg = self.basis().keys().highest_weight_vector()
 325         todo = set([mg])
 326         self._ambient_basis = {mg: self._gen}
 327         self._order = [mg]
 328         self._elements_by_weight = {mg.weight(): [mg]}
 329         self._support_by_weight = {mg.weight(): list(self._gen.support())}
 330         full_support = set(self._gen.support())
 331         d = self.cartan_type().symmetrizer()
 332         print("   building basis")
 333         while todo:
 334             x = todo.pop()
 335             v = self._ambient_basis[x]
 336             for i in I:
 337                 y = x.f(i)
 338                 if y is None or y in self._ambient_basis:
 339                     continue
 340                 wt = y.weight()
 341                 vp = v.f(i)
 342 
 343                 if (not fast_basis) and full_support.issuperset(vp.support()):
 344                     # If there is a new support, then it must be linearly independent
 345                     #   from the previous weight basis elements.
 346                     wt_vectors = [self._ambient_basis[b] for b in self._elements_by_weight[wt]]
 347                     wt_vectors.append(vp)
 348                     M = matrix([[vec[s] for s in self._support_by_weight[wt]]
 349                                 for vec in wt_vectors])
 350                     if M.rank() != M.nrows():
 351                         # This vector is already in the span of the weight basis
 352                         continue
 353 
 354                 self._order.append(y)
 355                 if wt in self._elements_by_weight:
 356                     self._elements_by_weight[wt].append(y)
 357                     self._support_by_weight[wt].extend(s for s in vp.support()
 358                                                        if s not in self._support_by_weight[wt])
 359                 else:
 360                     self._elements_by_weight[wt] = [y]
 361                     self._support_by_weight[wt] = list(vp.support())
 362                 full_support.update(vp.support())
 363                 todo.add(y)
 364                 # self._ambient_basis[y] = v.f(i)
 365                 self._ambient_basis[y] = ~y.epsilon(i) * vp
 366 
 367         assert len(self._ambient_basis) == self.basis().keys().cardinality(), ("%s != %s -- missing an element in the basis"
 368                         % (len(self._ambient_basis), self.basis().keys().cardinality()))
 369 
 370         # Fix an order for the ambient support,
 371         #   doesn't matter which order (well, maybe computationally...)
 372         full_support = list(full_support)
 373         self._support_order = {x: i for i,x in enumerate(full_support)}
 374 
 375         # Safety checks (if desired)
 376         if not check:
 377             return
 378         print("   running checks")
 379         MS = MatrixSpace(R, len(self._ambient_basis), len(full_support), sparse=True)
 380         B = MS({(i,self._support_order[x]): coeff for i,g in enumerate(self._ambient_basis.values())
 381                 for x,coeff in g})
 382         assert B.rank() == len(self._ambient_basis), (B.rank(), len(self._ambient_basis))
 383 
 384     def lift(self, elt):
 385         if elt == 0:
 386             return self._ambient.zero()
 387         return self._ambient.sum(c * self._ambient_basis[i] for i,c in elt)
 388 
 389     def retract(self, vec):
 390         if vec == 0:
 391             return self.zero()
 392         # Since this is a weight basis and the ambient basis has the same
 393         #   weight as this, restrict to the ambient elements and basis elements
 394         #   with the same weights that appear in ``vec``.
 395         wts = set(tensor_basis_wt(x) for x in vec.support())  # FIXME: In practice, x is a tuple, but it shouldn't be
 396         S = {}
 397         for wt in wts:
 398             for x in self._support_by_weight[wt]:
 399                 S[x] = len(S)
 400         order = []
 401         for wt in wts:
 402             order.extend(self._elements_by_weight[wt])
 403         #order = [x for x in self._order if x.weight() in wts]
 404         MS = MatrixSpace(self.base_ring(), len(S), len(order)+1)
 405         mat = {(S[x],0): c for x,c in vec}
 406         for i,b in enumerate(order):
 407             for x,c in self._ambient_basis[b]:
 408                 mat[S[x],i+1] = c
 409         ker = MS(mat).right_kernel_matrix(basis='echelon')
 410         assert ker.nrows() == 1
 411         ker = ker[0]
 412         assert ker[0] == self.base_ring().one()
 413         return self._from_dict({order[i-1]: -c for i,c in ker.items() if i != 0},
 414                                coerce=False, remove_zeros=False)
 415 
 416     def cartan_type(self):
 417         return self._ambient.cartan_type()
 418 
 419     @cached_method
 420     def e_on_basis(self, i, b):
 421         return self.retract(self._ambient_basis[b].e(i))
 422 
 423     @cached_method
 424     def f_on_basis(self, i, b):
 425         return self.retract(self._ambient_basis[b].f(i))
 426 
 427     @cached_method
 428     def h_on_basis(self, i, b, power=1):
 429         # We are assuming this a weight basis
 430         C = self.basis().keys()
 431         WLR = C.weight_lattice_realization()
 432         alc = WLR.simple_coroots()
 433         return b.weight().scalar(alc[i]) * power
 434 
 435     def maximal_vector(self):
 436         return self.retract(self._gen)
 437 
 438     Element = ReprElement # Faster to cache the action on the basis elements
 439 
 440 # -----------------------------------------------------------------------------------------
 441 
 442 class SubRepresentationGenericBasis(SubRepresentation):
 443     """
 444     INPUT:
 445 
 446     - ``gen`` -- the generator
 447     - ``C`` -- the crystal this is isomorphic to
 448     - ``check`` -- verify the basis constructed really is a basis
 449     - ``fast_basis`` -- if ``True``, then just use the first `f_i` action to
 450       construct a new basis element
 451     """
 452     def __init__(self, gen, r, s=None, q=None, check=True):
 453         # Something which is guaranteed to have this correct cardinality
 454         # This is a bit of a hack, but it will work at least.
 455         if s is None:
 456             C = r
 457         else:
 458             P = RootSystem(gen.parent().cartan_type()).weight_space()
 459             C = crystals.LSPaths(P(r))
 460         SubRepresentation.__init__(self, gen, C, check=check)
 461 
 462     def _build_basis(self, check=True, fast_basis=True):
 463         # Data
 464         print("   initializing _build_basis")
 465         A = self._ambient
 466         R = A.base_ring()
 467         I = self.cartan_type().index_set()
 468         mg = self.basis().keys().module_generators[0]
 469         todo = set([mg])
 470         self._ambient_basis = {mg: self._gen}
 471         self._order = [mg]
 472         self._support_by_weight = {mg.weight(): list(self._gen.support())}
 473         full_support = set(self._gen.support())
 474         d = self.cartan_type().symmetrizer()
 475         alpha = mg.parent().weight_lattice_realization().simple_roots()
 476 
 477         print("   grouping elements by weight")
 478         self._elements_by_weight = {}
 479         for rc in self.basis().keys():
 480             wt = rc.weight()
 481             if wt in self._elements_by_weight:
 482                 self._elements_by_weight[wt].append(rc)
 483             else:
 484                 self._elements_by_weight[wt] = [rc]
 485 
 486         wt_space_dim = {wt: 0 for wt in self._elements_by_weight}
 487         wt_space_dim[mg.weight()] = 1
 488 
 489         print("   building basis")
 490         #count = 0
 491         while todo:
 492             x = todo.pop()
 493             v = self._ambient_basis[x]
 494             for i in I:
 495                 vp = v.f(i)
 496                 if vp == 0:
 497                     continue
 498                 wt = x.weight() - alpha[i]
 499                 cur_dim = wt_space_dim[wt]
 500 
 501                 if full_support.issuperset(vp.support()):
 502                     # If there is a new support, then it must be linearly independent
 503                     #   from the previous weight basis elements.
 504                     wt_vectors = [self._ambient_basis[b] for b in self._elements_by_weight[wt][:cur_dim]]
 505                     wt_vectors.append(vp)
 506                     M = matrix([[vec[s] for s in self._support_by_weight[wt]]
 507                                 for vec in wt_vectors])
 508                     if M.rank() == cur_dim:
 509                         # This vector is already in the span of the weight basis
 510                         continue
 511 
 512                 y = self._elements_by_weight[wt][cur_dim]
 513                 self._order.append(y)
 514                 if wt in self._support_by_weight:
 515                     self._support_by_weight[wt].extend(s for s in vp.support()
 516                                                        if s not in self._support_by_weight[wt])
 517                 else:
 518                     self._support_by_weight[wt] = list(vp.support())
 519                 full_support.update(vp.support())
 520                 todo.add(y)
 521                 # self._ambient_basis[y] = v.f(i)
 522                 self._ambient_basis[y] = vp
 523                 wt_space_dim[wt] += 1
 524                 #count += 1
 525                 #if count % 100 == 0:
 526                 #    print(count)
 527 
 528         assert len(self._ambient_basis) == self.basis().keys().cardinality(), ("%s != %s -- missing an element in the basis"
 529                         % (len(self._ambient_basis), self.basis().keys().cardinality()))
 530 
 531         # Fix an order for the ambient support,
 532         #   doesn't matter which order (well, maybe computationally...)
 533         full_support = list(full_support)
 534         self._support_order = {x: i for i,x in enumerate(full_support)}
 535 
 536 # -----------------------------------------------------------------------------------------
 537 
 538 class RepresentationTensor(CombinatorialFreeModule_Tensor):
 539     @staticmethod
 540     def __classcall_private__(cls, modules, **options):
 541         return CombinatorialFreeModule_Tensor.__classcall_private__(cls, modules, **options)
 542 
 543     def cartan_type(self):
 544         return self._sets[0].cartan_type()
 545 
 546     def e_on_basis(self, i, b):
 547         mon = [self._sets[k].monomial(elt) for k,elt in enumerate(b)]
 548         t = self.tensor_constructor(self._sets)
 549         ret = self.zero()
 550         for k,elt in enumerate(b):
 551             ret += t(*(mon[:k] + [self._sets[k].e_on_basis(i, elt)] + mon[k+1:]))
 552         return ret
 553 
 554     def f_on_basis(self, i, b):
 555         mon = [self._sets[k].monomial(elt) for k,elt in enumerate(b)]
 556         t = self.tensor_constructor(self._sets)
 557         ret = self.zero()
 558         for k,elt in enumerate(b):
 559             ret += t(*(mon[:k] + [self._sets[k].f_on_basis(i, elt)] + mon[k+1:]))
 560         return ret
 561 
 562     def h_on_basis(self, i, b, power=1):
 563         return sum(self._sets[k].h_on_basis(i, elt, power) for k,elt in enumerate(b))
 564 
 565     Element = ReprElement
 566 
 567 # -----------------------------------------------------------------------------------------
 568 
 569 ReprMinuscule.Tensor = RepresentationTensor
 570 ReprAdjoint.Tensor = RepresentationTensor
 571 SubRepresentation.Tensor = RepresentationTensor
 572 
 573 # -----------------------------------------------------------------------------------------
 574 
 575 def path_to_seq(p, G):
 576     return [G.edge_label(p[i], p[i+1]) for i in range(len(p)-1)]
 577 
 578 def apply_e(d, elt):
 579     for i in reversed(d):
 580         elt = elt.e(i)
 581     return elt
 582 
 583 def apply_f(d, elt):
 584     for i in reversed(d):
 585         elt = elt.f(i)
 586     return elt
 587 
 588 def gen_relations(hwd, G):
 589     """
 590     INPUT:
 591 
 592     - ``hwd`` -- a dict whose keys are elements of the crystal
 593       and whose values are the corresponding highest weight elements
 594     - ``G`` -- the digraph of the crystal tensor product
 595     """
 596     K = hwd.keys()
 597     rels = {}
 598     for k in K:
 599         for kp in K:
 600             if k == kp:
 601                 continue
 602             p = G.shortest_path(k, kp)
 603             data = [G.edge_label(p[i], p[i+1]) for i in range(len(p)-1)]
 604             ret = hwd[k]
 605             for i in data:
 606                 ret = ret.f(i)
 607             rels[k,kp] = ret
 608     return rels
 609 
 610 def lcm_factor(factors):
 611     common = list(reduce(lambda x,y: x.union(y), [set(p[0] for p in f) for f in factors]))
 612     def find(f, x):
 613         for p in f:
 614             if p[0] == x:
 615                 return p[1]
 616         return 0
 617     exp = [max(find(f, x) for f in factors) for x in common]
 618     return prod(common[i]**e for i,e in enumerate(exp))
 619 
 620 def verify_representation(V):
 621     ct = V.cartan_type()
 622     d = ct.symmetrizer()
 623     I = ct.index_set()
 624     A = ct.cartan_matrix()
 625     al = RootSystem(ct).weight_lattice().simple_roots()
 626     ac = RootSystem(ct).weight_lattice().simple_coroots()
 627     for x in V.basis():
 628         for i in I:
 629             for j in I:
 630                 assert x.e(j).h(i,1) - x.h(i,1).e(j) == al[i].scalar(ac[j]) * x.e(j), "[h,e] = Ae -- i: {}, j: {}, x: {}".format(i,j,x)
 631                 assert x.f(j).h(i,1) - x.h(i,1).f(j) == -al[i].scalar(ac[j]) * x.f(j), "[h,f] = -Af -- i: {}, j: {}, x: {}".format(i,j,x)
 632                 if i == j:
 633                     assert x.f(i).e(i) - x.e(i).f(i) == x.h(i,1), "[e,f] = h -- i: {} == j: {}".format(i, j)
 634                     continue
 635                 assert x.f(j).e(i) - x.e(i).f(j) == 0, "[e,f] = 0 -- i: {} j: {}".format(i, j)
 636                 # Check Serre
 637                 aij = A[I.index(i),I.index(j)]
 638                 assert 0 == sum((-1)^n
 639                            * binomial(1-aij, n)
 640                            * apply_e([i]*(1-aij-n) + [j] + [i]*n, x)
 641                            for n in range(1-aij+1)), "Serre e -- i: {}, j: {}".format(i,j)
 642                 assert 0 == sum((-1)^n
 643                            * binomial(1-aij, n)
 644                            * apply_f([i]*(1-aij-n) + [j] + [i]*n, x)
 645                            for n in range(1-aij+1)), "Serre f -- i: {}, j: {}".format(i,j)
 646 
 647 # Use the entire crystal
 648 def compute_highest_weight_vectors_full(V, I0, sparse=True, verbose=True):
 649     if verbose: print("  initializing highest weight vectors computation")
 650     order = V.get_order()
 651     R = V.base_ring()
 652     B = V.basis()
 653     if sparse:
 654         order_index = {k: j for j,k in enumerate(order)}
 655         @parallel
 656         def build_mat(i):
 657             data = {}
 658             for pos,k in enumerate(order):
 659                 for kp,c in B[k].e(i).monomial_coefficients().items():
 660                     data[order_index[kp],pos] = c
 661             return matrix(data, ring=R, nrows=len(order), ncols=len(order), sparse=True)
 662     else:
 663         @parallel
 664         def build_mat(i):
 665             data = []
 666             for k in order:
 667                 row = B[k].e(i)
 668                 data += [row[kp] for kp in order]
 669             return matrix(data, ring=R, nrows=len(order), ncols=len(order)).transpose()
 670 
 671     if verbose: print("  building E action matrices")
 672     Emat = [out for inp,out in build_mat(list(I0))]
 673     if verbose: print("  stacking...")
 674     S = matrix.block([[Em] for Em in Emat], sparse=sparse)
 675     #S.change_ring(SR)
 676     if verbose: print("  computing kernel")
 677     Ker = S.right_kernel_matrix()
 678     #Ker = Ker.change_ring(R)
 679     print(Ker.rank())
 680     return [V.from_vector(b) for b in Ker.rows()]
 681 
 682 # FIXME: Make the indices of a tensor product of KR modules be the
 683 #    tensor product of KR crystals. It will make functions like this
 684 #    require less special care!
 685 def compute_highest_weight_vectors(V, I0, TC, sparse=True, verbose=True, brute_force=False, group_by_weight=False):
 686     """
 687     - ``V`` -- tensor product of KR modules
 688     - ``I0`` -- classical index set
 689     - ``TC`` -- tensor product of KR crystals
 690 
 691     OUTPUT:
 692 
 693     - the vectors in ``V``
 694     - the classically highest weight elements in ``TC``
 695 
 696     .. WARNING::
 697 
 698         The ``i``-th position in these lists do not necessarily correspond
 699         (although they should be the same length).
 700     """
 701     if brute_force:
 702         if verbose: print("  initializing highest weight vectors computation")
 703         order = TC.list()  # We will need this list later, so +1 for caching
 704         dom_wt_elts = []
 705         cl_hw_elts = []
 706 
 707         if verbose: print("  finding dominant weight elements")
 708         for bt in order:
 709             b = TC(*bt)
 710             wt = b.weight()
 711             if all(wt[i] >= 0 for i in I0):  # Assume it is expressed using fundamental weights for speed
 712                 if all(b.e(i) is None for i in I0):
 713                     cl_hw_elts.append(b)
 714                 dom_wt_elts.append(b)
 715         # We restrict to the weights of the highest weight elements
 716         highest_weights = set(b.weight() for b in cl_hw_elts)
 717         # Make sure cl_hw_elts are first so they become pivots
 718         dom_wt_elts = ([tuple(b) for b in cl_hw_elts]
 719                        + [tuple(b) for b in dom_wt_elts
 720                           if b.weight() in highest_weights and b not in cl_hw_elts])
 721     else:
 722         if verbose: print("  initializing highest weight vectors computation")
 723         if verbose: print("   finding I0 highest weight elements in the crystal")
 724         cl_hw_elts = TC.classically_highest_weight_vectors()
 725         dom_wt_elts = [tuple(x) for x in cl_hw_elts]  # Make sure these are first so they are pivots
 726         highest_weights = set(b.weight() for b in cl_hw_elts)
 727         def mult(C):
 728             ret = {}
 729             for x in C:
 730                 wt = x.weight()
 731                 if wt in ret:
 732                     ret[wt].append(x)
 733                 else:
 734                     ret[wt] = [x]
 735             return ret
 736         if verbose: print("   computing multiplicies in tensor factors")
 737         mL, mR = mult(TC.crystals[0]), mult(TC.crystals[1])
 738         if verbose: print("  finding dominant weight elements")
 739         total = len(mL) * len(mR)
 740         div = total // 10 if total > 10 else 1
 741         count = 0
 742         for la in mL:
 743             for mu in mR:
 744                 count += 1
 745                 if count % div == 0 and verbose:
 746                     print("   {}".format(count * 100.0 / total))
 747                 if la + mu not in highest_weights:
 748                     continue
 749                 dom_wt_elts += [(x,y) for x in mL[la] for y in mR[mu]
 750                                 if (x,y) not in dom_wt_elts]
 751 
 752     R = V.base_ring()
 753     B = V.basis()
 754 
 755     grouped_dom_wt_elts = {}
 756     for elt in dom_wt_elts:
 757         wt = tensor_basis_wt(elt)
 758         if wt in grouped_dom_wt_elts:
 759             grouped_dom_wt_elts[wt].append(elt)
 760         else:
 761             grouped_dom_wt_elts[wt] = [elt]
 762 
 763     @parallel
 764     def compute_hw_elts(wt):
 765         dom_wt_elts = grouped_dom_wt_elts[wt]
 766 
 767         # We compute the E_i action restricted to these vectors
 768         if verbose: print("  {}: computing image of restricted E action of {} elements".format(wt, len(dom_wt_elts)))
 769         im_vecs = reduce(lambda X,Y: X.union(Y),
 770                          [B[k].e(i).monomial_coefficients(copy=False)
 771                           for k in dom_wt_elts for i in I0], set())
 772         im_vecs = list(im_vecs)
 773         if verbose: print("  {}: total support {}".format(wt, len(im_vecs)))
 774 
 775         if sparse:
 776             order_index = {k: j for j,k in enumerate(im_vecs)}
 777             #@parallel
 778             def build_mat(i):
 779                 data = {}
 780                 for pos,k in enumerate(dom_wt_elts):
 781                     for kp,c in B[k].e(i).monomial_coefficients(copy=False).items():
 782                         data[order_index[kp],pos] = c
 783                 return matrix(data, ring=R, nrows=len(im_vecs), ncols=len(dom_wt_elts), sparse=True)
 784         else:
 785             #@parallel
 786             def build_mat(i):
 787                 data = []
 788                 for k in dom_wt_elts:
 789                     row = B[k].e(i)
 790                     data += [row[kp] for kp in im_vecs]
 791                 return matrix(data, ring=R, nrows=len(dom_wt_elts), ncols=len(im_vecs)).transpose()
 792 
 793         if verbose: print("  {}: building E action matrices".format(wt))
 794         #Emat = [out for inp,out in build_mat(list(I0))]
 795         Emat = [build_mat(i) for i in I0]
 796         if verbose: print("  {}: stacking...".format(wt))
 797         S = matrix.block([[Em] for Em in Emat], sparse=sparse)
 798         #S.change_ring(SR)
 799         if verbose: print("  {}: computing kernel of {} matrix".format(wt, S.dimensions()))
 800         Ker = S.right_kernel_matrix()
 801         #Ker = Ker.change_ring(R)
 802         return Ker
 803 
 804     if group_by_weight:
 805         ret = {inp[0][0]: [V._from_dict({grouped_dom_wt_elts[inp[0][0]][i]: c for i,c in b.items()})
 806                            for b in Ker.rows()]
 807                for inp,Ker in compute_hw_elts(list(grouped_dom_wt_elts))}
 808         ret_hw = {wt: [] for wt in ret}
 809         for wt in ret:
 810             for x in cl_hw_elts:
 811                 if x.weight() == wt:
 812                     ret_hw[wt].append(x)
 813         return (ret, ret_hw)
 814 
 815     return (sum([[V._from_dict({grouped_dom_wt_elts[inp[0][0]][i]: c for i,c in b.items()})
 816                   for b in Ker.rows()]
 817                  for inp,Ker in compute_hw_elts(list(grouped_dom_wt_elts))],
 818                 []),
 819             tuple(cl_hw_elts))
 820 
 821     #ret_elts = []
 822     #for inp,Ker in compute_hw_elts(list(grouped_dom_wt_elts)):
 823     #    ret_elts.extend(V._from_dict({grouped_dom_wt_elts[inp[0][0]][i]: c for i,c in b.items()})
 824     #                    for b in Ker.rows())
 825     #
 826     #return (ret_elts, tuple(cl_hw_elts))
 827 
 828 def build_root_paths(ct):
 829     """
 830     Return a ``dict`` of positive roots and a path of simple root operators
 831     to obtain the result.
 832     """
 833     ct = CartanType(ct)
 834     I = ct.index_set()
 835     Q = RootSystem(ct).root_lattice()
 836     Phi = set(Q.positive_roots())
 837     al = Q.simple_roots()
 838     ret = {al[i]: [i] for i in al.keys()}
 839     next_level = dict(ret)
 840     while next_level:
 841         cur_level = next_level
 842         next_level = {}
 843         for beta in cur_level:
 844             for i in I:
 845                 gamma = beta + al[i]
 846                 if gamma in Phi and gamma not in ret:
 847                     ret[gamma] = cur_level[beta] + [i]
 848                     next_level[gamma] = ret[gamma]
 849     return ret
 850 
 851 def build_root_operators(ct):
 852     ct = CartanType(ct)
 853     paths = build_root_paths(ct)
 854     F = FreeMonoid(ct.index_set())
 855     A = F.algebra(QQ)
 856     x = A.algebra_generators()
 857     ret = {}
 858     for beta in paths:
 859         p = iter(paths[beta])
 860         cur = x[next(p)]
 861         for i in p:
 862             cur = cur * x[i] - x[i] * cur
 863         ret[beta] = [(t.to_word_list(), c) for t,c in cur]
 864     return ret
 865 
 866 def apply_f_operators(ops, v):
 867     r"""
 868     Apply ``ops`` to ``v``.
 869 
 870     INPUT:
 871 
 872     - ``ops`` -- a list of pairs ``(F, c)``, where ``F`` is a list
 873       of indices and ``c`` is the scaling coefficient
 874     - ``v`` -- the vector of the representation
 875 
 876     OUTPUT:
 877 
 878     ``sum( c * F(v) for F, c in ops )``
 879 
 880     EXAMPLES::
 881 
 882         sage: # S is B(\Lambda_4) in type E_6 constructed from above
 883         sage: v = S.maximal_vector()
 884         sage: al = RootSystem(['E',6]).root_lattice().simple_roots()
 885         sage: b1 = al[1] + 1*al[2] + 2*al[3] + 3*al[4] + 2*al[5] + al[6]
 886         sage: b2 = al[1] + 2*al[2] + 2*al[3] + 3*al[4] + 2*al[5] + al[6]
 887         sage: ops = build_root_operators(['E',6])
 888         sage: vzero = apply_f_operators(ops[b2], apply_f_operators(ops[b1], v))
 889         sage: vzero != 0
 890         True
 891 
 892     The slow way of building the orbit (but still reasonably fast)::
 893 
 894         sage: orbit = set([vzero])
 895         sage: nl = [vzero]
 896         sage: I = CartanType(['E',6]).index_set()
 897         sage: while nl:
 898         ....:     cur = nl
 899         ....:     nl = []
 900         ....:     for vec in cur:
 901         ....:         for i in I:
 902         ....:             vs = vec.s(i)
 903         ....:             if vs in orbit or -vs in orbit:
 904         ....:                 continue
 905         ....:             orbit.add(vs)
 906         ....:             nl.append(vs)
 907         sage: len(orbit)                                                                          
 908         240
 909         sage: matrix([[vec[b] for b in wt0] for vec in orbit]).rank()
 910         45
 911     """
 912     ret = v.parent().zero()
 913     for F, c in ops:
 914         temp = v
 915         for i in reversed(F):
 916             temp = temp.f(i)
 917         ret += c * temp
 918     return ret

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2022-12-30 01:29:45, 7.2 KB) [[attachment:Factorization into q-integers.ipynb]]
  • [get | view] (2022-12-24 00:36:50, 34.2 KB) [[attachment:lie_algebra_reprs.sage]]
  • [get | view] (2022-12-24 00:36:55, 11.2 KB) [[attachment:q_characters.sage]]
  • [get | view] (2022-12-24 00:37:02, 1.2 KB) [[attachment:specht_modules.sage]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.