2 * Copyright (c) 2018, S. Gilles <sgilles@math.umd.edu>
4 * Permission to use, copy, modify, and/or distribute this software
5 * for any purpose with or without fee is hereby granted, provided
6 * that the above copyright notice and this permission notice appear
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS *ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING AL*L IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EV*ENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
14 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 * This is an implementation of the algorithm of Berenstein, Fomin,
31 * and Zelevinsky from "Cluster Algebras III", which produces quivers
32 * for the double Bruhat cell G^{u,v}.
35 #define zabs(x) (((x) < 0) ? -(x) : (x))
36 #define zabsdiff(x, y) ((x) < (y) ? ((y) - (x)) : ((x) - (y)))
37 #define zmin(x, y) (((x) < (y)) ? (x) : (y))
38 #define zmax(x, y) (((x) > (y)) ? (x) : (y))
39 #define zsgn(x) ((x) < 0 ? -1 : (x) > 0 ? 1 : 0)
41 /* Which of the Lie classifications we're looking at */
42 enum dynkin
{ INVALID
, An
, Bn
, Cn
, Dn
, G2
, F4
, E6
, E7
, E8
};
44 /* Cartan matrix entry a_{i,j}, given dynkin type. 1-based. */
45 static int aij(enum dynkin typ
, size_t n
, size_t i
, size_t j
)
49 size_t max_idx
= (i
> j
) ? i
: j
;
63 } else if (zabsdiff(i
, j
) == 1) {
72 /* TODO: do you have Bn and Cn switched? You always do that */
77 } else if (zabsdiff(i
, j
) == 1) {
82 } else if (typ
== Cn
&&
99 } else if (zabsdiff(i
, j
) == 1 &&
103 } else if ((i
== n
- 3 &&
137 } else if (zabsdiff(i
, j
) == 1) {
146 k
= (typ
== E6
) ? 6 : (typ
== E7
) ? 7 : 8;
152 } else if (zabsdiff(i
, j
) == 1 &&
155 } else if (zabsdiff(i
, j
) == 2 &&
167 const int x_mult
= 25;
168 const int y_mult
= 25;
170 /* Given vertex idx of k, return vertex idx of k⁺ */
171 static int find_plus(int k
, size_t *u
, size_t lu
, size_t *v
, size_t lv
)
173 size_t vk
= (size_t) -1;
178 for (int j
= k
+ 1; j
<= (int) (lu
+ lv
); ++j
) {
179 size_t vj
= (size_t) -1;
181 vj
= (j
<= (int) lu
) ? u
[j
- 1] : v
[j
- 1 - lu
];
191 for (int j
= k
+ 1; j
<= (int) (lu
+ lv
); ++j
) {
192 size_t vj
= (size_t) -1;
194 vj
= (j
<= (int) lu
) ? u
[j
- 1] : v
[j
- 1 - lu
];
200 } else if ((int) lu
+ 1 <= k
&&
201 k
<= (int) (lu
+ lv
)) {
204 for (int j
= k
+ 1; j
<= (int) (lu
+ lv
); ++j
) {
205 size_t vj
= v
[j
- 1 - lu
];
216 /* Given k in { -1, ..., -r } U { 1, 2, ..., l(u) + l(v) }, return the vertex idx for it */
217 static size_t v_of(int k
, int r
, size_t lu
, size_t lv
)
223 k
<= (int) (lu
+ lv
)) {
231 static int run_bfzIII(struct quiver
*qq
, enum dynkin typ
, size_t r
, size_t *u
,
232 size_t lu
, size_t *v
, size_t lv
)
235 size_t nl
= 1 + snprintf(0, 0, "%d%zu", -1 * (int) r
, lu
+ lv
);
237 const char *errstr
= 0;
241 uint32_t c_froz
= 0x4ce7ff;
242 uint32_t c_nonf
= 0xad7fa8;
243 int need_fatness_run
= 1;
245 if (!(nbuf
= malloc(nl
))) {
249 if (!(i
= calloc(r
+ lu
+ lv
+ 1, sizeof *i
))) {
253 if (!(e
= calloc(r
+ lu
+ lv
+ 1, sizeof *e
))) {
257 /* First, add { -1, -2, ..., -r } */
258 for (int k
= -1; k
>= -1 * (int) r
; k
--) {
259 size_t vv
= v_of(k
, r
, lu
, lv
);
262 sprintf(nbuf
, "%d", k
);
264 if (quiver_add_vertex(qq
, 0, nbuf
, 1, 50 * x
, 50 * i
[vv
],
265 c_froz
, &errstr
) < 0) {
266 fprintf(stderr
, "%s\n", errstr
);
267 fprintf(stderr
, L("quiver_add_vertex failed\n"));
274 /* Now add { 1, 2, ..., u_seq_len + v_seq_len } */
275 for (int k
= 1; k
<= (int) (lu
+ lv
); ++k
) {
276 size_t vv
= v_of(k
, r
, lu
, lv
);
277 int kplus
= find_plus(k
, u
, lu
, v
, lv
);
278 uint32_t c
= (kplus
<= (int) (lu
+ lv
)) ? c_nonf
: c_froz
;
280 i
[vv
] = 1 + ((k
<= (int) lu
) ? u
[k
- 1] : v
[k
- lu
- 1]);
281 sprintf(nbuf
, "%d", k
);
283 if (quiver_add_vertex(qq
, 0, nbuf
, 1, 50 * x
, 50 * i
[vv
], c
,
285 fprintf(stderr
, "%s\n", errstr
);
286 fprintf(stderr
, L("quiver_add_vertex failed\n"));
293 /* Now add edges by remark 2.4 */
294 for (int k
= -r
; k
<= (int) (lu
+ lv
); ++k
) {
295 int kplus
= find_plus(k
, u
, lu
, v
, lv
);
296 size_t vk
= v_of(k
, r
, lu
, lv
);
302 for (int l
= -r
; l
<= (int) (lu
+ lv
); ++l
) {
303 int lplus
= find_plus(l
, u
, lu
, v
, lv
);
306 p
<= (int) lu
) ? -1 : 1;
307 int q
= zmin((int) kplus
, (int) lplus
);
309 q
<= (int) lu
) ? -1 : 1;
310 size_t vl
= v_of(l
, r
, lu
, lv
);
311 size_t idx
= vk
* qq
->v_len
+ vl
;
312 struct rational
*e
= &qq
->e
[idx
];
321 e
->p
= -1 * zsgn(k
- l
) * eip
;
324 eip
* eiq
* (k
- l
) * (kplus
- lplus
) > 0) {
325 e
->p
= -1 * zsgn(k
- l
) * eip
* aij(typ
, r
,
334 * Now modify the fatness of various vertices to normalize |sigma|.
336 * We could just compute this by looking at the y-position
337 * and the Dynkin type, but this serves as a nice sanity check.
339 while (need_fatness_run
) {
340 need_fatness_run
= 0;
342 for (size_t j
= 0; j
< qq
->v_num
; ++j
) {
343 struct vertex
*v
= &qq
->v
[j
];
345 for (size_t k
= 0; k
< qq
->v_num
; ++k
) {
346 struct vertex
*w
= &qq
->v
[k
];
347 struct rational
*e
= &qq
->e
[j
* qq
->v_len
+ k
];
348 struct rational
*f
= &qq
->e
[k
* qq
->v_len
+ j
];
350 if (zabs(e
->p
* v
->fatness
) > zabs(f
->p
*
354 need_fatness_run
= 1;
355 } else if (zabs(e
->p
* v
->fatness
) < zabs(f
->p
*
360 need_fatness_run
= 1;
366 quiver_save_to_file(qq
, stdout
, 0);
377 /* "e" -> { }, "1,2" -> { 1, 2 } */
378 static int parse_word(const char *s
, size_t n
, size_t **out_word
,
387 if (!(strcmp(s
, "e"))) {
394 for (const char *p
= s
; *p
; p
++) {
398 if (!(seq
= calloc(len
, sizeof *seq
))) {
403 seq
[j
] = strtoll(s
, 0, 0) - 1;
412 for (const char *p
= s
; *p
; p
++) {
418 seq
[j
] = strtoll(p
+ 1, &err
, 0) - 1;
441 static void usage(char *argv0
)
444 "Usage: %s -c <Dynkin classification> [ -u <word>] [-v <word>]\n",
447 " Dynkin classification: Something like \u2018F4\u2019; permitted are\n");
448 printf(" A\u2081, A\u2082, A\u2083, \u2026\n");
449 printf(" B\u2081, B\u2082, B\u2083, \u2026\n");
450 printf(" C\u2081, C\u2082, C\u2083, \u2026\n");
451 printf(" D\u2081, D\u2082, D\u2083, \u2026\n");
452 printf(" G\u2082, F\u2084, E\u2086, E\u2087, E\u2088\n");
454 " Word: something like \u20181,2,1,2\u2019 (\u2018e\u2019 is permitted)\n");
455 printf(" if none given, \u2018e\u2019 is assumed\n");
459 int main(int argc
, char **argv
)
463 enum dynkin typ
= INVALID
;
470 size_t u_seq_len
= 0;
471 size_t v_seq_len
= 0;
472 struct quiver q
= { 0 };
474 while ((opt
= getopt(argc
, argv
, "hc:u:v:")) != -1) {
492 n
= strtoll(optarg
+ 1, &p
, 0);
497 n
= strtoll(optarg
+ 1, &p
, 0);
502 n
= strtoll(optarg
+ 1, &p
, 0);
507 n
= strtoll(optarg
+ 1, &p
, 0);
511 n
= strtoll(optarg
+ 1, &p
, 0);
525 "Type E may only be E\u2086, E\u2087, or E\u2088\n");
534 if (optarg
[1] == '4' &&
540 "Type F may only be F\u2084\n");
547 if (optarg
[1] == '2' &&
553 "Type G may only be G\u2082\n");
559 "Invalid Dynkin classification: \u2018%s\u2019\n",
568 fprintf(stderr
, "Invalid n: \u2018%s\u2019\n",
579 "Dynkin classification is required (ex: \u2018-c F4\u2019)\n");
589 for (size_t i
= 0; i
< n
; ++i
) {
592 for (size_t j
= 0; j
< n
; ++j
) {
593 printf("%3d ", bij(typ
, n
, i
, j
));
603 if (parse_word(uword
, n
, &u_seq
, &u_seq_len
) < 0) {
604 fprintf(stderr
, "Invalid u-word: \u2018%s\u2019\n", uword
);
609 if (parse_word(vword
, n
, &v_seq
, &v_seq_len
) < 0) {
610 fprintf(stderr
, "Invalid v-word: \u2018%s\u2019\n", vword
);
615 if ((ret
= run_bfzIII(&q
, typ
, n
, u_seq
, u_seq_len
, v_seq
, v_seq_len
)) <
617 fprintf(stderr
, "BFZIII algorithm failed\n");