diff options
Diffstat (limited to 'apps/plugins/puzzles/src/dsf.c')
-rw-r--r-- | apps/plugins/puzzles/src/dsf.c | 411 |
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 | |||
17 | struct 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 | |||
57 | static 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 | } | ||
57 | done: | ||
58 | 70 | ||
59 | sfree(printed_elements); | 71 | return dsf; |
60 | sfree(equal_elements); | 72 | } |
61 | sfree(inverse_elements); | ||
62 | }*/ | ||
63 | 73 | ||
64 | void dsf_init(int *dsf, int size) | 74 | DSF *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; | 79 | DSF *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 | ||
77 | int *snew_dsf(int size) | 84 | DSF *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); | 89 | void 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 | ||
89 | int dsf_canonify(int *dsf, int index) | 107 | void 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 | ||
94 | void dsf_merge(int *dsf, int v1, int v2) | 122 | |
123 | void 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 | ||
99 | int dsf_size(int *dsf, int index) { | 133 | static 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 | |||
140 | static 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 | ||
103 | int edsf_canonify(int *dsf, int index, bool *inverse_return) | 150 | int 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 | |||
161 | void 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. */ | 201 | bool 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; | 206 | int 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 | |||
212 | static 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 | |||
222 | static 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 | |||
236 | int 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 | |||
250 | void 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]; | |
145 | void 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 | |||
297 | int 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 | } |