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.You are not allowed to attach a file to this page.