summaryrefslogtreecommitdiff
path: root/apps/plugins/puzzles/src/dsf.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/puzzles/src/dsf.c')
-rw-r--r--apps/plugins/puzzles/src/dsf.c411
1 files changed, 262 insertions, 149 deletions
diff --git a/apps/plugins/puzzles/src/dsf.c b/apps/plugins/puzzles/src/dsf.c
index 832bb3005a..bed564f8ec 100644
--- a/apps/plugins/puzzles/src/dsf.c
+++ b/apps/plugins/puzzles/src/dsf.c
@@ -5,188 +5,301 @@
5 */ 5 */
6 6
7#include <assert.h> 7#include <assert.h>
8#include <limits.h>
8#include <string.h> 9#include <string.h>
9 10
10#include "puzzles.h" 11#include "puzzles.h"
11 12
12/*void print_dsf(int *dsf, int size) 13#define DSF_INDEX_MASK (UINT_MAX >> 1)
14#define DSF_FLAG_CANONICAL (UINT_MAX & ~(UINT_MAX >> 1))
15#define DSF_MAX (DSF_INDEX_MASK + 1)
16
17struct DSF {
18 /*
19 * Size of the dsf.
20 */
21 size_t size;
22
23 /*
24 * Main array storing the data structure.
25 *
26 * If n is the canonical element of an equivalence class,
27 * parent_or_size[n] holds the number of elements in that class,
28 * bitwise-ORed with DSF_FLAG_CANONICAL.
29 *
30 * If n is not the canonical element, parent_or_size[n] holds the
31 * index of another element nearer to the root of the tree for
32 * that class.
33 */
34 unsigned *parent_or_size;
35
36 /*
37 * Extra storage for flip tracking.
38 *
39 * If n is not a canonical element, flip[n] indicates whether the
40 * sense of this element is flipped relative to parent_or_size[n].
41 *
42 * If n is a canonical element, flip[n] is unused.
43 */
44 unsigned char *flip;
45
46 /*
47 * Extra storage for minimal-element tracking.
48 *
49 * If n is a canonical element, min[n] holds the index of the
50 * smallest value in n's equivalence class.
51 *
52 * If n is not a canonical element, min[n] is unused.
53 */
54 unsigned *min;
55};
56
57static DSF *dsf_new_internal(int size, bool flip, bool min)
13{ 58{
14 int *printed_elements = snewn(size, int); 59 DSF *dsf;
15 int *equal_elements = snewn(size, int);
16 int *inverse_elements = snewn(size, int);
17 int printed_count = 0, equal_count, inverse_count;
18 int i, n;
19 bool inverse;
20 60
21 memset(printed_elements, -1, sizeof(int) * size); 61 assert(0 < size && size <= DSF_MAX && "Bad dsf size");
22 62
23 while (1) { 63 dsf = snew(DSF);
24 equal_count = 0; 64 dsf->size = size;
25 inverse_count = 0; 65 dsf->parent_or_size = snewn(size, unsigned);
26 for (i = 0; i < size; ++i) { 66 dsf->flip = flip ? snewn(size, unsigned char) : NULL;
27 if (!memchr(printed_elements, i, sizeof(int) * size)) 67 dsf->min = min ? snewn(size, unsigned) : NULL;
28 break; 68
29 } 69 dsf_reinit(dsf);
30 if (i == size)
31 goto done;
32
33 i = dsf_canonify(dsf, i);
34
35 for (n = 0; n < size; ++n) {
36 if (edsf_canonify(dsf, n, &inverse) == i) {
37 if (inverse)
38 inverse_elements[inverse_count++] = n;
39 else
40 equal_elements[equal_count++] = n;
41 }
42 }
43
44 for (n = 0; n < equal_count; ++n) {
45 fprintf(stderr, "%d ", equal_elements[n]);
46 printed_elements[printed_count++] = equal_elements[n];
47 }
48 if (inverse_count) {
49 fprintf(stderr, "!= ");
50 for (n = 0; n < inverse_count; ++n) {
51 fprintf(stderr, "%d ", inverse_elements[n]);
52 printed_elements[printed_count++] = inverse_elements[n];
53 }
54 }
55 fprintf(stderr, "\n");
56 }
57done:
58 70
59 sfree(printed_elements); 71 return dsf;
60 sfree(equal_elements); 72}
61 sfree(inverse_elements);
62}*/
63 73
64void dsf_init(int *dsf, int size) 74DSF *dsf_new(int size)
65{ 75{
66 int i; 76 return dsf_new_internal(size, false, false);
77}
67 78
68 for (i = 0; i < size; i++) dsf[i] = 6; 79DSF *dsf_new_flip(int size)
69 /* Bottom bit of each element of this array stores whether that 80{
70 * element is opposite to its parent, which starts off as 81 return dsf_new_internal(size, true, false);
71 * false. Second bit of each element stores whether that element
72 * is the root of its tree or not. If it's not the root, the
73 * remaining 30 bits are the parent, otherwise the remaining 30
74 * bits are the number of elements in the tree. */
75} 82}
76 83
77int *snew_dsf(int size) 84DSF *dsf_new_min(int size)
78{ 85{
79 int *ret; 86 return dsf_new_internal(size, false, true);
80 87}
81 ret = snewn(size, int); 88
82 dsf_init(ret, size); 89void dsf_reinit(DSF *dsf)
90{
91 size_t i;
92
93 /* Every element starts as the root of an equivalence class of size 1 */
94 for (i = 0; i < dsf->size; i++)
95 dsf->parent_or_size[i] = DSF_FLAG_CANONICAL | 1;
83 96
84 /*print_dsf(ret, size); */ 97 /* If we're tracking minima then every element is also its own min */
98 if (dsf->min)
99 for (i = 0; i < dsf->size; i++)
100 dsf->min[i] = i;
85 101
86 return ret; 102 /* No need to initialise dsf->flip, even if it exists, because
103 * only the entries for non-root elements are meaningful, and
104 * currently there are none. */
87} 105}
88 106
89int dsf_canonify(int *dsf, int index) 107void dsf_copy(DSF *to, DSF *from)
90{ 108{
91 return edsf_canonify(dsf, index, NULL); 109 assert(to->size == from->size && "Mismatch in dsf_copy");
110 memcpy(to->parent_or_size, from->parent_or_size,
111 to->size * sizeof(*to->parent_or_size));
112 if (to->flip) {
113 assert(from->flip && "Copying a non-flip dsf to a flip one");
114 memcpy(to->flip, from->flip, to->size * sizeof(*to->flip));
115 }
116 if (to->min) {
117 assert(from->min && "Copying a non-min dsf to a min one");
118 memcpy(to->min, from->min, to->size * sizeof(*to->min));
119 }
92} 120}
93 121
94void dsf_merge(int *dsf, int v1, int v2) 122
123void dsf_free(DSF *dsf)
95{ 124{
96 edsf_merge(dsf, v1, v2, false); 125 if (dsf) {
126 sfree(dsf->parent_or_size);
127 sfree(dsf->flip);
128 sfree(dsf->min);
129 sfree(dsf);
130 }
97} 131}
98 132
99int dsf_size(int *dsf, int index) { 133static inline size_t dsf_find_root(DSF *dsf, size_t n)
100 return dsf[dsf_canonify(dsf, index)] >> 2; 134{
135 while (!(dsf->parent_or_size[n] & DSF_FLAG_CANONICAL))
136 n = dsf->parent_or_size[n];
137 return n;
138}
139
140static inline void dsf_path_compress(DSF *dsf, size_t n, size_t root)
141{
142 while (!(dsf->parent_or_size[n] & DSF_FLAG_CANONICAL)) {
143 size_t prev = n;
144 n = dsf->parent_or_size[n];
145 dsf->parent_or_size[prev] = root;
146 }
147 assert(n == root);
101} 148}
102 149
103int edsf_canonify(int *dsf, int index, bool *inverse_return) 150int dsf_canonify(DSF *dsf, int n)
104{ 151{
105 int start_index = index, canonical_index; 152 size_t root;
106 bool inverse = false;
107 153
108/* fprintf(stderr, "dsf = %p\n", dsf); */ 154 assert(0 <= n && n < dsf->size && "Overrun in dsf_canonify");
109/* fprintf(stderr, "Canonify %2d\n", index); */
110 155
111 assert(index >= 0); 156 root = dsf_find_root(dsf, n);
157 dsf_path_compress(dsf, n, root);
158 return root;
159}
160
161void dsf_merge(DSF *dsf, int n1, int n2)
162{
163 size_t r1, r2, s1, s2, root;
164
165 assert(0 <= n1 && n1 < dsf->size && "Overrun in dsf_merge");
166 assert(0 <= n2 && n2 < dsf->size && "Overrun in dsf_merge");
167 assert(!dsf->flip && "dsf_merge on a flip dsf");
168
169 /* Find the root elements */
170 r1 = dsf_find_root(dsf, n1);
171 r2 = dsf_find_root(dsf, n2);
172
173 if (r1 == r2) {
174 /* Classes are already the same, so we have a common root */
175 root = r1;
176 } else {
177 /* Classes must be merged */
178
179 /* Decide which one to use as the overall root, based on size */
180 s1 = dsf->parent_or_size[r1] & DSF_INDEX_MASK;
181 s2 = dsf->parent_or_size[r2] & DSF_INDEX_MASK;
182 if (s1 > s2) {
183 dsf->parent_or_size[r2] = root = r1;
184 } else {
185 dsf->parent_or_size[r1] = root = r2;
186 }
187 dsf->parent_or_size[root] = (s1 + s2) | DSF_FLAG_CANONICAL;
112 188
113 /* Find the index of the canonical element of the 'equivalence class' of 189 if (dsf->min) {
114 * which start_index is a member, and figure out whether start_index is the 190 /* Update the min of the merged class */
115 * same as or inverse to that. */ 191 unsigned m1 = dsf->min[r1], m2 = dsf->min[r2];
116 while ((dsf[index] & 2) == 0) { 192 dsf->min[root] = m1 < m2 ? m1 : m2;
117 inverse ^= (dsf[index] & 1); 193 }
118 index = dsf[index] >> 2;
119/* fprintf(stderr, "index = %2d, ", index); */
120/* fprintf(stderr, "inverse = %d\n", inverse); */
121 } 194 }
122 canonical_index = index; 195
123 196 /* Path-compress both paths from n1 and n2 so they point at the new root */
124 if (inverse_return) 197 dsf_path_compress(dsf, n1, root);
125 *inverse_return = inverse; 198 dsf_path_compress(dsf, n2, root);
126 199}
127 /* Update every member of this 'equivalence class' to point directly at the 200
128 * canonical member. */ 201bool dsf_equivalent(DSF *dsf, int n1, int n2)
129 index = start_index; 202{
130 while (index != canonical_index) { 203 return dsf_canonify(dsf, n1) == dsf_canonify(dsf, n2);
131 int nextindex = dsf[index] >> 2; 204}
132 bool nextinverse = inverse ^ (dsf[index] & 1); 205
133 dsf[index] = (canonical_index << 2) | inverse; 206int dsf_size(DSF *dsf, int n)
134 inverse = nextinverse; 207{
135 index = nextindex; 208 size_t root = dsf_canonify(dsf, n);
209 return dsf->parent_or_size[root] & DSF_INDEX_MASK;
210}
211
212static inline size_t dsf_find_root_flip(DSF *dsf, size_t n, unsigned *flip)
213{
214 *flip = 0;
215 while (!(dsf->parent_or_size[n] & DSF_FLAG_CANONICAL)) {
216 *flip ^= dsf->flip[n];
217 n = dsf->parent_or_size[n];
218 }
219 return n;
220}
221
222static inline void dsf_path_compress_flip(DSF *dsf, size_t n, size_t root,
223 unsigned flip)
224{
225 while (!(dsf->parent_or_size[n] & DSF_FLAG_CANONICAL)) {
226 size_t prev = n;
227 unsigned flip_prev = flip;
228 n = dsf->parent_or_size[n];
229 flip ^= dsf->flip[prev];
230 dsf->flip[prev] = flip_prev;
231 dsf->parent_or_size[prev] = root;
136 } 232 }
233 assert(n == root);
234}
235
236int dsf_canonify_flip(DSF *dsf, int n, bool *inverse)
237{
238 size_t root;
239 unsigned flip;
240
241 assert(0 <= n && n < dsf->size && "Overrun in dsf_canonify_flip");
242 assert(dsf->flip && "dsf_canonify_flip on a non-flip dsf");
243
244 root = dsf_find_root_flip(dsf, n, &flip);
245 dsf_path_compress_flip(dsf, n, root, flip);
246 *inverse = flip;
247 return root;
248}
249
250void dsf_merge_flip(DSF *dsf, int n1, int n2, bool inverse)
251{
252 size_t r1, r2, s1, s2, root;
253 unsigned f1, f2;
254
255 assert(0 <= n1 && n1 < dsf->size && "Overrun in dsf_merge_flip");
256 assert(0 <= n2 && n2 < dsf->size && "Overrun in dsf_merge_flip");
257 assert(dsf->flip && "dsf_merge_flip on a non-flip dsf");
258
259 /* Find the root elements */
260 r1 = dsf_find_root_flip(dsf, n1, &f1);
261 r2 = dsf_find_root_flip(dsf, n2, &f2);
262
263 if (r1 == r2) {
264 /* Classes are already the same, so we have a common root */
265 assert((f1 ^ f2 ^ inverse) == 0 && "Inconsistency in dsf_merge_flip");
266 root = r1;
267 } else {
268 /* Classes must be merged */
137 269
138 assert(!inverse); 270 /* Decide which one to use as the overall root, based on size */
139 271 s1 = dsf->parent_or_size[r1] & DSF_INDEX_MASK;
140/* fprintf(stderr, "Return %2d\n", index); */ 272 s2 = dsf->parent_or_size[r2] & DSF_INDEX_MASK;
141 273 if (s1 > s2) {
142 return index; 274 dsf->parent_or_size[r2] = root = r1;
143} 275 dsf->flip[r2] = f1 ^ f2 ^ inverse;
144 276 f2 ^= dsf->flip[r2];
145void edsf_merge(int *dsf, int v1, int v2, bool inverse) 277 } else {
146{ 278 root = r2;
147 bool i1, i2; 279 dsf->parent_or_size[r1] = root = r2;
148 280 dsf->flip[r1] = f1 ^ f2 ^ inverse;
149/* fprintf(stderr, "dsf = %p\n", dsf); */ 281 f1 ^= dsf->flip[r1];
150/* fprintf(stderr, "Merge [%2d,%2d], %d\n", v1, v2, inverse); */ 282 }
151 283 dsf->parent_or_size[root] = (s1 + s2) | DSF_FLAG_CANONICAL;
152 v1 = edsf_canonify(dsf, v1, &i1); 284
153 assert(dsf[v1] & 2); 285 if (dsf->min) {
154 inverse ^= i1; 286 /* Update the min of the merged class */
155 v2 = edsf_canonify(dsf, v2, &i2); 287 unsigned m1 = dsf->min[r1], m2 = dsf->min[r2];
156 assert(dsf[v2] & 2); 288 dsf->min[root] = m1 < m2 ? m1 : m2;
157 inverse ^= i2; 289 }
158
159/* fprintf(stderr, "Doing [%2d,%2d], %d\n", v1, v2, inverse); */
160
161 if (v1 == v2)
162 assert(!inverse);
163 else {
164 /*
165 * We always make the smaller of v1 and v2 the new canonical
166 * element. This ensures that the canonical element of any
167 * class in this structure is always the first element in
168 * it. 'Keen' depends critically on this property.
169 *
170 * (Jonas Koelker previously had this code choosing which
171 * way round to connect the trees by examining the sizes of
172 * the classes being merged, so that the root of the
173 * larger-sized class became the new root. This gives better
174 * asymptotic performance, but I've changed it to do it this
175 * way because I like having a deterministic canonical
176 * element.)
177 */
178 if (v1 > v2) {
179 int v3 = v1;
180 v1 = v2;
181 v2 = v3;
182 }
183 dsf[v1] += (dsf[v2] >> 2) << 2;
184 dsf[v2] = (v1 << 2) | inverse;
185 } 290 }
186
187 v2 = edsf_canonify(dsf, v2, &i2);
188 assert(v2 == v1);
189 assert(i2 == inverse);
190 291
191/* fprintf(stderr, "dsf[%2d] = %2d\n", v2, dsf[v2]); */ 292 /* Path-compress both paths from n1 and n2 so they point at the new root */
293 dsf_path_compress_flip(dsf, n1, root, f1);
294 dsf_path_compress_flip(dsf, n2, root, f2);
295}
296
297int dsf_minimal(DSF *dsf, int n)
298{
299 size_t root;
300
301 assert(dsf->min && "dsf_minimal on a non-min dsf");
302
303 root = dsf_canonify(dsf, n);
304 return dsf->min[root];
192} 305}