-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add seek_backward function with tests #2819
Conversation
Codecov Report
@@ Coverage Diff @@
## main #2819 +/- ##
=======================================
Coverage 89.79% 89.79%
=======================================
Files 30 30
Lines 29474 29474
Branches 5737 5737
=======================================
Hits 26465 26465
Misses 1726 1726
Partials 1283 1283
Flags with carried forward coverage won't be shown. Click here to find out more. Continue to review full report in Codecov by Sentry.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good @duncanMR!
This is very subtle, but I think you've hit on a good point. The out_range should really just be empty when the seeking from NULL. Do you think you could update the forward and reverse iters to account for this (and add tests to verify)?
# print("Current interval:", old_left, old_right) | ||
# print("New interval:", left, right) | ||
# print("index:", index, "out_range:", self.tree_pos.out_range) | ||
if old_index == -1: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, this doesn't smell right to me. I think we need to look at the initial conditions to think about why we don't need to exclude for the null tree. I guess we should really take care of this by setting the out_range to be empty, in the TreePosition.seek_forward and TreePosition.seek_backward functions, rather than having to reason about it here. As you point out, we should have no edges to remove, so there's no point in iterating over the out_range at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense to me, I'll give that a try now. It worked in the seek_forward
case because it was checking if e_left < old_right = 0
but I soon realised that it didn't work out so neatly when translated to seek_backward
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After some experiments, an approach I've found that works is as follows, from the TreePosition.seek_forward
function as an example:
j = right_current_index
self.out_range.start = j
while j < M and right_coords[right_order[j]] <= left:
j += 1
self.out_range.stop = j
if self.index == -1:
#No edges, so out_range should be empty
self.out_range.start = self.out_range.stop
The out_range.stop
value still needs to be updated for later iterations to work, but setting start = stop prevents StatefulTree.seek_forward
from iterating over the out_range
. It works similarly in the seek_backward
case. Is that what you had in mind?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just pushed a commit with these changes. The tests are rather trivial; I couldn't think of another way to check the out_range
is empty without adding code to track if StatefulTree.seek_x
is looping over the out_range
or not.
Looks good, let's review when we meet tomorrow |
I'm revising some of the tests for clarity. Just posting my reasoning here since it will be hard to read from the commits. We currently have two tests of this form: def test_forward_to_prev(self, index):
tree1 = StatefulTree(self.ts())
tree1.iter_forward(index)
tree1.prev()
tree2 = StatefulTree(self.ts())
tree2.iter_forward(index - 1)
tree1.assert_equal(tree2)
tree2 = StatefulTree(self.ts())
tree2.iter_backward(index - 1)
tree1.assert_equal(tree2)
def test_seek_forward_next_prev(self, index):
tree1 = StatefulTree(self.ts())
tree1.iter_forward(index)
tree1.prev()
tree2 = StatefulTree(self.ts())
tree2.seek_forward(index - 1)
tree1.assert_equal(tree2)
tree2 = StatefulTree(self.ts())
tree2.iter_backward(index - 1)
tree1.assert_equal(tree2)
So this is what we are left with: def test_seek_forward_then_prev(self, index):
tree1 = StatefulTree(self.ts())
tree1.seek_forward(index)
tree1.prev()
tree2 = StatefulTree(self.ts())
tree2.seek_forward(index - 1)
tree1.assert_equal(tree2)
def test_iter_backward_matches_iter_forward(self, index):
ts = self.ts()
tree1 = StatefulTree(ts)
tree1.iter_forward(index)
tree2 = StatefulTree(ts)
tree2.iter_backward(index)
tree1.assert_equal(tree2) As discussed with @jeromekelleher, I'm also going to make generic functions for the tests that are repeated across multiple classes, to reduce unnecessary repetition. I'm still going to make separate functions for |
Sounds great, thanks @duncanMR! |
I just committed the test changes and print statement cleanups. Is it okay if I squash the commits for merging? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, LGTM. Let's squash and merge
a5dbfea
to
1d533ad
Compare
I rebased and squashed, so it should be ready now. |
Can you create an issue to track adding the new |
Description
Addresses the first part of #2794, to create a
seek_backward
function which can reverse down a tree sequence (or jump to any tree from the null state). Given the symmetry betweenseek_forward
andseek_backward
, I just translated all the tests from the former to the latter. All of them pass now. In both theTreePosition
andStatefulTree
versions ofseek_backward
, I resorted to explicitly handling the null case with if statements because I couldn't see a more elegant way that works in all cases; I may have missed a neater solution there.I included some commented-out print statements to match the ones currently in
seek_forward
; I can easily remove them if need be.PR Checklist: