13 The input is mc = [ (1, g1), (2, g2), ..., (m, gm) ][:], where
15 gk = Δ^{γ_k}(y) for y in N_{-} .
17 Note that the first r coordinates are not coordinates
18 assigned to the quiver vertices. This is because they turn
19 out to be rational functions of solely edge coordinates.
21 The output is [ `X(i1, t1), `X(i2, t2), ..., `X(im, tm) ][:],
22 which give factorization coordinates for x in N_{+}, such
25 y = π_{-}(x) = w0^{-1} [ x w0^{-1} ]_{+} wo
27 Note that, due to the π_{-}(x) stuff, this map is actually
28 (ΨΦΨ)(u). Give minor coordinates for u, receive factorization
29 coordinates for (ΨΦΨ)(u).
31 const interior_fc_from_mc : (kc : KC_type, mc : minor_coordinate[:] -> std.result(factorization_coordinate[:], byte[:]))
32 const interior_fc_from_mc_and_undo_psi_phi_psi : (kc : KC_type, mc : minor_coordinate[:] -> std.result(factorization_coordinate[:], byte[:]))
35 The inverse: given [ `X(i1, v1), ... `X(im, vm) ][:], produce
38 Note that, due to the π_{-}(x) stuff, this map is actually
39 (ΨΦΨ)^{-1}(u). Give factorization coordinates for u, receive
40 minor coordinates for (ΨΦΨ)^{-1}(u).
42 const interior_mc_from_fc : (kc : KC_type, fc : factorization_coordinate[:] -> std.result(minor_coordinate[:], byte[:]))
45 A degenerate case - minor coordinate are exactly
46 factorization coordinates on edges.
48 Note that this means that if mc[k] = (j, v), that j is used as
52 const edge_mc_from_fc : (kc : KC_type, fc : factorization_coordinate[:] -> std.result(minor_coordinate[:], byte[:]))
53 const edge_fc_from_mc : (kc : KC_type, mc : minor_coordinate[:] -> std.result(factorization_coordinate[:], byte[:]))
56 A specialized, degenerate case. Given H = [ `H(i1, v1), ...,
61 Which may be 1, or may be a product of vjs.
63 const chi : (fc : factorization_coordinate[:], j : weyl_reflection -> std.option(yakmo.ratfunc#))
66 Another specialized, degenerate case. Given H = [ [.k=k1,
67 .c=c1], ..., [.k=kn, .c=cn] ], and k, return the ci
68 corresponding to ki = k.
70 const delta_gamma_k : (h : minor_coordinate[:], k : int -> yakmo.ratfunc#)
72 /* The Φ and Ψ maps. */
73 const psi : (kc : KC_type, fc : factorization_coordinate[:] -> std.result(factorization_coordinate[:], byte[:]))
74 const phi : (kc : KC_type, fc : factorization_coordinate[:] -> std.result(factorization_coordinate[:], byte[:]))
75 const phi_inv : (kc : KC_type, fc : factorization_coordinate[:] -> std.result(factorization_coordinate[:], byte[:]))
77 /* ι : given (y, h, x), return (X, Y, H) such that yhx = XHY */
78 const iota : (kc : KC_type, y : factorization_coordinate[:], h : factorization_coordinate[:], x : factorization_coordinate[:] -> std.result((factorization_coordinate[:], factorization_coordinate[:], factorization_coordinate[:]), byte[:]))
81 compute w(h) = w h w^-1, where w \in W and h is given by
82 factorization coordinates. TODO: remove apply_word, it's
83 superceded by apply_wk.
85 apply_wk computes w_k h w_k⁻¹. required_sign is a little
86 special: it controls whether the "numerator", "denominator",
87 or "entire fraction" is returned (scare quotes because the
88 exponents are treated abstractly).
90 const apply_word : (kc : KC_type, w : weyl_reflection[:], h : factorization_coordinate[:] -> std.result(factorization_coordinate[:], byte[:]))
91 const apply_wk : (kc : KC_type, k : int, h : factorization_coordinate[:], required_sign : int -> std.result(factorization_coordinate[:], byte[:]))
93 /* Convenience methods for fiddling with H */
94 const multiply_h_mc_by_sG : (kc : KC_type, h : minor_coordinate[:] -> std.result(minor_coordinate[:], byte[:]))
95 const apply_wo_of_inv : (kc : KC_type, h : minor_coordinate[:] -> std.result(minor_coordinate[:], byte[:]))
97 /* Take a jumbled mess of factorization coords, put it in Y H X (or other) format */
98 type canonical_ordering = union
103 const canonicalize_factorization_coords : (kc : KC_type, fc : factorization_coordinate[:]#, ord : canonical_ordering -> std.result(void, byte[:]))
106 Given an alpha constructed from a quiver (missing the first
107 $rank coordinates, fill them in
109 const fill_in_alpha : (kc : KC_type, alpha : conf_3_star# -> std.result(void, byte[:]))
110 const fill_in_u_from_h01_h12_h20 : (kc : KC_type, u : minor_coordinate[:]#, h01 : minor_coordinate[:], h12 : minor_coordinate[:], h02 : minor_coordinate[:] -> std.result(void, byte[:]))
113 The "other" Ψ maps. These are the ones that split Conf₄* into
116 const psi_02 : (kc : KC_type, alpha : conf_4_star# -> std.result((conf_3_star#, conf_3_star#), byte[:]))
117 const psi_13 : (kc : KC_type, alpha : conf_4_star# -> std.result((conf_3_star#, conf_3_star#), byte[:]))
119 /* Perform non-quiver rotation */
120 const rotate : (kc : KC_type, alpha : conf_3_star# -> std.result(conf_3_star#, byte[:]))
123 const interior_fc_from_mc = {kc, mc
124 var c = get_coxeter_elt(kc)
125 var iforward = get_w0(kc)
126 if mc.len != iforward.len
127 -> `std.Err std.fmt("expected {} minor coordinates, got {}", iforward.len, mc.len)
129 for var k = 0; k < mc.len; ++k
131 -> `std.Err std.fmt("expected minor coordinate {} to be Δ^{{γ_{}}}, was declared as Δ^{{γ_{}}}", k + 1, k + 1, mc[k].k)
135 var irev : weyl_reflection[:] = std.slalloc(iforward.len)
136 for var k = 0; k < iforward.len; ++k
137 irev[k] = iforward[iforward.len - 1 - k]
141 var rank : int = get_n(kc)
142 var A : int[:][:] = get_cartan_matrix(kc)
144 var fc : factorization_coordinate[:] = [][:]
146 for var k = 0; k < iforward.len; ++k
148 Construct t_{k + 1}. This is given by (in the
149 following notation, everything is 1-based):
151 den = delta^{w_{k + 0} ω_{i_k}}(y) · delta^{w_{k + 1} ω_{i_k}}(y)
152 num = prod_{j != i_k} ( delta^{w_k ω_j}(y) )^{-A_{j, i_k}}
155 Since our input is minor coordinates of y, computing
156 these deltas is simply a matter of figuring out which
157 γ_k each thing refers to.
160 var num : yakmo.ratfunc# = yakmo.rid()
162 for var j = 0; j < rank; ++j
163 /* Simplify w_k ω_j to some chamber weight */
164 var jw : weyl_reflection = (j + 1 : weyl_reflection)
165 var which_k = simplify_chamber_weight(irev[:irev.len - k], jw, irev.len)
171 Now that we know the chamber weight, pull out
172 the correct coordinate, raise it to
173 -A_{j,i_k}, and multiply the result into the
176 var this_delta_of_y = mc[which_k - 1].c
177 for var l = 0; l > A[j][iforward[k] - 1]; --l
178 yakmo.rmul_ip(num, this_delta_of_y)
182 var den : yakmo.ratfunc# = t.dup(mc[k].c)
184 if irev.len - k - 1 > 0
185 var other_k = simplify_chamber_weight(irev[:irev.len - k - 1], iforward[k], irev.len)
187 yakmo.rmul_ip(den, mc[other_k - 1].c)
191 match yakmo.div_maybe(num, den)
192 | `std.None: -> `std.Err std.fmt("t_{} = [ {} ] / [ {} ] is not a Laurent polynomial: damn", k + 1, num, den)
193 | `std.Some x: std.slpush(&fc, `X(iforward[k], x))
201 Given w_j ω_l = (s_i1 s_i2 ⋯ s_im) ω_l, with w_j a prefix of i^{-1},
202 elements from the end of w_j, repeatedly, following the rule
204 for i != j, s_i ω_j = ω_j .
206 The result will either be 1) a shorter prefix of i^{-1}, or 2) empty.
207 If it's a shorter prefix of length k, then we've found γ_k, so we
208 return k. If it's empty, we should just return 0 (we don't
209 particularly care about which ω_j we're using in that case).
211 To ensure that w_j is really a prefix of i^{-1}, the input is simply
212 i^{-1} and the length of that prefix.
214 const simplify_chamber_weight = {w : weyl_reflection[:], which_omega : weyl_reflection, full_len : std.size
215 while w.len > 0 && w[w.len - 1] != which_omega
223 -> (full_len - w.len : int) + 1
226 const interior_mc_from_fc = {kc, fc
227 var bkl : yakmo.Z#[:][:] = [][:]
229 | `std.Err e: -> `std.Err std.fmt("get_bkl({}): {}", kc, e)
233 var mc : minor_coordinate[:] = [][:]
234 var w0 : weyl_reflection[:] = get_w0(kc)
237 First, make sure the factorization coordinates follow our
238 idea of the longest word.
241 -> `std.Err std.fmt("expected {} factorization coordinates, got {}", w0.len, fc.len)
244 var fcv = std.slalloc(fc.len)
245 for var j = 0; j < fc.len; ++j
249 -> `std.Err std.fmt("factorization coordinate {} should be X({}, _), was X({}, _)", j + 1, w0[j], i)
252 | `Y (i, l): -> `std.Err std.fmt("factorization coordinate {} should be X({}, _), was Y({}, _)", j + 1, w0[j], i)
253 | `H (i, l): -> `std.Err std.fmt("factorization coordinate {} should be X({}, _), was H({}, _)", j + 1, w0[j], i)
258 for var k = 0; k < fc.len; ++k
259 var gk : yakmo.ratfunc# = yakmo.rid()
260 for var l = k; l < fc.len; l++
261 /* gk *= (fcv[l])^bkl(k,l) */
262 var power = (t.dup(bkl[k][l]) : std.bigint#)
266 while !std.bigiszero(power)
267 match yakmo.div_maybe(gk, factor)
268 | `std.None: -> `std.Err std.fmt("cannot compute g_{}; could not divide {} / {}", k + 1, gk, factor)
273 std.bigaddi(power, 1)
276 while !std.bigiszero(power)
277 yakmo.rmul_ip(gk, fcv[l])
278 std.bigaddi(power, -1)
283 yakmo.reduceratfunc(gk)
284 std.slpush(&mc, [ .k = k + 1, .c = gk ])
288 Don't __dispose__; that will recurse and kill the variables,
289 which actually belong to the input fc.
296 const edge_mc_from_fc = {kc : KC_type, fc : factorization_coordinate[:]
299 /* We're allowed to omit `H(_, 1), it's the identity */
300 -> `std.Err std.fmt("expected {} factorization coordinates, got {}", rank, fc.len)
302 var mc : minor_coordinate[:] = [][:]
303 for var k = 1; k <= rank; ++k
304 std.slpush(&mc, [ .k = k, .c = yakmo.rid() ])
306 for var k = 0; k < fc.len; ++k
310 `H(coxeter[j], rf) =~= [ .k = j, rf ]
312 Also, the minor coordinate with .k = j is at index j.
314 var j = inv_coxeter(kc, i)
315 yakmo.rmul_ip(mc[j].c, val)
316 | _: -> `std.Err std.fmt("expected factorization coordinate {} to be H(_ ,_), got {}", k + 1, fc[k])
323 const edge_fc_from_mc = {kc : KC_type, mc : minor_coordinate[:]
325 var c = std.try(get_coxeter_elt(kc))
327 -> `std.Err std.fmt("expected {} minor coordinates, got {}", rank, mc.len)
330 for var k = 0; k < rank; ++k
331 /* `H(coxeter[j], rf) =~= [ .k = j, rf ] */
332 std.slpush(&fc, `H(c[k], delta_gamma_k(mc, k + 1)))
341 [ `X(i1, v1), `X(i2, v2), ... `X(im, vm) ][:] = x in N_{+} ∩ G_0 w_0,
345 [ `Y(im, vm), `Y(i{m-1}, v{m-1}), ... `Y(i1, v1) ][:] = y in N_{-} ∩ w_0 G_0,
351 const phi = {kc : KC_type, fc : factorization_coordinate[:]
352 var i : weyl_reflection[:] = get_w0(kc)
353 var ireverse : weyl_reflection[:] = std.slalloc(i.len)
354 for var k = 0; k < i.len; ++k
355 ireverse[k] = i[i.len - 1 - k]
358 var ret : factorization_coordinate[:] = std.slalloc(fc.len)
360 /* Ensure that fc may actually be something in the set we care about */
362 -> `std.Err std.fmt("fc.len = {}, expected {}", fc.len, i.len)
364 for var j = 0; j < fc.len; ++j
368 -> `std.Err std.fmt("coordinate {} was X({}, _), should have been X({}, _)", j + 1, k, i[j])
370 ret[j] = `X(k, t.dup(l))
371 | `Y (k, _): -> `std.Err std.fmt("coordinate {} was Y({}, _), should have been X({}, _)", j + 1, k, i[j])
372 | `H (k, _): -> `std.Err std.fmt("coordinate {} was H({}, _), should have been X({}, _)", j + 1, k, i[j])
377 Consider (ret, i), representing (initially) the product x w0.
378 Look at the last factorization element of x and the first
379 Weyl reflection of w0.
381 They had better be X(i, _) and s_i for the same i. So use identity
383 X(i, t) s_i = Y(i, 1/t)
385 to transform the right end of x and the left end of the word.
387 Rem: we're actually using w0^-1 here, so that it lines up
388 with the factorization of x correctly. That's okay, because
389 w0^-1 * w0 * w0 = w0, and w0^2 is an element of H, which is
390 ignored by [·]_{-}. Therefore
392 [ x w0 ]_{-} = [x w0^{-1} w0^2 ]_{-} = [ x w0^{-1} ]_{-}.
394 for var j = 0; j < i.len; ++j
395 match ret[ret.len - 1]
398 -> `std.Err std.fmt("coordinates, word = {}, {}, this doesn't work[1]", ret, i[j:])
401 /* Quick inversion */
402 if val.num.terms.len == 0
403 -> `std.Err std.fmt("coordinates, word = {}, {}, this doesn't work[2]", ret, i[j:])
405 std.swap(&val.num, &val.den)
406 ret[ret.len - 1] = `Y(xj, val)
407 | _: -> `std.Err std.fmt("coordinates, word = {}, {}, this doesn't work[3]", ret, i[j:])
410 match canonicalize_factorization_coords(kc, &ret, `Ordering_YHX)
412 | `std.Err e: -> `std.Err std.fmt("canonicalize: {}", e)
417 We now have something in form Y H X. We had better have
418 exactly i.len Y-shaped elements, because we created one for
419 each element of i. So let's kill everything after that.
423 | _: -> `std.Err std.fmt("not enough elements of Y in decomposition: expected {}, got {}", i.len, ret)
426 while ret.len > i.len
428 | `X(_, xval): __dispose__(xval)
429 | `H(_, hval): __dispose__(hval)
430 | `Y(_, _): -> `std.Err std.fmt("too many elements of Y in decomposition: expected {}, got {}", i.len, ret)
432 std.sldel(&ret, i.len)
441 [ `Y(im, vm), ..., `Y(i2, v2), `Y(i1, v1) ][:] = y in N_{-} ∩ w_0 G_0,
445 [ `X(i1, v1), `X(i2, v2), ..., `X(im, vm) ][:] = x in N_{+} ∩ G_0 w_0,
447 such that Φ(x) = y. We do this by computing w₀( [w₀⁻¹ y]_{-} ).
449 const phi_inv = {kc : KC_type, fc : factorization_coordinate[:]
450 var i : weyl_reflection[:] = get_w0(kc)
451 var ireverse : weyl_reflection[:] = std.slalloc(i.len)
452 for var k = 0; k < i.len; ++k
453 ireverse[k] = i[i.len - 1 - k]
456 var ret : factorization_coordinate[:] = std.slalloc(fc.len)
458 /* Ensure that fc may actually be something in the set we care about */
460 -> `std.Err std.fmt("fc.len = {}, expected {}", fc.len, i.len)
462 for var j = 0; j < fc.len; ++j
466 -> `std.Err std.fmt("coordinate {} was Y({}, _), should have been Y({}, _)", j + 1, k, ireverse[j])
468 ret[j] = `Y(k, t.dup(l))
469 | `X (k, _): -> `std.Err std.fmt("coordinate {} was X({}, _), should have been X({}, _)", j + 1, k, i[j])
470 | `H (k, _): -> `std.Err std.fmt("coordinate {} was H({}, _), should have been X({}, _)", j + 1, k, i[j])
474 for var j = 0; j < i.len; ++j
475 match ret[ret.len - 1]
478 -> `std.Err std.fmt("coordinates, word = {}, {}, this doesn't work[1]", ret, ireverse[j:])
481 /* Quick inversion */
482 if val.num.terms.len == 0
483 -> `std.Err std.fmt("coordinates, word = {}, {}, this doesn't work[2]", ret, ireverse[j:])
485 std.swap(&val.num, &val.den)
486 ret[ret.len - 1] = `X(yj, val)
487 | _: -> `std.Err std.fmt("coordinates, word = {}, {}, this doesn't work[5]", ret, ireverse[j:])
490 canonicalize_factorization_coords(kc, &ret, `Ordering_XHY)
495 | _: -> `std.Err std.fmt("not enough elements of X in decomposition: expected {}, got {}", i.len, ret)
498 while ret.len > i.len
500 | `Y(_, xval): __dispose__(xval)
501 | `H(_, hval): __dispose__(hval)
502 | `X(_, _): -> `std.Err std.fmt("too many elements of X in decomposition: expected {}, got {}", i.len, ret)
504 std.sldel(&ret, i.len)
511 const iota = { kc : KC_type, y, h, x
513 var total : factorization_coordinate[:] = [][:]
514 for q : [ y, h, x ][:]
515 for var j = 0; j < q.len; ++j
517 | `Y(k, v): std.slpush(&total, `Y(k, t.dup(v)))
518 | `H(k, v): std.slpush(&total, `H(k, t.dup(v)))
519 | `X(k, v): std.slpush(&total, `X(k, t.dup(v)))
524 match canonicalize_factorization_coords(kc, &total, `Ordering_XYH)
526 | `std.Err e: -> `std.Err std.fmt("canonicalize_factorization_coords: {}", e)
530 It's possible that canonicalize didn't put things into pure X
531 Y H form, for example if dividing by zero would happen. So we
532 have to be picking when splitting this up into components.
534 var xout : factorization_coordinate[:] = [][:]
535 var yout : factorization_coordinate[:] = [][:]
536 var hout : factorization_coordinate[:] = [][:]
541 | `X(i, v): std.slpush(&xout, `X(i, v))
549 | `X(_, _): -> `std.Err std.fmt("canonicalization failed (trailing X)")
550 | `Y(i, v): std.slpush(&yout, `Y(i, v))
558 | `X(_, _): -> `std.Err std.fmt("canonicalization failed (trailing X)")
559 | `Y(_, _): -> `std.Err std.fmt("canonicalization failed (trailing Y)")
560 | `H(i, v): std.slpush(&hout, `H(i, v))
566 -> `std.Ok (xout, yout, hout)
569 const chi = {fc : factorization_coordinate[:], j : weyl_reflection
570 var ret = yakmo.rid()
571 for var k = 0; k < fc.len; ++k
575 yakmo.rmul_ip(ret, x)
586 const delta_gamma_k = {h : minor_coordinate[:], k : int
587 for var j = 0; j < h.len; ++j
596 /* Given a list of X, Y, H, 1) swap the order, and 2) swap between X and Y. */
602 var ret : factorization_coordinate[:] = std.slalloc(fc.len)
604 for var j = 0; j < fc.len; ++j
605 var k = fc.len - 1 - j
607 | `H (i, l): ret[k] = `H(i, t.dup(l))
608 | `X (i, l): ret[k] = `Y(i, t.dup(l))
609 | `Y (i, l): ret[k] = `X(i, t.dup(l))
613 /* TODO: maybe unnecessary */
614 for var j = 0; j < ret.len; ++j
616 | `H (i, rf): yakmo.reduceratfunc(rf)
617 | `X (i, rf): yakmo.reduceratfunc(rf)
618 | `Y (i, rf): yakmo.reduceratfunc(rf)
625 const apply_word = {kc, w, h_orig
626 var A : int[:][:] = get_cartan_matrix(kc)
627 var h = std.sldup(h_orig)
628 for var k = 0; k < h_orig.len; ++k
629 h[k] = t.dup(h_orig[k])
632 /* Make sure we collapse all duplicates */
633 match canonicalize_factorization_coords(kc, &h, `Ordering_YHX)
636 auto (e : t.doomed_str)
637 -> `std.Err std.fmt("initial canonicalize: {}", e)
640 for var k = 0; k < h.len; ++k
643 | _: -> `std.Err std.fmt("did not expect to apply Weyl action to anything but H")
645 We could handle this: just construct
647 xi(-1) yi(1) xi(-1) g xi(1) yi(-1) xi(1),
649 canonicalize it, and ship it back. But that's
656 Using Lusztig's calculus, it is straight-forward to show that for
658 w = si, H = h1^a1 h2^a2 ⋯ hr^ar, [ A_{ij} ] the Cartan matrix,
662 w(H) = H hi^( \prod_k ak^A_{ki} )
664 therefore we can apply each si to h by multiplying around the
665 various components of h
667 for var j = w.len - 1; j >= 0; --j
668 var i : weyl_reflection = w[j]
670 /* First, find `H(i, _) so that we can mess with the variable */
673 for var k = 0; k < h.len; ++k
675 | `H(imaybe, amaybe):
687 std.slpush(&h, `H(i, ai))
690 /* Now build the \prod_j aj^A_{ji} factor */
691 var factor : yakmo.ratfunc# = yakmo.rid()
693 for var l = 0; l < h.len; ++l
696 var Aki = A[k - 1][i - 1]
698 for var z = 0; z > Aki; --z
699 yakmo.rmul_ip(factor, ak)
705 for var z = 0; z < Aki; ++z
706 yakmo.rmul_ip(factor, aki)
713 yakmo.rmul_ip(ai, factor)
714 yakmo.reduceratfunc(ai)
720 /* Compute w_k h w_k⁻¹. Note that to get w_k = w₀, use k = 1. */
721 const apply_wk = {kc, k, h_orig, required_sign
722 var wk_H_action_exps = get_wk_H_action_exps(kc)
723 var h = std.sldup(h_orig)
726 -> `std.Err std.fmt("k = {} is wrong. (For w₀, use k=1)", k)
728 for var l = 0; l < h_orig.len; ++l
729 h[l] = `H((l + 1 : weyl_reflection), yakmo.rid())
732 for var i = 0; i < rank; ++i
733 for var j = 0; j < rank; ++j
734 var e = wk_H_action_exps[k - 1][i][j]
735 var chiv : yakmo.ratfunc#
736 match chi(h_orig, (j + 1 : weyl_reflection))
737 | `std.Some chivv: chiv = chivv
738 | `std.None: chiv = yakmo.rid()
742 var a : yakmo.ratfunc# = yakmo.rid()
744 for var l = 0; l < h.len; ++l
746 | `H(imaybe, amaybe):
747 if imaybe == (i + 1 : weyl_reflection)
757 std.slpush(&h, `H((i + 1 : weyl_reflection), a))
760 if e > 0 && required_sign >= 0
761 for var z = 0; z < e; ++z
762 yakmo.rmul_ip(a, chiv)
764 elif e < 0 && required_sign <= 0
765 match yakmo.finv(chiv)
767 for var z = 0; z > e; --z
768 yakmo.rmul_ip(a, hoji)
779 const canonicalize_factorization_coords = {kc : KC_type, fc : factorization_coordinate[:]#, ord : canonical_ordering
783 X(i, s) Y(j, t) = Y(j, t) X(i, s) for i != j
785 X(i, s) Y(i, t) = Y(i, t/(1 + st)) H(i, 1 + st) X(i, 1 + st)
787 H(i, s) Y(j, t) = Y(j, t s^{-A_{i,j}}) H(i, s)
789 Y(j, t) H(i, s) = H(i, s) Y(j, s^{A_{i,j}})
791 H(i, s) X(j, t) = X(j, t s^{A_{i,j}}) H(i, s)
793 X(j, t) H(i, s) = H(i, s) X(j, t s^{-A_{i,j}})
795 To move the components around until nothing more can be done.
797 Sometimes, we may find ourselves attempting to compute
798 infinity accidentally.
800 Ex 1: s_1 h_1(foo) s_1^-1. This expands out to
802 X(1, -1) Y(1, 1) X(1, -1) H(1, foo), X(1, 1) Y(1, -1) X(1, 1)
804 The H is "supposed" to move through the Xs and Ys
805 (direction doesn't really matter), which then cancel out
806 after creating a few more Hs. However, the naive, greedy
807 algorithm immediately runs into problems trying to switch
808 the first X and Y, since that involves division by zero.
810 As a workaround, just ignore division by zero. This means
811 the result might not always be in perfect Y H X form.
813 var A : int[:][:] = get_cartan_matrix(kc)
814 var one : yakmo.ratfunc# = yakmo.rid()
818 This typemess is so that I can keep all the ordering
819 information on the guard line. Splitting things into ordering
820 functions and such just doesn't work with my head.
822 type YH_ordering = union
826 type YX_ordering = union
830 type HX_ordering = union
851 var need_another_pass = true
852 while need_another_pass
853 need_another_pass = false
854 for var j = fc#.len - 2; j >= 0 && j + 1 < fc#.len; --j
855 match (fc#[j + 0], fc#[j + 1], yh, yx, hx)
856 | (`X(xi, xval), `Y(yj, yval), _, `Y_LT_X, _):
858 fc#[j + 0] = `Y(yj, yval)
859 fc#[j + 1] = `X(xi, xval)
860 need_another_pass = true
862 var one_plus_st : yakmo.ratfunc# = yakmo.rmul(xval, yval)
863 yakmo.gadd_ip(one_plus_st, one)
865 match yakmo.finv(one_plus_st)
866 | `std.None: /* Ex 1? */
868 need_another_pass = true
869 var t_over = yakmo.rmul(yval, opsti)
870 yakmo.reduceratfunc(t_over)
871 fc#[j + 0] = `Y(yj, t_over)
872 var s_over = yakmo.rmul(xval, opsti)
873 fc#[j + 1] = `X(xi, s_over)
874 yakmo.reduceratfunc(s_over)
875 std.slput(fc, j + 1, `H(xi, t.dup(one_plus_st)))
880 | (`Y(yi, yval), `X(xj, xval), _, `X_LT_Y, _):
882 fc#[j + 0] = `X(xj, xval)
883 fc#[j + 1] = `Y(yi, yval)
884 need_another_pass = true
886 var one_plus_st : yakmo.ratfunc# = yakmo.rmul(xval, yval)
887 yakmo.gadd_ip(one_plus_st, one)
889 match yakmo.finv(one_plus_st)
890 | `std.None: /* Ex 1? */
892 need_another_pass = true
893 var t_over = yakmo.rmul(xval, opsti)
894 yakmo.reduceratfunc(t_over)
895 fc#[j + 0] = `X(xj, t_over)
896 var s_over = yakmo.rmul(yval, opsti)
897 fc#[j + 1] = `Y(yi, s_over)
898 yakmo.reduceratfunc(s_over)
899 std.slput(fc, j + 1, `H(xj, t.dup(opsti)))
904 | (`X(xj, xval), `H(hi, hval), _, _, `H_LT_X):
905 need_another_pass = true
906 /* A is 0-based, xj and hi are 1-based */
907 var Aij = A[hi - 1][xj - 1]
909 match yakmo.finv(hval)
910 | `std.None: -> `std.Err std.fmt("cannot invert {} while simplifying {}", hval, fc#)
912 for var k = 0; k < Aij; ++k
913 yakmo.rmul_ip(xval, hvali)
915 yakmo.reduceratfunc(xval)
919 for var k = 0; k > Aij; --k
920 yakmo.rmul_ip(xval, hval)
922 yakmo.reduceratfunc(xval)
924 fc#[j + 0] = `H(hi, hval)
925 fc#[j + 1] = `X(xj, xval)
926 | (`H(hi, hval), `X(xj, xval), _, _, `X_LT_H):
927 need_another_pass = true
928 /* A is 0-based, xj and hi are 1-based */
929 var Aij = A[hi - 1][xj - 1]
931 match yakmo.finv(hval)
932 | `std.None: -> `std.Err std.fmt("cannot invert {} while simplifying {}", hval, fc#)
934 for var k = 0; k > Aij; --k
935 yakmo.rmul_ip(xval, hvali)
937 yakmo.reduceratfunc(xval)
941 for var k = 0; k < Aij; ++k
942 yakmo.rmul_ip(xval, hval)
944 yakmo.reduceratfunc(xval)
946 fc#[j + 0] = `X(xj, xval)
947 fc#[j + 1] = `H(hi, hval)
948 | (`H(hi, hval), `Y(yj, yval), `Y_LT_H, _, _):
949 need_another_pass = true
950 var Aij = A[hi - 1][yj - 1]
952 match yakmo.finv(hval)
953 | `std.None: -> `std.Err std.fmt("cannot invert {} while simplifying {}", hval, fc#)
955 for var k = 0; k < Aij; ++k
956 yakmo.rmul_ip(yval, hvali)
958 yakmo.reduceratfunc(yval)
962 for var k = 0; k > Aij; --k
963 yakmo.rmul_ip(yval, hval)
965 yakmo.reduceratfunc(yval)
967 fc#[j + 0] = `Y(yj, yval)
968 fc#[j + 1] = `H(hi, hval)
969 | (`Y(yj, yval), `H(hi, hval), `H_LT_Y, _, _):
970 need_another_pass = true
971 var Aij = A[hi - 1][yj - 1]
973 match yakmo.finv(hval)
974 | `std.None: -> `std.Err std.fmt("cannot invert {} while simplifying {}", hval, fc#)
976 for var k = 0; k > Aij; --k
977 yakmo.rmul_ip(yval, hvali)
979 yakmo.reduceratfunc(yval)
983 for var k = 0; k < Aij; ++k
984 yakmo.rmul_ip(yval, hval)
986 yakmo.reduceratfunc(yval)
988 fc#[j + 0] = `H(hi, hval)
989 fc#[j + 1] = `Y(yj, yval)
990 | (`H(hi, hval1), `H(hj, hval2), _, _, _):
992 fc#[j + 0] = `H(hj, hval2)
993 fc#[j + 1] = `H(hi, hval1)
994 need_another_pass = true
996 yakmo.rmul_ip(hval1, hval2)
999 if std.eq(hval1.num, hval1.den)
1003 need_another_pass = true
1005 | (`X(xi, xval1), `X(xj, xval2), _, _, _):
1007 yakmo.gadd_ip(xval1, xval2)
1009 std.sldel(fc, j + 1)
1010 if yakmo.eq_gid(xval1)
1014 need_another_pass = true
1016 | (`Y(yi, yval1), `Y(yj, yval2), _, _, _):
1018 yakmo.gadd_ip(yval1, yval2)
1020 std.sldel(fc, j + 1)
1021 if yakmo.eq_gid(yval1)
1025 need_another_pass = true
1027 | (_, `H(hi, hval), _, _, _):
1028 if std.eq(hval.num, hval.den)
1030 std.sldel(fc, j + 1)
1031 need_another_pass = true
1033 | (`H(hi, hval), _, _, _, _):
1034 if std.eq(hval.num, hval.den)
1037 need_another_pass = true
1042 //for var j = 0; j < fc#.len; ++j
1044 // | `H (i, rf): yakmo.reduceratfunc(rf)
1045 // | `X (i, rf): yakmo.reduceratfunc(rf)
1046 // | `Y (i, rf): yakmo.reduceratfunc(rf)
1055 const fill_in_alpha = {kc : KC_type, alpha : conf_3_star#
1056 var rank = get_n(kc)
1059 if alpha.u.len == w0.len
1061 elif alpha.u.len != w0.len - rank
1062 -> `std.Err std.fmt("alpha.u is not complete, and it's not missing exactly r elements")
1066 match edge_fc_from_mc(kc, alpha.h1)
1067 | `std.Ok q: h1_fc = q
1068 | `std.Err e: -> `std.Err std.fmt("edge_fc_from_mc(h1): {}", e)
1073 match edge_fc_from_mc(kc, alpha.h2)
1074 | `std.Ok q: h2_fc = q
1075 | `std.Err e: -> `std.Err std.fmt("edge_fc_from_mc(h2): {}", e)
1080 match edge_fc_from_mc(kc, alpha.h3)
1081 | `std.Ok q: h3_fc = q
1082 | `std.Err e: -> `std.Err std.fmt("edge_fc_from_mc(h3): {}", e)
1086 var h1_h3_fc : factorization_coordinate[:] = [][:]
1087 for var j = 0; j < h1_fc.len; ++j
1089 | `H(i, v): std.slpush(&h1_h3_fc, `H(i, t.dup(v)))
1090 | _: -> `std.Err std.fmt("h1 has non-H elements")
1093 for var j = 0; j < h3_fc.len; ++j
1095 | `H(i, v): std.slpush(&h1_h3_fc, `H(i, t.dup(v)))
1096 | _: -> `std.Err std.fmt("h3 has non-H elements")
1099 match canonicalize_factorization_coords(kc, &h1_h3_fc, `Ordering_YHX)
1101 | `std.Err e: -> `std.Err std.fmt("canonicalize_factorization_coords( h1 h3 ): {}", e)
1106 match apply_wk(kc, 1, h1_h3_fc, 0)
1107 | `std.Ok q: wo_h1_h3_fc = q
1108 | `std.Err e: -> `std.Err std.fmt("w₀(h1 h3): {}", e)
1113 for var j = 0; j < wo_h1_h3_fc.len; ++j
1114 match wo_h1_h3_fc[j]
1115 | `H(i, v): std.slpush(&mash, `H(i, t.dup(v)))
1116 | _: -> `std.Err std.fmt("w₀(h1 h3) has non-H elements")
1119 for var j = 0; j < h2_fc.len; ++j
1121 | `H(i, v): std.slpush(&mash, `H(i, t.dup(v)))
1122 | _: -> `std.Err std.fmt("h2 has non-H elements")
1125 match canonicalize_factorization_coords(kc, &mash, `Ordering_YHX)
1127 | `std.Err e: -> `std.Err std.fmt("canonicalize_factorization_coords( w₀(h1 h3) h2 ): {}", e)
1131 for var j = 0; j < mash.len; ++j
1136 yakmo.reduceratfunc(vi)
1139 | `std.None: -> `std.Err std.fmt("cannot invert w₀(h1 h3) h2")
1141 | _: -> `std.Err std.fmt("w₀(h1 h3) h2 contains non-H elements")
1145 match edge_mc_from_fc(kc, mash)
1147 for var j = 0; j < alpha.u.len; ++j
1148 std.slpush(&mc, alpha.u[j])
1153 | `std.Err e: -> `std.Err std.fmt("edge_mc_from_fc(mash): {}", e)
1157 const fill_in_u_from_h01_h12_h20 = {kc : KC_type, u : minor_coordinate[:]#, h01 : minor_coordinate[:], h12 : minor_coordinate[:], h20 : minor_coordinate[:]
1165 match fill_in_alpha(kc, &alpha)
1167 | `std.Err e: -> `std.Err std.fmt("fill_in_alpha: {}", e)
1175 /* Given h in minor coordinates, compute w₀(h⁻¹) */
1176 const apply_wo_of_inv = {kc : KC_type, h : minor_coordinate[:]
1178 match edge_fc_from_mc(kc, h)
1179 | `std.Err e: -> `std.Err std.fmt("edge_fc_from_mc({}, h): {}", kc, e)
1180 | `std.Ok y: h_fc = y
1184 var h_inv : factorization_coordinate[:] = std.slalloc(h_fc.len)
1185 for var k = 0; k < h_fc.len; ++k
1189 | `std.Some ci: h_inv[k] = `H(i, ci)
1190 | `std.None: -> `std.Err std.fmt("cannot invert h")
1192 | _: -> `std.Err std.fmt("h contained non-H elements")
1198 match apply_wk(kc, 1, h_inv, 0)
1199 | `std.Ok y: wo_h_inv = y
1200 | `std.Err e: -> `std.Err std.fmt("apply_wk({}, 1, h_inv, 0): {}", e)
1205 match edge_mc_from_fc(kc, wo_h_inv)
1206 | `std.Ok y: wo_h_inv_mc = y
1207 | `std.Err e: -> `std.Err std.fmt("edge_mc_from_fc({}, wo(h^-1)): {}", kc, e)
1210 -> `std.Ok wo_h_inv_mc
1213 /* Given h in minor coordinates, compute h sG = h w₀ w₀ */
1214 const multiply_h_mc_by_sG = {kc : KC_type, h : minor_coordinate[:]
1217 | `std.Err e: -> `std.Err std.fmt("get_sG: {}", e)
1218 | `std.Ok sGG: sG = sGG
1222 match edge_fc_from_mc(kc, h)
1223 | `std.Err e: -> `std.Err std.fmt("edge_fc_from_mc({}, h): {}", kc, e)
1224 | `std.Ok y: h_fc = y
1226 for var k = 0; k < sG.len; ++k
1227 std.slpush(&h_fc, t.dup(sG[k]))
1230 match canonicalize_factorization_coords(kc, &h_fc, `Ordering_YHX)
1232 | `std.Err e: -> `std.Err std.fmt("canonicalize_factorization_coords: {}", e)
1236 match edge_mc_from_fc(kc, h_fc)
1237 | `std.Err e: -> `std.Err std.fmt("edge_mc_from_fc({}, h sG) {}", kc, e)
1238 | `std.Ok y: -> `std.Ok y
1242 /* Return ( rot(α₁₂₀) = rot(g₁ N, g₂ N, g₀ sG N), α₀₂₃ = (g₀ N, g₂ N, g₃) ) */
1243 const psi_02 = {kc : KC_type, alpha : conf_4_star#
1245 α₁₂₀ (in terms of α = (g₀ N, g₁ N, g₂ N, g₃ N) ) is (g₁ N, g₂ N, g₀ sG N)
1246 - h₁ = [w₀⁻¹ g₁⁻¹ g₂]₀ = h₁₂
1247 - h₂ = [w₀⁻¹ g₂⁻¹ g₀ sG]₀ = h₂₀ sG = w₀(h₀₂⁻¹) sG sG = w₀(h₀₂⁻¹)
1248 - h₃ = [w₀⁻¹ sG⁻¹ g₀⁻¹ g₁]₀ = sG h₀₁ = h₀₁ sG
1252 match apply_wo_of_inv(kc, alpha.h02)
1253 | `std.Err e: -> `std.Err std.fmt("w₀(h₀₂⁻¹): {}", e)
1254 | `std.Ok h: wo_h02_inv = h
1258 match multiply_h_mc_by_sG(kc, alpha.h01)
1259 | `std.Err e: -> `std.Err std.fmt("h₀₁ sG: {}", e)
1260 | `std.Ok h: h01_sG = h
1263 var alpha_120_base : conf_3_star = [
1264 .h1 = t.dup(alpha.h12),
1267 .u = t.dup(alpha.u),
1269 var alpha_120 = auto std.mk(alpha_120_base)
1271 var alpha_012 : conf_3_star#
1272 match rotate(kc, alpha_120)
1273 | `std.Err e: -> `std.Err std.fmt("rotate(α₁₂₀): {}", e)
1274 | `std.Ok a: alpha_012 = a
1278 α₀₂₃ (in terms of α as above):
1279 - h1 = [w₀⁻¹ g₀⁻¹ g₂]₀ = h₀₂
1280 - h2 = [w₀⁻¹ g₂⁻¹ g₃]₀ = h₂₃
1281 - h3 = [w₀⁻¹ g₃⁻¹ g₀]₀ = h₃₀ = w₀(h₀₃⁻¹) sG
1285 match apply_wo_of_inv(kc, alpha.h03)
1286 | `std.Err e: -> `std.Err std.fmt("w₀(h₀₃⁻¹): {}", e)
1287 | `std.Ok h: h30_sans_sG = h
1291 match multiply_h_mc_by_sG(kc, h30_sans_sG)
1292 | `std.Err e: -> `std.Err std.fmt("h₃₀ sG: {}", e)
1293 | `std.Ok h: h30 = h
1295 var alpha_023 : conf_3_star = [
1296 .h1 = t.dup(alpha.h02),
1297 .h2 = t.dup(alpha.h23),
1299 .u = t.dup(alpha.v),
1302 -> `std.Ok (alpha_012, std.mk(alpha_023))
1305 /* Return ( α₁₂₃ = (g₁ N, g₂ N, g₃), rot(α₁₃₀) = rot(g₁ sG N, g₃ N, g₀ N) ) */
1306 const psi_13 = {kc : KC_type, alpha : conf_4_star#
1308 if alpha.u.len != w0.len || alpha.v.len != w0.len
1309 -> `std.Err std.fmt("u ({}) and/or v ({}) are too short ({})", alpha.u.len, alpha.v.len, w0.len)
1312 /* Compute the components for ι: k = w₀(h₀₂ h₁₂⁻¹), Φ⁻¹(v) and u. */
1316 match interior_fc_from_mc_and_undo_psi_phi_psi(kc, alpha.v)
1317 | `std.Ok q: v_fc = q
1318 | `std.Err e: -> `std.Err std.fmt("interior_fc_from_mc_and_undo_ΨΦΨ(v): {}", e)
1322 match phi_inv(kc, v_fc)
1323 | `std.Err e: -> `std.Err std.fmt("Φ⁻¹(v): {}", e)
1324 | `std.Ok q: phi_inverse_v = q
1330 match interior_fc_from_mc_and_undo_psi_phi_psi(kc, alpha.u)
1331 | `std.Ok q: u_fc = q
1332 | `std.Err e: -> `std.Err std.fmt("interior_fc_from_mc_and_undo_ΨΦΨ(u): {}", e)
1338 match edge_fc_from_mc(kc, alpha.h02)
1339 | `std.Ok fc: h02_fc = fc
1340 | `std.Err e: -> `std.Err std.fmt("h₀₂ broken: {}", e)
1345 match edge_fc_from_mc(kc, alpha.h12)
1346 | `std.Ok fc: h12_fc = fc
1347 | `std.Err e: -> `std.Err std.fmt("h₁₂ broken: {}", e)
1351 var h12_h02i = [][:]
1352 for var k = 0; k < h12_fc.len; ++k
1353 std.slpush(&h12_h02i, t.dup(h12_fc[k]))
1356 for var k = 0; k < h02_fc.len; ++k
1360 | `std.Some vi: std.slpush(&h12_h02i, `H(j, vi))
1361 | `std.None: -> `std.Err std.fmt("cannot invert h₀₂")
1363 | _: -> `std.Err std.fmt("h₀₂ contains non-H elements")
1367 match canonicalize_factorization_coords(kc, &h12_h02i, `Ordering_YHX)
1369 | `std.Err e: -> `std.Err std.fmt("canonicalize(h₁₂ h₀₂⁻¹): {}", e)
1374 match apply_wk(kc, 1, h12_h02i, 0)
1375 | `std.Ok kk: k = kk
1376 | `std.Err e: -> `std.Err std.fmt("w₀(h₁₂ h₀₂⁻¹): {}", e)
1379 /* The results of ι: c, d, l */
1380 var phi_inverse_c, d, l
1381 match iota(kc, u_fc, k, phi_inverse_v)
1382 | `std.Ok ii: (phi_inverse_c, d, l) = ii
1383 | `std.Err e: -> `std.Err std.fmt("iota(u, k, Φ⁻¹(v)): {}", e)
1390 match phi(kc, phi_inverse_c)
1392 | `std.Err e: -> `std.Err std.fmt("Φ(phi_inverse_c): {}", e)
1397 match interior_mc_from_fc_and_do_psi_phi_psi(kc, c)
1398 | `std.Ok q: c_mc = q
1399 | `std.Err e: -> `std.Err std.fmt("interior_mc_from_fc_and_do_psi_phi_psi(c): {}", e)
1403 match interior_mc_from_fc_and_do_psi_phi_psi(kc, d)
1404 | `std.Ok q: d_mc = q
1405 | `std.Err e: -> `std.Err std.fmt("interior_mc_from_fc_and_do_psi_phi_psi(d): {}", e)
1409 α₁₂₃ (in terms of α = (g₀ N, g₁ N, g₂ N, g₃ N) ) is (g₁ N, g₂ N, g₃ N)
1410 - h₁ = [w₀⁻¹ g₁⁻¹ g₂]₀ = h₁₂
1411 - h₂ = [w₀⁻¹ g₂⁻¹ g₃]₀ = h₂₃
1412 - h₃ = [w₀⁻¹ g₃⁻¹ g₁]₀ = h₃₁ = w₀(h₁₃⁻¹) sG
1416 match apply_wk(kc, 1, l, 0)
1417 | `std.Ok q: wo_l = q
1418 | `std.Err e: -> `std.Err std.fmt("w₀(l): {}", e)
1423 match edge_fc_from_mc(kc, alpha.h03)
1424 | `std.Ok q: h03_fc = q
1425 | `std.Err e: -> `std.Err std.fmt("edge_fc_from_mc(h₀₃): {}", e)
1429 for var k = 0; k < wo_l.len; ++k
1431 | `H(j, v): std.slpush(&h13_fc, `H(j, t.dup(v)))
1432 | _: -> `std.Err std.fmt("w₀(l) contained non-H")
1435 for var k = 0; k < h03_fc.len; ++k
1437 | `H(j, v): std.slpush(&h13_fc, `H(j, t.dup(v)))
1438 | _: -> `std.Err std.fmt("h₀₃ contained non-H")
1441 match canonicalize_factorization_coords(kc, &h13_fc, `Ordering_YHX)
1443 | `std.Err e: -> `std.Err std.fmt("h₁₃ is broken")
1448 match edge_mc_from_fc(kc, h13_fc)
1449 | `std.Ok q: h13 = q
1450 | `std.Err e: -> `std.Err std.fmt("edge_mc_from_fc(h₁₃): {}", e)
1454 for var j = 0; j < h13.len; ++j
1455 yakmo.reduceratfunc(h13[j].c)
1459 match apply_wo_of_inv(kc, h13)
1460 | `std.Ok q: wo_h13i = q
1461 | `std.Err e: -> `std.Err std.fmt("w₀(h₁₃⁻¹): {}", e)
1466 match multiply_h_mc_by_sG(kc, wo_h13i)
1467 | `std.Ok q: h31 = q
1468 | `std.Err e: -> `std.Err std.fmt("w₀(h₁₃⁻¹) sG: {}", e)
1471 for var j = 0; j < h31.len; ++j
1472 yakmo.reduceratfunc(h31[j].c)
1475 var alpha_123 : conf_3_star = [
1476 .h1 = t.dup(alpha.h12),
1477 .h2 = t.dup(alpha.h23),
1483 α₁₃₀ (in terms of α) is (g₁ sG N, g₃ N, g₀ N)
1484 - h₁ = [w₀⁻¹ sG g₁⁻¹ g₃]₀ = h₁₃ sG
1485 - h₂ = [w₀⁻¹ g₃⁻¹ g₀]₀ = h₃₀
1486 - h₃ = [w₀⁻¹ g₀⁻¹ g₁]₀ = h₀₁
1490 match multiply_h_mc_by_sG(kc, h13)
1491 | `std.Ok q: h13_sG = q
1492 | `std.Err e: -> `std.Err std.fmt("h₁₃ sG: {}", e)
1496 match apply_wo_of_inv(kc, alpha.h03)
1497 | `std.Err e: -> `std.Err std.fmt("w₀(h₀₃⁻¹): {}", e)
1498 | `std.Ok h: wo_h03i = h
1503 match multiply_h_mc_by_sG(kc, wo_h03i)
1504 | `std.Err e: -> `std.Err std.fmt("w₀(h₀₃⁻¹) sG: {}", e)
1505 | `std.Ok h: h30 = h
1509 match multiply_h_mc_by_sG(kc, alpha.h01)
1510 | `std.Ok q: h01_sG = q
1511 | `std.Err e: -> `std.Err std.fmt("h₀₁ sG: {}", e)
1514 var alpha_130_base : conf_3_star = [
1520 var alpha_130 = auto std.mk(alpha_130_base)
1522 var alpha_013 : conf_3_star#
1523 match rotate(kc, alpha_130)
1524 | `std.Err e: -> `std.Err std.fmt("rotate(α₁₃₀): {}", e)
1525 | `std.Ok a: alpha_013 = a
1528 -> `std.Ok (std.mk(alpha_123), alpha_013)
1532 Like interior_fc_from_mc, but undo ΨΦΨ as well.
1534 This isn't the default because Zickert's paper treats ΨΦΨ as a
1537 const interior_fc_from_mc_and_undo_psi_phi_psi = {kc, y
1538 var psi_phi_psi_y_fc
1539 match interior_fc_from_mc(kc, y)
1540 | `std.Ok q: psi_phi_psi_y_fc = q
1541 | `std.Err e: -> `std.Err std.fmt("interior_fc_from_mc(y): {}", e)
1543 auto psi_phi_psi_y_fc
1546 match psi(kc, psi_phi_psi_y_fc)
1547 | `std.Ok q: phi_psi_y_fc = q
1548 | `std.Err e: -> `std.Err std.fmt("Ψ( ΨΦΨ(y) ): {}", e)
1553 match phi_inv(kc, phi_psi_y_fc)
1554 | `std.Ok q: psi_y_fc = q
1555 | `std.Err e: -> `std.Err std.fmt("Φ⁻¹( ΦΨ(y) ): {}", e)
1560 match psi(kc, psi_y_fc)
1561 | `std.Ok q: y_fc = q
1562 | `std.Err e: -> `std.Err std.fmt("Ψ( Ψ(y) ): {}", e)
1569 Like interior_mc_from_fc, but undo (ΨΦΨ)⁻¹ as well.
1571 This isn't the default because Zickert's paper treats ΨΦΨ as a
1574 const interior_mc_from_fc_and_do_psi_phi_psi = {kc, y
1577 | `std.Ok q: psi_y = q
1578 | `std.Err e: -> `std.Err std.fmt("Ψ(y): {}", e)
1583 match phi(kc, psi_y)
1584 | `std.Ok q: phi_psi_y = q
1585 | `std.Err e: -> `std.Err std.fmt("Φ( Ψ(y) ): {}", e)
1590 match psi(kc, phi_psi_y)
1591 | `std.Ok q: psi_phi_psi_y = q
1592 | `std.Err e: -> `std.Err std.fmt("Ψ( ΦΨ(y) ): {}", e)
1597 match interior_mc_from_fc(kc, psi_phi_psi_y)
1598 | `std.Ok q: y_mc = q
1599 | `std.Err e: -> `std.Err std.fmt("interior_mc_from_fc(ΨΦΨ(y)): {}", e)
1605 const rotate = {kc : KC_type, alpha : conf_3_star#
1606 var c = std.try(get_coxeter_elt(kc))
1607 var sigmaG : weyl_reflection[:] = [][:]
1608 match get_sigmaG_permutation(kc)
1609 | `std.Err e: -> `std.Err std.fmt("cannot compute σG for {}: {}", kc, e)
1610 | `std.Ok perm: sigmaG = perm
1614 For the hi, factorization coordinates are exactly minor
1615 coordinates. For u, there's some work to do.
1617 var fc_h1 : factorization_coordinate[:] = [][:]
1618 var fc_h2 : factorization_coordinate[:] = [][:]
1619 var fc_h3 : factorization_coordinate[:] = [][:]
1620 var fc_u : factorization_coordinate[:] = [][:]
1622 match edge_fc_from_mc(kc, alpha.h1)
1624 auto (e : t.doomed_str)
1625 -> `std.Err std.fmt("edge_fc_from_mc(alpha.h1 = {}): {}", alpha.h1, e)
1626 | `std.Ok y: fc_h1 = y
1628 canonicalize_factorization_coords(kc, &fc_h1, `Ordering_YHX)
1631 match edge_fc_from_mc(kc, alpha.h2)
1633 auto (e : t.doomed_str)
1634 -> `std.Err std.fmt("edge_fc_from_mc(alpha.h2 = {}): {}", alpha.h2, e)
1635 | `std.Ok y: fc_h2 = y
1637 canonicalize_factorization_coords(kc, &fc_h2, `Ordering_YHX)
1640 match edge_fc_from_mc(kc, alpha.h3)
1642 auto (e : t.doomed_str)
1643 -> `std.Err std.fmt("edge_fc_from_mc(alpha.h3 = {}): {}", alpha.h3, e)
1644 | `std.Ok y: fc_h3 = y
1646 canonicalize_factorization_coords(kc, &fc_h3, `Ordering_YHX)
1649 match interior_fc_from_mc(kc, alpha.u)
1651 auto (e : t.doomed_str)
1652 -> `std.Err std.fmt("interior_fc_from_mc(alpha.u = {}): {}", alpha.u, e)
1653 | `std.Ok y: fc_u = y
1657 for var j = 0; j < fc_u.len; ++j
1659 | `H (i, rf): yakmo.reduceratfunc(rf)
1660 | `X (i, rf): yakmo.reduceratfunc(rf)
1661 | `Y (i, rf): yakmo.reduceratfunc(rf)
1665 /* Demand that h1, h2, h3 are in correct, increasing order */
1666 var rank = get_n(kc)
1667 if fc_h1.len != fc_h2.len || fc_h2.len != fc_h3.len || fc_h3.len != rank
1668 -> `std.Err std.fmt("alpha.hi do not all have the same length")
1671 for var j = 0; j < fc_h1.len; ++j
1672 match (fc_h1[j], fc_h2[j], fc_h3[j])
1673 | (`H(i1, _), `H(i2, _), `H(i3, _)):
1674 if i1 != j + 1 || i2 != j + 1 || i3 != j + 1
1675 -> `std.Err std.fmt("alpha.hi are not in order")
1677 | _: -> `std.Err std.fmt("alpha.hi are not elements of maximal torus (j = {})", j)
1682 First, construct (Φ Ψ)(u). Since our tranlation between
1683 minor and factorization coordinates necessarily conjugates by
1684 ΨΦΨ, we actually compute (Ψ Φ) and trust the conjugation to
1687 var half_rotated_fc_u : factorization_coordinate[:] = [][:]
1690 auto (e : t.doomed_str)
1691 -> `std.Err std.fmt("Ψ(u): {}", e)
1693 match psi(kc, phi_u)
1695 auto (e : t.doomed_str)
1696 -> `std.Err std.fmt("(ΦΨ)[(ΨΦΨ)(u)]: {}", e)
1697 | `std.Ok psi_phi_u: half_rotated_fc_u = psi_phi_u
1701 for var j = 0; j < half_rotated_fc_u.len; ++j
1702 match half_rotated_fc_u[j]
1703 | `X(_, rf): yakmo.reduceratfunc(rf)
1704 | `Y(_, rf): yakmo.reduceratfunc(rf)
1705 | `H(_, rf): yakmo.reduceratfunc(rf)
1710 At this point, conjugate by [w0(h1) h2]^{-1}. Specifically,
1711 jam all the `H(i, ___)s that make up this element onto the
1712 left of half_rotated_fc_u, their inverses on the right, call
1713 canonicalize_factorization_coords. All those Hs had better
1714 bubble through the Ys and annihilate themselves.
1716 match psi(kc, half_rotated_fc_u)
1718 auto (e : t.doomed_str)
1719 -> `std.Err std.fmt("Ψ(half_rotated_u): {}", e)
1721 __dispose__(half_rotated_fc_u)
1722 half_rotated_fc_u = x
1726 Pull out all the ratfunc#s from fc_hi. They had better be in
1727 the right order, because we checked above.
1729 var h1_rf : yakmo.ratfunc#[:] = std.slalloc((rank : std.size))
1730 var h2_rf : yakmo.ratfunc#[:] = std.slalloc((rank : std.size))
1731 for var j = 0; j < rank; ++j
1733 | `H(_, rf): h1_rf[j] = rf
1738 | `H(_, rf): h2_rf[j] = rf
1743 var pre_conjugation_length = half_rotated_fc_u.len
1744 for var j = 0; j < fc_h1.len; ++j
1745 /* h1_{σG[j]}^{+1} goes on the left, ^{-1} on the right */
1746 var sigmaj = sigmaG[j + 1] - 1
1747 std.slput(&half_rotated_fc_u, 0, `H(j + 1, t.dup(h1_rf[sigmaj])))
1748 match yakmo.finv(h1_rf[sigmaj])
1749 | `std.Some v: std.slpush(&half_rotated_fc_u, `H(j + 1, v))
1750 | `std.None: -> `std.Err std.fmt("cannot conjugate by [w0(h1) h2]^{{-1}}: cannot invert {}", fc_h1[sigmaj])
1753 /* h2_j^{-1} goes on the left, ^{+1} on the right */
1754 std.slpush(&half_rotated_fc_u, `H(j + 1, t.dup(h2_rf[j])))
1755 match yakmo.finv(h2_rf[j])
1756 | `std.Some v: std.slput(&half_rotated_fc_u, 0, `H(j + 1, v))
1757 | `std.None: -> `std.Err std.fmt("cannot conjugate by [w0(h1) h2]^{{-1}}: cannot invert {}", fc_h2[j])
1760 canonicalize_factorization_coords(kc, &half_rotated_fc_u, `Ordering_YHX)
1761 var post_conjugation_length = half_rotated_fc_u.len
1762 if pre_conjugation_length != post_conjugation_length
1763 -> `std.Err std.fmt("conjugating by [w0(h1) h2]^{{-1}} did not go as expected: result is {}", half_rotated_fc_u)
1769 match psi(kc, half_rotated_fc_u)
1771 auto (e : t.doomed_str)
1772 -> `std.Err std.fmt("Ψ(half_rotated_u): {}", e)
1774 __dispose__(half_rotated_fc_u)
1775 half_rotated_fc_u = x
1778 /* Finish off the rotation with another hit of ΨΦ */
1779 for var j = 0; j < half_rotated_fc_u.len; ++j
1780 match half_rotated_fc_u[j]
1781 | `X(_, rf): yakmo.reduceratfunc(rf)
1782 | `Y(_, rf): yakmo.reduceratfunc(rf)
1783 | `H(_, rf): yakmo.reduceratfunc(rf)
1786 var full_rotated_fc_u : factorization_coordinate[:] = [][:]
1787 match phi(kc, half_rotated_fc_u)
1789 auto (e : t.doomed_str)
1790 -> `std.Err std.fmt("Ψ(half_rotated_u): {}", e)
1791 | `std.Ok round_2_phi_u:
1792 for var j = 0; j < round_2_phi_u.len; ++j
1793 match round_2_phi_u[j]
1794 | `X(_, rf): yakmo.reduceratfunc(rf)
1795 | `Y(_, rf): yakmo.reduceratfunc(rf)
1796 | `H(_, rf): yakmo.reduceratfunc(rf)
1799 match psi(kc, round_2_phi_u)
1801 auto (e : t.doomed_str)
1802 -> `std.Err std.fmt("(ΦΨ)[half_rotated_u]: {}", e)
1803 | `std.Ok psi_phi_u: full_rotated_fc_u = psi_phi_u
1807 auto half_rotated_fc_u
1809 /* Now, take new_u back to minor coordinates */
1810 var rotated_mc_u = [][:]
1811 match interior_mc_from_fc(kc, full_rotated_fc_u)
1813 auto (e : t.doomed_str)
1814 -> `std.Err std.fmt("interior_mc_from_fc({}, full_rotated_u = {}): {}", kc, full_rotated_fc_u, e)
1816 for var j = 0; j < m.len; ++j
1817 yakmo.reduceratfunc(m[j].c)
1820 __dispose__(full_rotated_fc_u)
1823 var ret_h1 = std.sldup(alpha.h3)
1824 var ret_h2 = std.sldup(alpha.h1)
1825 var ret_h3 = std.sldup(alpha.h3)
1826 for var k = 0; k < alpha.h1.len; ++k
1827 ret_h1[k] = [ .k = alpha.h3[k].k, .c = t.dup(alpha.h3[k].c) ]
1828 ret_h2[k] = [ .k = alpha.h3[k].k, .c = t.dup(alpha.h1[k].c) ]
1829 ret_h3[k] = [ .k = alpha.h3[k].k, .c = t.dup(alpha.h2[k].c) ]
1831 var retbase : conf_3_star = [
1838 -> `std.Ok std.mk(retbase)