From f957dad821f1ead0ffee0e7004304687f0ff59ae Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Fri, 5 Apr 2024 17:03:41 -0500 Subject: [PATCH] rbyd-rr: Implemented very ugly, but working! diverging 2-3 nodes It's a mess, but all tests are passing. We're still recoloring the diverging alt, so hopefully I won't need to eat my words, but at least on paper this should be able to preserve colors for all 2-3 permutations of the diverging alt. The key observation here is that diverging 2-3 nodes have three possible permutations: 1. Diverging on the black alt: .-> .-> .-> .---b-> .---b-> .---b-> | .-> => r-b-b-> => | .-b-> | .-b-> rm me | | | | | .-> rm me | .-> | | r-b-b-> '-b-> r-b-b-> ^ ^ diverging diverging 2. Diverging on the red alt: .-> r-b-b-> .---> .---b-> rm me | | | | .-> rm me => | | .-> => | | .-b-> | '-b-> r-b-b-> | | .-> | .-> | .-> r-b-b-> '---b-> '---b-> ^ ^ diverging diverging 3. Diverging on both alts: .-> b---b-> .---b-> .---b-> rm me | | | .-> rm me => | => | | .-b-> rm me | | | | .-> rm me | .-> | r-b-b-> '---b-> b---b-> ^^^ ^ diverging diverging With 3., both diverging, being the tricky one, where we need to both switch to the diverged state while also collapsing the 3-node into a 2-node. 1. and 2. can both be deduplicated with a well-timed flip, but so far it seems like 3. needs its own special case. At least these can all be contained as extra conditions in the diverging alt logic, reducing the possible states. lfs_rbyd_appendattr is a complete mess now, and a lot of the diverging logic is duplicated everywhere, but at least things seem to be working. --- lfs.c | 500 +++++++++++++++++++++++++++------------------------------- 1 file changed, 235 insertions(+), 265 deletions(-) diff --git a/lfs.c b/lfs.c index 87c52c47..8d8dfc03 100644 --- a/lfs.c +++ b/lfs.c @@ -2962,16 +2962,227 @@ again:; // do bounds want to take different paths? begin diverging if (!diverged - && lfsr_tag_follow2( - alt, weight, + // try to wait for black alt to avoid red alt corner cases + && (lfsr_tag_isblack(alt) + // give up if we find a yellow alt + || lfsr_tag_isred(p_alts[0])) + // diverged red? + && ((lfsr_tag_isred(p_alts[0]) + && lfsr_tag_follow( + p_alts[0], p_weights[0], + lower_rid, upper_rid, + a_rid, a_tag) + ^ lfsr_tag_follow( + p_alts[0], p_weights[0], + lower_rid, upper_rid, + b_rid, b_tag)) + // diverged black? + || lfsr_tag_follow2( + alt, weight, + p_alts[0], p_weights[0], + lower_rid, upper_rid, + a_rid, a_tag) + ^ lfsr_tag_follow2( + alt, weight, + p_alts[0], p_weights[0], + lower_rid, upper_rid, + b_rid, b_tag))) { +// // both diverging? collapse +// if (lfsr_tag_follow( +// p_alts[0], p_weights[0], +// lower_rid, upper_rid, +// a_rid, a_tag) +// ^ lfsr_tag_follow( +// p_alts[0], p_weights[0], +// lower_rid, upper_rid, +// b_rid, b_tag) +// && lfsr_tag_follow2( +// alt, weight, +// p_alts[0], p_weights[0], +// lower_rid, upper_rid, +// a_rid, a_tag) +// ^ lfsr_tag_follow2( +// alt, weight, +// p_alts[0], p_weights[0], +// lower_rid, upper_rid, +// b_rid, b_tag)) { +// printf("%04x->%04x: dcollapse 0x%x w%d 0x%x w%d\n", +// branch, +// rbyd->eoff, +// alt, +// weight, +// p_alts[0], +// p_weights[0]); +// alt = p_alts[0] & ~LFSR_TAG_R; +// weight = p_weights[0]; +// jump = p_jumps[0]; +// lfsr_rbyd_p_pop(p_alts, p_weights, p_jumps); +// branch_ = branch; +// } + + // diverged red? flip + if (lfsr_tag_isred(p_alts[0]) + && (lfsr_tag_follow( + p_alts[0], p_weights[0], + lower_rid, upper_rid, + a_rid, a_tag) + ^ lfsr_tag_follow( + p_alts[0], p_weights[0], + lower_rid, upper_rid, + b_rid, b_tag))) { + printf("%04x->%04x: dflip 0x%x w%d 0x%x w%d\n", + branch, + rbyd->eoff, + alt, + weight, + p_alts[0], + p_weights[0]); + + if (lfsr_tag_isparallel(alt, p_alts[0])) { + lfsr_tag_flip2(&alt, &weight, + p_alts[0], p_weights[0], + lower_rid, upper_rid); + lfs_swap32(&jump, &branch_); + } + + lfs_swap16(&p_alts[0], &alt); + lfs_swap32(&p_weights[0], &weight); + lfs_swap32(&p_jumps[0], &jump); + p_alts[0] |= LFSR_TAG_R; + alt &= ~LFSR_TAG_R; + + lfsr_tag_flip2(&alt, &weight, p_alts[0], p_weights[0], - lower_rid, upper_rid, - a_rid, a_tag) - ^ lfsr_tag_follow2( - alt, weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid, - b_rid, b_tag)) { + lower_rid, upper_rid); + lfs_swap32(&jump, &branch_); + + // both diverging? collapse + if (lfsr_tag_follow( + p_alts[0], p_weights[0], + lower_rid, upper_rid, + a_rid, a_tag) + ^ lfsr_tag_follow( + p_alts[0], p_weights[0], + lower_rid, upper_rid, + b_rid, b_tag)) { + printf("%04x->%04x: dcollapse 0x%x w%d 0x%x w%d\n", + branch, + rbyd->eoff, + alt, + weight, + p_alts[0], + p_weights[0]); +// if (!lfsr_tag_isparallel(alt, p_alts[0])) { +// lfsr_tag_flip2(&alt, &weight, +// p_alts[0], p_weights[0], +// lower_rid, upper_rid); +// lfs_swap32(&jump, &branch_); +// } + +// if (lfsr_tag_follow( +// p_alts[0], p_weights[0], +// lower_rid, upper_rid, +// a_rid, a_tag)) { +// if (lfsr_tag_isparallel(alt, p_alts[0])) { +// lfsr_tag_flip2(&alt, &weight, +// p_alts[0], p_weights[0], +// lower_rid, upper_rid); +// lfs_swap32(&jump, &branch_); +// } +// +// lfs_swap16(&p_alts[0], &alt); +// lfs_swap32(&p_weights[0], &weight); +// lfs_swap32(&p_jumps[0], &jump); +// p_alts[0] |= LFSR_TAG_R; +// alt &= ~LFSR_TAG_R; +// +// lfsr_tag_flip2(&alt, &weight, +// p_alts[0], p_weights[0], +// lower_rid, upper_rid); +// lfs_swap32(&jump, &branch_); +// } + + LFS_ASSERT(lfsr_tag_isparallel(alt, p_alts[0])); + + alt = alt & ~LFSR_TAG_R; //p_alts[0] & ~LFSR_TAG_R; + weight += p_weights[0]; + jump = p_jumps[0]; + lfsr_rbyd_p_pop(p_alts, p_weights, p_jumps); + + printf("%04x->%04x: -> 0x%x w%d 0x%x w%d (%x %x)\n", + branch, + rbyd->eoff, + alt, + weight, + p_alts[0], + p_weights[0], + jump, + branch_); + } + } +// +// +// // flip red +// if (lfsr_tag_isred(p_alts[0]) +// && lfsr_tag_follow2( +// p_alts[0], p_weights[0], +// lower_rid, upper_rid, +// a_rid, a_tag +// ^ lfsr_tag_follow( +// p_alts[0], p_weights[0], +// lower_rid, upper_rid, +// b_rid, b_tag))) { +// +// +// +// // diverging red? flip +// if (lfsr_tag_isred(p_alts[0]) +// && (lfsr_tag_follow( +// p_alts[0], p_weights[0], +// lower_rid, upper_rid, +// a_rid, a_tag) +// ^ lfsr_tag_follow( +// p_alts[0], p_weights[0], +// lower_rid, upper_rid, +// b_rid, b_tag))) { +// printf("%04x->%04x: dflip 0x%x w%d 0x%x w%d\n", +// branch, +// rbyd->eoff, +// alt, +// weight, +// p_alts[0], +// p_weights[0]); +// if (lfsr_tag_isparallel(alt, p_alts[0])) { +// lfsr_tag_flip2(&alt, &weight, +// p_alts[0], p_weights[0], +// lower_rid, upper_rid); +// lfs_swap32(&jump, &branch_); +// } +// +// lfs_swap16(&p_alts[0], &alt); +// lfs_swap32(&p_weights[0], &weight); +// lfs_swap32(&p_jumps[0], &jump); +// p_alts[0] |= LFSR_TAG_R; +// alt &= ~LFSR_TAG_R; +// +// lfsr_tag_flip2(&alt, &weight, +// p_alts[0], p_weights[0], +// lower_rid, upper_rid); +// lfs_swap32(&jump, &branch_); +// +// } +// +// // diverging black? +// if (lfsr_tag_follow2( +// alt, weight, +// p_alts[0], p_weights[0], +// lower_rid, upper_rid, +// a_rid, a_tag) +// ^ lfsr_tag_follow2( +// alt, weight, +// p_alts[0], p_weights[0], +// lower_rid, upper_rid, +// b_rid, b_tag)) { printf("%04x->%04x: diverge 0x%x w%d 0x%x w%d\n", branch, rbyd->eoff, @@ -3024,6 +3235,8 @@ again:; weight_ -= p_weights[0]; } lower_rid += weight - weight_; +// a_rid += weight - weight_; +// b_rid += weight - weight_; weight = weight_; // lower_rid += weight; // weight = d_rid - lower_rid + weight; @@ -3081,60 +3294,18 @@ again:; diverged = true; } + goto dont_trim_me; + } + // trim unreachable diverged alts so they end up pruned - } else if (diverged - // TODO simpler way to express this? - && !(lfsr_tag_isred(p_alts[0]) -// && (lfsr_tag_follow( -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// a_rid, a_tag) -// ^ lfsr_tag_follow( -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// b_rid, b_tag))) -// && !(lfsr_tag_follow2( -// alt, weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// a_rid, a_tag) -// ^ lfsr_tag_follow2( -// alt, weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// b_rid, b_tag)) - && lfsr_tag_follow( - p_alts[0], p_weights[0], - lower_rid, upper_rid, - a_rid, a_tag)) -// && !(lfsr_tag_follow2( -// alt, weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// a_rid, a_tag) -// ^ lfsr_tag_follow2( -// alt, weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// b_rid, b_tag))) -// && lfsr_tag_follow2( -// alt, weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// b_rid, b_tag)) - && (d_upper - ^ lfsr_tag_isgt(alt) - ^ lfsr_tag_follow2( - alt, weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid, - a_rid, a_tag))) { -// && !(d_upper -// ^ lfsr_tag_isgt(alt) -// ^ lfsr_tag_follow( -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// a_rid, a_tag))) { + if (diverged + && (d_upper + ^ lfsr_tag_isgt(alt) + ^ lfsr_tag_follow2( + alt, weight, + p_alts[0], p_weights[0], + lower_rid, upper_rid, + a_rid, a_tag))) { if (lfsr_tag_follow2( alt, weight, p_alts[0], p_weights[0], @@ -3156,211 +3327,9 @@ again:; &lower_rid, &upper_rid, &lower_tag, &upper_tag); weight = 0; - - // TODO doc, cleanup? - // trim inner branches of the divering node itself - } else if (diverged - && !d_upper - && lfsr_tag_isred(p_alts[0]) - && lfsr_tag_follow( - p_alts[0], p_weights[0], - lower_rid, upper_rid, - a_rid, a_tag) -// && (!d_upper -// ^ lfsr_tag_isgt(alt) -// ^ lfsr_tag_follow2( -// alt, weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// b_rid, b_tag))) { - && (lfsr_tag_follow2( - alt, weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid, - a_rid, a_tag) - ^ lfsr_tag_follow2( - alt, weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid, - b_rid, b_tag))) { - if (lfsr_tag_follow2( - alt, weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid, - b_rid, b_tag)) { - lfsr_tag_flip2( - &alt, &weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid); - lfs_swap32(&jump, &branch_); - } - printf("%04x->%04x: d0trim 0x%x w%d -> w0\n", - branch, - rbyd->eoff, - alt, - weight); -// lfsr_tag_trim( -// alt, weight, -// &lower_rid, &upper_rid, -// &lower_tag, &upper_tag); -// weight = 0; - alt = (p_alts[0] & ~LFSR_TAG_R) | (alt & LFSR_TAG_R); - weight = p_weights[0]; - jump = p_jumps[0]; - lfsr_rbyd_p_pop(p_alts, p_weights, p_jumps); } -// if (!lfsr_d_isdiverged(d_state) -// && lfsr_tag_follow2(alt, weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// a_rid, a_tag) -// ^ lfsr_tag_follow2(alt, weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// b_rid, b_tag)) { -// printf("%04x->%04x: %cdiverge 0x%x w%d 0x%x w%d\n", -// branch, -// rbyd->eoff, -// lfsr_tag_isred(alt) ? 'r' : 'b', -// alt, -// weight, -// p_alts[0], -// p_weights[0]); -// LFS_ASSERT(d_state != LFSR_D_NOTDIVERGING); -// -// // transition to the diverged state -// // -// // note that if red alt diverged if would have been -// // caught on the previous pass -// d_state = lfsr_d_diverge(d_state); -// -// // TODO trim or something? -// if (d_state != LFSR_D_DIVERGEDUPPER) { -// if (lfsr_tag_follow2( -// alt, weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// a_rid, a_tag)) { -// lfsr_tag_flip2( -// &alt, &weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid); -// lfs_swap32(&jump, &branch_); -// } -// -// lfsr_tag_trim2( -// alt, weight, -// p_alts[0], p_weights[0], -// &lower_rid, &upper_rid, -// &lower_tag, &upper_tag); -// } -// -// // stitch together diverged branches -// if (d_state == LFSR_D_DIVERGEDUPPER) { -// if (lfsr_tag_isle(alt)) { -// alt = LFSR_TAG_ALT( -// LFSR_TAG_LE, -// (!lfsr_tag_isred(p_alts[0])) -// ? (LFSR_TAG_R & alt) -// : LFSR_TAG_B, -// d_tag); -// printf("%04x->%04x: dle 0x%x %d w%d (%d %d)\n", -// branch, -// rbyd->eoff, -// d_tag, -// d_rid, -// weight, -// lower_rid, -// upper_rid); -// lower_rid += weight; -// weight = d_rid - lower_rid + weight; -// if (lfsr_tag_isred(p_alts[0]) -// && lfsr_tag_isle(p_alts[0])) { -// weight -= p_weights[0]; -// } -// lower_rid -= weight; -// jump = d_branch; -// } else { -// lfsr_tag_flip2( -// &alt, &weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid); -// alt = LFSR_TAG_ALT( -// LFSR_TAG_LE, -// (false) // (!lfsr_tag_isred(p_alts[0])) -// ? (LFSR_TAG_R & alt) -// : LFSR_TAG_B, -// d_tag); -// printf("%04x->%04x: dgt 0x%x %d w%d (%d %d)\n", -// branch, -// rbyd->eoff, -// d_tag, -// d_rid, -// weight, -// lower_rid, -// upper_rid); -// lower_rid += weight; -// weight = d_rid - lower_rid + weight; -// if (lfsr_tag_isred(p_alts[0]) -// && lfsr_tag_isle(p_alts[0])) { -// weight -= p_weights[0]; -// } -// lower_rid -= weight; -// lfsr_tag_flip2( -// &alt, &weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid); -// branch_ = d_branch; -// } -// -// printf("%04x->%04x: dtag 0x%x w%d (%d %d)\n", -// branch, -// rbyd->eoff, -// alt, -// weight, -// lower_rid, -// upper_rid); -// -// // TODO doc -// y_branch = d_branch; -// goto dont_trim_me; -// } -// -// branch = branch_; -// continue; -// } - -// // trim unreachable diverged alts so they end up pruned -// if ((lfsr_d_isdiverged(d_state) -// && (d_state == LFSR_D_DIVERGEDUPPER) -// ^ lfsr_tag_isgt(alt) -// ^ lfsr_tag_follow2( -// alt, weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// a_rid, a_tag)) -// // this includes all diverging-lower alts -// || d_state == LFSR_D_DIVERGINGLOWER) { -// if (lfsr_tag_follow2( -// alt, weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid, -// a_rid, a_tag)) { -// lfsr_tag_flip2( -// &alt, &weight, -// p_alts[0], p_weights[0], -// lower_rid, upper_rid); -// lfs_swap32(&jump, &branch_); -// } -// lfsr_tag_trim( -// alt, weight, -// &lower_rid, &upper_rid, -// &lower_tag, &upper_tag); -// weight = 0; -// } - -// dont_trim_me:; + dont_trim_me:; // prune? // b // .-'| .-'| @@ -3527,6 +3496,7 @@ again:; lfs_swap32(&jump, &branch_); } + // TODO flatten this if statement if (lfsr_tag_isred(p_alts[0])) { // should've taken red alt? needs a flip // r