Put reference to arXiv preprint in README.
[fgc-section-5.git] / kc.myr
blob3185f0d275767a6ce83e8771f129c7af470853a2
1 use std
3 use yakmo
5 use "types"
6 use "zzz"
8 /*
9    We use a Dynkin diagrams based on data in Knapp, appendix C. Most of
10    them have form
12         1     2     3            n
13         o --> o --> o -- ... --> o .
15    For B, C, F, the nodes may be of different weights. For these, the
16    Coxeter element is { 1, 2, ..., n } or { n, n - 1, ..., 1 } (see
17    below).
19    For E_{6,7,8}, the node ordering is odd, so the Coxeter element needs
20    to be considered carefully.
22    For A_{2n + 1}, the ordering is extremely odd, due to the cyclic
23    nature of the extended Dynkin diagram:
25        1     2            n
26        o --> o --> .. --> o
27                            \
28                             o (n+1)
29                            /
30        o --> o --> .. --> o
31     (2n+1)  2n          (n+2)
34    Note that the weights in the quiver are backwards from the weights in
35    the Dynkin diagrams: for example, the normal diagram for C_n is
37        (1) -- (1) -- (1) -- ... -- (1) -- (2)
39    however, when we construct the quiver, the weights will be
41        (2) -- (2) -- (2) -- ... -- (2) -- (1).
42  */
44 pkg =
45         impl std.equatable KC_type
46         impl std.hashable KC_type
48         const parse_KC_type : (str : byte[:] -> std.result(KC_type, byte[:]))
49         const get_n : (kc : KC_type -> int)
50         const get_weight : (kc : KC_type, j : weyl_reflection -> (int,int))
51         const coxeter_num : (kc : KC_type -> int)
52         const get_edges : (kc : KC_type -> (weyl_reflection, weyl_reflection)[:])
53         const get_tree_partition : (kc : KC_type -> weyl_reflection[:][:])
54         const get_simple_roots : (kc : KC_type -> vector#[:])
55         const get_fundamental_weights : (kc : KC_type -> vector#[:])
56         const inv_coxeter : (kc : KC_type, s : weyl_reflection -> std.size)
58         /*
59            Functions below this comment have their results cached: do
60            not free results (even error strings, if those are possible)
62            TODO: move more functions down to here..
63          */
64         const get_coxeter_elt : (kc : KC_type -> std.result(weyl_reflection[:], byte[:]))
65         const get_cartan_matrix : (kc : KC_type -> int[:][:])
66         const get_w0 : (kc : KC_type -> weyl_reflection[:])
69 var cartan_matrix_stored : std.htab(KC_type, int[:][:])#
70 var coxeter_elt_stored : std.htab(KC_type, std.result(weyl_reflection[:], byte[:]))#
71 var w0_stored : std.htab(KC_type, weyl_reflection[:])#
73 const __init__ = {
74         cartan_matrix_stored = std.mkht()
75         coxeter_elt_stored = std.mkht()
76         w0_stored = std.mkht()
79 const __finit__ = {
80         for (key, val) : std.byhtkeyvals(cartan_matrix_stored)
81                 __dispose__(val)
82         ;;
83         std.htfree(cartan_matrix_stored)
85         for (key, val) : std.byhtkeyvals(coxeter_elt_stored)
86                 match val
87                 | `std.Ok x: __dispose__(x)
88                 | `std.Err e: std.slfree(e)
89                 ;;
90         ;;
91         std.htfree(coxeter_elt_stored)
93         for (key, val) : std.byhtkeyvals(w0_stored)
94                 __dispose__(val)
95         ;;
96         std.htfree(w0_stored)
99 impl std.equatable KC_type =
100         eq = {a, b
101                 match (a, b)
102                 | (`A n1, `A n2): -> n1 == n2
103                 | (`B n1, `B n2): -> n1 == n2
104                 | (`C n1, `C n2): -> n1 == n2
105                 | (`D n1, `D n2): -> n1 == n2
106                 | (`E6,   `E6): -> true
107                 | (`E7,   `E7): -> true
108                 | (`E8,   `E8): -> true
109                 | (`F4,   `F4): -> true
110                 | (`G2,   `G2): -> true
111                 | (_,     _): -> false
112                 ;;
113         }
116 impl std.hashable KC_type =
117         hash = {kc
118                 match kc
119                 | `A n: -> (n : uint64) ^ (0x100 << 32)
120                 | `B n: -> (n : uint64) ^ (0x101 << 32)
121                 | `C n: -> (n : uint64) ^ (0x110 << 32)
122                 | `D n: -> (n : uint64) ^ (0x111 << 32)
123                 | `E6:  -> 0
124                 | `E7:  -> 1
125                 | `E8:  -> 2
126                 | `F4:  -> 3
127                 | `G2:  -> 4
128                 ;;
129         }
132 const parse_KC_type = { str : byte[:]
133         if str.len < 2
134                 -> `std.Err std.fmt("Unknown Killing—Cartan type “{}”", str)
135         ;;
137         var n = 0
138         match std.intparse(str[1:])
139         | `std.Some nn: n = nn
140         | `std.None: -> `std.Err std.fmt("Unknown Killing—Cartan type “{}”", str)
141         ;;
143         if n < 0
144                 -> `std.Err std.fmt("Killing—Cartan subscript “{}” should be positive", str[1:])
145         ;;
147         match (std.toupper((str[0] : char)), n)
148         | ('A', _): -> `std.Ok `A n
149         | ('B', _): -> `std.Ok `B n
150         | ('C', _): -> `std.Ok `C n
151         | ('D', _): -> `std.Ok `D n
152         | ('E', 6): -> `std.Ok `E6
153         | ('E', 7): -> `std.Ok `E7
154         | ('E', 8): -> `std.Ok `E8
155         | ('E', _): -> `std.Err std.fmt("Killing—Cartan type E must be one of “E6”, “E7”, “E8”")
156         | ('F', 4): -> `std.Ok `F4
157         | ('F', _): -> `std.Err std.fmt("Killing—Cartan type F must be “F4”")
158         | ('G', 2): -> `std.Ok `G2
159         | ('G', _): -> `std.Err std.fmt("Killing—Cartan type G must be “G2”")
160         | (c, _): -> `std.Err std.fmt("Killing—Cartan type {} unknown/unsupported", c)
161         ;;
164 const coxeter_num = {kc : KC_type
165         match kc
166         | `A n: -> n + 1
167         | `B n: -> 2*n
168         | `C n: -> 2*n
169         | `D n:
170                 if n == 1
171                         -> 2
172                 ;;
173                 -> 2*n - 2
174         | `E6:  -> 12
175         | `E7:  -> 18
176         | `E8:  -> 30
177         | `F4:  -> 12
178         | `G2:  -> 6
179         ;;
182 const get_n = {kc : KC_type
183         match kc
184         | `A n: -> n
185         | `B n: -> n
186         | `C n: -> n
187         | `D n: -> n
188         | `E6:  -> 6
189         | `E7:  -> 7
190         | `E8:  -> 8
191         | `F4:  -> 4
192         | `G2:  -> 2
193         ;;
197    The coxeter element is 1-based. For C2 is it [1, 2][:]. This is
198    because the entries should be used for vertex names, not arithmetic.
199  */
200 const get_coxeter_elt = {kc : KC_type
201         match std.htget(coxeter_elt_stored, kc)
202         | `std.Some stored: -> stored
203         | _:
204         ;;
206         var ret
207         match kc
208         | `E6: ret = `std.Ok std.sldup([2,4,3,5,1,6][:])
209         | `E7: ret = `std.Ok std.sldup([7,6,5,4,2,3,1][:])
210         | `E8: ret = `std.Ok std.sldup([8,7,6,5,4,2,3,1][:])
211         | `G2: ret = `std.Ok std.sldup([1, 2][:])
212         | `D nn:
213                 var l : weyl_reflection[:] = [][:]
214                 for var j = 1; j <= nn; ++j
215                         std.slpush(&l, (j : weyl_reflection))
216                 ;;
218                 ret = `std.Ok l
219         | `A nn:
220                 /*
221                    The result will not be a Coxeter element
222                    corresponding to a well-rooted, tree-like quiver. In
223                    the case n is even, this gives garbage. In the case n
224                    is odd, this gives an anti-well-rooted tree-like
225                    quiver. Whatever.
226                  */
227                 if nn % 2 == 0
228                         ret = `std.Err std.fmt("Coxeter elements for A_2n do not form w0")
229                 else
230                         var l : weyl_reflection[:] = [][:]
232                         for var j = (nn + 1) / 2; j >= 1; --j
233                                 std.slpush(&l, (j : weyl_reflection))
234                                 if j != nn - j + 1
235                                         std.slpush(&l, (nn - j + 1 : weyl_reflection))
236                                 ;;
237                         ;;
239                         ret = `std.Ok l
240                 ;;
241         | _:
242                 /* Take the easy way out */
243                 var l : weyl_reflection[:] = [][:]
244                 var n = get_n(kc)
245                 for var j = 0; j < n; ++j
246                         std.slpush(&l, (j + 1 : weyl_reflection))
247                 ;;
249                 ret = `std.Ok l
250         ;;
252         std.htput(coxeter_elt_stored, kc, ret)
253         -> ret
257    Based on the Dynkin diagram, as encoded by get_edges and get_weight.
258  */
259 const get_cartan_matrix = {kc
260         match std.htget(cartan_matrix_stored, kc)
261         | `std.Some stored: -> stored
262         | _:
263         ;;
265         var rank = get_n(kc)
266         var edges : (weyl_reflection, weyl_reflection)[:] = auto get_edges(kc)
268         var A : int[:][:] = std.slalloc((rank : std.size))
269         for var j = 0; j < rank; ++j
270                 A[j] = std.slalloc((rank : std.size))
271                 for var k = 0; k < rank; ++k
272                         if j == k
273                                 A[j][k] = 2
274                         else
275                                 A[j][k] = 0
276                         ;;
277                 ;;
278         ;;
280         for (j, k) : edges
281                 var wj = get_weight(kc, j).1
282                 var wk = get_weight(kc, k).1
284                 /* Quick, dumb gcd that works for this specific case only */
285                 var d = std.min(wj, wk)
286                 if wj == wk
287                         d = wj
288                 ;;
290                 A[j - 1][k - 1] = -1 * wk / d
291                 A[k - 1][j - 1] = -1 * wj / d
292         ;;
294         std.htput(cartan_matrix_stored, kc, A)
295         -> A
298 const get_edges = {kc
299         var edges : (weyl_reflection, weyl_reflection)[:] = [][:]
300         match kc
301         | `A n:
302                 for var i = 1; i + 1 <= (n + 1) / 2; ++i
303                         std.slpush(&edges, ((i + 1 : weyl_reflection), (i : weyl_reflection)))
304                         std.slpush(&edges, ((n - i : weyl_reflection), (n - i + 1 : weyl_reflection)))
305                 ;;
307                 -> edges
308         | `D n:
309                 if n < 3
310                         -> [][:]
311                 else
312                         for var i = 1; i + 1 <= (n - 2); ++i
313                                 std.slpush(&edges, ((i : weyl_reflection), (i + 1 : weyl_reflection)))
314                         ;;
315                         std.slpush(&edges, ((n - 2 : weyl_reflection), (n - 1 : weyl_reflection)))
316                         std.slpush(&edges, ((n - 2 : weyl_reflection), (n - 0 : weyl_reflection)))
317                 ;;
319                 -> edges
320         | `E6: -> std.sldup([(2, 4), (4, 5), (5, 6), (4, 3), (3, 1)][:])
321         | `E7: -> std.sldup([(7,6), (6,5), (5,4), (4,2), (4,3), (3,1)][:])
322         | `E8: -> std.sldup([(8,7), (7,6), (6,5), (5,4), (4,2), (4,3), (3,1)][:])
323         | _:
324                 var nn = get_n(kc)
325                 for var i = 1; i + 1 <= nn; ++i
326                         std.slpush(&edges, ((i : weyl_reflection), (i + 1 : weyl_reflection)))
327                 ;;
329                 -> edges
330         ;;
334    All from Knapp. Return { ω_1, ω_2, …, ω_n}, with each given as
335    coefficients of the standard vector basis { e_i }.
337    So, for E8, ω_1 is NOT [ 4, 5, 7, ... ][:]. It is 4α_1 + 5α_2 + ...
338  */
339 const get_fundamental_weights = {kc
340         var ret : vector#[:] = [][:]
342         var zero : yakmo.Q# = yakmo.gid()
343         var one : yakmo.Q# = yakmo.rid()
344         auto zero
345         auto one
346         var mone : yakmo.Q# = auto yakmo.gneg(one)
347         var half : yakmo.Q# = auto std.try(yakmo.Qfrom(1,2))
348         var mhalf : yakmo.Q# = auto std.try(yakmo.Qfrom(-1,2))
350         var coeffs : (int[:], int)[:] = [][:]
351         match kc
352         | `A n:
353                 for var j = 0; j < n; ++j
354                         var new_w = std.slalloc((n + 1 : std.size))
355                         for var k = 0; k <= j; ++k
356                                 new_w[k] = t.dup(one)
357                         ;;
358                         for var k = j + 1; k < n + 1; ++k
359                                 new_w[k] = t.dup(zero)
360                         ;;
362                         var summand = auto std.try(yakmo.Qfrom(-1 * (j + 1), n + 1))
363                         for var k = 0; k < n + 1; ++k
364                                 yakmo.gadd_ip(new_w[k], summand)
365                         ;;
367                         std.slpush(&ret, std.mk([ .c = new_w ]))
368                 ;;
370                 -> ret
371         | `B n:
372                 for var j = 0; j < n - 1; ++j
373                         var new_w = std.slalloc((n : std.size))
374                         for var k = 0; k < j + 1; ++k
375                                 new_w[k] = t.dup(one)
376                         ;;
377                         for var k = j + 1; k < n; ++k
378                                 new_w[k] = t.dup(zero)
379                         ;;
380                         std.slpush(&ret, std.mk([ .c = new_w ]))
381                 ;;
383                 var w_n = std.slalloc((n : std.size))
384                 for var k = 0; k < n; ++k
385                         w_n[k] = t.dup(half)
386                 ;;
387                 std.slpush(&ret, std.mk([ .c = w_n ]))
389                 -> ret
390         | `C n:
391                 for var j = 0; j < n; ++j
392                         var new_w = std.slalloc((n : std.size))
393                         for var k = 0; k < j + 1; ++k
394                                 new_w[k] = t.dup(one)
395                         ;;
396                         for var k = j + 1; k < n; ++k
397                                 new_w[k] = t.dup(zero)
398                         ;;
399                         std.slpush(&ret, std.mk([ .c = new_w ]))
400                 ;;
402                 -> ret
403         | `D n:
404                 if n == 1
405                         -> get_fundamental_weights(`A 1)
406                 ;;
408                 for var j = 0; j < n - 2; ++j
409                         var new_w = std.slalloc((n : std.size))
410                         for var k = 0; k < j + 1; ++k
411                                 new_w[k] = t.dup(one)
412                         ;;
413                         for var k = j + 1; k < n; ++k
414                                 new_w[k] = t.dup(zero)
415                         ;;
416                         std.slpush(&ret, std.mk([ .c = new_w ]))
417                 ;;
419                 var w_nm1 = std.slalloc((n : std.size))
420                 for var k = 0; k < n - 1; ++k
421                         w_nm1[k] = t.dup(half)
422                 ;;
423                 w_nm1[n - 1] = t.dup(mhalf)
424                 std.slpush(&ret, std.mk([ .c = w_nm1 ]))
426                 var w_n = std.slalloc((n : std.size))
427                 for var k = 0; k < n - 1; ++k
428                         w_n[k] = t.dup(half)
429                 ;;
430                 w_n[n - 1] = t.dup(half)
431                 std.slpush(&ret, std.mk([ .c = w_n ]))
433                 -> ret
435         /* For the exceptional ones, construct in terms of simple roots */
436         | `E6:
437                 coeffs = [
438                         ([  4,  3,  5,  6,  4,  2][:], 3),
439                         ([  1,  2,  2,  3,  2,  1][:], 1),
440                         ([  5,  6, 10, 12,  8,  4][:], 3),
441                         ([  2,  3,  4,  6,  4,  2][:], 1),
442                         ([  4,  6,  8, 12, 10,  5][:], 3),
443                         ([  2,  3,  4,  6,  5,  4][:], 3),
444                 ][:]
445         | `E7:
446                 coeffs = [
447                         ([  2,  2,  3,  4,  3,  2,  1][:], 1),
448                         ([  4,  7,  8, 12,  9,  6,  3][:], 2),
449                         ([  3,  4,  6,  8,  6,  4,  2][:], 1),
450                         ([  4,  6,  8, 12,  9,  6,  3][:], 1),
451                         ([  6,  9, 12, 18, 15, 10,  5][:], 2),
452                         ([  2,  3,  4,  6,  5,  4,  2][:], 1),
453                         ([  2,  3,  4,  6,  5,  4,  3][:], 2),
454                 ][:]
455         | `E8:
456                 coeffs = [
457                         ([  4,  5,  7, 10,  8,  6,  4,  2][:], 1),
458                         ([  5,  8, 10, 15, 12,  9,  6,  3][:], 1),
459                         ([  7, 10, 14, 20, 16, 12,  8,  4][:], 1),
460                         ([ 10, 15, 20, 30, 24, 18, 12,  6][:], 1),
461                         ([  8, 12, 16, 24, 20, 15, 10,  5][:], 1),
462                         ([  6,  9, 12, 18, 15, 12,  8,  4][:], 1),
463                         ([  4,  6,  8, 12, 10,  8,  6,  3][:], 1),
464                         ([  2,  3,  4,  6,  5,  4,  3,  2][:], 1),
465                 ][:]
466         | `F4:
467                 coeffs = [
468                         ([  2,  3,  2,  1][:], 1),
469                         ([  3,  6,  4,  2][:], 1),
470                         ([  4,  8,  6,  3][:], 1),
471                         ([  2,  4,  3,  2][:], 1),
472                 ][:]
473         | `G2:
474                 coeffs = [
475                         ([  2,  1][:], 1),
476                         ([  3,  2][:], 1),
477                 ][:]
478         ;;
480         var simple_roots = auto get_simple_roots(kc)
481         for (a, p) : coeffs
482                 /* new_c = (a · simple_roots) / p */
483                 var new_c = std.slalloc(simple_roots[0].c.len)
484                 for var k = 0; k < new_c.len; ++k
485                         new_c[k] = t.dup(zero)
486                 ;;
488                 for var j = 0; j < a.len; ++j
489                         var mul = auto yakmo.QfromZ(a[j])
491                         /* new_c += (a[j])(simple_roots[j]) */
492                         for var k = 0; k < new_c.len; ++k
493                                 yakmo.gadd_ip(new_c[k], auto yakmo.rmul(mul, simple_roots[j].c[k]))
494                         ;;
495                 ;;
497                 /* new_c /= p */
498                 if p != 1
499                         var r = auto yakmo.QfromZ(p)
500                         match yakmo.finv(r)
501                         | `std.Some ri:
502                                 for var k = 0; k < new_c.len; ++k
503                                         yakmo.rmul_ip(new_c[k], ri)
504                                 ;;
505                                 auto ri
506                         | _: /* I guarantee this won't happen, since user input doesn't touch here. */
507                         ;;
508                 ;;
509                 std.slpush(&ret, std.mk([ .c = new_c ]))
510         ;;
512         -> ret
516    All from Knapp. Return Π = { α_1, α_2, …, α_n}, with each vector
517    given as coefficients of the standard vector basis { e_i }. The
518    returned array (of the α_is) is 0-based. Each individual α_i is
519    0-based.
520  */
521 const get_simple_roots = {kc
522         var ret : vector#[:] = [][:]
523         var zero : yakmo.Q# = yakmo.gid()
524         var one : yakmo.Q# = yakmo.rid()
525         var mone : yakmo.Q# = auto yakmo.gneg(one)
526         var half : yakmo.Q# = std.try(yakmo.Qfrom(1, 2))
527         var mhalf : yakmo.Q# = yakmo.gneg(half)
528         auto zero
529         auto one
530         auto half
531         auto mhalf
532         match kc
533         | `A n:
534                 var new_c = std.slalloc((n : std.size) + 1)
535                 var new_v = [ .c = new_c ]
536                 for var j = 1; j <= n; ++j
537                         std.slfill(new_c, zero)
538                         new_c[(j - 1) + 0] = one
539                         new_c[(j - 1) + 1] = mone
540                         std.slpush(&ret, t.dup(&new_v))
541                 ;;
542                 std.slfree(new_c)
543         | `B n:
544                 var new_c = std.slalloc((n : std.size))
545                 var new_v = [ .c = new_c ]
546                 for var j = 1; j < n; ++j
547                         std.slfill(new_c, zero)
548                         new_c[(j - 1) + 0] = one
549                         new_c[(j - 1) + 1] = mone
550                         std.slpush(&ret, t.dup(&new_v))
551                 ;;
552                 std.slfill(new_c, zero)
553                 new_c[n - 1] = one
554                 std.slpush(&ret, t.dup(&new_v))
555                 std.slfree(new_c)
556         | `C n:
557                 var new_c = std.slalloc((n : std.size))
558                 var new_v = [ .c = new_c ]
559                 for var j = 1; j < n; ++j
560                         std.slfill(new_c, zero)
561                         new_c[(j - 1) + 0] = one
562                         new_c[(j - 1) + 1] = mone
563                         std.slpush(&ret, t.dup(&new_v))
564                 ;;
565                 std.slfill(new_c, zero)
566                 new_c[n - 1] = auto yakmo.gadd(one, one)
567                 std.slpush(&ret, t.dup(&new_v))
568                 std.slfree(new_c)
569         | `D n:
570                 if n == 1
571                         -> get_simple_roots(`A 1)
572                 ;;
574                 var new_c = std.slalloc((n : std.size))
575                 var new_v = [ .c = new_c ]
576                 for var j = 1; j < n; ++j
577                         std.slfill(new_c, zero)
578                         new_c[(j - 1) + 0] = one
579                         new_c[(j - 1) + 1] = mone
580                         std.slpush(&ret, t.dup(&new_v))
581                 ;;
582                 std.slfill(new_c, zero)
583                 if n >= 2
584                         new_c[n - 2] = one
585                 ;;
586                 if n >= 1
587                         new_c[n - 1] = one
588                 ;;
589                 std.slpush(&ret, t.dup(&new_v))
590                 std.slfree(new_c)
591         | `E6:
592                 std.slpush(&ret, t.dup(&[ .c = [ half, mhalf, mhalf, mhalf, mhalf, mhalf, mhalf,  half][:] ]))
593                 std.slpush(&ret, t.dup(&[ .c = [  one,   one,  zero,  zero,  zero,  zero,  zero,  zero][:] ]))
594                 std.slpush(&ret, t.dup(&[ .c = [ mone,   one,  zero,  zero,  zero,  zero,  zero,  zero][:] ]))
595                 std.slpush(&ret, t.dup(&[ .c = [ zero,  mone,   one,  zero,  zero,  zero,  zero,  zero][:] ]))
596                 std.slpush(&ret, t.dup(&[ .c = [ zero,  zero,  mone,   one,  zero,  zero,  zero,  zero][:] ]))
597                 std.slpush(&ret, t.dup(&[ .c = [ zero,  zero,  zero,  mone,   one,  zero,  zero,  zero][:] ]))
598         | `E7:
599                 std.slpush(&ret, t.dup(&[ .c = [ half, mhalf, mhalf, mhalf, mhalf, mhalf, mhalf,  half][:] ]))
600                 std.slpush(&ret, t.dup(&[ .c = [  one,   one,  zero,  zero,  zero,  zero,  zero,  zero][:] ]))
601                 std.slpush(&ret, t.dup(&[ .c = [ mone,   one,  zero,  zero,  zero,  zero,  zero,  zero][:] ]))
602                 std.slpush(&ret, t.dup(&[ .c = [ zero,  mone,   one,  zero,  zero,  zero,  zero,  zero][:] ]))
603                 std.slpush(&ret, t.dup(&[ .c = [ zero,  zero,  mone,   one,  zero,  zero,  zero,  zero][:] ]))
604                 std.slpush(&ret, t.dup(&[ .c = [ zero,  zero,  zero,  mone,   one,  zero,  zero,  zero][:] ]))
605                 std.slpush(&ret, t.dup(&[ .c = [ zero,  zero,  zero,  zero,  mone,   one,  zero,  zero][:] ]))
606         | `E8:
607                 std.slpush(&ret, t.dup(&[ .c = [ half, mhalf, mhalf, mhalf, mhalf, mhalf, mhalf,  half][:] ]))
608                 std.slpush(&ret, t.dup(&[ .c = [  one,   one,  zero,  zero,  zero,  zero,  zero,  zero][:] ]))
609                 std.slpush(&ret, t.dup(&[ .c = [ mone,   one,  zero,  zero,  zero,  zero,  zero,  zero][:] ]))
610                 std.slpush(&ret, t.dup(&[ .c = [ zero,  mone,   one,  zero,  zero,  zero,  zero,  zero][:] ]))
611                 std.slpush(&ret, t.dup(&[ .c = [ zero,  zero,  mone,   one,  zero,  zero,  zero,  zero][:] ]))
612                 std.slpush(&ret, t.dup(&[ .c = [ zero,  zero,  zero,  mone,   one,  zero,  zero,  zero][:] ]))
613                 std.slpush(&ret, t.dup(&[ .c = [ zero,  zero,  zero,  zero,  mone,   one,  zero,  zero][:] ]))
614                 std.slpush(&ret, t.dup(&[ .c = [ zero,  zero,  zero,  zero,  zero,  mone,   one,  zero][:] ]))
615         | `F4:
616                 std.slpush(&ret, t.dup(&[ .c = [ half, mhalf, mhalf, mhalf][:] ]))
617                 std.slpush(&ret, t.dup(&[ .c = [ zero,  zero,  zero,   one][:] ]))
618                 std.slpush(&ret, t.dup(&[ .c = [ zero,  zero,   one,  mone][:] ]))
619                 std.slpush(&ret, t.dup(&[ .c = [ zero,   one,  mone,  zero][:] ]))
620         | `G2:
621                 var mtwo = yakmo.QfromZ(-2)
622                 std.slpush(&ret, t.dup(&[ .c = [  one,  mone,  zero][:] ]))
623                 std.slpush(&ret, t.dup(&[ .c = [ mtwo,   one,   one][:] ]))
624         ;;
626         -> ret
630    Return 0 or 1 such that the sum of bits of j + eventh_bit(j) is even.
631    For use with E6, E7, E8 only, which all use R⁸ as V, so we need only
632    check the first 7 bits.
633  */
634 var eventh_bit = {j : int
635         var b = 0
636         b += (j & 0b0000001 == 0) ? 0 : 1
637         b += (j & 0b0000010 == 0) ? 0 : 1
638         b += (j & 0b0000100 == 0) ? 0 : 1
639         b += (j & 0b0001000 == 0) ? 0 : 1
640         b += (j & 0b0010000 == 0) ? 0 : 1
641         b += (j & 0b0100000 == 0) ? 0 : 1
642         b += (j & 0b1000000 == 0) ? 0 : 1
644         -> b % 2
647 const get_tree_partition = {t
648         var partition : weyl_reflection[:][:] = [][:]
649         match t
650         | `A n:
651                 std.slpush(&partition, [][:])
652                 var nw : weyl_reflection = (n : weyl_reflection)
653                 for var i = (n + 1) / 2; i >= 1; --i
654                         var iw : weyl_reflection = (i : weyl_reflection)
655                         if i == n - i + 1
656                                 std.slpush(&partition, std.sldup([ iw ][:]))
657                         else
658                                 std.slpush(&partition, std.sldup([ iw, nw - iw + 1 ][:]))
659                         ;;
660                 ;;
662                 -> partition
663         | `D n:
664                 var nw : weyl_reflection = (n : weyl_reflection)
665                 if n < 3
666                         -> get_tree_partition(`A n)
667                 else
668                         std.slpush(&partition, [][:])
669                         for var i = 1; i <= (n - 2); ++i
670                                 var iw : weyl_reflection = (i : weyl_reflection)
671                                 std.slpush(&partition, std.sldup([ iw ][:]))
672                         ;;
673                         std.slpush(&partition, std.sldup([nw - 1, nw - 0][:]))
674                 ;;
676                 -> partition
677         | `E6:
678                 std.slpush(&partition, [][:])
679                 std.slpush(&partition, std.sldup([ 2 ][:]))
680                 std.slpush(&partition, std.sldup([ 4 ][:]))
681                 std.slpush(&partition, std.sldup([ 3, 5 ][:]))
682                 std.slpush(&partition, std.sldup([ 1, 6 ][:]))
683                 -> partition
684         | `E7:
685                 std.slpush(&partition, [][:])
686                 std.slpush(&partition, std.sldup([ 7 ][:]))
687                 std.slpush(&partition, std.sldup([ 6 ][:]))
688                 std.slpush(&partition, std.sldup([ 5 ][:]))
689                 std.slpush(&partition, std.sldup([ 4 ][:]))
690                 std.slpush(&partition, std.sldup([ 3, 2 ][:]))
691                 std.slpush(&partition, std.sldup([ 1 ][:]))
692                 -> partition
693         | `E8:
694                 std.slpush(&partition, [][:])
695                 std.slpush(&partition, std.sldup([ 8 ][:]))
696                 std.slpush(&partition, std.sldup([ 7 ][:]))
697                 std.slpush(&partition, std.sldup([ 6 ][:]))
698                 std.slpush(&partition, std.sldup([ 5 ][:]))
699                 std.slpush(&partition, std.sldup([ 4 ][:]))
700                 std.slpush(&partition, std.sldup([ 3, 2 ][:]))
701                 std.slpush(&partition, std.sldup([ 1 ][:]))
702                 -> partition
703         | _:
704                 var nn = get_n(t)
705                 std.slpush(&partition, [][:])
706                 for var i = 1; i <= nn; ++i
707                         var iw : weyl_reflection = (i : weyl_reflection)
708                         std.slpush(&partition, std.sldup([ iw ][:]))
709                 ;;
711                 -> partition
712         ;;
716    Get the weight for the vertex that will have j as the first subscript
717    (so j is 1-based, because this comes from names, not indices).
719    This returns both Dynkin diagram weights and quiver weights, which
720    are dual to each other. The return value is (quiver, dynkin)
721  */
722 const get_weight = {t : KC_type, j : weyl_reflection
723         if j <= 0 || (j : int) > get_n(t)
724                 -> (0,0)
725         ;;
727         match (t, j)
728         | (`A _, _): -> (1,1)
729         | (`B n, _):
730                 if (j : int) == n
731                         -> (2,1)
732                 else
733                         -> (1,2)
734                 ;;
735         | (`C n, _):
736                 if (j : int) == n
737                         -> (1,2)
738                 else
739                         -> (2,1)
740                 ;;
741         | (`D _, _): -> (1,1)
742         | (`E6, _):  -> (1,1)
743         | (`E7, _):  -> (1,1)
744         | (`E8, _):  -> (1,1)
746         | (`F4, 1):  -> (2,1)
747         | (`F4, 2):  -> (2,1)
748         | (`F4, 3):  -> (1,2)
749         | (`F4, 4):  -> (1,2)
750         | (`F4, _):  -> (0,0) /* impossible */
752         | (`G2, 1):  -> (3,1)
753         | (`G2, 2):  -> (1,3)
754         | (`G2, _):  -> (0,0) /* impossible */
755         ;;
758 const get_w0 = {kc
759         match std.htget(w0_stored, kc)
760         | `std.Some stored: -> stored
761         | _:
762         ;;
764         var w : weyl_reflection[:] = [][:]
765         match kc
766         | `A n:
767                 if n % 2 == 0
768                         for var l = n; l > 0; --l;
769                                 for var i = 1; i <= n; ++i
770                                         std.slpush(&w, (i : weyl_reflection))
771                                 ;;
772                         ;;
773                 else
774                         var c = std.try(get_coxeter_elt(kc))
775                         var h = coxeter_num(kc)
776                         var hh = h / 2
777                         for var j = 0; j < hh; ++j
778                                 std.sljoin(&w, c)
779                         ;;
780                 ;;
781         | _:
782                 var c = std.try(get_coxeter_elt(kc))
783                 var h = coxeter_num(kc)
784                 var hh = h / 2
785                 for var j = 0; j < hh; ++j
786                         std.sljoin(&w, c)
787                 ;;
788         ;;
790         std.htput(w0_stored, kc, w)
791         -> w
794 const inv_coxeter = {kc : KC_type, s : weyl_reflection
795         match get_coxeter_elt(kc)
796         | `std.Ok c:
797                 for var j = 0; j < c.len; ++j
798                         if c[j] == s
799                                 -> j
800                         ;;
801                 ;;
802         | `std.Err e:
803         ;;
805         -> -1