rbyd-rr: Cleaned up diverged+pruning interactions
This mainly cleans up the lingering/prune goto noodle soup. Which
duplicates a bit of code but allows for some forward progress cleaning
things up.
Some things to note:
- We can preserve the coloring of diverging red nodes, at least as long
as the non-diverging red alt occurs before the diverging black alt.
.-----> .---b->
| .-b-> | '-> rm me
| | '-> rm me | .--->
r-b---> r-b--->
^ ^
diverging, can preserve diverging, can't preserve currently
Note this only affects the upper divering path. The lower diverging
path doesn't care about colors until the diverging alt is found.
This isn't perfect. Recoloring some diverging red alts _can_ result in
unbalancing the tree by +-1 every range operation. Though this is at
least a significant improvement over the previous +-2x every range
operation in the previous algorithm.
Still, it may be worth further work in the future to eliminate this
+-1 unbalancing caused by the diverging alt itself. Unfortunately the
interactions with red flips and yellow splits get quite tricky...
Note also that maintaining _perfect_ balance during range operations
is impossible as long as we need to propagate yellow recolorings
tail-recursively. Consider what should happen if both paths from the
diverging alt were yellow nodes...
- We can make diverged pruning implicit by simply trimming the alts from
the rid/tag bounds so they appear unreachable to the common pruning
logic.
Note this only works because diverging pruning is eager and only
prunes outward-facing alts.
This commit is contained in:
@@ -2911,7 +2911,6 @@ again:;
|
||||
// make jump absolute
|
||||
jump = branch - jump;
|
||||
lfs_size_t branch_ = branch + d;
|
||||
lingering:;
|
||||
|
||||
// do bounds want to take different paths? begin diverging
|
||||
if (!lfsr_d_isdiverged(d_state)
|
||||
@@ -2925,47 +2924,76 @@ again:;
|
||||
b_rid, b_tag)) {
|
||||
LFS_ASSERT(d_state != LFSR_D_NOTDIVERGING);
|
||||
|
||||
// take care of any lingering red alts before diverging
|
||||
if (lfsr_tag_isred(p_alts[0])) {
|
||||
goto prune;
|
||||
// note that if red alt diverged if would have been caught
|
||||
// on the previous pass
|
||||
d_state = lfsr_d_diverge(d_state);
|
||||
printf("%04x->%04x: diverging 0x%x w%d\n",
|
||||
branch,
|
||||
rbyd->eoff,
|
||||
alt,
|
||||
weight);
|
||||
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);
|
||||
|
||||
// begin diverging
|
||||
} else {
|
||||
d_state = lfsr_d_diverge(d_state);
|
||||
printf("%04x->%04x: diverging 0x%x w%d\n",
|
||||
// stitch together diverged branches
|
||||
if (d_state == LFSR_D_DIVERGEDUPPER) {
|
||||
printf("%04x->%04x: stitching: 0x%x w%d, 0x%x\n",
|
||||
branch,
|
||||
rbyd->eoff,
|
||||
alt,
|
||||
weight);
|
||||
|
||||
// stitch together diverged branches
|
||||
if (d_state == LFSR_D_DIVERGEDUPPER) {
|
||||
printf("%04x->%04x: stitching: 0x%x w%d, 0x%x\n",
|
||||
branch,
|
||||
rbyd->eoff,
|
||||
d_tag,
|
||||
d_rid - lower_rid,
|
||||
d_branch);
|
||||
err = lfsr_rbyd_p_push(lfs, rbyd,
|
||||
p_alts, p_weights, p_jumps,
|
||||
LFSR_TAG_ALT(LFSR_TAG_LE, LFSR_TAG_B, d_tag),
|
||||
d_rid - lower_rid,
|
||||
d_branch);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
//lfsr_rbyd_p_recolor(p_alts, p_weights, p_jumps);
|
||||
d_tag,
|
||||
d_rid - lower_rid,
|
||||
d_branch);
|
||||
err = lfsr_rbyd_p_push(lfs, rbyd,
|
||||
p_alts, p_weights, p_jumps,
|
||||
LFSR_TAG_ALT(LFSR_TAG_LE, LFSR_TAG_B, d_tag),
|
||||
d_rid - lower_rid + weight,
|
||||
d_branch);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
goto prune;
|
||||
//lfsr_rbyd_p_recolor(p_alts, p_weights, p_jumps);
|
||||
}
|
||||
|
||||
y_branch = branch;
|
||||
branch = branch_;
|
||||
continue;
|
||||
|
||||
// don't write diverging lower alts
|
||||
} else if (d_state == LFSR_D_DIVERGINGLOWER) {
|
||||
goto prune;
|
||||
}
|
||||
if (lfsr_tag_follow(
|
||||
alt, weight,
|
||||
lower_rid, upper_rid,
|
||||
a_rid, a_tag)) {
|
||||
lfsr_tag_flip(
|
||||
&alt, &weight,
|
||||
lower_rid, upper_rid);
|
||||
lfs_swap32(&jump, &branch_);
|
||||
}
|
||||
lfsr_tag_trim(
|
||||
alt, weight,
|
||||
&lower_rid, &upper_rid,
|
||||
&lower_tag, &upper_tag);
|
||||
|
||||
// TODO can we move y_branch updates to beginning of loop?
|
||||
y_branch = branch;
|
||||
branch = branch_;
|
||||
continue;
|
||||
}
|
||||
// if (lfsr_d_isdiverged(d_state)) {
|
||||
// alt &= ~LFSR_TAG_R;
|
||||
// }
|
||||
@@ -2976,7 +3004,8 @@ again:;
|
||||
// goto prune;
|
||||
// }
|
||||
|
||||
// prune because of diverged paths?
|
||||
// trim unreachable alts created by diverged paths so they
|
||||
// will be pruned
|
||||
if (lfsr_d_isdiverged(d_state)
|
||||
&& (d_state == LFSR_D_DIVERGEDUPPER)
|
||||
^ lfsr_tag_isgt(alt)
|
||||
@@ -2985,10 +3014,6 @@ again:;
|
||||
p_alts[0], p_weights[0],
|
||||
lower_rid, upper_rid,
|
||||
a_rid, a_tag)) {
|
||||
// note, yellow prunes always follow and have no weight, it's
|
||||
// only diverged pruning that needs all these special cases
|
||||
|
||||
// eagerly flip in case we are ambiguous yellow alts
|
||||
if (lfsr_tag_follow2(
|
||||
alt, weight,
|
||||
p_alts[0], p_weights[0],
|
||||
@@ -3004,28 +3029,6 @@ again:;
|
||||
alt, weight,
|
||||
&lower_rid, &upper_rid,
|
||||
&lower_tag, &upper_tag);
|
||||
|
||||
// red alts we can collapse
|
||||
if (lfsr_tag_isred(p_alts[0])) {
|
||||
printf("%04x->%04x: drprune 0x%x w%d\n",
|
||||
branch,
|
||||
rbyd->eoff,
|
||||
alt,
|
||||
weight);
|
||||
goto prune;
|
||||
|
||||
// black alts just become unreachable, if we pruned these
|
||||
// it would break the coloring of our tree
|
||||
} else {
|
||||
printf("%04x->%04x: dbprune 0x%x w%d\n",
|
||||
branch,
|
||||
rbyd->eoff,
|
||||
alt,
|
||||
weight);
|
||||
alt = LFSR_TAG_ALT(LFSR_TAG_LE, LFSR_TAG_B, 0);
|
||||
weight = 0;
|
||||
// jump = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// prune?
|
||||
@@ -3055,19 +3058,23 @@ again:;
|
||||
lfs_swap32(&jump, &branch_);
|
||||
}
|
||||
|
||||
// red alts we can collapse
|
||||
// collapse unreachable red alts
|
||||
if (lfsr_tag_isred(p_alts[0])) {
|
||||
printf("%04x->%04x: yrprune 0x%x w%d\n",
|
||||
printf("%04x->%04x: rprune 0x%x w%d\n",
|
||||
branch,
|
||||
rbyd->eoff,
|
||||
alt,
|
||||
weight);
|
||||
goto prune;
|
||||
alt = p_alts[0] & ~LFSR_TAG_R;
|
||||
weight = p_weights[0];
|
||||
jump = p_jumps[0];
|
||||
branch_ = branch;
|
||||
lfsr_rbyd_p_pop(p_alts, p_weights, p_jumps);
|
||||
|
||||
// black alts just become unreachable, if we pruned these
|
||||
// make unreachable black alts alt-nevers, if we prune these
|
||||
// it would break the coloring of our tree
|
||||
} else {
|
||||
printf("%04x->%04x: ybprune 0x%x w%d\n",
|
||||
printf("%04x->%04x: bprune 0x%x w%d\n",
|
||||
branch,
|
||||
rbyd->eoff,
|
||||
alt,
|
||||
@@ -3229,40 +3236,6 @@ again:;
|
||||
branch = branch_;
|
||||
continue;
|
||||
|
||||
prune:;
|
||||
// handle any lingering red alts
|
||||
if (lfsr_tag_isred(p_alts[0])) {
|
||||
alt = p_alts[0] & ~LFSR_TAG_R;
|
||||
weight = p_weights[0];
|
||||
jump = p_jumps[0];
|
||||
branch_ = branch;
|
||||
lfsr_rbyd_p_pop(p_alts, p_weights, p_jumps);
|
||||
goto lingering;
|
||||
|
||||
// prune black alts
|
||||
} else {
|
||||
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);
|
||||
|
||||
// TODO can we move y_branch updates to beginning of loop?
|
||||
y_branch = branch;
|
||||
branch = branch_;
|
||||
continue;
|
||||
}
|
||||
|
||||
// found end of tree?
|
||||
} else {
|
||||
// update the found tag
|
||||
|
||||
Reference in New Issue
Block a user