-
-
Notifications
You must be signed in to change notification settings - Fork 10.9k
ENH: np.unique: support hash based unique for string dtype #28767
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
base: main
Are you sure you want to change the base?
Conversation
d9333fa
to
a6dc86a
Compare
@seberg @ngoldbaum |
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 think the implementation of fnv-1a in this PR isn't correct. Maybe we should just be using the (public-domain licensed) reference implementation: https://github.com/lcn2/fnv.
I didn't look closely at the rest after I noticed this issue.
template<typename T> | ||
// function to caluculate the hash of a string | ||
template <typename T> | ||
size_t str_hash(const T *str, npy_intp num_chars) { |
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.
Note that npy_ucs4
is four bytes and fnv-1a operates on octets of data (e.g. individual bytes).
The reference implementation takes a void *
pointer and immediately casts it to unsigned char *
. You could do similar.
We could also add the reference implementation as a vendored dependency (e.g. a git submodule). The license is compatible.
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.
Thanks for the suggestion.
If we go the submodule route for lcn2/fnv, where in the NumPy tree would you like the submodule to live? Let me know your preferred path and I’ll add it accordingly.
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.
Vendoring would work for me as well (e.g. copying a single header the way stlab does in adobe/fnv.hpp).
If we go with a vendored file instead of a submodule, which path in the NumPy tree would you prefer for it to live?
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 would probably vendor it as a git submodule in numpy/_core/src/common
, next to pythoncapi-compat
. Maybe take a look at the PR adding pythoncapi-compat
as a vendered dependency to see how that header-only vendored dependency is integrated into the numpy build system.
I only have a slight preference for a git submodule, since it makes updating the vendored code marginally easier. If you feel like it's easier to structure it as just a copy/pasted new header file (that includes a note about the original copyright and license), I'd probably just put that header in numpy/_core/src/multiarray
.
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.
Tried the submodule approach, but ran into two blockers:
- the reference source expects to be built with a plain
make
step that is not available on every platform/toolchain we target. - the code still uses legacy BSD typedefs such as
u_int32_t
; that builds fine on Linux/macOS but fails to compile on WASM, Windows/Clang, etc.
Because of these two issues the submodule route looks impractical for NumPy at the moment.
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.
Fair enough, thanks for checking. Vendoring a somewhat adapted version makes sense.
Description
This PR introduces hash-based uniqueness extraction support for NPY_STRING, NPY_UNICODE, and NPY_VSTRING types in NumPy's np.unique function.
The existing hash-based unique implementation, previously limited to integer data types, has been generalized to accommodate additional data types including string-related ones. Minor refactoring was also performed to improve maintainability and readability.
Benchmark Results
The following benchmark demonstrates significant performance improvement from the new implementation.
The test scenario (1 billion strings array) follows the experimental setup described #26018 (comment)
Result
close #28364