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
23 /* Attempt to store a fraction in out, reducing if possible */
24 static int reduce_fraction(int_fast32_t n
, uint_fast32_t d
, struct
25 rational
*out
, const char **out_errstr
)
30 for (j
= 0; j
< ((sizeof primes
) / (sizeof primes
[0])); ++j
) {
45 if (n
> INT_FAST8_MAX
||
48 IF_NZ_SET(out_errstr
, L("unrepresentable fraction"));
53 *out
= (struct rational
) { .p
= n
, .q
= d
};
59 static int add_to_fraction(int_fast8_t a
, uint_fast8_t b
, struct rational
*out
,
60 const char **out_errstr
)
62 int_fast32_t n
= a
* out
->q
+ out
->p
* b
;
63 uint_fast32_t d
= b
* out
->q
;
65 return reduce_fraction(n
, d
, out
, out_errstr
);
68 /* Add an arrow of weight a/b from i -> j, affecting e(i,j) and e(j,i) */
69 int quiver_add_to_edge(struct quiver
*q
, size_t i
, size_t j
, int_fast8_t a
,
70 uint_fast8_t b
, const char **out_errstr
)
76 IF_NZ_SET(out_errstr
, L("nonexistant quiver"));
81 if (i
>= q
->vertices_num
||
82 j
>= q
->vertices_num
) {
83 IF_NZ_SET(out_errstr
, L("edge includes nonexistant vertex"));
88 k
= (i
* q
->vertices_len
+ j
);
90 if ((ret
= add_to_fraction(a
* q
->vertices
[i
].fatness
, b
,
91 &(q
->edges
[k
]), out_errstr
))) {
95 k
= (j
* q
->vertices_len
+ i
);
97 if ((ret
= add_to_fraction(-1 * a
* q
->vertices
[j
].fatness
, b
,
98 &(q
->edges
[k
]), out_errstr
))) {
107 /* Add a vertex with a name and weight */
108 int quiver_add_vertex(struct quiver
*q
, size_t *out_i
, const char *name
,
109 uint_fast16_t fatness
, const char **out_errstr
)
113 size_t l
= strlen(name
);
119 IF_NZ_SET(out_errstr
, L("invalid quiver"));
124 if (!(newname
= malloc(l
+ 1))) {
126 IF_NZ_SET(out_errstr
, L("malloc"));
131 strcat(newname
, name
);
133 if (q
->vertices_num
>= q
->vertices_len
) {
134 newsize
= (q
->vertices_len
+ 8) * (q
->vertices_len
+ 8);
136 if (!(newmem
= realloc(q
->edges
, newsize
*
137 sizeof q
->edges
[0]))) {
139 IF_NZ_SET(out_errstr
, L("too many vertices"));
145 newsize
= q
->vertices_len
+ 8;
147 if (!(newmem
= realloc(q
->vertices
, newsize
*
148 sizeof q
->vertices
[0]))) {
150 IF_NZ_SET(out_errstr
, L("too many vertices"));
155 q
->vertices
= newmem
;
156 q
->vertices_len
+= 8;
159 for (k
= 0; k
<= q
->vertices_num
; ++k
) {
160 q
->edges
[k
* q
->vertices_len
+ q
->vertices_num
] = (struct
161 rational
) { .p
= 0, .q
= 1 };
162 q
->edges
[q
->vertices_num
* q
->vertices_len
+ k
] = (struct
163 rational
) { .p
= 0, .q
= 1 };
166 q
->vertices
[q
->vertices_num
] = (struct vertex
) { .name
= newname
,
167 .fatness
= fatness
};
168 *out_i
= q
->vertices_num
;
174 /* Mutate the quiver at vertex k */
175 int quiver_mutate(struct quiver
*q
, size_t k
, const char **out_errstr
)
182 struct rational
*eik
;
183 struct rational
*eij
;
184 struct rational
*ekj
;
188 IF_NZ_SET(out_errstr
, L("invalid quiver"));
193 /* Step one: complete all triangles */
194 for (i
= 0; i
< q
->vertices_num
; ++i
) {
199 ik
= i
* q
->vertices_len
+ k
;
200 eik
= &(q
->edges
[ik
]);
202 for (j
= 0; j
< q
->vertices_num
; ++j
) {
208 ij
= i
* q
->vertices_len
+ j
;
209 eij
= &(q
->edges
[ij
]);
210 kj
= k
* q
->vertices_len
+ j
;
211 ekj
= &(q
->edges
[kj
]);
213 if (eik
->p
* ekj
->p
<= 0) {
217 if ((ret
= add_to_fraction(abs(eik
->p
) * ekj
->p
,
218 eik
->q
* ekj
->q
, eij
, out_errstr
))) {
224 /* Step two: invert all edges that touch k */
225 for (i
= 0; i
< q
->vertices_num
; ++i
) {
230 ik
= i
* q
->vertices_len
+ k
;
231 eik
= &(q
->edges
[ik
]);