rbyd: Potential y-prune disambiguity with more jump >= branch trickery?

Idea!

The problem isn't so much that y-pruning recolors and diverged-pruning
doesn't recolor, but that we are unconditionally recoloring based on
the assumed yellow node direction.

Consider all possible yellow prune permutations:

          <y                      <r
  .-------'|              .-------'|
  |       <r  prune y     |        |
  |  .----'|    =>        |     .--'
  |  |    <b              |    <b
  |  |  .-'|              |  .-'|
  1  2  3  4           1  2  3  4  x

                                  <r
                       .----------'|
              prune r  |           |
                =>     |        .--'
                       |       <b
                       |     .-'|
                       1  2  3  4  x

                                  <b
                       .----------'|
              prune b  |           |
                =>     |  .--------'
                       |  |
                       |  |
                       1  2  3  4  x

Note these all maintain the color balance of our tree, but we only need
to recolor the yellow alt when it's the black alt we're pruning.

But how do we know if it's the black alt we're pruning? Well, we can use
the same trick we used in unflipping y-splits. The black alt is the only
alt where jump >= the current branch.

This is true because we always split yellow nodes as soon as we see
them.

---

This idea is promising, but needs a bit of work.

So, uh, please ignore the additional test failures:

  test_rbyd+balance before: 312/385878 failed
  test_rbyd+balance after:  300/385878 failed (-3.8%)

Curiously, these are now actual test failures and not just balance
failures. I can't decide if that's a good sign or not.

Code changes:

           code          stack          ctx
  before: 38860           2624          640
  after:  38880 (+0.1%)   2624 (+0.0%)  640 (+0.0%)
This commit is contained in:
Christopher Haster
2025-01-25 14:25:36 -06:00
parent 69adb1f033
commit c89c846329
+16 -8
View File
@@ -3504,6 +3504,11 @@ static int lfsr_rbyd_appendrat(lfs_t *lfs, lfsr_rbyd_t *rbyd,
a_tag = lfs_max(a_tag, 0x1);
b_tag = lfs_max(b_tag, 0x1);
LFS_DEBUG("%04x: rbyd append %d %04x %d %04x",
lfsr_rbyd_eoff(rbyd),
a_rid, a_tag,
b_rid, b_tag);
// keep track of diverged state
//
// this is only used if we operate on a range of tags, in which case
@@ -3635,7 +3640,8 @@ trunk:;
if (lfsr_tag_unreachable(
p[0].alt, p[0].weight,
lower_rid, upper_rid,
lower_tag, upper_tag)) {
lower_tag, upper_tag)
&& p[0].jump >= branch_) {
LFS_DEBUG("%04x->%04x: yprune",
branch, lfsr_rbyd_eoff(rbyd));
alt &= ~LFSR_TAG_R;
@@ -3652,10 +3658,11 @@ trunk:;
// | | .----'| | .----'| |
// 1 2 3 4 4 1 2 3 4 4 2
} else if (lfsr_tag_unreachable2(
alt, weight,
p[0].alt, p[0].weight,
lower_rid, upper_rid,
lower_tag, upper_tag)) {
alt, weight,
p[0].alt, p[0].weight,
lower_rid, upper_rid,
lower_tag, upper_tag)
&& jump >= branch_) {
LFS_DEBUG("%04x->%04x: rprune",
branch, lfsr_rbyd_eoff(rbyd));
alt = p[0].alt & ~LFSR_TAG_R;
@@ -3878,8 +3885,9 @@ trunk:;
lower_rid, upper_rid,
a_rid, a_tag,
b_rid, b_tag);
// TODO I think this logic is wrong, what's correct here?
if (diverging_red) {
LFS_DEBUG("%04x->%04x: div r pruning",
LFS_DEBUG("%04x->%04x: div r trimming",
branch, lfsr_rbyd_eoff(rbyd));
// trim so alt is pruned
lfsr_tag_trim(
@@ -3902,7 +3910,7 @@ trunk:;
if (diverging
&& (!lfsr_tag_isred(alt)
|| lfsr_tag_isred(p[0].alt))) {
LFS_DEBUG("%04x->%04x: div trimming",
LFS_DEBUG("%04x->%04x: div b trimming",
branch, lfsr_rbyd_eoff(rbyd));
// trim so alt is pruned
lfsr_tag_trim(
@@ -4000,7 +4008,7 @@ trunk:;
// | | <b | <b |
// | | .-'| | .-'| |
// 1 2 3 4 1 2 3 4 1
if (branch_ <= branch) {
if (branch_ < branch) {
LFS_DEBUG("%04x->%04x: ysplit b",
branch, lfsr_rbyd_eoff(rbyd));
// TODO hwat, >= solves this??