{"id":15065415,"url":"https://github.com/jvdd/argminmax","last_synced_at":"2025-05-16T09:05:37.821Z","repository":{"id":60591672,"uuid":"544024280","full_name":"jvdd/argminmax","owner":"jvdd","description":"Efficient argmin \u0026 argmax","archived":false,"fork":false,"pushed_at":"2025-02-05T13:43:46.000Z","size":557,"stargazers_count":62,"open_issues_count":8,"forks_count":9,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-04T03:36:51.711Z","etag":null,"topics":["argmax","argmin","avx2","avx512","ndarray","neon","numpy","rust","rust-lang","simd","sse"],"latest_commit_sha":null,"homepage":"https://docs.rs/argminmax/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jvdd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"jvdd"}},"created_at":"2022-10-01T12:45:43.000Z","updated_at":"2025-03-05T17:57:50.000Z","dependencies_parsed_at":"2024-01-16T16:20:57.773Z","dependency_job_id":"35ddf6cc-00b3-4209-8e91-3d9fa1a587ce","html_url":"https://github.com/jvdd/argminmax","commit_stats":{"total_commits":134,"total_committers":3,"mean_commits":"44.666666666666664","dds":"0.23880597014925375","last_synced_commit":"e9aa0784647d94ee63f923988776fc2ec0c3ea9a"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jvdd%2Fargminmax","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jvdd%2Fargminmax/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jvdd%2Fargminmax/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jvdd%2Fargminmax/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jvdd","download_url":"https://codeload.github.com/jvdd/argminmax/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254501557,"owners_count":22081528,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["argmax","argmin","avx2","avx512","ndarray","neon","numpy","rust","rust-lang","simd","sse"],"created_at":"2024-09-25T00:38:06.880Z","updated_at":"2025-05-16T09:05:32.814Z","avatar_url":"https://github.com/jvdd.png","language":"Rust","funding_links":["https://github.com/sponsors/jvdd"],"categories":[],"sub_categories":[],"readme":"# ArgMinMax\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://crates.io/crates/argminmax\"\u003e\n    \u003cimg src=\"https://img.shields.io/crates/v/argminmax.svg\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"\"\u003e\n    \u003cimg src=\"https://shields.io/badge/license-MIT-blue\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://docs.rs/argminmax/latest/argminmax/\"\u003e\n    \u003cimg src=\"https://docs.rs/argminmax/badge.svg\" alt=\"rust docs\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/jvdd/argminmax/actions\"\u003e\n    \u003cimg src=\"https://github.com/jvdd/argminmax/actions/workflows/ci.yml/badge.svg\" alt=\"Build and test\"/\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\u003e Efficient argmin \u0026amp; argmax (in 1 function) with SIMD (SSE, AVX(2), AVX512\u003csup\u003e1\u003c/sup\u003e, NEON\u003csup\u003e1\u003c/sup\u003e) ⚡\n\n\u003c!-- This project uses [SIMD](https://en.wikipedia.org/wiki/Single_instruction,_multiple_data) to compute argmin and argmax in a single function.   --\u003e\n\n🚀 The functions are generic over the type of the array, so it can be used on `\u0026[T]` or `Vec\u003cT\u003e` where `T` can be `f16`\u003csup\u003e2\u003c/sup\u003e, `f32`\u003csup\u003e2\u003c/sup\u003e, `f64`\u003csup\u003e3\u003c/sup\u003e, `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`.\n\n🤝 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)\u003csup\u003e4\u003c/sup\u003e, apache [`arrow::PrimitiveArray`](https://docs.rs/arrow/latest/arrow/array/struct.PrimitiveArray.html)\u003csup\u003e5\u003c/sup\u003e and [`arrow2::PrimitiveArray`](https://docs.rs/arrow2/latest/arrow2/array/struct.PrimitiveArray.html)\u003csup\u003e6\u003c/sup\u003e.\n\n⚡ **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. \n\n👀 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).\n\n🪄 **Efficient support for f16 and uints**: through (bijective aka symmetric) bitwise operations, f16 (optional\u003csup\u003e1\u003c/sup\u003e) and uints are converted to ordered integers, allowing to use integer SIMD instructions.\n\n\u003e \u003ci\u003e\u003csup\u003e1\u003c/sup\u003e for \u003ccode\u003eAVX512\u003c/code\u003e and most of \u003ccode\u003eNEON\u003c/code\u003e you should enable the (default) `\"nightly_simd\"` feature (requires nightly Rust).\u003c/i\u003e  \n\u003e \u003ci\u003e\u003csup\u003e2\u003c/sup\u003e for \u003ccode\u003ef16\u003c/code\u003e you should enable the `\"half\"` feature.\u003c/i\u003e  \n\u003e \u003ci\u003e\u003csup\u003e3\u003c/sup\u003e for \u003ccode\u003ef32\u003c/code\u003e and \u003ccode\u003ef64\u003c/code\u003e you should enable the (default) `\"float\"` feature.\u003c/i\u003e  \n\u003e \u003ci\u003e\u003csup\u003e4\u003c/sup\u003e for \u003ccode\u003endarray::ArrayBase\u003c/code\u003e you should enable the `\"ndarray\"` feature.\u003c/i\u003e  \n\u003e \u003ci\u003e\u003csup\u003e5\u003c/sup\u003e for \u003ccode\u003earrow::PrimitiveArray\u003c/code\u003e you should enable the `\"arrow\"` feature.\u003c/i\u003e  \n\u003e \u003ci\u003e\u003csup\u003e6\u003c/sup\u003e for \u003ccode\u003earrow2::PrimitiveArray\u003c/code\u003e you should enable the `\"arrow2\"` feature.\u003c/i\u003e\n\n## Installing\n\nAdd the following to your `Cargo.toml`:\n\n```toml\n[dependencies]\nargminmax = \"0.6.1\"\n```\n\n## Example usage\n\n```rust\nuse argminmax::ArgMinMax;  // import trait\n\nlet arr: Vec\u003ci32\u003e = (0..200_000).collect();  // create a vector\n\nlet (min, max) = arr.argminmax();  // apply extension\n\nprintln!(\"min: {}, max: {}\", min, max);\nprintln!(\"arr[min]: {}, arr[max]: {}\", arr[min], arr[max]);\n```\n\n## Traits\n\n### `ArgMinMax`\n\nImplemented for `ints`, `uints`, and `floats` (if `\"float\"` feature enabled).\n\nProvides the following functions:\n- `argminmax`: returns the index of the minimum and maximum element in the array.\n\u003c!-- - `argmin`: returns the index of the minimum element in the array. --\u003e\n\u003c!-- - `argmax`: returns the index of the maximum element in the array. --\u003e\n\nWhen dealing with NaNs, `ArgMinMax` its functions ignore NaNs. For more info see [Limitations](#limitations).\n\n### `NaNArgMinMax`\n\nImplemented for `floats` (if `\"float\"` feature enabled).\n\nProvides the following functions:\n- `nanargminmax`: returns the index of the minimum and maximum element in the array.\n\u003c!-- - `nanargmin`: returns the index of the minimum element in the array. --\u003e\n\u003c!-- - `nanargmax`: returns the index of the maximum element in the array. --\u003e\n\nWhen dealing with NaNs, `NaNArgMinMax` its functions return the first NaN its index. For more info see [Limitations](#limitations).\n\n\u003e 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`.\n\n\n## Features\n- [default] **\"nightly_simd\"**: enables the use of non-stable SIMD intrinsics (`AVX512` and most of `NEON`), which are only available on nightly Rust.\n- [default] **\"float\"**: support `f32` and `f64` argminmax (uses NaN-handling - [see below](#limitations)).\n- **\"half\"**: support `f16` argminmax (through using the [`half`](https://docs.rs/half/latest/half) crate).\n- **\"ndarray\"**: add `ArgMinMax` trait to [`ndarray`](https://docs.rs/ndarray/latest/ndarray) its `Array1` \u0026 `ArrayView1`.\n- **\"arrow\"**: add `ArgMinMax` trait to [`arrow`](https://docs.rs/arrow/latest/arrow) its `PrimitiveArray`.\n\n## Benchmarks\n\nBenchmarks 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).\n\nSee `/benches/results`.\n\n\u003c!-- *For example, finding the argmin \u0026 argmax in an array of 10,000,000  random `f32` elements is 3.5x faster than the scalar implementation (taking 2.4ms vs 8.5ms).* --\u003e\n\nRun the benchmarks yourself with the following command:\n```bash\ncargo bench --quiet --message-format=short --features half | grep \"time:\"\n```\n\n## Tests\n\nTo run the tests use the following command:\n```bash\ncargo test --message-format=short --all-features\n```\n\n## Limitations\n\nThe library handles NaNs! 🚀 \n\n\u003c!-- For NaN-handling there are two variants:\n- **Ignore NaN**: NaNs are ignored and the index of the highest / lowest non-NaN value is returned.\n- **Return NaN**: the first NaN value is returned. --\u003e\n\nSome (minor) limitations:\n- `ArgMinMax` its functions ignores NaN values.\n  - ❗ When the array contains exclusively NaNs and/or infinities unexpected behaviour can occur (index 0 is returned).\n- `NaNArgMinMax` its functions returns the first NaN its index (if any present).\n  - ❗ When multiple bit-representations for NaNs are used, no guarantee is made that the first NaN is returned.\n\n---\n\n## Acknowledgements\n\nSome parts of this library are inspired by the great work of [minimalrust](https://github.com/minimalrust)'s [argmm](https://github.com/minimalrust/argmm) project.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjvdd%2Fargminmax","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjvdd%2Fargminmax","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjvdd%2Fargminmax/lists"}