2 * Copyright (c) 2016-2021, S. Gilles <sgilles@sgilles.net>
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 ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT 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. */
46 aij(enum dynkin typ
, size_t n
, size_t i
, size_t j
)
50 size_t max_idx
= (i
> j
) ? i
: j
;
64 } else if (zabsdiff(i
, j
) == 1) {
73 /* TODO: do you have Bn and Cn switched? You always do that */
78 } else if (zabsdiff(i
, j
) == 1) {
83 } else if (typ
== Bn
&&
100 } else if (zabsdiff(i
, j
) == 1 &&
104 } else if ((i
== n
- 3 &&
138 } else if (zabsdiff(i
, j
) == 1) {
147 k
= (typ
== E6
) ? 6 : (typ
== E7
) ? 7 : 8;
153 } else if (zabsdiff(i
, j
) == 1 &&
156 } else if (zabsdiff(i
, j
) == 2 &&
168 const int x_mult
= 25;
169 const int y_mult
= 25;
171 /* Given vertex idx of k, return vertex idx of k⁺ */
173 find_plus(int k
, size_t *u
, size_t lu
, size_t *v
, size_t lv
)
175 size_t vk
= (size_t) -1;
180 for (int j
= 1; j
<= (int) (lu
+ lv
); ++j
) {
181 size_t vj
= (size_t) -1;
183 vj
= (j
<= (int) lu
) ? u
[j
- 1] : v
[j
- 1 - lu
];
193 for (int j
= k
+ 1; j
<= (int) (lu
+ lv
); ++j
) {
194 size_t vj
= (size_t) -1;
196 vj
= (j
<= (int) lu
) ? u
[j
- 1] : v
[j
- 1 - lu
];
202 } else if ((int) lu
+ 1 <= k
&&
203 k
<= (int) (lu
+ lv
)) {
206 for (int j
= k
+ 1; j
<= (int) (lu
+ lv
); ++j
) {
207 size_t vj
= v
[j
- 1 - lu
];
218 /* Given k in { -1, ..., -r } U { 1, 2, ..., l(u) + l(v) }, return the vertex idx for it */
220 v_of(int k
, int r
, size_t lu
, size_t lv
)
226 k
<= (int) (lu
+ lv
)) {
235 run_bfzIII(struct quiver
*qq
, enum dynkin typ
, size_t r
, size_t *u
, size_t lu
,
236 size_t *v
, size_t lv
, int ymult
)
239 size_t nl
= 1 + snprintf(0, 0, "%d%zu", -1 * (int) r
, lu
+ lv
);
241 const char *errstr
= 0;
245 uint32_t c_froz
= 0x4ce7ff;
246 uint32_t c_nonf
= 0xad7fa8;
247 int need_fatness_run
= 1;
249 if (!(nbuf
= malloc(nl
))) {
253 if (!(i
= calloc(r
+ lu
+ lv
+ 1, sizeof *i
))) {
257 if (!(e
= calloc(r
+ lu
+ lv
+ 1, sizeof *e
))) {
261 /* First, add { -1, -2, ..., -r } */
262 for (int k
= -1; k
>= -1 * (int) r
; k
--) {
263 size_t vv
= v_of(k
, r
, lu
, lv
);
266 sprintf(nbuf
, "%d", k
);
268 if (quiver_add_vertex(qq
, 0, nbuf
, 1, 50 * x
, ymult
* 50 *
269 i
[vv
], c_froz
, &errstr
) < 0) {
270 fprintf(stderr
, "%s\n", errstr
);
271 fprintf(stderr
, L("quiver_add_vertex failed\n"));
278 /* Now add { 1, 2, ..., u_seq_len + v_seq_len } */
279 for (int k
= 1; k
<= (int) (lu
+ lv
); ++k
) {
280 size_t vv
= v_of(k
, r
, lu
, lv
);
281 int kplus
= find_plus(k
, u
, lu
, v
, lv
);
282 uint32_t c
= (kplus
<= (int) (lu
+ lv
)) ? c_nonf
: c_froz
;
284 i
[vv
] = 1 + ((k
<= (int) lu
) ? u
[k
- 1] : v
[k
- lu
- 1]);
285 sprintf(nbuf
, "%d", k
);
287 if (quiver_add_vertex(qq
, 0, nbuf
, 1, 50 * x
, ymult
* 50 *
288 i
[vv
], c
, &errstr
) < 0) {
289 fprintf(stderr
, "%s\n", errstr
);
290 fprintf(stderr
, L("quiver_add_vertex failed\n"));
297 /* Now add edges by remark 2.4 */
298 for (int k
= -r
; k
<= (int) (lu
+ lv
); ++k
) {
299 int kplus
= find_plus(k
, u
, lu
, v
, lv
);
300 size_t vk
= v_of(k
, r
, lu
, lv
);
306 for (int l
= -r
; l
<= (int) (lu
+ lv
); ++l
) {
307 int lplus
= find_plus(l
, u
, lu
, v
, lv
);
310 p
<= (int) lu
) ? -1 : 1;
311 int q
= zmin((int) kplus
, (int) lplus
);
313 q
<= (int) lu
) ? -1 : 1;
314 size_t vl
= v_of(l
, r
, lu
, lv
);
315 size_t idx
= vk
* qq
->v_len
+ vl
;
316 struct rational
*e
= &qq
->e
[idx
];
325 e
->p
= zsgn(k
- l
) * eip
;
328 eip
* eiq
* (k
- l
) * (kplus
- lplus
) > 0) {
329 e
->p
= zsgn(k
- l
) * eip
* aij(typ
, r
, i
[vk
],
337 * Now modify the fatness of various vertices to normalize |sigma|.
339 * We could just compute this by looking at the y-position
340 * and the Dynkin type, but this serves as a nice sanity check.
342 while (need_fatness_run
) {
343 need_fatness_run
= 0;
345 for (size_t j
= 0; j
< qq
->v_num
; ++j
) {
346 struct vertex
*v
= &qq
->v
[j
];
348 for (size_t k
= 0; k
< qq
->v_num
; ++k
) {
349 struct vertex
*w
= &qq
->v
[k
];
350 struct rational
*e
= &qq
->e
[j
* qq
->v_len
+ k
];
351 struct rational
*f
= &qq
->e
[k
* qq
->v_len
+ j
];
353 if (zabs(e
->p
* v
->fatness
) > zabs(f
->p
*
357 need_fatness_run
= 1;
358 } else if (zabs(e
->p
* v
->fatness
) < zabs(f
->p
*
363 need_fatness_run
= 1;
369 quiver_save_to_file(qq
, stdout
, 0);
379 /* "e" -> { }, "1,2" -> { 1, 2 } */
381 parse_word(const char *s
, size_t n
, size_t **out_word
, size_t *out_len
)
389 if (!(strcmp(s
, "e"))) {
396 for (const char *p
= s
; *p
; p
++) {
400 if (!(seq
= calloc(len
, sizeof *seq
))) {
406 seq
[j
] = strtoll(s
, 0, 0) - 1;
415 for (const char *p
= s
; *p
; p
++) {
421 seq
[j
] = strtoll(p
+ 1, &err
, 0) - 1;
448 "Usage: %s -c <Dynkin classification> [ -u <word>] [-v <word>] [ -U ]\n",
451 " Dynkin classification: Something like \u2018F4\u2019; permitted are\n");
452 printf(" A\u2081, A\u2082, A\u2083, \u2026\n");
453 printf(" B\u2081, B\u2082, B\u2083, \u2026\n");
454 printf(" C\u2081, C\u2082, C\u2083, \u2026\n");
455 printf(" D\u2081, D\u2082, D\u2083, \u2026\n");
456 printf(" G\u2082, F\u2084, E\u2086, E\u2087, E\u2088\n");
458 " Word: something like \u20181,2,1,2\u2019 (\u2018e\u2019 is permitted)\n");
459 printf(" if none given, \u2018e\u2019 is assumed\n");
461 printf(" With -U, -r is above -1. Without, -1 is above -r\n");
466 main(int argc
, char **argv
)
470 enum dynkin typ
= INVALID
;
478 size_t u_seq_len
= 0;
479 size_t v_seq_len
= 0;
480 struct quiver q
= { 0 };
482 while ((opt
= getopt(argc
, argv
, "hUc:u:v:")) != -1) {
503 n
= strtoll(optarg
+ 1, &p
, 0);
508 n
= strtoll(optarg
+ 1, &p
, 0);
513 n
= strtoll(optarg
+ 1, &p
, 0);
518 n
= strtoll(optarg
+ 1, &p
, 0);
522 n
= strtoll(optarg
+ 1, &p
, 0);
536 "Type E may only be E\u2086, E\u2087, or E\u2088\n");
545 if (optarg
[1] == '4' &&
551 "Type F may only be F\u2084\n");
558 if (optarg
[1] == '2' &&
564 "Type G may only be G\u2082\n");
570 "Invalid Dynkin classification: \u2018%s\u2019\n",
579 fprintf(stderr
, "Invalid n: \u2018%s\u2019\n",
590 "Dynkin classification is required (ex: \u2018-c F4\u2019)\n");
598 if (parse_word(uword
, n
, &u_seq
, &u_seq_len
) < 0) {
599 fprintf(stderr
, "Invalid u-word: \u2018%s\u2019\n", uword
);
604 if (parse_word(vword
, n
, &v_seq
, &v_seq_len
) < 0) {
605 fprintf(stderr
, "Invalid v-word: \u2018%s\u2019\n", vword
);
610 if ((ret
= run_bfzIII(&q
, typ
, n
, u_seq
, u_seq_len
, v_seq
, v_seq_len
,
612 fprintf(stderr
, "BFZIII algorithm failed\n");