Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/jvdd/argminmax
Efficient argmin & argmax
https://github.com/jvdd/argminmax
argmax argmin avx2 avx512 ndarray neon numpy rust rust-lang simd sse
Last synced: 22 days ago
JSON representation
Efficient argmin & argmax
- Host: GitHub
- URL: https://github.com/jvdd/argminmax
- Owner: jvdd
- License: mit
- Created: 2022-10-01T12:45:43.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2024-10-28T10:19:44.000Z (23 days ago)
- Last Synced: 2024-10-28T13:42:25.927Z (23 days ago)
- Topics: argmax, argmin, avx2, avx512, ndarray, neon, numpy, rust, rust-lang, simd, sse
- Language: Rust
- Homepage: https://docs.rs/argminmax/
- Size: 543 KB
- Stars: 56
- Watchers: 2
- Forks: 5
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# ArgMinMax
> Efficient argmin & argmax (in 1 function) with SIMD (SSE, AVX(2), AVX5121, NEON1) ⚡
🚀 The functions are generic over the type of the array, so it can be used on `&[T]` or `Vec` where `T` can be `f16`2, `f32`2, `f64`3, `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`.
🤝 The trait is implemented for [`slice`](https://doc.rust-lang.org/std/primitive.slice.html), [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html), 1D [`ndarray::ArrayBase`](https://docs.rs/ndarray/latest/ndarray/struct.ArrayBase.html)4, apache [`arrow::PrimitiveArray`](https://docs.rs/arrow/latest/arrow/array/struct.PrimitiveArray.html)5 and [`arrow2::PrimitiveArray`](https://docs.rs/arrow2/latest/arrow2/array/struct.PrimitiveArray.html)6.
⚡ **Runtime CPU feature detection** is used to select the most efficient implementation for the current CPU. This means that the same binary can be used on different CPUs without recompilation.
👀 The SIMD implementation contains **no if checks**, ensuring that the runtime of the function is independent of the input data its order (best-case = worst-case = average-case).
🪄 **Efficient support for f16 and uints**: through (bijective aka symmetric) bitwise operations, f16 (optional1) and uints are converted to ordered integers, allowing to use integer SIMD instructions.
> 1 for
AVX512
and most ofNEON
you should enable the (default) `"nightly_simd"` feature (requires nightly Rust).
> 2 forf16
you should enable the `"half"` feature.
> 3 forf32
andf64
you should enable the (default) `"float"` feature.
> 4 forndarray::ArrayBase
you should enable the `"ndarray"` feature.
> 5 forarrow::PrimitiveArray
you should enable the `"arrow"` feature.
> 6 forarrow2::PrimitiveArray
you should enable the `"arrow2"` feature.## Installing
Add the following to your `Cargo.toml`:
```toml
[dependencies]
argminmax = "0.6.1"
```## Example usage
```rust
use argminmax::ArgMinMax; // import traitlet arr: Vec = (0..200_000).collect(); // create a vector
let (min, max) = arr.argminmax(); // apply extension
println!("min: {}, max: {}", min, max);
println!("arr[min]: {}, arr[max]: {}", arr[min], arr[max]);
```## Traits
### `ArgMinMax`
Implemented for `ints`, `uints`, and `floats` (if `"float"` feature enabled).
Provides the following functions:
- `argminmax`: returns the index of the minimum and maximum element in the array.When dealing with NaNs, `ArgMinMax` its functions ignore NaNs. For more info see [Limitations](#limitations).
### `NaNArgMinMax`
Implemented for `floats` (if `"float"` feature enabled).
Provides the following functions:
- `nanargminmax`: returns the index of the minimum and maximum element in the array.When dealing with NaNs, `NaNArgMinMax` its functions return the first NaN its index. For more info see [Limitations](#limitations).
> Tip 💡: if you know that there are no NaNs in your the array, we advise you to use `ArgMinMax` as this should be 5-30% faster than `NaNArgMinMax`.
## Features
- [default] **"nightly_simd"**: enables the use of non-stable SIMD intrinsics (`AVX512` and most of `NEON`), which are only available on nightly Rust.
- [default] **"float"**: support `f32` and `f64` argminmax (uses NaN-handling - [see below](#limitations)).
- **"half"**: support `f16` argminmax (through using the [`half`](https://docs.rs/half/latest/half) crate).
- **"ndarray"**: add `ArgMinMax` trait to [`ndarray`](https://docs.rs/ndarray/latest/ndarray) its `Array1` & `ArrayView1`.
- **"arrow"**: add `ArgMinMax` trait to [`arrow`](https://docs.rs/arrow/latest/arrow) its `PrimitiveArray`.## Benchmarks
Benchmarks on my laptop *(AMD Ryzen 7 4800U, 1.8 GHz, 16GB RAM)* using [criterion](https://github.com/bheisler/criterion.rs) show that the function is 3-20x faster than the scalar implementation (depending of data type).
See `/benches/results`.
Run the benchmarks yourself with the following command:
```bash
cargo bench --quiet --message-format=short --features half | grep "time:"
```## Tests
To run the tests use the following command:
```bash
cargo test --message-format=short --all-features
```## Limitations
The library handles NaNs! 🚀
Some (minor) limitations:
- `ArgMinMax` its functions ignores NaN values.
- ❗ When the array contains exclusively NaNs and/or infinities unexpected behaviour can occur (index 0 is returned).
- `NaNArgMinMax` its functions returns the first NaN its index (if any present).
- ❗ When multiple bit-representations for NaNs are used, no guarantee is made that the first NaN is returned.---
## Acknowledgements
Some parts of this library are inspired by the great work of [minimalrust](https://github.com/minimalrust)'s [argmm](https://github.com/minimalrust/argmm) project.