Controls work (sans deleting, previewing edges)
[clav.git] / quiver.c
blob838321b48615fc8a0e6c25caec44896236d55960
1 #include <errno.h>
2 #include <stddef.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
8 #include "macros.h"
9 #include "quiver.h"
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[] = {
16 /* */
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 /* GCD */
24 static int gcd(uint_fast8_t x, uint_fast8_t y)
26 uint_fast8_t r = 0;
28 if (!x &&
29 !y) {
30 return 1;
33 while (y) {
34 r = x % y;
35 x = y;
36 y = r;
39 return x;
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)
46 if (!n &&
47 d) {
48 *out = (struct rational) { .p = 0, .q = 1 };
50 return 0;
53 for (size_t j = 0; j < ((sizeof primes) / (sizeof primes[0])); ++j) {
54 uint32_t p = primes[j];
56 if (j &&
57 p * 2 > d) {
58 break;
61 while (n % p == 0 &&
62 d % p == 0) {
63 n = n / p;
64 d = d / p;
68 if (n > INT_FAST8_MAX ||
69 n < INT_FAST8_MIN ||
70 d == 0 ||
71 d > UINT_FAST8_MAX) {
72 IF_NZ_SET(out_errstr, L("unrepresentable fraction"));
74 return EDOM;
77 *out = (struct rational) { .p = n, .q = d };
79 return 0;
82 /* out += a/b */
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)
96 int ret = 0;
98 if (!q) {
99 IF_NZ_SET(out_errstr, L("nonexistant quiver"));
101 return EINVAL;
104 if (i >= q->v_num ||
105 j >= q->v_num) {
106 IF_NZ_SET(out_errstr, L("edge includes nonexistant vertex"));
108 return EINVAL;
111 if (i == j) {
112 IF_NZ_SET(out_errstr, L("loops are not allowed"));
114 return EINVAL;
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,
122 out_errstr))) {
123 return ret;
126 if ((ret = add_to_fraction(-1 * a * q->v[i].fatness, b * d, eji,
127 out_errstr))) {
128 return ret;
131 return 0;
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
137 char **out_errstr)
139 void *newmem = 0;
140 char *newname;
142 if (!q) {
143 IF_NZ_SET(out_errstr, L("invalid quiver"));
145 return EINVAL;
148 if (!name) {
149 if (!(newname = malloc(snprintf(0, 0, "%zu", q->v_num) + 1))) {
150 int sv_err = errno;
152 IF_NZ_SET(out_errstr, L("malloc"));
154 return sv_err;
157 sprintf(newname, "%zu", q->v_num);
158 } else {
159 if (!(newname = malloc(strlen(name) + 1))) {
160 int sv_err = errno;
162 IF_NZ_SET(out_errstr, L("malloc"));
164 return sv_err;
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)))) {
175 int sv_err = errno;
177 IF_NZ_SET(out_errstr, L("too many vertices"));
179 return sv_err;
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 };
201 q->e = newmem;
203 if (!(newmem = (realloc(q->v, newlen * sizeof (*q->v))))) {
204 int sv_err = errno;
206 IF_NZ_SET(out_errstr, L("too many vertices"));
208 return sv_err;
211 q->v = newmem;
212 q->v_len = newlen;
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 =
217 1 };
218 q->e[q->v_num * q->v_len + k] = (struct rational) { .p = 0, .q =
219 1 };
222 q->v[q->v_num] = (struct vertex) { .name = newname, .fatness = fatness,
223 .x = x, .y = y };
225 if (out_i) {
226 *out_i = q->v_num;
229 q->v_num++;
231 return 0;
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)
238 int ret = 0;
240 if (i >= q->v_num) {
241 IF_NZ_SET(out_errstr, L("invalid vertex"));
243 return EINVAL;
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"));
252 return EINVAL;
255 for (size_t j = 0; j < q->v_num; ++j) {
256 if (i == j) {
257 continue;
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))) {
266 return ret;
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))) {
274 return ret;
278 q->v[i].fatness = new_fatness;
280 return ret;
283 /* Delete a vertex (and all associated edges) */
284 int quiver_delete_vertex(struct quiver *q, size_t i, const char **out_errstr)
286 if (i >= q->v_num) {
287 IF_NZ_SET(out_errstr, L("invalid vertex"));
289 return EINVAL;
292 if (q->v_num == 1) {
293 q->v_num = 0;
294 free(q->v[0].name);
296 return 0;
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 */
314 free(q->v[i].name);
316 for (size_t j = i + 1; j < q->v_num; ++j) {
317 q->v[j - 1] = q->v[j];
320 q->v_num--;
321 q->v[q->v_num] = (struct vertex) { 0 };
323 return 0;
326 /* Mutate the quiver at vertex k */
327 int quiver_mutate(struct quiver *q, size_t k, const char **out_errstr)
329 int ret = 0;
331 if (!q) {
332 IF_NZ_SET(out_errstr, L("invalid quiver"));
334 return EINVAL;
337 /* Step one: complete all triangles */
338 for (size_t i = 0; i < q->v_num; ++i) {
339 if (i == k) {
340 continue;
343 struct rational *eik = &(q->e[i * q->v_len + k]);
345 for (size_t j = 0; j < q->v_num; ++j) {
346 if (j == k ||
347 j == i) {
348 continue;
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) {
355 continue;
358 if ((ret = add_to_fraction(abs(eik->p) * ekj->p,
359 eik->q * ekj->q, eij,
360 out_errstr))) {
361 return ret;
366 /* Step two: invert all edges that touch k */
367 for (size_t i = 0; i < q->v_num; ++i) {
368 if (i == k) {
369 continue;
372 struct rational *eik = &(q->e[i * q->v_len + k]);
373 struct rational *eki = &(q->e[k * q->v_len + i]);
375 eik->p = -eik->p;
376 eki->p = -eki->p;
379 return 0;