11 #define MAX_SUPPORTED_EDGE_NUM (((size_t) -1) >> 2)
12 #define MAX_SUPPORTED_VERTEX_NUM (((size_t) -1) >> 2)
14 /* Primes for reducing fractions */
15 static uint32_t primes
[] = {
17 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
18 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139,
19 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223,
20 227, 229, 233, 239, 241, 251
24 static int gcd(uint_fast8_t x
, uint_fast8_t y
)
42 /* Attempt to store a fraction in out, reducing if possible */
43 static int reduce_fraction(int_fast32_t n
, uint_fast32_t d
, struct
44 rational
*out
, const char **out_errstr
)
48 *out
= (struct rational
) { .p
= 0, .q
= 1 };
53 for (size_t j
= 0; j
< ((sizeof primes
) / (sizeof primes
[0])); ++j
) {
54 uint32_t p
= primes
[j
];
68 if (n
> INT_FAST8_MAX
||
72 IF_NZ_SET(out_errstr
, L("unrepresentable fraction"));
77 *out
= (struct rational
) { .p
= n
, .q
= d
};
83 static int add_to_fraction(int_fast8_t a
, uint_fast8_t b
, struct rational
*out
,
84 const char **out_errstr
)
86 int_fast32_t n
= a
* out
->q
+ out
->p
* b
;
87 uint_fast32_t d
= b
* out
->q
;
89 return reduce_fraction(n
, d
, out
, out_errstr
);
92 /* Add an arrow of weight a/b from i -> j, affecting e(i,j) and e(j,i) */
93 int quiver_add_to_edge(struct quiver
*q
, size_t i
, size_t j
, int_fast8_t a
,
94 uint_fast8_t b
, const char **out_errstr
)
99 IF_NZ_SET(out_errstr
, L("nonexistant quiver"));
106 IF_NZ_SET(out_errstr
, L("edge includes nonexistant vertex"));
112 IF_NZ_SET(out_errstr
, L("loops are not allowed"));
117 struct rational
*eij
= &(q
->e
[i
* q
->v_len
+ j
]);
118 struct rational
*eji
= &(q
->e
[j
* q
->v_len
+ i
]);
119 uint_fast8_t d
= gcd(q
->v
[i
].fatness
, q
->v
[j
].fatness
);
121 if ((ret
= add_to_fraction(a
* q
->v
[j
].fatness
, b
* d
, eij
,
126 if ((ret
= add_to_fraction(-1 * a
* q
->v
[i
].fatness
, b
* d
, eji
,
134 /* Add a vertex with a name and weight */
135 int quiver_add_vertex(struct quiver
*q
, size_t *out_i
, const char *name
,
136 uint_fast16_t fatness
, int x
, int y
, const
143 IF_NZ_SET(out_errstr
, L("invalid quiver"));
149 if (!(newname
= malloc(snprintf(0, 0, "%zu", q
->v_num
) + 1))) {
152 IF_NZ_SET(out_errstr
, L("malloc"));
157 sprintf(newname
, "%zu", q
->v_num
);
159 if (!(newname
= malloc(strlen(name
) + 1))) {
162 IF_NZ_SET(out_errstr
, L("malloc"));
167 strcpy(newname
, name
);
170 if (q
->v_num
>= q
->v_len
) {
171 size_t newlen
= q
->v_len
+ 8;
173 /* XXX: check for overflow here */
174 if (!(newmem
= malloc(newlen
* newlen
* sizeof (*q
->e
)))) {
177 IF_NZ_SET(out_errstr
, L("too many vertices"));
182 for (size_t j
= 0; j
< q
->v_num
; ++j
) {
183 for (size_t k
= 0; k
< q
->v_num
; ++k
) {
184 ((struct rational
*) newmem
)[j
* newlen
+ k
] =
185 q
->e
[j
* q
->v_len
+ k
];
188 for (size_t k
= q
->v_num
; k
< newlen
; ++k
) {
189 ((struct rational
*) newmem
)[j
* newlen
+ k
] =
190 (struct rational
) { .p
= 0, .q
= 1 };
194 for (size_t j
= q
->v_num
; j
< newlen
; ++j
) {
195 for (size_t k
= 0; k
< newlen
; ++k
) {
196 ((struct rational
*) newmem
)[j
* newlen
+ k
] =
197 (struct rational
) { .p
= 0, .q
= 1 };
203 if (!(newmem
= (realloc(q
->v
, newlen
* sizeof (*q
->v
))))) {
206 IF_NZ_SET(out_errstr
, L("too many vertices"));
215 for (size_t k
= 0; k
<= q
->v_num
; ++k
) {
216 q
->e
[k
* q
->v_len
+ q
->v_num
] = (struct rational
) { .p
= 0, .q
=
218 q
->e
[q
->v_num
* q
->v_len
+ k
] = (struct rational
) { .p
= 0, .q
=
222 q
->v
[q
->v_num
] = (struct vertex
) { .name
= newname
, .fatness
= fatness
,
234 /* Increase or decrease the fatness of a vertex, readjusting edges as well */
235 int quiver_adjust_fatness(struct quiver
*q
, size_t i
, int_fast8_t fatness_adj
,
236 const char **out_errstr
)
241 IF_NZ_SET(out_errstr
, L("invalid vertex"));
246 int new_fatness
= q
->v
[i
].fatness
+ fatness_adj
;
248 if (new_fatness
<= 0 ||
249 new_fatness
> UINT_FAST8_MAX
) {
250 IF_NZ_SET(out_errstr
, L("invalid new fatness"));
255 for (size_t j
= 0; j
< q
->v_num
; ++j
) {
260 uint_fast8_t d_orig
= gcd(q
->v
[i
].fatness
, q
->v
[j
].fatness
);
261 uint_fast8_t d_new
= gcd(new_fatness
, q
->v
[j
].fatness
);
262 size_t k
= i
* q
->v_len
+ j
;
264 if ((ret
= reduce_fraction(q
->e
[k
].p
* d_orig
, q
->e
[k
].q
*
265 d_new
, &(q
->e
[k
]), out_errstr
))) {
269 k
= j
* q
->v_len
+ i
;
271 if ((ret
= reduce_fraction(q
->e
[k
].p
* d_orig
* q
->v
[i
].fatness
,
272 q
->e
[k
].q
* d_new
* new_fatness
,
273 &(q
->e
[k
]), out_errstr
))) {
278 q
->v
[i
].fatness
= new_fatness
;
283 /* Delete a vertex (and all associated edges) */
284 int quiver_delete_vertex(struct quiver
*q
, size_t i
, const char **out_errstr
)
287 IF_NZ_SET(out_errstr
, L("invalid vertex"));
299 /* First, shift everything over to the left */
300 for (size_t j
= 0; j
< q
->v_num
; ++j
) {
301 for (size_t k
= i
+ 1; k
< q
->v_num
; ++k
) {
302 q
->e
[q
->v_len
* j
+ k
- 1] = q
->e
[q
->v_len
* j
+ k
];
306 /* Second, shift everything below row i up */
307 for (size_t j
= i
+ 1; j
< q
->v_num
; ++j
) {
308 for (size_t k
= 0; k
< q
->v_num
; ++k
) {
309 q
->e
[q
->v_len
* (j
- 1) + k
] = q
->e
[q
->v_len
* j
+ k
];
313 /* Now shift the vertex names/lengths over */
316 for (size_t j
= i
+ 1; j
< q
->v_num
; ++j
) {
317 q
->v
[j
- 1] = q
->v
[j
];
321 q
->v
[q
->v_num
] = (struct vertex
) { 0 };
326 /* Mutate the quiver at vertex k */
327 int quiver_mutate(struct quiver
*q
, size_t k
, const char **out_errstr
)
332 IF_NZ_SET(out_errstr
, L("invalid quiver"));
337 /* Step one: complete all triangles */
338 for (size_t i
= 0; i
< q
->v_num
; ++i
) {
343 struct rational
*eik
= &(q
->e
[i
* q
->v_len
+ k
]);
345 for (size_t j
= 0; j
< q
->v_num
; ++j
) {
351 struct rational
*eij
= &(q
->e
[i
* q
->v_len
+ j
]);
352 struct rational
*ekj
= &(q
->e
[k
* q
->v_len
+ j
]);
354 if (eik
->p
* ekj
->p
<= 0) {
358 if ((ret
= add_to_fraction(abs(eik
->p
) * ekj
->p
,
359 eik
->q
* ekj
->q
, eij
,
366 /* Step two: invert all edges that touch k */
367 for (size_t i
= 0; i
< q
->v_num
; ++i
) {
372 struct rational
*eik
= &(q
->e
[i
* q
->v_len
+ k
]);
373 struct rational
*eki
= &(q
->e
[k
* q
->v_len
+ i
]);