Stop the analysis pass in Loopy's redraw routine from being
[sgt/puzzles] / dsf.c
diff --git a/dsf.c b/dsf.c
index f4deb1e..aa22392 100644 (file)
--- a/dsf.c
+++ b/dsf.c
@@ -9,7 +9,7 @@
 
 #include "puzzles.h"
 
-void print_dsf(int *dsf, int size)
+/*void print_dsf(int *dsf, int size)
 {
     int *printed_elements = snewn(size, int);
     int *equal_elements = snewn(size, int);
@@ -58,19 +58,27 @@ done:
     sfree(printed_elements);
     sfree(equal_elements);
     sfree(inverse_elements);
+}*/
+
+void dsf_init(int *dsf, int size)
+{
+    int i;
+
+    for (i = 0; i < size; i++) dsf[i] = 6;
+    /* Bottom bit of each element of this array stores whether that
+     * element is opposite to its parent, which starts off as
+     * false. Second bit of each element stores whether that element
+     * is the root of its tree or not.  If it's not the root, the
+     * remaining 30 bits are the parent, otherwise the remaining 30
+     * bits are the number of elements in the tree.  */
 }
 
 int *snew_dsf(int size)
 {
-    int i;
     int *ret;
     
     ret = snewn(size, int);
-    for (i = 0; i < size; i++) {
-        /* Bottom bit of each element of this array stores whether that element
-         * is opposite to its parent, which starts off as false */
-        ret[i] = i << 1; 
-    }
+    dsf_init(ret, size);
 
     /*print_dsf(ret, size); */
 
@@ -87,6 +95,10 @@ void dsf_merge(int *dsf, int v1, int v2)
     edsf_merge(dsf, v1, v2, FALSE);
 }
 
+int dsf_size(int *dsf, int index) {
+    return dsf[dsf_canonify(dsf, index)] >> 2;
+}
+
 int edsf_canonify(int *dsf, int index, int *inverse_return)
 {
     int start_index = index, canonical_index;
@@ -100,9 +112,9 @@ int edsf_canonify(int *dsf, int index, int *inverse_return)
     /* Find the index of the canonical element of the 'equivalence class' of
      * which start_index is a member, and figure out whether start_index is the
      * same as or inverse to that. */
-    while ((dsf[index] >> 1) != index) {
+    while ((dsf[index] & 2) == 0) {
         inverse ^= (dsf[index] & 1);
-       index = dsf[index] >> 1;
+       index = dsf[index] >> 2;
 /*        fprintf(stderr, "index = %2d, ", index); */
 /*        fprintf(stderr, "inverse = %d\n", inverse); */
     }
@@ -115,9 +127,9 @@ int edsf_canonify(int *dsf, int index, int *inverse_return)
      * canonical member. */
     index = start_index;
     while (index != canonical_index) {
-       int nextindex = dsf[index] >> 1;
+       int nextindex = dsf[index] >> 2;
         int nextinverse = inverse ^ (dsf[index] & 1);
-       dsf[index] = (canonical_index << 1) | inverse;
+       dsf[index] = (canonical_index << 2) | inverse;
         inverse = nextinverse;
        index = nextindex;
     }
@@ -132,21 +144,45 @@ int edsf_canonify(int *dsf, int index, int *inverse_return)
 void edsf_merge(int *dsf, int v1, int v2, int inverse)
 {
     int i1, i2;
-    
+
 /*    fprintf(stderr, "dsf = %p\n", dsf); */
 /*    fprintf(stderr, "Merge [%2d,%2d], %d\n", v1, v2, inverse); */
     
     v1 = edsf_canonify(dsf, v1, &i1);
+    assert(dsf[v1] & 2);
     inverse ^= i1;
     v2 = edsf_canonify(dsf, v2, &i2);
+    assert(dsf[v2] & 2);
     inverse ^= i2;
 
 /*    fprintf(stderr, "Doing [%2d,%2d], %d\n", v1, v2, inverse); */
 
     if (v1 == v2)
         assert(!inverse);
-    else
-        dsf[v2] = (v1 << 1) | !!inverse;
+    else {
+       assert(inverse == 0 || inverse == 1);
+       /*
+        * We always make the smaller of v1 and v2 the new canonical
+        * element. This ensures that the canonical element of any
+        * class in this structure is always the first element in
+        * it. 'Keen' depends critically on this property.
+        *
+        * (Jonas Koelker previously had this code choosing which
+        * way round to connect the trees by examining the sizes of
+        * the classes being merged, so that the root of the
+        * larger-sized class became the new root. This gives better
+        * asymptotic performance, but I've changed it to do it this
+        * way because I like having a deterministic canonical
+        * element.)
+        */
+       if (v1 > v2) {
+           int v3 = v1;
+           v1 = v2;
+           v2 = v3;
+       }
+       dsf[v1] += (dsf[v2] >> 2) << 2;
+       dsf[v2] = (v1 << 2) | !!inverse;
+    }
     
     v2 = edsf_canonify(dsf, v2, &i2);
     assert(v2 == v1);