Repository navigation
Make numpy.searchsorted match NumPy when first argument is unsorted
#7005
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3740,17 +3740,43 @@ def bincount_impl(a, weights=None, minlength=0): | |
|
|
||
|
|
||
| def _searchsorted(func): | ||
| def searchsorted_inner(a, v): | ||
| n = len(a) | ||
| def searchsorted_inner(a, v, v_last, lo, hi, n): | ||
| """Perform inner loop of searchsorted (i.e. a binary search). | ||
|
|
||
| This is loosely based on the NumPy implementation in [1]_. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| a: 1-D array_like | ||
| The input array. | ||
| v: array_like | ||
| The current value to insert into `a`. | ||
| v_last: array_like | ||
| The previous value inserted into `a`. | ||
| lo: int | ||
| The initial/previous "low" value of the binary search. | ||
| hi: int | ||
| The initial/previous "high" value of the binary search. | ||
| n: int | ||
| The length of `a`. | ||
|
|
||
|
|
||
| .. [1] https://github.com/numpy/numpy/blob/809e8d26b03f549fd0b812a17b8a166bcd966889/numpy/core/src/npysort/binsearch.cpp#L173 | ||
| """ # noqa: E501 | ||
| if np.isnan(v): | ||
| # Find the first nan (i.e. the last from the end of a, | ||
| # since there shouldn't be many of them in practice) | ||
| for i in range(n, 0, -1): | ||
| if not np.isnan(a[i - 1]): | ||
| return i | ||
| return 0 | ||
| lo = 0 | ||
| hi = n | ||
|
|
||
| if v_last < v: | ||
| hi = n | ||
| else: | ||
| lo = 0 | ||
| hi = hi + 1 if hi < n else n | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The tests don't appear to exercise the true branch?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All the tests, or just the unordered one?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I threw in some
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I manually checked the coverage of the branches and both are covered by the unordered tests.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I found the branches a bit confusing. From what I understand the values of And perhaps add a comment to describe why this is needed?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just saw the numpy implementation, it seems like this code matches that implementation, so probably best to leave as is. |
||
|
|
||
| while hi > lo: | ||
| mid = (lo + hi) >> 1 | ||
| if func(a[mid], (v)): | ||
|
|
@@ -3782,24 +3808,36 @@ def searchsorted(a, v, side='left'): | |
| if isinstance(v, types.Array): | ||
| # N-d array and output | ||
| def searchsorted_impl(a, v, side='left'): | ||
| n = len(a) | ||
| lo = 0 | ||
| hi = n | ||
| out = np.empty(v.shape, np.intp) | ||
| v_last = v.flat[0] | ||
| for view, outview in np.nditer((v, out)): | ||
| index = loop_impl(a, view.item()) | ||
| outview.itemset(index) | ||
| lo = loop_impl(a, view.item(), v_last, lo, hi, n) | ||
| v_last = view.item() | ||
| outview.itemset(lo) | ||
| return out | ||
|
|
||
| elif isinstance(v, types.Sequence): | ||
| # 1-d sequence and output | ||
| def searchsorted_impl(a, v, side='left'): | ||
| n = len(a) | ||
| lo = 0 | ||
| hi = n | ||
| out = np.empty(len(v), np.intp) | ||
| v_last = v[0] | ||
| for i in range(len(v)): | ||
| out[i] = loop_impl(a, v[i]) | ||
| lo = loop_impl(a, v[i], v_last, lo, hi, n) | ||
| out[i] = lo | ||
| v_last = v[i] | ||
| return out | ||
| else: | ||
| # Scalar value and output | ||
| # Note: NaNs come last in Numpy-sorted arrays | ||
| def searchsorted_impl(a, v, side='left'): | ||
| return loop_impl(a, v) | ||
| n = len(a) | ||
| return loop_impl(a, v, v, 0, n, n) | ||
|
|
||
| return searchsorted_impl | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.