bool join (patch& p1, patch p2, tree t) { //cout << "Join " << p1 << LF << "with " << p2 << LF; if (get_type (p1) == PATCH_AUTHOR && get_type (p2) == PATCH_AUTHOR && get_author (p1) == get_author (p2)) { double author= get_author (p1); patch q1= p1[0]; patch q2= p2[0]; bool r= join (q1, q2, t); if (r) p1= patch (author, q1); return r; } if (get_type (p1) == PATCH_MODIFICATION && get_type (p2) == PATCH_MODIFICATION) { modification m1= get_modification (p1); modification m2= get_modification (p2); modification i2= get_inverse (p2); modification i1= get_inverse (p1); bool r= join (m1, m2, t); bool v= join (i2, i1, clean_apply (p2, clean_apply (p1, t))); if (r && v) p1= patch (m1, i2); return r && v; } if (get_type (p1) == PATCH_COMPOUND && nr_children (p1) > 0 && nr_children (remove_set_cursor (p1)) == 1 && nr_children (p1[0]) == 1) { patch q= p1[0]; bool rf= join (q, p2, t); if (rf) p1= q; return rf; } if (get_type (p2) == PATCH_COMPOUND && nr_children (p2) > 0 && nr_children (remove_set_cursor (p2)) == 1 && nr_children (p2[0]) == 1) { patch q= p2[0]; bool rf= join (p1, q, t); if (rf) { array<patch> a= children (p1); array<patch> b= children (p2); p1= patch (append (a, range (b, 1, N(b)))); } return rf; } return false; }
patch invert (patch p, tree t) { switch (get_type (p)) { case PATCH_MODIFICATION: return patch (get_inverse (p), get_modification (p)); case PATCH_BRANCH: ASSERT (N(p) <= 1, "ambiguous application"); case PATCH_COMPOUND: { int i, n=N(p); array<patch> r(n); for (i=0; i<n; i++) { r[n-1-i]= invert (p[i], t); t= clean_apply (p[i], t); } return patch (get_type (p) == PATCH_BRANCH, r); } case PATCH_BIRTH: return patch (get_author (p), !get_birth (p)); case PATCH_AUTHOR: return patch (get_author (p), invert (p[0], t)); default: FAILED ("unsupported patch type"); return patch (); } }
tree clean_apply (patch p, tree t) { switch (get_type (p)) { case PATCH_MODIFICATION: return clean_apply (t, get_modification (p)); case PATCH_BRANCH: ASSERT (N(p) <= 1, "ambiguous application"); case PATCH_COMPOUND: case PATCH_AUTHOR: for (int i=0; i<N(p); i++) t= clean_apply (p[i], t); return t; case PATCH_BIRTH: return t; default: FAILED ("unsupported patch type"); return t; } }
void test_invert () { tree t1= test_tree (); for (int i=0; i<42; i++) { modification m1= test_modification (i); tree t2= clean_apply (t1, m1); modification m2= invert (m1, t1); tree t3= clean_apply (t2, m2); modification m3= invert (m2, t2); if (m1 != m3 || t1 != t3) { cout << "t1= " << t1 << "\n"; cout << "m1= " << m1 << "\n"; cout << "t2= " << t2 << "\n"; cout << "m2= " << m2 << "\n"; cout << "t3= " << t3 << "\n"; FAILED ("inconsistency"); } } }
void test_commute () { tree tt= test_tree (); for (int i=0; i<42; i++) for (int j=0; j<42; j++) { modification m1= test_modification (i); modification m2= test_modification (j); modification t1= m1; modification t2= m2; debug_std << "m1 = " << m1 << "\n"; debug_std << "m2 = " << m2 << "\n"; bool r= swap (m1, m2); modification u1= m1; modification u2= m2; if (!r) debug_std << " Modifications do not commute\n\n"; else { debug_std << "m1' = " << m1 << "\n"; debug_std << "m2' = " << m2 << "\n"; if (clean_apply (clean_apply (tt, t1), t2) != clean_apply (clean_apply (tt, m1), m2)) { failed_error << "t1 = " << clean_apply (clean_apply (tt, t1), t2) << "\n"; failed_error << "t2 = " << clean_apply (clean_apply (tt, m1), m2) << "\n"; FAILED ("inconsistency"); } r= swap (m1, m2); if (!r) debug_std << "r = " << r << "\n"; else if (m1 != t1 || m2 != t2) { debug_std << "m1''= " << m1 << "\n"; debug_std << "m2''= " << m2 << "\n"; r= swap (m1, m2); if (!r) debug_std << "r = " << r << "\n"; else if (m1 != u1 || m2 != u2) { debug_std << "m1* = " << m1 << "\n"; debug_std << "m2* = " << m2 << "\n"; r= false; } } if (r) debug_std << " Consistency check succeeded\n\n"; else { failed_error << " Consistency check failed\n\n"; FAILED ("inconsistency"); } } } }
bool is_applicable (patch p, tree t) { switch (get_type (p)) { case PATCH_MODIFICATION: return is_applicable (t, get_modification (p)); case PATCH_COMPOUND: for (int i=0; i<N(p); i++) { if (!is_applicable (p[i], t)) return false; t= clean_apply (p[i], t); } return true; case PATCH_BRANCH: case PATCH_AUTHOR: for (int i=0; i<N(p); i++) if (!is_applicable (p[i], t)) return false; return true; case PATCH_BIRTH: return true; default: FAILED ("unsupported patch type"); return false; } }