Kwker

Rust API reference

Every public function and type of the kwker crate, with its signature and description (Kwker 0.1.0). The functions are at the crate root (kwker::sort, kwker::top_k, ...); kwker::dist and kwker::arrow are modules.

Kwker: sorting, selection, top-k, argsort and key-value sorting of numeric slices, in place, with the fastest engine for the CPU chosen once at run time (AVX-512 or AVX2 on x86-64, NEON or SVE on ARM, portable elsewhere).

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut v = vec![3.5f64, 0.5, 2.0, 1.0];
kwker::sort(&mut v);
assert_eq!(v, [0.5, 1.0, 2.0, 3.5]);

let scores = [12, 7, 30, 18];
let (top, at): (Vec<i32>, Vec<usize>) = kwker::top_k(&scores, 2, Order::DESCENDING, true);
assert_eq!((top, at), (vec![30, 18], vec![2, 3]));

Key types: u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, and the low-precision floats F16, Bf16, F8E5M2 and F8E4M3. Every engine returns the same result; isa names the one in use.

Sorting, selection and top-k

sort Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort<T: Sortable>(v: &mut [T])

Sorts v in place, smallest first.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
let mut v = vec![30, 10, 20];
kwker::sort(&mut v);
assert_eq!(v, [10, 20, 30]);

Notes

Remarks: Not stable (rule 5): keys that are equal but can be told apart (NaNs with different bits) may change places. Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

Examples: Quickstart: Kwker Core: Sort an array, Core concepts: In place or a copy, Runtime controls: Fallback switches, Sorting: Sort in place

sort_descending Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_descending<T: Sortable>(v: &mut [T])

Sorts v in place, largest first.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
let mut v = vec![1.5f32, 3.0, 2.25];
kwker::sort_descending(&mut v);
assert_eq!(v, [3.0, 2.25, 1.5]);

Notes

Examples: Quickstart: Kwker Core: Largest first, or a sorted copy, Core concepts: Special float values, Sorting: Largest first, Sorting: Missing values (NaN)

sort_by_order Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_by_order<T: Sortable>(v: &mut [T], order: Order)

Sorts v in place in the given order: ascending or descending, NaNs first or last.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::{Direction, NanPlacement, Order};

let mut v = vec![2.0f64, f64::NAN, 1.0];
kwker::sort_by_order(&mut v, Order { direction: Direction::Ascending, nans: NanPlacement::First });
assert!(v[0].is_nan());
assert_eq!(v[1..], [1.0, 2.0]);

Notes

Examples: Core concepts: Special float values, Sorting: Missing values (NaN)

select_nth Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn select_nth<T: Sortable>(v: &mut [T], k: usize)

Puts the key a full sort would put at position k into v[k], smaller or equal keys before it and larger or equal keys after it, like slice::select_nth_unstable.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
let mut v = vec![50, 10, 40, 20, 30];
kwker::select_nth(&mut v, 2);
assert_eq!(v[2], 30); // the median

Panics

If k >= v.len().

Notes

Examples: Quickstart: Kwker Core: The median, without a full sort, Top-k and selection: The median and other positions

select_nth_by_order Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn select_nth_by_order<T: Sortable>(v: &mut [T], k: usize, order: Order)

select_nth in the given order: with Order::DESCENDING, v[k] gets the (k+1)-th largest key.

Arguments

Panics

If k >= v.len().

partial_sort Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partial_sort<T: Sortable>(v: &mut [T], k: usize)

Puts the k smallest keys of v, sorted, into v[..k].

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
let mut v = vec![50, 10, 40, 20, 30];
kwker::partial_sort(&mut v, 2);
assert_eq!(v[..2], [10, 20]);

Notes

Remarks: The first k positions hold exactly what a full sort puts there; the rest hold the other keys in any order (rule 8). Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

Examples: Top-k and selection: Sort only the beginning

partial_sort_by_order Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partial_sort_by_order<T: Sortable>(v: &mut [T], k: usize, order: Order)

partial_sort in the given order: with Order::DESCENDING, the k largest keys, largest first.

Arguments

argsort Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort<T: Sortable, I: Index>(v: &[T], order: Order) -> Vec<I>

Returns the positions that sort v: v[p[0]], v[p[1]], ... is in order. Equal keys keep their input order.

Arguments

Returns

One position per key, in the index type I you choose (u32, usize, ...; see Index).

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let p: Vec<u32> = kwker::argsort(&[30, 10, 20], Order::ASCENDING);
assert_eq!(p, [1, 2, 0]);

Panics

If v.len() does not fit the index type I.

Remarks: Stable (rule 6): equal keys keep their input order, so the same input always gives the same positions. Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

Examples: Quickstart: Kwker Core: Get the order, not the sorted data, Order and ranking: The order of an array: argsort, Large data: Use several cores, Languages: The same calls in every language

argsort_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_into<T: Sortable>(v: &[T], order: Order, out: &mut [u64])

argsort into a buffer you provide, with no result vector.

Arguments

Panics

If out.len() != v.len().

Remarks: Stable (rule 6): equal keys keep their input order, so the same input always gives the same positions. Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

argselect Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argselect<T: Sortable, I: Index>(v: &[T], k: usize, order: Order) -> Vec<I>

Returns the positions of the k first keys of v in order, in no particular order: the positions of top_k's keys.

Arguments

Returns

min(k, v.len()) positions in the index type I you choose.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut at: Vec<u32> = kwker::argselect(&[12, 7, 30, 18], 2, Order::ASCENDING);
at.sort();
assert_eq!(at, [0, 1]);

Panics

If v.len() does not fit the index type I.

Remarks: The positions of the stable order's first k keys, in any order (rule 6). Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

Examples: Top-k and selection: Only the positions

top_k Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k<T: Sortable, I: Index>(
    v: &[T],
    k: usize,
    order: Order,
    sorted: bool,
) -> (Vec<T>, Vec<I>)

Returns the k first keys of v in order and their positions: the k smallest with Order::ASCENDING, the k largest with Order::DESCENDING.

Arguments

Returns

(values, positions): min(k, v.len()) keys and their positions in v, in the index type I you choose (u32, usize, ...).

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let (top, at): (Vec<i32>, Vec<usize>) = kwker::top_k(&[12, 7, 30, 18], 2, Order::DESCENDING, true);
assert_eq!(top, [30, 18]);
assert_eq!(at, [2, 3]);

Panics

If v.len() does not fit the index type I.

Notes

Remarks: The first k keys of the stable order and their positions; equal keys keep their input order (rule 9). Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

Examples: Quickstart: Kwker Core: Find the top results, Use Kwker from Rust: The program, Top-k and selection: The k largest or smallest values, Languages: The same calls in every language

top_k_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_into<T: Sortable, I: Index>(
    v: &[T],
    order: Order,
    sorted: bool,
    values: &mut [T],
    indices: &mut [I],
) -> usize

top_k into buffers you provide, with no result vectors.

Arguments

Returns

k, the number of entries written.

Panics

If v.len() does not fit the index type I.

Notes

Remarks: The first k keys of the stable order and their positions; equal keys keep their input order (rule 9). Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

top_k_indices_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_indices_into<T: Sortable>(
    v: &[T],
    order: Order,
    sorted: bool,
    out: &mut [u64],
) -> usize

The positions of top_k into a buffer you provide, with no result vectors.

Arguments

Returns

k, the number of positions written.

Sortable Page

RustAdd kwker to Cargo.toml, then cargo run.
pub trait Sortable: Copy + Sealed { }

Key types sort accepts: u32, i32, f32, u64, i64, f64 (the engines), and the 8- and 16-bit keys u8, i8, u16, i16, F16, Bf16, F8E5M2, F8E4M3 (counting sorts).

Direction Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum Direction {
    Ascending,
    Descending,
}

Sort direction.

Variants

NanPlacement Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum NanPlacement {
    Last,
    First,
}

Where NaN keys go (floating-point keys; ignored for integers), independent of the direction.

Variants

Order Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct Order {
    pub direction: Direction,
    pub nans: NanPlacement,
}

An ordering policy: direction and NaN placement. Order::default() is the order of sort.

Fields

Order::ASCENDING Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const ASCENDING: Order;

Ascending, NaNs last (the order of sort).

Order::DESCENDING Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const DESCENDING: Order;

Descending, NaNs last.

Index Page

RustAdd kwker to Cargo.toml, then cargo run.
pub trait Index: Copy + Send + Sync + 'static { }

Index types of index-producing operations (u8, u16, u32, u64, usize). An index type of b bits needs len <= 2^b (lane-relative indices: the lane length).

Key-value sorts

sort_kv_stable Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_kv_stable<K: Sortable, V: Copy>(keys: &mut [K], values: &mut [V])

Sorts keys in place, smallest first, and moves values with them. Equal keys keep their values in input order.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
let mut keys = vec![2, 1, 2, 1];
let mut names = vec!["c", "a", "d", "b"];
kwker::sort_kv_stable(&mut keys, &mut names);
assert_eq!(keys, [1, 1, 2, 2]);
assert_eq!(names, ["a", "b", "c", "d"]);

Panics

If keys and values have different lengths.

Notes

Remarks: Stable (rule 6): equal keys keep their input order, so the same input always gives the same positions. Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

Examples: Sorting keys with values: Keep equal keys in order: the stable sort

sort_kv_stable_by_order Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_kv_stable_by_order<K: Sortable, V: Copy>(keys: &mut [K], values: &mut [V], order: Order)

sort_kv_stable in the given order. Equal keys keep their values in input order in every order.

Arguments

Panics

If keys and values have different lengths.

sort_with_indices Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_with_indices<K: Sortable, I: Index + Sortable + Ord>(
    keys: &mut [K],
    order: Order,
) -> Vec<I>

Sorts keys in place and returns where each sorted key came from: a sort and an argsort in one call. Use the positions to reorder other columns the same way.

Arguments

Returns

One input position per key, as u32 or u64. Equal keys keep their input order.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut keys = vec![30, 10, 20];
let from: Vec<u32> = kwker::sort_with_indices(&mut keys, Order::ASCENDING);
assert_eq!(keys, [10, 20, 30]);
assert_eq!(from, [1, 2, 0]);

Panics

If keys.len() does not fit the index type I.

sort_kv Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_kv<K: Sortable, V: Copy>(keys: &mut [K], values: &mut [V])

Sorts keys in place, smallest first, and moves values with them: each value stays with its key.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
let mut prices = vec![30, 10, 20];
let mut items = vec!['c', 'a', 'b'];
kwker::sort_kv(&mut prices, &mut items);
assert_eq!(prices, [10, 20, 30]);
assert_eq!(items, ['a', 'b', 'c']);

Panics

If keys and values have different lengths.

Notes

Remarks: Unless the stable form is asked for, pairs with equal keys may come out in any order; the stable form keeps their input order (rule 6). Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

Examples: Core concepts: In place or a copy, Sorting keys with values: Sort keys and values together

sort_kv_by_order Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_kv_by_order<K: Sortable, V: Copy>(keys: &mut [K], values: &mut [V], order: Order)

sort_kv in the given order.

Arguments

Panics

If keys and values have different lengths.

select_nth_kv Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn select_nth_kv<K: Sortable, V: Copy>(keys: &mut [K], values: &mut [V], k: usize)

select_nth on key-value pairs: the pair a full sort_kv would put at position k moves there, with smaller or equal keys before it and larger or equal keys after it.

Arguments

Panics

If k >= keys.len() or keys and values have different lengths.

Notes

select_nth_kv_by_order Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn select_nth_kv_by_order<K: Sortable, V: Copy>(
    keys: &mut [K],
    values: &mut [V],
    k: usize,
    order: Order,
)

select_nth_kv in the given order.

Arguments

Panics

If k >= keys.len() or keys and values have different lengths.

partial_sort_kv Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partial_sort_kv<K: Sortable, V: Copy>(keys: &mut [K], values: &mut [V], k: usize)

partial_sort on key-value pairs: puts the k pairs with the smallest keys, sorted, at the front.

Arguments

Panics

If keys and values have different lengths.

Notes

Remarks: The first k positions hold exactly what a full sort puts there; the rest hold the other keys in any order (rule 8). Unless the stable form is asked for, pairs with equal keys may come out in any order; the stable form keeps their input order (rule 6).

partial_sort_kv_by_order Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partial_sort_kv_by_order<K: Sortable, V: Copy>(
    keys: &mut [K],
    values: &mut [V],
    k: usize,
    order: Order,
)

partial_sort_kv in the given order: with Order::DESCENDING, the k pairs with the largest keys.

Arguments

Panics

If keys and values have different lengths.

Examples: Sorting keys with values: Only the first k pairs

KeyValue Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct KeyValue<K, V> {
    pub key: K,
    pub value: V,
}

A key and its value in one record (#[repr(C)]: the key first). Sorted by the key only.

Fields

Key types

F16 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct F16(pub u16);

IEEE 754 binary16 (half precision) bits. Ordered as a float; F16::to_f32 decodes exactly.

F16::to_f32 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn to_f32(self) -> f32

The value as f32 (exact).

Bf16 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct Bf16(pub u16);

bfloat16 bits (the top half of an f32). Ordered as a float; Bf16::to_f32 decodes exactly.

Bf16::to_f32 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn to_f32(self) -> f32

The value as f32 (exact: the bits are its top half).

F8E5M2 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct F8E5M2(pub u8);

OCP FP8 E5M2 bits (1 sign, 5 exponent, 2 mantissa bits; infinities and NaNs as in IEEE 754).

F8E5M2::to_f32 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn to_f32(self) -> f32

The value as f32 (exact).

F8E4M3 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct F8E4M3(pub u8);

OCP FP8 E4M3 bits, the "FN" variant (1 sign, 4 exponent, 3 mantissa bits; no infinities, NaN = S.1111.111).

F8E4M3::to_f32 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn to_f32(self) -> f32

The value as f32 (exact).

128-bit keys

sort_u128 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_u128(v: &mut [u128], order: Order)

Sorts unsigned 128-bit keys in place.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut v = vec![3u128 << 100, 1, 2];
kwker::sort_u128(&mut v, Order::ASCENDING);
assert_eq!(v, [1, 2, 3u128 << 100]);

Notes

sort_i128 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_i128(v: &mut [i128], order: Order)

sort_u128 for signed 128-bit keys.

Arguments

select_nth_u128 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn select_nth_u128(v: &mut [u128], k: usize, order: Order)

Puts the key a full sort would put at position k into v[k], the keys ordered before it in front of it and the others after it.

Arguments

Panics

If k >= v.len().

select_nth_i128 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn select_nth_i128(v: &mut [i128], k: usize, order: Order)

select_nth_u128 for signed 128-bit keys.

Arguments

Panics

If k >= v.len().

partial_sort_u128 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partial_sort_u128(v: &mut [u128], k: usize, order: Order)

Puts the k first keys of v in order, sorted, into v[..k].

Arguments

Notes

partial_sort_i128 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partial_sort_i128(v: &mut [i128], k: usize, order: Order)

partial_sort_u128 for signed 128-bit keys.

Arguments

top_k_u128 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_u128(v: &[u128], k: usize, order: Order) -> (Vec<u128>, Vec<u64>)

Returns the k first keys of v in order, sorted, and their positions.

Arguments

Returns

(values, positions), min(k, v.len()) of each. Equal keys go to the earlier position first.

top_k_i128 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_i128(v: &[i128], k: usize, order: Order) -> (Vec<i128>, Vec<u64>)

top_k_u128 for signed 128-bit keys.

Arguments

Returns

(values, positions), min(k, v.len()) of each.

argsort_u128 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_u128(v: &[u128], order: Order) -> Vec<u64>

Returns the positions that sort v. Equal keys keep their input order.

Arguments

Returns

One position per key.

argsort_i128 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_i128(v: &[i128], order: Order) -> Vec<u64>

argsort_u128 for signed 128-bit keys.

Arguments

Returns

One position per key.

sort_kv_u128 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_kv_u128<V: Copy>(keys: &mut [u128], values: &mut [V], order: Order)

Sorts unsigned 128-bit keys in place and moves values with them. Equal keys keep their values in input order.

Arguments

Panics

If keys and values have different lengths.

Notes

sort_kv_i128 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_kv_i128<V: Copy>(keys: &mut [i128], values: &mut [V], order: Order)

sort_kv_u128 for signed 128-bit keys.

Arguments

Panics

If keys and values have different lengths.

Permutations, partitions and streams

partition_by_threshold Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partition_by_threshold<T: Sortable>(v: &mut [T], t: T, order: Order) -> usize

Moves the keys that come before t in order to the front of v and returns how many there are.

Arguments

Returns

The size of the front part.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut v = vec![5, 1, 7, 3, 9];
let n = kwker::partition_by_threshold(&mut v, 5, Order::ASCENDING);
assert_eq!(n, 2);
assert!(v[..n].iter().all(|&x| x < 5));

Notes

partition_by Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partition_by<T, F: FnMut(&T) -> bool>(v: &mut [T], pred: F) -> usize

Moves the elements for which pred returns true to the front of v and returns how many there are.

Arguments

Returns

The size of the front part.

Notes

stable_partition_by Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn stable_partition_by<T: Copy, F: FnMut(&T) -> bool>(v: &mut [T], pred: F) -> usize

partition_by that keeps both parts in their input order.

Arguments

Returns

The size of the front part.

Notes

partition_multiway Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partition_multiway<T: Sortable>(v: &mut [T], splitters: &[T], order: Order) -> Vec<usize>

Splits v into buckets by a list of splitters: bucket 0 holds the keys before splitters[0], bucket i the keys from splitters[i - 1] up to splitters[i], and the last bucket the keys from the last splitter on.

Arguments

Returns

The bucket boundaries: splitters.len() + 2 offsets from 0 to v.len(); bucket i is v[b[i]..b[i + 1]].

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut v = vec![7, 1, 15, 3, 12, 8];
let b = kwker::partition_multiway(&mut v, &[5, 10], Order::ASCENDING);
assert_eq!(b, [0, 2, 4, 6]);

Panics

If splitters is not sorted in order.

Notes

is_valid Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn is_valid(validity: &[u8], i: usize) -> bool

Reads bit i of an Arrow-style validity bitmap: true for a value, false for a null.

Arguments

argsort_nullable Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_nullable<T: Sortable>(
    values: &[T],
    validity: &[u8],
    order: Order,
    nulls_first: bool,
) -> Vec<usize>

Returns the positions that sort an array with nulls: the values in order, the nulls together first or last. Equal values and the nulls keep their input order.

Arguments

Returns

One position per value.

sort_nullable Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_nullable<T: Sortable>(
    values: &mut [T],
    validity: &mut [u8],
    order: Order,
    nulls_first: bool,
) -> usize

Sorts an array with nulls in place: the values in order, the nulls together first or last. The bitmap is rewritten to match.

Arguments

Returns

The number of valid values.

sort_kv_nullable Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_kv_nullable<K: Sortable, V: Copy>(
    keys: &mut [K],
    validity: &mut [u8],
    values: &mut [V],
    order: Order,
    nulls_first: bool,
) -> usize

Sorts keys with nulls and moves values with them: the valid keys in order (equal keys keep their input order), the null keys together first or last. The bitmap is rewritten to match.

Arguments

Returns

The number of valid keys.

Permutation Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct Permutation {
    /* private fields */
}

A reordering of n elements: element i of the result is element indices[i] of the input, the form crate::argsort returns. Use it to sort several columns by one key column: build it once with Permutation::sorting, then apply it to every column.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::{Order, Permutation};

let ages = [41, 23, 35];
let mut names = ["Ana", "Bo", "Cy"];
let p = Permutation::sorting(&ages, Order::ASCENDING);
p.apply(&mut names);
assert_eq!(names, ["Bo", "Cy", "Ana"]);

Permutation::identity Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn identity(n: usize) -> Self

The permutation that leaves n elements in place.

Permutation::sorting Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sorting<T: Sortable>(keys: &[T], order: Order) -> Self

The permutation that sorts keys in order. Equal keys keep their input order.

Arguments

Permutation::from_indices Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn from_indices(idx: Vec<usize>) -> Option<Self>

A permutation from its indices: element i of the result is element idx[i] of the input.

Returns

None unless every index of 0..idx.len() occurs exactly once.

Permutation::len Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn len(&self) -> usize

Number of elements.

Permutation::is_empty Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn is_empty(&self) -> bool

True for the permutation of nothing.

Permutation::as_slice Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn as_slice(&self) -> &[usize]

The gather indices.

Permutation::into_vec Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn into_vec(self) -> Vec<usize>

The gather indices, by value.

Permutation::is_identity Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn is_identity(&self) -> bool

True if every element stays in place.

Permutation::gather Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn gather<V: Copy>(&self, src: &[V]) -> Vec<V>

Returns src reordered: out[i] = src[indices[i]].

Permutation::gather_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn gather_into<V: Copy>(&self, src: &[V], out: &mut [V])

gather into out, which must have the permutation's length.

Permutation::scatter Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn scatter<V: Copy>(&self, src: &[V]) -> Vec<V>

Returns src with the reordering undone: out[indices[i]] = src[i].

Permutation::apply Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn apply<V>(&self, data: &mut [V])

Reorders data in place, as gather would, without copying it.

Notes

Permutation::apply_inverse Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn apply_inverse<V>(&self, data: &mut [V])

Undoes apply in place, as scatter would.

Permutation::inverse Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn inverse(&self) -> Self

The inverse permutation: applying a permutation and then its inverse leaves data unchanged.

Permutation::then Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn then(&self, next: &Permutation) -> Permutation

The permutation that applies self, then next: x.apply(self); x.apply(next) equals x.apply(self.then(next)).

TopKStream Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct TopKStream<T: Sortable> {
    /* private fields */
}

The k first keys (in an Order) of data that arrives in chunks, without keeping the data. push each chunk, then read the result. Streams filled separately, for example one per thread with push_at, combine with merge.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::{Order, TopKStream};

let mut s = TopKStream::new(2, Order::DESCENDING);
s.push(&[5, 1, 9]);
s.push(&[7, 3]);
let (top, at) = s.result(true);
assert_eq!(top, [9, 7]);
assert_eq!(at, [2, 3]);

Notes

TopKStream::new Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn new(k: usize, order: Order) -> Self

An empty stream that keeps the k first keys in order.

TopKStream::push Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn push(&mut self, chunk: &[T])

Adds the next chunk; its positions continue after the elements pushed so far.

TopKStream::push_at Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn push_at(&mut self, chunk: &[T], first: u64)

Adds a chunk whose first element has stream position first, so chunks can come in any order.

TopKStream::merge Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn merge(&mut self, other: &TopKStream<T>)

Adds the candidates of another stream with the same k and order.

TopKStream::seen Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn seen(&self) -> u64

The number of elements pushed so far: the position push gives the next element.

TopKStream::result Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn result(&self, sorted: bool) -> (Vec<T>, Vec<u64>)

Returns the k first keys (fewer if fewer were pushed) and their stream positions.

Arguments

Rows and segments

sort_rows Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_rows<T: Sortable>(data: &mut [T], row_len: usize, order: Order)

Sorts every row of a row-major table in place.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut t = vec![3, 1, 2, 9, 7, 8];
kwker::sort_rows(&mut t, 3, Order::ASCENDING);
assert_eq!(t, [1, 2, 3, 7, 8, 9]);

Panics

If row_len does not divide data.len() (empty data takes any row_len).

Remarks: Not stable (rule 5): keys that are equal but can be told apart (NaNs with different bits) may change places. Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

Examples: Sorting: Sort each row

sort_segments Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_segments<T: Sortable, I: Index>(data: &mut [T], offsets: &[I], order: Order)

Sorts every segment data[offsets[i]..offsets[i + 1]] in place: segments of any length, one after another.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut v = vec![2, 1, 9, 8, 7];
kwker::sort_segments(&mut v, &[0u32, 2, 5], Order::ASCENDING);
assert_eq!(v, [1, 2, 7, 8, 9]);

Notes

Remarks: Not stable (rule 5): keys that are equal but can be told apart (NaNs with different bits) may change places. Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

top_k_rows Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_rows<T: Sortable, I: Index>(
    data: &[T],
    row_len: usize,
    k: usize,
    order: Order,
    sorted: bool,
    values: &mut [T],
    indices: &mut [I],
)

The k first keys of every row and their positions within the row, as crate::top_k gives for one row.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let scores = [0.1f32, 0.7, 0.2, 0.9, 0.3, 0.8];
let (mut top, mut at) = (vec![0.0f32; 2], vec![0u32; 2]);
kwker::top_k_rows(&scores, 3, 1, Order::DESCENDING, true, &mut top, &mut at);
assert_eq!(top, [0.7, 0.9]);
assert_eq!(at, [1, 0]);

Panics

If row_len does not divide data.len(), k > row_len, or an output does not hold rows x k entries.

Remarks: The first k keys of the stable order and their positions; equal keys keep their input order (rule 9). Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

top_k_segments Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_segments<T: Sortable, I: Index, J: Index>(
    data: &[T],
    offsets: &[J],
    k: usize,
    order: Order,
    sorted: bool,
    values: &mut [T],
    indices: &mut [I],
)

The k first keys of every segment and their positions within the segment.

Arguments

Notes

Examples: Top-k and selection: Top-k per group

argsort_rows Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_rows<T: Sortable, I: Index>(
    data: &[T],
    row_len: usize,
    order: Order,
    indices: &mut [I],
)

The positions that sort every row, counted within the row, as crate::argsort gives for one row.

Arguments

Panics

If row_len does not divide data.len() or indices.len() != data.len().

Remarks: Stable (rule 6): equal keys keep their input order, so the same input always gives the same positions. Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

sort_rows_indexed Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_rows_indexed<T: Sortable>(
    data: &[T],
    row_len: usize,
    order: Order,
    values: &mut [T],
    indices: &mut [u64],
)

Sorts every row into values and writes where each sorted key came from into indices, like torch.sort(stable=True): a sort and an argsort in one call.

Arguments

Panics

If row_len does not divide data.len() or an output does not hold data.len() entries.

kth_rows Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn kth_rows<T: Sortable>(
    data: &[T],
    row_len: usize,
    k: usize,
    order: Order,
    nan_first: bool,
    values: &mut [T],
    indices: &mut [u64],
)

The key at position k of every sorted row and its position in the row, like torch.kthvalue. With k = (row_len - 1) / 2 this is each row's median.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let t = [5, 1, 3, 9, 7, 8];
let (mut med, mut at) = (vec![0; 2], vec![0u64; 2]);
kwker::kth_rows(&t, 3, 1, Order::ASCENDING, false, &mut med, &mut at);
assert_eq!(med, [3, 8]);
assert_eq!(at, [2, 2]);

Panics

If row_len does not divide data.len(), k >= row_len, or an output does not hold one entry per row.

Notes

argsort_segments Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_segments<T: Sortable, I: Index, J: Index>(
    data: &[T],
    offsets: &[J],
    order: Order,
    indices: &mut [I],
)

The positions that sort every segment, counted within the segment, written at the segment's place in indices.

Arguments

argpartition_rows Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argpartition_rows<T: Sortable, I: Index>(
    data: &[T],
    row_len: usize,
    kth: usize,
    order: Order,
    indices: &mut [I],
)

numpy.argpartition for every row: per row, the positions arranged so that slot kth holds the position of the row's key at sorted position kth, the slots before it the positions of smaller keys and the slots after it the others.

Arguments

Panics

If row_len does not divide data.len(), kth >= row_len, or indices.len() != data.len().

Notes

argpartition_segments Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argpartition_segments<T: Sortable, I: Index, J: Index>(
    data: &[T],
    offsets: &[J],
    kth: usize,
    order: Order,
    indices: &mut [I],
)

argpartition_rows for segments of any length, written at each segment's place in indices.

Arguments

Notes

sort_rows_mt Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_rows_mt<T: Sortable + Send + Sync>(
    data: &mut [T],
    row_len: usize,
    order: Order,
    threads: usize,
)

sort_rows on several threads; the result is the same.

Arguments

Remarks: Not stable (rule 5): keys that are equal but can be told apart (NaNs with different bits) may change places. Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for. Threads change only the speed: the result follows the same rules on any thread count (rule 10).

argsort_rows_mt Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_rows_mt<T: Sortable + Send + Sync, I: Index>(
    data: &[T],
    row_len: usize,
    order: Order,
    indices: &mut [I],
    threads: usize,
)

argsort_rows on several threads; the result is the same.

Arguments

Remarks: Stable (rule 6): equal keys keep their input order, so the same input always gives the same positions. Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for. Threads change only the speed: the result follows the same rules on any thread count (rule 10).

sort_rows_indexed_mt Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_rows_indexed_mt<T: Sortable + Send + Sync>(
    data: &[T],
    row_len: usize,
    order: Order,
    values: &mut [T],
    indices: &mut [u64],
    threads: usize,
)

sort_rows_indexed on several threads; the result is the same.

Arguments

top_k_rows_mt Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_rows_mt<T: Sortable + Send + Sync, I: Index>(
    data: &[T],
    row_len: usize,
    k: usize,
    order: Order,
    sorted: bool,
    values: &mut [T],
    indices: &mut [I],
    threads: usize,
)

top_k_rows on several threads; the result is the same.

Arguments

Remarks: The first k keys of the stable order and their positions; equal keys keep their input order (rule 9). Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for. Threads change only the speed: the result follows the same rules on any thread count (rule 10).

sort_segments_mt Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_segments_mt<T: Sortable + Send + Sync, I: Index>(
    data: &mut [T],
    offsets: &[I],
    order: Order,
    threads: usize,
)

sort_segments on several threads; the result is the same.

Arguments

Remarks: Not stable (rule 5): keys that are equal but can be told apart (NaNs with different bits) may change places. Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for. Threads change only the speed: the result follows the same rules on any thread count (rule 10).

Along an axis

sort_axis_strided Page

RustAdd kwker to Cargo.toml, then cargo run.
pub unsafe fn sort_axis_strided<T: Sortable>(
    base: *mut T,
    shape: &[usize],
    strides: &[isize],
    axis: usize,
    order: Order,
)

Sorts every lane along axis of a strided N-dimensional array in place, like numpy.sort(a, axis).

Arguments

Safety

Every element reachable through shape and strides from base must be valid and writable, and no two index tuples may address the same element (a stride of 0 along axis excepted).

sort_axis Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_axis<T: Sortable>(data: &mut [T], shape: &[usize], axis: usize, order: Order)

Sorts every lane along axis of a row-major (C-order) array in place, like numpy.sort(a, axis).

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

// a 2 x 3 array sorted down its columns (axis 0)
let mut a = vec![4, 2, 9, 1, 5, 3];
kwker::sort_axis(&mut a, &[2, 3], 0, Order::ASCENDING);
assert_eq!(a, [1, 2, 3, 4, 5, 9]);

Panics

If the shape's product is not data.len() or axis >= shape.len().

argsort_axis_strided Page

RustAdd kwker to Cargo.toml, then cargo run.
pub unsafe fn argsort_axis_strided<T: Sortable, I: Index>(
    base: *const T,
    shape: &[usize],
    strides: &[isize],
    axis: usize,
    order: Order,
    out: *mut I,
    out_strides: &[isize],
)

The positions that sort every lane along axis of a strided array, counted within the lane, like numpy.argsort(a, axis). Equal keys keep their input order.

Arguments

Safety

Every element reachable through shape / strides from base must be readable, every element through shape / out_strides from out writable, and no two index tuples may address the same output element.

sort_axis_indexed_strided Page

RustAdd kwker to Cargo.toml, then cargo run.
pub unsafe fn sort_axis_indexed_strided<T: Sortable, I: Index>(
    base: *const T,
    shape: &[usize],
    strides: &[isize],
    axis: usize,
    order: Order,
    vals: *mut T,
    out: *mut I,
    out_strides: &[isize],
)

Sorts every lane along axis of a strided array into vals and writes each sorted key's position in its lane into out, like torch.sort(x, dim, stable=True), without a transposed copy.

Arguments

Safety

Every element reachable through shape / strides from base must be readable, every element through shape / out_strides from vals and (unless null) out writable, no two index tuples may address the same output element, and the outputs may not overlap each other or the input.

kth_axis_strided Page

RustAdd kwker to Cargo.toml, then cargo run.
pub unsafe fn kth_axis_strided<T: Sortable>(
    base: *const T,
    shape: &[usize],
    strides: &[isize],
    axis: usize,
    k: usize,
    order: Order,
    nan_first: bool,
    vals: *mut T,
    out: *mut u64,
    out_strides: &[isize],
)

The key at sorted position k of every lane along axis of a strided array, and its position in the lane, like torch.kthvalue(x, k + 1, dim) or torch.median(x, dim).

Arguments

Safety

Every element reachable through shape / strides from base must be readable, and every result slot through the other dimensions of out_strides from vals and out writable and distinct.

quantile_axis_strided Page

RustAdd kwker to Cargo.toml, then cargo run.
pub unsafe fn quantile_axis_strided<T: Sortable + Send + Sync>(
    base: *const T,
    shape: &[usize],
    strides: &[isize],
    axis: usize,
    qs: &[f64],
    ignore_nan: bool,
    interp: Interpolation,
    below: *mut T,
    above: *mut T,
    weight: *mut f64,
    out_strides: &[isize],
    threads: usize,
)

The order statistics behind torch.quantile(x, qs, dim) for every lane along axis of a strided array: for each quantile the two neighbouring keys and the weight between them (the result is below + weight * (above - below), as crate::quantile_lane gives for one lane).

Arguments

Safety

Every element reachable through shape / strides from base must be readable, and every output row writable.

quantile_axis_strided_ex Page

RustAdd kwker to Cargo.toml, then cargo run.
pub unsafe fn quantile_axis_strided_ex<T: Sortable + Send + Sync>(
    base: *const T,
    shape: &[usize],
    strides: &[isize],
    axis: usize,
    qs: &[f64],
    ignore_nan: bool,
    interp: Interpolation,
    f32_ranks: bool,
    below: *mut T,
    above: *mut T,
    weight: *mut f64,
    out_strides: &[isize],
    threads: usize,
)

quantile_axis_strided that can match older torch releases bit for bit on float32 input.

Arguments

Safety

As quantile_axis_strided.

argsort_axis Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_axis<T: Sortable, I: Index>(
    data: &[T],
    shape: &[usize],
    axis: usize,
    order: Order,
    out: &mut [I],
)

The positions that sort every lane along axis of a row-major (C-order) array, counted within the lane, like numpy.argsort(a, axis). Equal keys keep their input order.

Arguments

Panics

If data or out does not hold the shape's product of elements.

MAX_DIMS Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const MAX_DIMS: usize = 64;

At most this many dimensions (NumPy's limit): the lane iteration keeps its state on the stack.

Searching

lower_bound Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn lower_bound<T: Sortable>(sorted: &[T], key: T, order: Order) -> usize

The first position in a sorted slice whose key does not come before key, like C++ std::lower_bound.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

assert_eq!(kwker::lower_bound(&[10, 20, 20, 30], 20, Order::ASCENDING), 1);

upper_bound Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn upper_bound<T: Sortable>(sorted: &[T], key: T, order: Order) -> usize

The first position in a sorted slice whose key comes after key, like C++ std::upper_bound.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

assert_eq!(kwker::upper_bound(&[10, 20, 20, 30], 20, Order::ASCENDING), 3);

equal_range Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn equal_range<T: Sortable>(sorted: &[T], key: T, order: Order) -> Range<usize>

The positions in a sorted slice that hold key.

Arguments

Returns

The range from lower_bound to upper_bound; empty when key is not there.

Notes

searchsorted_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn searchsorted_into<T: Sortable>(
    sorted: &[T],
    queries: &[T],
    side: Side,
    order: Order,
    out: &mut [u64],
)

Finds where each query would go in a sorted slice, like numpy.searchsorted and torch.searchsorted.

Arguments

Panics

If out.len() != queries.len().

Remarks: -0.0 and +0.0 compare equal here, as in NumPy (rule 14).

searchsorted Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn searchsorted<T: Sortable>(sorted: &[T], queries: &[T], side: Side, order: Order) -> Vec<u64>

Finds where each query would go in a sorted slice, like numpy.searchsorted and torch.searchsorted.

Arguments

Returns

One position per query.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::{Order, Side};

let at = kwker::searchsorted(&[10, 20, 30], &[5, 20, 35], Side::Left, Order::ASCENDING);
assert_eq!(at, [0, 1, 3]);

Remarks: -0.0 and +0.0 compare equal here, as in NumPy (rule 14).

Examples: Searching sorted data: Where does a value go? searchsorted

bucketize Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn bucketize<T: Sortable>(values: &[T], boundaries: &[T], right: bool, order: Order) -> Vec<u64>

The bucket of every value between sorted boundaries, like torch.bucketize.

Arguments

Returns

One bucket number per value, from 0 to boundaries.len().

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let b = kwker::bucketize(&[1, 5, 10], &[2, 6], false, Order::ASCENDING);
assert_eq!(b, [0, 1, 2]);

Remarks: -0.0 and +0.0 compare equal here, as in NumPy (rule 14).

Examples: Searching sorted data: Which bucket? bucketize

bucket_counts Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn bucket_counts<T: Sortable>(
    values: &[T],
    boundaries: &[T],
    right: bool,
    order: Order,
) -> Vec<u64>

Counts the values in each bucket of bucketize: a histogram with the edges you give.

Arguments

Returns

boundaries.len() + 1 counts.

Remarks: -0.0 and +0.0 compare equal here, as in NumPy (rule 14).

Examples: Searching sorted data: How many in each bucket? bucket_counts

bucket_counts_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn bucket_counts_into<T: Sortable>(
    values: &[T],
    boundaries: &[T],
    right: bool,
    order: Order,
    counts: &mut [u64],
)

bucket_counts into a buffer you provide.

Arguments

Panics

If counts.len() != boundaries.len() + 1.

Remarks: -0.0 and +0.0 compare equal here, as in NumPy (rule 14).

Side Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum Side {
    Left,
    Right,
}

Which end of a run of equal keys searchsorted reports: Left is the first position whose key does not come before the query (lower_bound); Right is the first position whose key comes after it (upper_bound).

Variants

Ranks

rank_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn rank_into<T: Sortable>(v: &[T], order: Order, ties: RankTies, out: &mut [u64])

rank into a buffer you provide.

Arguments

Panics

If out.len() != v.len().

Remarks: Ordinal ranks give equal keys increasing ranks in input order (rule 6). Equal values are one key here, as in NumPy: -0.0 and +0.0 are equal, and so are all NaNs (rule 13).

rank Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn rank<T: Sortable>(v: &[T], order: Order, ties: RankTies) -> Vec<u64>

The rank of every key, from 1, like SQL RANK() or pandas rank().

Arguments

Returns

One rank per key, in input order.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::{Order, RankTies};

let r = kwker::rank(&[30, 10, 20, 10], Order::ASCENDING, RankTies::Min);
assert_eq!(r, [4, 1, 3, 1]);

Notes

Remarks: Ordinal ranks give equal keys increasing ranks in input order (rule 6). Equal values are one key here, as in NumPy: -0.0 and +0.0 are equal, and so are all NaNs (rule 13).

Examples: Order and ranking: Ranks

rank_average Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn rank_average<T: Sortable>(v: &[T], order: Order) -> Vec<f64>

Average ranks, from 1: equal keys share the mean of their group's ranks, like scipy.stats.rankdata and pandas rank(method="average"). Spearman's correlation uses these.

Arguments

Returns

One rank per key, in input order.

Remarks: Equal values are one key here, as in NumPy: -0.0 and +0.0 are equal, and so are all NaNs (rule 13).

Examples: Order and ranking: Ranks

percent_rank Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn percent_rank<T: Sortable>(v: &[T], order: Order) -> Vec<f64>

SQL PERCENT_RANK(): (rank - 1) / (n - 1) for every key, between 0 and 1, with equal keys sharing their lowest rank.

Arguments

Returns

One value per key, in input order; all 0 for fewer than two keys.

Remarks: Equal values are one key here, as in NumPy: -0.0 and +0.0 are equal, and so are all NaNs (rule 13).

Examples: Order and ranking: Ranks

inverse_ranks Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn inverse_ranks(ranks: &[u64]) -> Option<Vec<u64>>

Turns ranks back into a sort order: from ranks 1..=n (as rank with RankTies::Ordinal returns), the positions that sort the keys, as crate::argsort would give.

Arguments

Returns

The positions, or None if ranks is not a permutation of 1..=n.

rank_rows Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn rank_rows<T: Sortable>(
    data: &[T],
    row_len: usize,
    order: Order,
    ties: RankTies,
    out: &mut [u64],
)

rank within every row of a row-major table.

Arguments

Panics

If row_len does not divide data.len() or out.len() != data.len().

count_inversions Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn count_inversions<T: Sortable>(v: &[T], order: Order) -> u64

Counts the pairs of keys that are out of order: positions i < j whose keys come the other way round in order. This is the number of discordant pairs in Kendall's tau.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

assert_eq!(kwker::count_inversions(&[3, 1, 2], Order::ASCENDING), 2);

Notes

RankTies Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum RankTies {
    Ordinal,
    Min,
    Max,
    Dense,
}

How rank ranks equal keys.

Variants

Quantiles

select_ranks Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn select_ranks<T: Sortable>(v: &mut [T], ranks: &[usize], order: Order)

Several crate::select_nth calls at once: afterwards v[r] holds the key a full sort would put there, for every r in ranks, and the keys between two selected positions lie between their keys.

Arguments

Panics

If a rank is v.len() or more.

quantile_lane_mt Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn quantile_lane_mt<T: Sortable + Send + Sync>(
    v: &[T],
    qs: &[f64],
    ignore_nan: bool,
    interp: Interpolation,
    below: &mut [T],
    above: &mut [T],
    weight: &mut [f64],
    threads: usize,
)

quantile_lane of one large lane on several threads; v is not changed.

Arguments

quantile_lane Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn quantile_lane<T: Sortable>(
    v: &mut [T],
    qs: &[f64],
    ignore_nan: bool,
    interp: Interpolation,
    below: &mut [T],
    above: &mut [T],
    weight: &mut [f64],
    ranks: &mut Vec<usize>,
)

The order statistics behind torch.quantile for one lane of values: for each quantile, the two neighbouring keys and the weight between them. The quantile is below + weight * (above - below).

Arguments

Notes

quantiles Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn quantiles<T: Sortable>(v: &mut [T], qs: &[f64], order: Order) -> Vec<T>

The keys at the given quantiles: quantile q is the key at sorted position floor(q * (n - 1)).

Arguments

Returns

One key per quantile.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut v: Vec<i32> = (1..=11).collect();
assert_eq!(kwker::quantiles(&mut v, &[0.0, 0.5, 1.0], Order::ASCENDING), [1, 6, 11]);

Panics

If v is empty or a quantile is outside [0, 1].

median Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn median<T: Sortable>(v: &mut [T], order: Order) -> T

The median of v; for an even count, the lower of the two middle keys.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut v = vec![5, 1, 4, 2];
assert_eq!(kwker::median(&mut v, Order::ASCENDING), 2);

Panics

If v is empty.

Interpolation Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum Interpolation {
    Linear,
    Lower,
    Higher,
    Midpoint,
    Nearest,
}

How torch.quantile interpolates between the two keys around a quantile.

Variants

Unique values

unique_inverse Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn unique_inverse<T: Sortable + Send + Sync>(
    data: &[T],
    inverse: Option<&mut [u64]>,
    want_counts: bool,
    threads: usize,
) -> (Vec<T>, Vec<u64>)

The distinct keys of data, sorted, like numpy.unique and torch.unique, with optional group numbers and counts.

Arguments

Returns

(values, counts): the distinct keys, smallest first, and their counts (empty unless want_counts).

Example

RustAdd kwker to Cargo.toml, then cargo run.
let mut inv = vec![0u64; 4];
let (vals, counts) = kwker::unique_inverse(&[3, 1, 3, 2], Some(&mut inv), true, 1);
assert_eq!(vals, [1, 2, 3]);
assert_eq!(counts, [1, 1, 2]);
assert_eq!(inv, [2, 0, 2, 1]);

Panics

If inverse is given and its length differs from data.len().

Notes

unique_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn unique_into<T: Sortable + Send + Sync>(data: &[T], out: &mut [T], threads: usize) -> usize

The distinct keys of data, sorted, into a buffer you provide.

Arguments

Returns

m, the number of distinct keys.

Panics

If out.len() != data.len().

Remarks: -0.0 and +0.0 are one value; every NaN is a value of its own, listed last (rule 15).

unique_inverse_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn unique_inverse_into<T: Sortable + Send + Sync>(
    data: &[T],
    values: &mut [T],
    inverse: Option<&mut [u64]>,
    counts: Option<&mut [u64]>,
    threads: usize,
) -> usize

unique_inverse into buffers you provide.

Arguments

Returns

m, the number of distinct keys.

Panics

If a buffer given is not as long as data.

Sorted sets

set_op Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn set_op<T: Sortable>(a: &[T], b: &[T], op: SetOp, multiset: bool, order: Order) -> Vec<T>

A set operation on two sorted slices: intersection, union, difference or symmetric difference. The result is sorted too.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::{Order, SetOp};

let both = kwker::set_op(&[1, 2, 2, 3], &[2, 2, 4], SetOp::Intersection, false, Order::ASCENDING);
assert_eq!(both, [2]);
let both = kwker::set_op(&[1, 2, 2, 3], &[2, 2, 4], SetOp::Intersection, true, Order::ASCENDING);
assert_eq!(both, [2, 2]);

Notes

Remarks: Equal values are one key here, as in NumPy: -0.0 and +0.0 are equal, and so are all NaNs (rule 13).

Examples: Groups, merges and sets: Set operations

set_intersection Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn set_intersection<T: Sortable>(a: &[T], b: &[T], multiset: bool, order: Order) -> Vec<T>

The keys in both a and b: set_op with SetOp::Intersection.

Arguments

set_union Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn set_union<T: Sortable>(a: &[T], b: &[T], multiset: bool, order: Order) -> Vec<T>

The keys in a or b: set_op with SetOp::Union.

Arguments

set_difference Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn set_difference<T: Sortable>(a: &[T], b: &[T], multiset: bool, order: Order) -> Vec<T>

The keys in a but not in b: set_op with SetOp::Difference.

Arguments

set_symmetric_difference Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn set_symmetric_difference<T: Sortable>(
    a: &[T],
    b: &[T],
    multiset: bool,
    order: Order,
) -> Vec<T>

The keys in exactly one of a and b: set_op with SetOp::SymmetricDifference.

Arguments

intersection_indices Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn intersection_indices<T: Sortable>(
    a: &[T],
    b: &[T],
    multiset: bool,
    order: Order,
) -> (Vec<u64>, Vec<u64>)

Where the common keys of two sorted slices are, in each of them, like numpy.intersect1d(return_indices=True). Use it to line up data that belongs to the keys.

Arguments

Returns

(positions in a, positions in b), in increasing order.

row_intersect_count Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn row_intersect_count<T: Sortable>(a: &[T], ka: usize, b: &[T], kb: usize, out: &mut [u64])

For every row, how many keys two tables have in common: for example recall@k, retrieved ids against the true ones.

Arguments

Panics

If the shapes do not agree.

Notes

row_unique_count Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn row_unique_count<T: Sortable>(a: &[T], k: usize, out: &mut [u64])

The number of distinct values in every row of a row-major table.

Arguments

Panics

If a.len() != out.len() * k.

Notes

isin_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn isin_into<T: Sortable>(elements: &[T], test: &[T], invert: bool, out: &mut [bool])

Tests every element for membership in a set of keys, like numpy.isin and torch.isin.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
let mut hit = vec![false; 4];
kwker::isin_into(&[1, 5, 3, 7], &[3, 1], false, &mut hit);
assert_eq!(hit, [true, false, true, false]);

Panics

If out.len() != elements.len().

Notes

SetOp Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum SetOp {
    Intersection,
    Union,
    Difference,
    SymmetricDifference,
}

Which operation set_op computes.

Variants

Merging

merge Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn merge<T: Sortable>(a: &[T], b: &[T], out: &mut [T], order: Order)

Merges two sorted slices into one sorted output. On equal keys, a's come first.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut out = vec![0; 5];
kwker::merge(&[1, 4, 6], &[2, 3], &mut out, Order::ASCENDING);
assert_eq!(out, [1, 2, 3, 4, 6]);

merge_kv Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn merge_kv<K: Sortable, V: Copy>(
    a_keys: &[K],
    a_values: &[V],
    b_keys: &[K],
    b_values: &[V],
    out_keys: &mut [K],
    out_values: &mut [V],
    order: Order,
)

Merges two sorted key-value sequences; each value moves with its key. On equal keys, a's come first.

Arguments

merge_in_place Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn merge_in_place<T: Sortable>(v: &mut [T], mid: usize, order: Order)

Merges the sorted halves v[..mid] and v[mid..] in place. On equal keys, the first half's come first.

Arguments

Notes

kway_merge Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn kway_merge<T: Sortable>(runs: &[&[T]], out: &mut [T], order: Order)

Merges any number of sorted runs into one sorted output. Equal keys keep run order, then position.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut out = vec![0; 6];
kwker::kway_merge(&[&[1, 5], &[2, 6], &[3, 4]], &mut out, Order::ASCENDING);
assert_eq!(out, [1, 2, 3, 4, 5, 6]);

Examples: Groups, merges and sets: Merge sorted lists: kway_merge

kway_merge_kv Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn kway_merge_kv<K: Sortable, V: Copy>(
    keys: &[&[K]],
    values: &[&[V]],
    out_keys: &mut [K],
    out_values: &mut [V],
    order: Order,
)

kway_merge of key-value runs: each value moves with its key.

Arguments

kway_merge_with Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn kway_merge_with<T: Sortable, F: FnMut(usize, usize)>(runs: &[&[T]], order: Order, emit: F)

The merged order of sorted runs, without moving anything: calls emit(run, index) for every element in merged order, so you can move records, rows or other data along.

Arguments

Notes

merge_sorted_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn merge_sorted_into<T: Sortable>(sorted: &mut Vec<T>, new: &mut [T], order: Order)

Adds new keys to a sorted vector: sorts new and merges it in, without sorting sorted again.

Arguments

Notes

Several sort keys

lexsort Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn lexsort(keys: &[(&dyn KeyColumn, Order)]) -> Permutation

The order that sorts rows by several key columns: by the first column, ties by the second, and so on, each column in its own order. Apply the result to every column of the table with Permutation::apply.

Arguments

Returns

A Permutation; rows with equal keys in every column keep their input order.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let city = vec![2, 1, 2];
let age = vec![30, 40, 20];
let p = kwker::lexsort(&[(&city, Order::ASCENDING), (&age, Order::DESCENDING)]);
assert_eq!(p.as_slice(), [1, 0, 2]);

Panics

If the columns have different lengths.

Examples: Order and ranking: Sort by several columns

lexsort_mt Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn lexsort_mt(keys: &[(&dyn KeyColumn, Order)], threads: usize) -> Permutation

lexsort on several threads; the result is the same.

Arguments

lexsort_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn lexsort_into(keys: &[(&dyn KeyColumn, Order)], threads: usize, out: &mut [u64])

lexsort into a buffer you provide, on several threads.

Arguments

Panics

If a column's length differs from out.len().

lex_top_k Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn lex_top_k(keys: &[(&dyn KeyColumn, Order)], k: usize) -> Vec<usize>

The first k rows of lexsort's order without sorting every row, like SQL ORDER BY a, b LIMIT k.

Arguments

Returns

The positions of the first k rows (fewer if there are fewer rows), in order.

Examples: Order and ranking: Sort by several columns

lex_select_nth Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn lex_select_nth(keys: &[(&dyn KeyColumn, Order)], k: usize) -> usize

The row at position k of lexsort's order, without sorting.

Arguments

Returns

The row's position in the input.

Panics

If k is not below the number of rows or the columns have different lengths.

KeyColumn Page

RustAdd kwker to Cargo.toml, then cargo run.
pub trait KeyColumn: Sync {
    fn rows(&self) -> usize;
}

A key column for lexsort: any slice or vector of a Sortable key type.

Records and fields

argsort_field Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_field<K: Sortable>(
    records: &[u8],
    n: usize,
    stride: usize,
    offset: usize,
    order: Order,
) -> Vec<u64>

The order of fixed-size binary records by one numeric field, without moving the records.

Arguments

Returns

One record number per record: record p[0] has the first key. Equal keys keep their input order.

Example

RustAdd kwker to Cargo.toml, then cargo run.
// 3 records of 12 bytes: an id (u32) and a price (f64, unaligned at offset 4)
let mut bytes = Vec::new();
for (id, price) in [(7u32, 2.5f64), (8, -1.0), (9, 0.25)] {
    bytes.extend_from_slice(&id.to_ne_bytes());
    bytes.extend_from_slice(&price.to_ne_bytes());
}
let p = kwker::argsort_field::<f64>(&bytes, 3, 12, 4, kwker::Order::ASCENDING);
assert_eq!(p, vec![1, 2, 0]);

Panics

If n records of stride bytes do not fit in records.

argsort_field_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_field_into<K: Sortable>(
    records: &[u8],
    n: usize,
    stride: usize,
    offset: usize,
    order: Order,
    out: &mut [u64],
)

argsort_field into a buffer you provide.

Arguments

top_k_field Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_field<K: Sortable>(
    records: &[u8],
    n: usize,
    stride: usize,
    offset: usize,
    k: usize,
    order: Order,
) -> Vec<u64>

The first k records by one numeric field, without sorting them all: SQL ORDER BY field LIMIT k over records that stay where they are.

Arguments

Returns

The first min(k, n) record numbers, in order. Equal keys keep their input order.

argsort_by_key Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_by_key<T, K: Sortable>(v: &[T], order: Order, key: impl FnMut(&T) -> K) -> Vec<u64>

The order of any objects by a numeric key you extract, without moving the objects.

Arguments

Returns

One position per object; equal keys keep their input order. crate::sort_by_extracted_key moves the objects.

take_records Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn take_records(src: &[u8], record_size: usize, idx: &[u64], dst: &mut [u8])

Copies records by position: record j of dst becomes record idx[j] of src.

Arguments

Panics

If a position is out of range or dst does not hold idx.len() records.

is_permutation Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn is_permutation(perm: &[u64]) -> bool

Whether perm holds every position of 0..perm.len() exactly once, as permute_in_place requires.

permute_in_place Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn permute_in_place<T>(v: &mut [T], perm: &[u64])

Reorders v in place so that position j gets the element that was at perm[j]: applies an argsort's result.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
let mut names = vec!["c", "a", "b"];
kwker::permute_in_place(&mut names, &[1, 2, 0]);
assert_eq!(names, ["a", "b", "c"]);

Panics

If perm is not a permutation of 0..v.len() (nothing is moved).

Notes

Examples: Order and ranking: Reorder records in place

permute_records_in_place Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn permute_records_in_place(records: &mut [u8], record_size: usize, perm: &[u64])

permute_in_place for raw records of a fixed size.

Arguments

Panics

If the sizes do not match or perm is not a permutation (nothing is moved).

sort_by_extracted_key Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_by_extracted_key<T, K: Sortable>(
    v: &mut [T],
    order: Order,
    key: impl FnMut(&T) -> K,
    how: ObjectMove,
)

Sorts objects of any type by a numeric key you extract. Equal keys keep their input order.

Arguments

Notes

sort_objects_by_key Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_objects_by_key<T, K: Sortable>(v: &mut [T], order: Order, key: impl FnMut(&T) -> K)

Sorts objects of any type by a numeric key you extract. Equal keys keep their input order.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut files = vec![("b.txt".to_string(), 300u64), ("a.txt".to_string(), 100)];
kwker::sort_objects_by_key(&mut files, Order::ASCENDING, |f| f.1);
assert_eq!(files[0].0, "a.txt");

sort_records_by_key Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_records_by_key<T: Copy, K: Sortable>(
    v: &mut [T],
    order: Order,
    key: impl FnMut(&T) -> K,
)

Sorts Copy records of any size by a numeric key you extract. Equal keys keep their input order.

Arguments

sort_records_stable Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_records_stable<K: Sortable, V: Copy>(r: &mut [KeyValue<K, V>])

sort_records that keeps records with equal keys in input order.

Arguments

Notes

sort_records_stable_by_order Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_records_stable_by_order<K: Sortable, V: Copy>(r: &mut [KeyValue<K, V>], order: Order)

sort_records_stable in the given order.

Arguments

sort_records Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_records<K: Sortable, V: Copy>(r: &mut [KeyValue<K, V>])

Sorts KeyValue records by key, smallest first.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::KeyValue;

let mut r = vec![KeyValue { key: 3, value: 'c' }, KeyValue { key: 1, value: 'a' }];
kwker::sort_records(&mut r);
assert_eq!(r[0].value, 'a');

Notes

sort_records_by_order Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_records_by_order<K: Sortable, V: Copy>(r: &mut [KeyValue<K, V>], order: Order)

sort_records in the given order.

Arguments

select_nth_records Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn select_nth_records<K: Sortable, V: Copy>(r: &mut [KeyValue<K, V>], k: usize, order: Order)

select_nth_kv on records: the record a full sort would put at position k moves there, with records of smaller or equal keys before it and the others after it.

Arguments

Panics

If k >= r.len().

partial_sort_records Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partial_sort_records<K: Sortable, V: Copy>(r: &mut [KeyValue<K, V>], k: usize, order: Order)

partial_sort_kv on records: puts the k records with the first keys, sorted, at the front.

Arguments

ObjectMove Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum ObjectMove {
    Auto,
    Gather,
    Cycles,
}

How sort_by_extracted_key moves the objects into their sorted places.

Variants

Masked and nullable data

top_k_masked Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_masked<T: Sortable>(
    v: &[T],
    mask: &[bool],
    k: usize,
    order: Order,
    sorted: bool,
) -> (Vec<T>, Vec<u64>)

The k first keys among the positions a mask selects, and their positions in v. No fill value or copy of the other keys is needed.

Arguments

Returns

(values, positions). Equal keys go to the earlier position first.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let (top, at) = kwker::top_k_masked(&[5, 9, 7, 8], &[true, false, true, true], 2, Order::DESCENDING, true);
assert_eq!(top, [8, 7]);
assert_eq!(at, [3, 2]);

Panics

If mask.len() != v.len().

Examples: Top-k and selection: Top-k with a filter

top_k_mask_u8 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_mask_u8<T: Sortable>(
    v: &[T],
    mask: &[u8],
    k: usize,
    order: Order,
    sorted: bool,
) -> (Vec<T>, Vec<u64>)

top_k_masked with one byte per key (nonzero takes part), as NumPy and PyTorch store bool arrays.

Arguments

top_k_valid Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_valid<T: Sortable>(
    v: &[T],
    validity: &[u8],
    k: usize,
    order: Order,
    sorted: bool,
) -> (Vec<T>, Vec<u64>)

top_k_masked with an Arrow-style validity bitmap (bit set = takes part).

Arguments

argsort_masked Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_masked<T: Sortable>(v: &[T], mask: &[bool], order: Order) -> Vec<u64>

The positions that sort the keys a mask selects, without filling the others with a sentinel or copying the array. Equal keys keep their input order.

Arguments

Returns

One position (into v) per selected key.

argsort_mask_u8 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_mask_u8<T: Sortable>(v: &[T], mask: &[u8], order: Order) -> Vec<u64>

argsort_masked with one byte per key (nonzero takes part).

Arguments

argsort_valid Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_valid<T: Sortable>(v: &[T], validity: &[u8], order: Order) -> Vec<u64>

argsort_masked with an Arrow-style validity bitmap (bit set = takes part).

Arguments

argsort_where Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_where<T: Sortable>(v: &[T], order: Order, pred: impl Fn(&T) -> bool) -> Vec<u64>

argsort_masked of the keys for which pred returns true.

Arguments

sort_masked Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_masked<T: Sortable>(v: &mut [T], mask: &[bool], order: Order)

Sorts the keys at the positions a mask selects among those positions; the other positions are left as they are.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut v = vec![9, 0, 3, 0, 1];
kwker::sort_masked(&mut v, &[true, false, true, false, true], Order::ASCENDING);
assert_eq!(v, [1, 0, 3, 0, 9]);

sort_mask_u8 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_mask_u8<T: Sortable>(v: &mut [T], mask: &[u8], order: Order)

sort_masked with one byte per key (nonzero takes part).

Arguments

sort_valid Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_valid<T: Sortable>(v: &mut [T], validity: &[u8], order: Order)

sort_masked with an Arrow-style validity bitmap (bit set = takes part).

Arguments

sort_where Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_where<T: Sortable>(v: &mut [T], order: Order, pred: impl Fn(&T) -> bool)

sort_masked of the keys for which pred returns true.

Arguments

top_k_by_group Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_by_group<T: Sortable, G: Sortable>(
    v: &[T],
    groups: &[G],
    k: usize,
    order: Order,
) -> (Vec<G>, Vec<usize>, Vec<u64>)

The k first keys of every group, for group labels in any order: SQL ROW_NUMBER() OVER (PARTITION BY g ORDER BY v) <= k.

Arguments

Returns

(labels, offsets, positions): the distinct labels, smallest first; group i's results are positions[offsets[i]..offsets[i + 1]], positions into v in order, at most k per group.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let (labels, offsets, at) = kwker::top_k_by_group(&[5, 9, 7, 8], &[1, 0, 1, 0], 1, Order::DESCENDING);
assert_eq!(labels, [0, 1]);
assert_eq!(offsets, [0, 1, 2]);
assert_eq!(at, [1, 2]);

Examples: Top-k and selection: Top-k per group

Group-by

group_codes Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn group_codes(keys: &[(&dyn KeyColumn, Order)], threads: usize) -> Groups

Numbers the groups of equal rows across one or more key columns, like pandas groupby or SQL GROUP BY. Group g is the g-th distinct key tuple in sorted order. Pass the codes to the group_* reductions.

Arguments

Returns

A Groups: each row's group code, and each group's first row and size.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::{GroupRows, Order};

let city = vec![2, 1, 2];
let sales = vec![10.0, 5.0, 2.5];
let g = kwker::group_codes(&[(&city, Order::ASCENDING)], 1);
assert_eq!(g.codes, [1, 0, 1]);
let (sum, count) = kwker::group_sum(&g.codes, g.len(), &sales, GroupRows { valid: None, skip_nan: false }, 1);
assert_eq!(sum, [5.0, 12.5]);
assert_eq!(count, [1, 2]);

Panics

If the columns have different lengths, or 2^32 rows or more.

Notes

Examples: Groups, merges and sets: Group several key columns: group_codes

group_codes_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn group_codes_into(
    keys: &[(&dyn KeyColumn, Order)],
    threads: usize,
    codes: &mut [u32],
    first: &mut [u64],
    sizes: &mut [u64],
) -> usize

group_codes into buffers you provide.

Arguments

Returns

The number of groups.

group_sum Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn group_sum<V: GroupValue>(
    codes: &[u32],
    groups: usize,
    values: &[V],
    rows: GroupRows<'_>,
    threads: usize,
) -> (Vec<V::Sum>, Vec<u64>)

The sum and the number of values in every group.

Arguments

Returns

(sums, counts), one entry per group. Sums are f64 for floats, i64 or u64 (wrapping) for integers.

Notes

group_count Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn group_count<V: GroupValue>(
    codes: &[u32],
    groups: usize,
    values: &[V],
    rows: GroupRows<'_>,
    threads: usize,
) -> Vec<u64>

The number of rows with a value in every group.

Arguments

group_min_max Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn group_min_max<V: GroupValue>(
    codes: &[u32],
    groups: usize,
    values: &[V],
    rows: GroupRows<'_>,
    max: bool,
    threads: usize,
) -> (Vec<V>, Vec<u64>)

The smallest or largest value in every group, and the number of values.

Arguments

Returns

(values, counts), one entry per group; the value of a group with count 0 is unspecified.

Notes

group_end_rows Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn group_end_rows<V: GroupValue>(
    codes: &[u32],
    groups: usize,
    values: &[V],
    rows: GroupRows<'_>,
    last: bool,
    threads: usize,
) -> Vec<u64>

The first or last row with a value in every group.

Arguments

Returns

One row number per group; NO_ROW for a group without a value.

group_median Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn group_median<V: GroupValue>(
    codes: &[u32],
    groups: usize,
    values: &[V],
    rows: GroupRows<'_>,
    threads: usize,
) -> (Vec<f64>, Vec<u64>)

The exact median of every group: the middle value, or the mean of the two middle values.

Arguments

Returns

(medians, counts), one entry per group; a group without values has median NaN.

group_quantile Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn group_quantile<V: GroupValue>(
    codes: &[u32],
    groups: usize,
    values: &[V],
    rows: GroupRows<'_>,
    q: f64,
    interp: Interpolation,
    threads: usize,
) -> (Vec<f64>, Vec<u64>)

The exact q quantile of every group, like pandas groupby().quantile(q, interpolation).

Arguments

Returns

(quantiles, counts), one entry per group; a group without values gives NaN.

Panics

If q is outside [0, 1].

Notes

group_cumsum Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn group_cumsum<V: GroupValue>(
    codes: &[u32],
    groups: usize,
    values: &[V],
    rows: GroupRows<'_>,
    out: &mut [V::Sum],
)

Each row's running sum within its group, in row order, like pandas groupby().cumsum().

Arguments

Panics

If out.len() != codes.len().

Notes

group_shift Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn group_shift<V: GroupValue>(
    codes: &[u32],
    groups: usize,
    values: &[V],
    periods: i64,
    out: &mut [f64],
)

Each row gets the value periods rows earlier in its group, like pandas groupby().shift(periods).

Arguments

Panics

If out.len() != codes.len().

group_diff Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn group_diff<V: GroupValue>(
    codes: &[u32],
    groups: usize,
    values: &[V],
    periods: i64,
    out: &mut [f64],
)

Each row's value minus the value periods rows earlier in its group, like pandas groupby().diff(periods).

Arguments

Panics

If out.len() != codes.len().

group_cumcount Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn group_cumcount(codes: &[u32], groups: usize, ascending: bool, out: &mut [u64])

Each row's position within its group, from 0, like pandas groupby().cumcount().

Arguments

Panics

If out.len() != codes.len() or a code is out of range.

group_rank Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn group_rank<V: GroupValue + Sortable>(
    codes: &[u32],
    groups: usize,
    values: &[V],
    rows: GroupRows<'_>,
    method: GroupRankMethod,
    pct: bool,
    order: Order,
    out: &mut [f64],
)

Each row's rank within its group, from 1, like pandas groupby().rank(method, ascending, pct).

Arguments

Panics

If out.len() != codes.len().

Notes

group_stats Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn group_stats<V: GroupValue>(
    codes: &[u32],
    groups: usize,
    values: &[V],
    rows: GroupRows<'_>,
    threads: usize,
) -> GroupStats<V>

The sum, count, smallest and largest value of every group, in one pass over the data.

Arguments

Returns

A GroupStats with one entry per group in each field.

run_lengths Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn run_lengths<T: Sortable>(v: &[T]) -> (Vec<T>, Vec<usize>)

Run-length encoding: each run of equal neighbouring keys and its length.

Arguments

Returns

(keys, lengths), one entry per run.

Example

RustAdd kwker to Cargo.toml, then cargo run.
let (keys, lens) = kwker::run_lengths(&[7, 7, 3, 7]);
assert_eq!(keys, [7, 3, 7]);
assert_eq!(lens, [2, 1, 1]);

group_boundaries Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn group_boundaries<T: Sortable>(sorted: &[T]) -> Vec<usize>

Where each run of equal keys starts in a sorted slice.

Arguments

Returns

The start of every run, then sorted.len(): group g is sorted[b[g]..b[g + 1]]. Empty for an empty slice.

unique_counts Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn unique_counts<T: Sortable>(v: &mut [T], order: Order) -> (Vec<T>, Vec<usize>)

Sorts v, then returns each distinct key and how often it occurs: a frequency table.

Arguments

Returns

(keys, counts), the keys in order.

sort_unique Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_unique<T: Sortable>(v: &mut [T], order: Order) -> usize

Sorts v and moves its distinct keys, in order, to the front.

Arguments

Returns

The number of distinct keys, m; they are in v[..m].

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut v = vec![3, 1, 3, 2, 1];
let m = kwker::sort_unique(&mut v, Order::ASCENDING);
assert_eq!(v[..m], [1, 2, 3]);

group_by_key Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn group_by_key<K: Sortable, V: Copy>(
    keys: &mut [K],
    values: &mut [V],
    order: Order,
) -> Vec<usize>

Groups key-value pairs by key: sorts them by key (values of equal keys keep their input order) and returns where each group starts.

Arguments

Returns

The group boundaries, as group_boundaries gives them.

reduce_by_key Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn reduce_by_key<K: Sortable, V: Reducible>(
    keys: &[K],
    values: &[V],
    op: Reduction,
    order: Order,
) -> (Vec<K>, Vec<V>)

Aggregates the values of each distinct key: a group-by with sum, min, max, first or last.

Arguments

Returns

(keys, results): each distinct key and its group's result.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::{Order, Reduction};

let (keys, totals) = kwker::reduce_by_key(&[2, 1, 2], &[10, 5, 3], Reduction::Sum, Order::ASCENDING);
assert_eq!(keys, [1, 2]);
assert_eq!(totals, [5, 13]);

Panics

If keys and values have different lengths.

Notes

Examples: Groups, merges and sets: Totals per key: reduce_by_key

mean_by_key Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn mean_by_key<K: Sortable, V: Reducible>(
    keys: &[K],
    values: &[V],
    order: Order,
) -> (Vec<K>, Vec<f64>)

The mean of the values of each distinct key.

Arguments

Returns

(keys, means); each mean sums its values as f64 in input order.

count_by_key Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn count_by_key<K: Sortable>(keys: &[K], order: Order) -> (Vec<K>, Vec<u64>)

How often each distinct key occurs, without changing keys.

Arguments

Returns

(keys, counts).

Examples: Groups, merges and sets: Totals per key: reduce_by_key

reduce_by_key_with Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn reduce_by_key_with<K: Sortable, V: Copy, A>(
    keys: &[K],
    values: &[V],
    order: Order,
    init: impl FnMut(&V) -> A,
    fold: impl FnMut(&mut A, &V),
) -> (Vec<K>, Vec<A>)

Your own aggregation per distinct key: init starts a group from its first value, fold adds the next ones, in input order.

Arguments

Returns

(keys, accumulators).

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

// the largest value and the count, per key
let (keys, acc) = kwker::reduce_by_key_with(&[1, 2, 1], &[4, 9, 6], Order::ASCENDING,
    |&v| (v, 1), |a, &v| { a.0 = a.0.max(v); a.1 += 1; });
assert_eq!(keys, [1, 2]);
assert_eq!(acc, [(6, 2), (9, 1)]);

NO_GROUP Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const NO_GROUP: u32 = u32::MAX;

The group code of a row that belongs to no group; reductions skip such rows.

NO_ROW Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const NO_ROW: u64 = u64::MAX;

The row number group_end_rows gives a group without a row that has a value.

Groups Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct Groups {
    pub codes: Vec<u32>,
    pub first: Vec<u64>,
    pub sizes: Vec<u64>,
}

The groups of a table's rows, from group_codes.

Fields

Groups::len Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn len(&self) -> usize

The number of groups.

Groups::is_empty Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn is_empty(&self) -> bool

No rows, no groups.

GroupValue Page

RustAdd kwker to Cargo.toml, then cargo run.
pub trait GroupValue: Copy + Send + Sync + PartialOrd + 'static {
    type Sum;
}

The value types the group reductions accept: the integer and float types.

GroupRows Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct GroupRows<'a> {
    pub valid: Option<&'a [u8]>,
    pub skip_nan: bool,
}

Which rows a group reduction reads.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::GroupRows;

// every row has a value, and NaN counts as no value (as pandas does)
let rows = GroupRows { valid: None, skip_nan: true };

Fields

GroupRankMethod Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum GroupRankMethod {
    Average,
    Min,
    Max,
    First,
    Dense,
}

How group_rank ranks equal values, as pandas groupby().rank(method=...).

Variants

GroupStats Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct GroupStats<V: GroupValue> {
    pub sum: Vec<V::Sum>,
    pub count: Vec<u64>,
    pub numbers: Vec<u64>,
    pub min: Vec<V>,
    pub max: Vec<V>,
}

The results of group_stats, one entry per group in each field.

Fields

Reduction Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum Reduction {
    Sum,
    Min,
    Max,
    First,
    Last,
}

The built-in aggregations of reduce_by_key.

Variants

Reducible Page

RustAdd kwker to Cargo.toml, then cargo run.
pub trait Reducible: Sortable { }

The value types reduce_by_key accepts: the integer and float types.

Rolling windows

median_filter3x3 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn median_filter3x3<T: WindowKey>(
    src: &[T],
    planes: usize,
    h: usize,
    w: usize,
    pad: WindowPad,
    out: &mut [T],
)

A 3 x 3 median filter over images or other 2-D planes, like kornia.filters.median_blur: each output value is the median of the 3 x 3 window around the input value.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::{median_filter3x3, WindowPad};
let img = [1u8, 9, 2, 8, 3, 7, 4, 6, 5];
let mut out = [0u8; 9];
median_filter3x3(&img, 1, 3, 3, WindowPad::Replicate, &mut out);
assert_eq!(out[4], 5);

Notes

median_filter3x3_backward Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn median_filter3x3_backward<T: WindowGrad>(
    src: &[T],
    out: &[T],
    grad_out: &[T],
    planes: usize,
    h: usize,
    w: usize,
    pad: WindowPad,
    grad_in: &mut [T],
)

The gradient of median_filter3x3: each output's gradient goes to the input value its median came from, as with the index torch.median returns.

Arguments

median_filter5x5 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn median_filter5x5<T: WindowKey>(
    src: &[T],
    planes: usize,
    h: usize,
    w: usize,
    pad: WindowPad,
    out: &mut [T],
)

A 5 x 5 median filter, as median_filter3x3.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::{median_filter5x5, WindowPad};
let img: Vec<u8> = (0..25).map(|i| (i * 7 % 25) as u8).collect();
let mut out = vec![0u8; 25];
median_filter5x5(&img, 1, 5, 5, WindowPad::Replicate, &mut out);
assert_eq!(out[12], 12);

Notes

median_filter5x5_backward Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn median_filter5x5_backward<T: WindowGrad>(
    src: &[T],
    out: &[T],
    grad_out: &[T],
    planes: usize,
    h: usize,
    w: usize,
    pad: WindowPad,
    grad_in: &mut [T],
)

The gradient of median_filter5x5, as median_filter3x3_backward.

Arguments

median_filter7x7 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn median_filter7x7<T: WindowKey>(
    src: &[T],
    planes: usize,
    h: usize,
    w: usize,
    pad: WindowPad,
    out: &mut [T],
)

A 7 x 7 median filter, as median_filter3x3.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::{median_filter7x7, WindowPad};
let img: Vec<u8> = (0..49).map(|i| (i * 10 % 49) as u8).collect();
let mut out = vec![0u8; 49];
median_filter7x7(&img, 1, 7, 7, WindowPad::Replicate, &mut out);
assert_eq!(out[24], 24);

Notes

median_filter7x7_backward Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn median_filter7x7_backward<T: WindowGrad>(
    src: &[T],
    out: &[T],
    grad_out: &[T],
    planes: usize,
    h: usize,
    w: usize,
    pad: WindowPad,
    grad_in: &mut [T],
)

The gradient of median_filter7x7, as median_filter3x3_backward.

Arguments

rolling_quantile Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn rolling_quantile<T: Reducible>(
    src: &[T],
    window: usize,
    q: f64,
    interp: Interpolation,
    out: &mut [f64],
)

A rolling quantile: out[i] is the q quantile of the last window values up to src[i], like pandas Series.rolling(window).quantile(q).

Arguments

Panics

If window is 0, q is outside [0, 1], or out.len() != src.len().

Notes

Examples: Top-k and selection: Medians and quantiles over a sliding window

rolling_median Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn rolling_median<T: Reducible>(src: &[T], window: usize, out: &mut [f64])

A rolling median, like pandas Series.rolling(window).median() and bottleneck's move_median. For an even window, the mean of the two middle values.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
let mut out = vec![0.0; 5];
kwker::rolling_median(&[1, 9, 2, 8, 3], 3, &mut out);
assert!(out[0].is_nan() && out[1].is_nan());
assert_eq!(out[2..], [2.0, 8.0, 3.0]);

Examples: Top-k and selection: Medians and quantiles over a sliding window

rolling_mad Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn rolling_mad<T: Reducible>(src: &[T], window: usize, out: &mut [f64])

A rolling median absolute deviation: for the last window values, the median of |x - m|, m being their median. Robust outlier filters (Hampel filters) use it.

Arguments

Panics

If window is 0 or out.len() != src.len().

Notes

Examples: Top-k and selection: Medians and quantiles over a sliding window

expanding_quantile Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn expanding_quantile<T: Reducible>(src: &[T], q: f64, interp: Interpolation, out: &mut [f64])

An expanding quantile: out[i] is the q quantile of all values up to src[i], like pandas Series.expanding().quantile(q).

Arguments

Panics

If q is outside [0, 1], out.len() != src.len(), or the length does not fit u32.

Notes

expanding_median Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn expanding_median<T: Reducible>(src: &[T], out: &mut [f64])

An expanding median, like pandas Series.expanding().median(): for an even count, the mean of the two middle values.

Arguments

rank_filter Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn rank_filter<T: WindowKey>(
    src: &[T],
    planes: usize,
    h: usize,
    w: usize,
    k: usize,
    rank: usize,
    out: &mut [T],
)

A k x k rank filter over valid windows (k 3, 5 or 7): every output is the key of rank rank (0 = the smallest, k * k - 1 the largest) among the k x k input keys of its window - minimum, percentile, median and maximum filters of images.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
let img: Vec<u8> = (0..16).collect();
let mut out = vec![0u8; 4];
kwker::rank_filter(&img, 1, 4, 4, 3, 0, &mut out); // the minimum of every 3 x 3 window
assert_eq!(out, [0, 1, 4, 5]);

Notes

Panics

If k is not 3, 5 or 7, rank >= k * k, a plane is smaller than k x k, or a slice length does not match.

WindowPad Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum WindowPad {
    Reflect,
    Replicate,
    Zeros,
    Valid,
}

What the median filters see past the edges of a plane.

Variants

WindowKey Page

RustAdd kwker to Cargo.toml, then cargo run.
pub trait WindowKey: Copy + PartialOrd + Default + Send + Sync + Sealed + 'static { }

The value types of the median filters: the 8- to 64-bit integers, f32 and f64.

WindowGrad Page

RustAdd kwker to Cargo.toml, then cargo run.
pub trait WindowGrad: WindowKey + Add<Output = Self> { }

The value types of the median filters' gradients: f32 and f64.

Statistics

cdf_distance_f64 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn cdf_distance_f64(a: &[f64], b: &[f64], kind: CdfDistance) -> f64

How far apart two samples' distributions are: SciPy's two-sample Kolmogorov-Smirnov statistic, wasserstein_distance or energy_distance (unweighted).

Arguments

Returns

The distance; NaN if a sample is empty or holds a NaN.

Notes

cdf_distance_f32 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn cdf_distance_f32(a: &[f32], b: &[f32], kind: CdfDistance) -> f64

How far apart two samples' distributions are: SciPy's two-sample Kolmogorov-Smirnov statistic, wasserstein_distance or energy_distance (unweighted).

Arguments

Returns

The distance; NaN if a sample is empty or holds a NaN.

Notes

histogram_f32 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn histogram_f32(x: &[f32], lo: f64, hi: f64, out: &mut [u64])

Counts values in equal-width bins, like np.histogram(x, bins, range=(lo, hi)), bin for bin.

Arguments

Panics

If out is empty, or lo or hi is not finite, or lo > hi.

Notes

histogram_f64 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn histogram_f64(x: &[f64], lo: f64, hi: f64, out: &mut [u64])

Counts values in equal-width bins, like np.histogram(x, bins, range=(lo, hi)), bin for bin.

Arguments

Panics

If out is empty, or lo or hi is not finite, or lo > hi.

Notes

average_precision Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn average_precision<T: Sortable>(scores: &[T], positive: &[u8]) -> f64

The average precision of a binary classifier's scores, like scikit-learn's average_precision_score.

Arguments

Returns

The average precision; NaN if a score is NaN, 0.0 if no example is positive.

Panics

If positive.len() != scores.len().

roc_auc Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn roc_auc<T: Sortable>(scores: &[T], positive: &[u8]) -> f64

The area under the ROC curve of a binary classifier's scores, like scikit-learn's roc_auc_score: the chance that a random positive scores above a random negative, ties counting half.

Arguments

Returns

The area, between 0 and 1; NaN if a score is NaN or one class is missing.

Example

RustAdd kwker to Cargo.toml, then cargo run.
let auc = kwker::roc_auc(&[0.9f32, 0.2, 0.7, 0.4], &[1, 0, 1, 0]);
assert_eq!(auc, 1.0);

Panics

If positive.len() != scores.len().

trim_mean Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn trim_mean<T: Reducible>(
    data: &[T],
    shape: &[usize],
    axis: usize,
    proportion: f64,
    out: &mut [f64],
)

The trimmed mean of every lane along axis, like scipy.stats.trim_mean: the mean without the floor(proportion * n) smallest and as many largest values.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
let mut out = [0.0];
kwker::trim_mean(&[1, 2, 3, 4, 100], &[5], 0, 0.2, &mut out);
assert_eq!(out[0], 3.0);

Panics

If the shape does not match, axis is out of range, out does not hold one value per lane, or proportion cuts more than all values.

Notes

weighted_quantile Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn weighted_quantile<T: Reducible, W: Reducible>(a: &[T], w: &[W], qs: &[f64], out: &mut [T])

Weighted quantiles, like NumPy's np.quantile(a, qs, weights=w, method="inverted_cdf"), value for value.

Arguments

Panics

If a is empty, w.len() != a.len(), or out.len() != qs.len().

Notes

CdfDistance Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum CdfDistance {
    KolmogorovSmirnov,
    Wasserstein,
    Energy,
}

Which distance cdf_distance_f64 and cdf_distance_f32 compute.

Variants

CdfDistance::terms_f64 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn terms_f64(a: &[f64], b: &[f64], squared: bool, terms: &mut [f64], deltas: &mut [f64]) -> bool

The two arrays SciPy's _cdf_distance reduces, for the pooled sorted values all of both samples: the CDF difference at each value but the last (|F_a - F_b|, or its square) and the gap to the next value - the same float64 operations as SciPy (searchsorted(side="right") / size, np.diff), so the caller's reduction of the two arrays gives SciPy's result bit for bit.

Arguments

Returns

false (nothing written) when a sample is empty or holds a NaN, or an output has another length.

Language-model sampling

top_n_sigma_rows Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_n_sigma_rows(x: &[f32], cols: usize, n: f32, fill: f32, out: &mut [f32])

Top-n-sigma sampling filter: in each row of logits, every logit below max - n * std becomes fill.

Arguments

Notes

min_p_rows Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn min_p_rows(x: &[f32], cols: usize, p: f32, fill: f32, out: &mut [f32])

Min-p sampling filter: in each row of logits, every logit whose probability is below p times the top probability becomes fill.

Arguments

top_k_filter_rows Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_filter_rows(x: &[f32], cols: usize, ks: &[u64], fill: f32, out: &mut [f32])

Top-k sampling filter with a k per row, like vLLM's apply_top_k_only: in each row, every logit below the row's k-th largest becomes fill.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
let mut out = [0.0f32; 4];
kwker::top_k_filter_rows(&[1.0, 4.0, 3.0, 2.0], 4, &[2], f32::NEG_INFINITY, &mut out);
assert_eq!(out, [f32::NEG_INFINITY, 4.0, 3.0, f32::NEG_INFINITY]);

Notes

top_p_rows Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_p_rows<T: Logit>(
    logits: &[T],
    row_len: usize,
    p: f64,
    ids: &mut Vec<u32>,
    ends: &mut Vec<usize>,
)

Nucleus (top-p) sampling: for each row of logits, the tokens with the highest probabilities whose total first reaches p, as Hugging Face and vLLM choose them.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
let (mut ids, mut ends) = (Vec::new(), Vec::new());
kwker::top_p_rows(&[0.0f32, 5.0, 4.0, -3.0], 4, 0.9, &mut ids, &mut ends);
assert_eq!(ids, [1, 2]);
assert_eq!(ends, [2]);

Panics

If row_len is 0 or does not divide logits.len(), row_len is 2^32 or more, or p is not above 0.

Notes

Logit Page

RustAdd kwker to Cargo.toml, then cargo run.
pub trait Logit: Sortable { }

The logit types top_p_rows accepts: f32 and f64.

As-of lookups

asof_indices Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn asof_indices(
    left_t: &[i64],
    right_t: &[i64],
    by: Option<(&[i64], &[i64])>,
    dir: AsofDirection,
    out: &mut [i64],
)

An as-of join: for each left row, the right row with the nearest earlier (or later) time, like pandas merge_asof and Polars join_asof.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::AsofDirection;

let mut out = [0i64; 2];
kwker::asof_indices(&[5, 12], &[0, 10, 20], None, AsofDirection::Backward, &mut out);
assert_eq!(out, [0, 1]);

Panics

If out.len() != left_t.len() or a by column's length differs from its side's times.

AsofDirection Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum AsofDirection {
    Backward,
    Forward,
    Nearest,
}

Which right row an as-of join matches.

Variants

Strings and bytes

sort_bytes Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_bytes<S: AsRef<[u8]>>(v: &mut [S])

Sorts strings in place in byte order; for UTF-8 text that is code point order.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
let mut v = vec!["pear", "apple", "fig"];
kwker::sort_bytes(&mut v);
assert_eq!(v, ["apple", "fig", "pear"]);

Notes

argsort_bytes Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_bytes<S: AsRef<[u8]>>(v: &[S]) -> Permutation

The order that sorts strings in byte order, without moving them. Equal strings keep their input order.

Arguments

Returns

A Permutation: apply it to the strings or to data that belongs to them.

collation_key Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn collation_key(s: &[u8], c: Collation, out: &mut Vec<u8>)

Appends the sort key of s under c to out: plain byte order of the keys is the collation's order.

Arguments

unique_strings Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn unique_strings<S: AsRef<[u8]>>(v: &[S], c: Collation) -> Vec<u64>

The distinct strings under a collation, in sorted order.

Arguments

Returns

The input position of each distinct string's first occurrence, in sorted order.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Collation;

let at = kwker::unique_strings(&["b", "A", "a", "B"], Collation::AsciiCaseless);
assert_eq!(at, [1, 0]);

argsort_strings Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_strings<S: AsRef<[u8]>>(v: &[S], c: Collation) -> Permutation

The order that sorts strings under a collation, without moving them. Equal strings keep their input order.

Arguments

Returns

A Permutation: the input positions in sorted order.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Collation;

let p = kwker::argsort_strings(&["file10", "file2", "file1"], Collation::Natural);
assert_eq!(p.as_slice(), [2, 1, 0]);

Examples: Strings: The order of strings

argsort_ucs4 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_ucs4(data: &[u32], width: usize, c: Collation) -> Permutation

The order of fixed-width UCS-4 strings (NumPy 'U' arrays) under a collation. Equal strings keep their input order.

Arguments

Returns

A Permutation: the input positions in sorted order.

sort_strings Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_strings<S: AsRef<[u8]>>(v: &mut [S], c: Collation)

Sorts strings in place under a collation. Equal strings keep their input order.

Arguments

Examples: Strings: Sort a list of strings

argsort_strings_table Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_strings_table<S: AsRef<[u8]>>(v: &[S], weights: &[u8; 256]) -> Permutation

The order of strings under a custom character order given as byte weights, like a COBOL ALPHABET clause. Strings compare by their bytes' weights, a prefix first.

Arguments

Returns

A Permutation; strings with equal weights keep their input order.

sort_strings_table Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_strings_table<S: AsRef<[u8]>>(v: &mut [S], weights: &[u8; 256])

Sorts strings in place under byte weights, as argsort_strings_table orders them.

Arguments

sort_by_string_key Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_by_string_key<T, S: AsRef<[u8]>>(v: &mut [T], c: Collation, key: impl FnMut(&T) -> S)

Sorts objects of any type by a string key you extract, such as a name field or a path. Equal keys keep their input order.

Arguments

Notes

sort_by_comparator Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_by_comparator<T>(v: &mut [T], cmp: impl FnMut(&T, &T) -> Ordering)

Sorts with a comparison function, for orders no key can express. This is Rust's standard stable sort.

Arguments

Notes

Collation Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum Collation {
    Bytes,
    AsciiCaseless,
    Natural,
    NaturalCaseless,
}

A string order: plain bytes, ASCII without case, or natural order with numbers by value.

Variants

TABLE_EBCDIC_037 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const TABLE_EBCDIC_037: [u8; 256] = _;

Byte weights for argsort_strings_table that sort ASCII (Latin-1) text in IBM EBCDIC code page 037 order, a mainframe's order: space, punctuation, lowercase, uppercase, then digits.

TABLE_FROM_EBCDIC_037 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const TABLE_FROM_EBCDIC_037: [u8; 256] = _;

The reverse of TABLE_EBCDIC_037: byte weights that sort EBCDIC 037 bytes in Latin-1 (ASCII) order.

Packed int4

sort_int4_packed Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_int4_packed(data: &mut [u8], n: usize, signed: bool, order: Order)

Sorts 4-bit integers packed two per byte (low nibble first) in place.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut d = kwker::pack_int4(&[9, 2, 7, 1]);
kwker::sort_int4_packed(&mut d, 4, false, Order::ASCENDING);
assert_eq!(kwker::unpack_int4(&d, 4), [1, 2, 7, 9]);

Panics

If data holds fewer than n.div_ceil(2) bytes.

argsort_int4_packed Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_int4_packed(data: &[u8], n: usize, signed: bool, order: Order) -> Vec<u32>

The positions that sort packed 4-bit integers. Equal values keep their input order.

Arguments

Returns

One position per value.

Panics

If data holds fewer than n.div_ceil(2) bytes or n exceeds u32::MAX.

top_k_int4_packed Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_int4_packed(data: &[u8], n: usize, k: usize, signed: bool, order: Order) -> Vec<u32>

The positions of the k first packed 4-bit integers in order, without sorting them all.

Arguments

Returns

The positions, in order; equal values in input order.

Panics

If data holds fewer than n.div_ceil(2) bytes or n exceeds u32::MAX.

pack_int4 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn pack_int4(values: &[u8]) -> Vec<u8>

Packs 4-bit values two per byte, low nibble first; each value keeps its low 4 bits.

Arguments

Returns

values.len().div_ceil(2) bytes.

unpack_int4 Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn unpack_int4(data: &[u8], n: usize) -> Vec<u8>

Unpacks the first n 4-bit values of data, one per byte (0..=15; signed values as their low 4 bits).

Arguments

Sparse arrays

coo_coalesce Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn coo_coalesce<I: Index, V: SparseValue>(
    rows: &[I],
    cols: &[I],
    vals: &[V],
    shape: (usize, usize),
    reduce: Reduce,
) -> Result<(Vec<I>, Vec<I>, Vec<V>), SparseError>

Sorts sparse coordinates (COO format) row by row and combines duplicates, like scipy.sparse's sum_duplicates.

Arguments

Returns

(rows, cols, vals), sorted by row, then column, each coordinate once; or a SparseError.

Notes

coo_to_csr Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn coo_to_csr<I: Index, V: SparseValue>(
    rows: &[I],
    cols: &[I],
    vals: &[V],
    shape: (usize, usize),
    reduce: Reduce,
) -> Result<(Vec<I>, Vec<I>, Vec<V>), SparseError>

Converts sparse coordinates (COO) to compressed rows (CSR), combining duplicates, like scipy.sparse's tocsr().

Arguments

Returns

(indptr, indices, data): row i's columns, ascending, are indices[indptr[i]..indptr[i + 1]] and its values the same range of data; or a SparseError.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Reduce;

let (indptr, indices, data) =
    kwker::coo_to_csr(&[0u32, 1, 0], &[1u32, 0, 1], &[1.0f64, 2.0, 3.0], (2, 2), Reduce::Sum).unwrap();
assert_eq!(indptr, [0, 1, 2]);
assert_eq!(indices, [1, 0]);
assert_eq!(data, [4.0, 2.0]);

coo_to_csc Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn coo_to_csc<I: Index, V: SparseValue>(
    rows: &[I],
    cols: &[I],
    vals: &[V],
    shape: (usize, usize),
    reduce: Reduce,
) -> Result<(Vec<I>, Vec<I>, Vec<V>), SparseError>

Converts sparse coordinates (COO) to compressed columns (CSC), combining duplicates.

Arguments

Returns

(indptr, indices, data): column j's rows, ascending, are indices[indptr[j]..indptr[j + 1]]; or a SparseError.

csr_to_csc Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn csr_to_csc<I: Index + Sync, V: Copy + Send + Sync>(
    indptr: &[I],
    indices: &[I],
    data: &[V],
    shape: (usize, usize),
) -> Result<(Vec<I>, Vec<I>, Vec<V>), SparseError>

Converts compressed rows (CSR) to compressed columns (CSC) without a sort. Duplicates are kept.

Arguments

Returns

(colptr, rows, data): column j's rows, ascending, are rows[colptr[j]..colptr[j + 1]]; or a SparseError.

csr_to_csc_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn csr_to_csc_into<I: Index + Sync, V: Copy + Send + Sync>(
    indptr: &[I],
    indices: &[I],
    data: &[V],
    shape: (usize, usize),
    colptr: &mut [I],
    rows: &mut [I],
    out: &mut [V],
) -> Result<(), SparseError>

csr_to_csc into buffers you provide.

Arguments

csr_to_csc_mt Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn csr_to_csc_mt<I: Index + Sync, V: Copy + Send + Sync>(
    indptr: &[I],
    indices: &[I],
    data: &[V],
    shape: (usize, usize),
    threads: usize,
) -> Result<(Vec<I>, Vec<I>, Vec<V>), SparseError>

csr_to_csc on several threads; the result is the same.

Arguments

csr_to_csc_into_mt Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn csr_to_csc_into_mt<I: Index + Sync, V: Copy + Send + Sync>(
    indptr: &[I],
    indices: &[I],
    data: &[V],
    shape: (usize, usize),
    colptr: &mut [I],
    rows: &mut [I],
    out: &mut [V],
    threads: usize,
) -> Result<(), SparseError>

csr_to_csc_into on several threads; the result is the same.

Arguments

csc_to_csr Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn csc_to_csr<I: Index + Sync, V: Copy + Send + Sync>(
    colptr: &[I],
    rows: &[I],
    data: &[V],
    shape: (usize, usize),
) -> Result<(Vec<I>, Vec<I>, Vec<V>), SparseError>

Converts compressed columns (CSC) to compressed rows (CSR) without a sort.

Arguments

Returns

(indptr, cols, data); or a SparseError.

csc_to_csr_mt Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn csc_to_csr_mt<I: Index + Sync, V: Copy + Send + Sync>(
    colptr: &[I],
    rows: &[I],
    data: &[V],
    shape: (usize, usize),
    threads: usize,
) -> Result<(Vec<I>, Vec<I>, Vec<V>), SparseError>

csc_to_csr on several threads; the result is the same.

Arguments

Reduce Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum Reduce {
    Sum,
    Prod,
    Min,
    Max,
    Mean,
}

How duplicate coordinates combine.

Variants

SparseValue Page

RustAdd kwker to Cargo.toml, then cargo run.
pub trait SparseValue: Copy + Sealed { }

The value types of the sparse operations: the integer and float types.

SparseError Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum SparseError {
    Lengths,
    OutOfRange,
    ShapeTooLarge,
    IndexTooNarrow,
}

Why a sparse operation refused its arguments.

Variants

Apache Arrow

arrow_argsort Page

RustAdd kwker to Cargo.toml, then cargo run.
pub unsafe fn arrow_argsort(
    schema: &ArrowSchema,
    array: &ArrowArray,
    options: ArrowSortOptions,
) -> Result<Vec<u64>, ArrowError>

The order that sorts an Apache Arrow array, read in place through the Arrow C data interface: what pyarrow.compute.array_sort_indices returns.

Arguments

Returns

One row position per row, or an ArrowError for an invalid or unsupported array.

Safety

schema and array must be live (not released) C data interface structures describing the same array, with buffers as long as their format, length and offset imply.

Notes

arrow_argsort_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub unsafe fn arrow_argsort_into(
    schema: &ArrowSchema,
    array: &ArrowArray,
    options: ArrowSortOptions,
    out: &mut [u64],
) -> Result<(), ArrowError>

arrow_argsort into a buffer you provide.

Arguments

Panics

If out's length differs from the array's.

Safety

As arrow_argsort.

arrow_top_k Page

RustAdd kwker to Cargo.toml, then cargo run.
pub unsafe fn arrow_top_k(
    schema: &ArrowSchema,
    array: &ArrowArray,
    k: usize,
    options: ArrowSortOptions,
) -> Result<Vec<u64>, ArrowError>

The first k rows of arrow_argsort's order without sorting every row, like SQL ORDER BY ... LIMIT k.

Arguments

Returns

The row positions, in order, or an ArrowError.

Safety

As arrow_argsort.

arrow_top_k_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub unsafe fn arrow_top_k_into(
    schema: &ArrowSchema,
    array: &ArrowArray,
    options: ArrowSortOptions,
    out: &mut [u64],
) -> Result<(), ArrowError>

arrow_top_k into a buffer you provide; k is out.len(), at most the array's length.

Arguments

Safety

As arrow_argsort.

arrow_argsort_chunks_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub unsafe fn arrow_argsort_chunks_into(
    schema: &ArrowSchema,
    arrays: &[&ArrowArray],
    options: ArrowSortOptions,
    out: &mut [u64],
) -> Result<(), ArrowError>

arrow_argsort of a chunked array (a pyarrow ChunkedArray, or a stream's batches) as one array, without combining the chunks first.

Arguments

Returns

Ok(()), or an ArrowError; types not supported here are Unsupported (combine the chunks, then call arrow_argsort).

Safety

schema must describe every chunk, and each chunk must be a live structure as for arrow_argsort.

arrow_dense_ranks Page

RustAdd kwker to Cargo.toml, then cargo run.
pub unsafe fn arrow_dense_ranks(
    schema: &ArrowSchema,
    array: &ArrowArray,
    ranks: &mut [u32],
) -> Result<usize, ArrowError>

Dense ranks of a string or binary Arrow array: each row's rank among the distinct values in byte order. Group-by keys use this.

Arguments

Returns

The number of distinct values, or Unsupported for other types.

Panics

If ranks' length differs from the array's.

Safety

As arrow_argsort.

arrow_dense_ranks_mt Page

RustAdd kwker to Cargo.toml, then cargo run.
pub unsafe fn arrow_dense_ranks_mt(
    schema: &ArrowSchema,
    array: &ArrowArray,
    threads: usize,
    ranks: &mut [u32],
) -> Result<usize, ArrowError>

arrow_dense_ranks on several threads; the ranks are the same.

Arguments

Safety

As arrow_argsort.

ArrowSchema Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct ArrowSchema {
    pub format: *const c_char,
    pub name: *const c_char,
    pub metadata: *const c_char,
    pub flags: i64,
    pub n_children: i64,
    pub children: *mut *mut ArrowSchema,
    pub dictionary: *mut ArrowSchema,
    pub release: Option<unsafe fn(*mut ArrowSchema)>,
    pub private_data: *mut c_void,
}

The Arrow C data interface's schema (struct ArrowSchema), as an exporter (pyarrow, arrow-rs, Arrow C++, DuckDB, Polars) fills it. The fields are the specification's (arrow.apache.org/docs/format/CDataInterface.html).

ArrowArray Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct ArrowArray {
    pub length: i64,
    pub null_count: i64,
    pub offset: i64,
    pub n_buffers: i64,
    pub n_children: i64,
    pub buffers: *mut *const c_void,
    pub children: *mut *mut ArrowArray,
    pub dictionary: *mut ArrowArray,
    pub release: Option<unsafe fn(*mut ArrowArray)>,
    pub private_data: *mut c_void,
}

The Arrow C data interface's array (struct ArrowArray); the fields are the specification's.

ArrowSortOptions Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct ArrowSortOptions {
    pub descending: bool,
    pub nulls_first: bool,
    pub by_codes: bool,
}

How arrow_argsort and arrow_top_k order rows. The default is ascending, nulls last, dictionaries by value.

Fields

ArrowError Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum ArrowError {
    Invalid(&'static str),
    Unsupported(String),
}

Why an Arrow array could not be ordered.

Variants

Files larger than memory

sort_file Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_file<T: Sortable + Send + Sync>(
    input: &Path,
    output: &Path,
    opts: &ExternalSort,
) -> Result<ExternalStats>

Sorts a binary file of numbers into another file, using a fixed amount of memory: files larger than memory work.

Arguments

Returns

What the sort did (see ExternalStats), or an I/O error.

Notes

Examples: Large data: Sort a file larger than memory

sort_file_with Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_file_with<T: Sortable + Send + Sync>(
    input: &Path,
    output: &Path,
    opts: &ExternalSort,
    ctl: &Control<'_>,
) -> Result<ExternalStats>

sort_file with cancellation and progress reports (see Control).

Arguments

Returns

As sort_file; a cancelled sort returns an error of kind Interrupted.

sort_file_records Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_file_records<K: Sortable>(
    input: &Path,
    output: &Path,
    record_size: usize,
    key_offset: usize,
    opts: &ExternalSort,
) -> Result<ExternalStats>

Sorts a file of fixed-size records by a numeric key field, using a fixed amount of memory. Records with equal keys keep their file order.

Arguments

Returns

What the sort did (see ExternalStats), or an error: InvalidInput when the key does not fit in a record, InvalidData when the file is not a whole number of records, or an I/O error.

Notes

sort_file_records_with Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_file_records_with<K: Sortable>(
    input: &Path,
    output: &Path,
    record_size: usize,
    key_offset: usize,
    opts: &ExternalSort,
    ctl: &Control<'_>,
) -> Result<ExternalStats>

sort_file_records with cancellation and progress reports (see Control), counted in records.

Arguments

ExternalSort Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct ExternalSort {
    pub memory: usize,
    pub temp_dir: Option<PathBuf>,
    pub order: Order,
    pub threads: usize,
    pub sync: bool,
}

Options of sort_file and sort_file_records. ExternalSort::default() uses 256 MiB, ascending order, one thread.

Fields

ExternalStats Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct ExternalStats {
    pub keys: u64,
    pub runs: usize,
    pub merge_passes: usize,
    pub bytes_spilled: u64,
    pub read_time: Duration,
    pub sort_time: Duration,
    pub merge_time: Duration,
    pub write_time: Duration,
}

What sort_file did: sizes and where the time went.

Fields

Distributed sorting

dist::sample Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sample<T: Sortable>(v: &[T], m: usize, base: u64, seed: u64) -> Vec<Splitter<T>>

A stratified random sample of m elements of v: one element at a random index in each of m equal strata (deterministic for a seed), with positions base + index. All of v when m >= v.len().

dist::sample_sorted Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sample_sorted<T: Sortable>(sorted: &[T], m: usize, base: u64) -> Vec<Splitter<T>>

The regular sample of locally sorted data (PSRS): the m elements at ranks (j + 1) n / (m + 1), positions base + index. All of sorted when m >= sorted.len().

Splitter Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct Splitter<T> {
    pub key: T,
    pub pos: u64,
}

A splitter: a key and the position that breaks ties between equal keys (see the module documentation).

Fields

PartitionDesc Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct PartitionDesc<T> {
    pub index: usize,
    pub lo: Option<Splitter<T>>,
    pub hi: Option<Splitter<T>>,
    pub order: Order,
}

One partition of a Partitioning: the (key, position) range [lo, hi) (None: unbounded on that side). A worker given only its descriptor can tell which elements are its own (PartitionDesc::contains).

Fields

PartitionDesc::contains Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn contains(&self, key: T, pos: u64) -> bool

Whether the element (key, pos) belongs to this partition.

dist::DistError Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum DistError {
    Malformed,
    WrongType(String),
    Unordered,
}

Why Partitioning::from_bytes refused its input.

Variants

Partitioning Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct Partitioning<T: Sortable> {
    /* private fields */
}

Splits a key space into parts ranges for distributed sorting: build it once from a sample of every worker's data (or from exact quantiles), send it to the workers, and each worker sends its elements in partition j to worker j. After every worker sorts what it received, the partitions concatenated in order are sorted.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::{Order, Partitioning};

let p = Partitioning::exact(&[50, 10, 40, 20, 30, 60], 3, 0, Order::ASCENDING);
assert_eq!(p.parts(), 3);
assert_eq!(p.counts(&[50, 10, 40, 20, 30, 60], 0), [2, 2, 2]);

Notes

Partitioning::from_sample Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn from_sample(sample: &[Splitter<T>], parts: usize, order: Order) -> Self

The partitioning whose splitters are the elements of rank j * len / parts (j = 1 .. parts) of sample (gathered from every worker), by (key, position) in order: near-equal partitions to the sample's accuracy. An empty sample gives one partition. Panics if parts is 0.

Partitioning::exact Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn exact(v: &[T], parts: usize, base: u64, order: Order) -> Self

Partitions with exactly balanced sizes: each of the parts partitions gets floor(n / parts) or ceil(n / parts) elements of v, whatever the duplicates.

Arguments

Panics

If parts is 0. An empty v gives one partition.

Partitioning::from_splitters Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn from_splitters(s: Vec<Splitter<T>>, order: Order) -> Result<Self, DistError>

The partitioning with these splitters (in order by (key, position) in order; equal ones give empty partitions), DistError::Unordered otherwise.

Partitioning::parts Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn parts(&self) -> usize

The number of partitions (splitters + 1).

Partitioning::splitters Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn splitters(&self) -> &[Splitter<T>]

The splitters.

Partitioning::order Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn order(&self) -> Order

The order.

Partitioning::part_of Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn part_of(&self, key: T, pos: u64) -> usize

The partition of the element (key, pos).

Partitioning::classify Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn classify(&self, v: &[T], base: u64, out: &mut [u32])

The partition of each element of v (positions base + index) into out (as long as v).

Partitioning::counts Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn counts(&self, v: &[T], base: u64) -> Vec<usize>

The number of elements of v (positions base + index) in each partition.

Partitioning::partition Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partition(&self, v: &mut [T], base: u64) -> Vec<usize>

Reorders v (positions base + index, taken before the reordering) by partition, in place, and returns the partition boundaries (parts() + 1 offsets: 0, ..., v.len()). Unordered inside a partition. Scratch: 4 bytes per element.

Partitioning::partition_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partition_into(&self, v: &[T], base: u64, out: &mut [T]) -> Vec<usize>

The elements of v (positions base + index) by partition into out (as long as v), stably (input order inside a partition); returns the partition boundaries.

Partitioning::partition_indices Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partition_indices(&self, v: &[T], base: u64) -> (Vec<u64>, Vec<usize>)

The indices of v's elements (positions base + index) grouped by partition, stably (ascending inside a partition), and the partition boundaries: send indices[off[j]..off[j + 1]] (keys, payloads, records) to worker j.

Partitioning::partition_indices_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partition_indices_into(&self, v: &[T], base: u64, ix: &mut [u64]) -> Vec<usize>

Partitioning::partition_indices into ix (as long as v); returns the partition boundaries.

Partitioning::split_points Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn split_points(&self, sorted: &[T], base: u64) -> Vec<usize>

The partition boundaries of locally sorted data: sorted in this order with equal keys kept in their original order (a stable sort; positions base + index in sorted) - parts() + 1 offsets, one binary search per splitter.

Partitioning::descriptors Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn descriptors(&self) -> Vec<PartitionDesc<T>>

The partitions' descriptors (ranges), one per partition.

Partitioning::to_bytes Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn to_bytes(&self) -> Vec<u8>

A compact byte form to send to workers: a header (format, key type, order), then each splitter's order key and position (little-endian u64s).

Partitioning::from_bytes Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn from_bytes(b: &[u8]) -> Result<Self, DistError>

The partitioning Partitioning::to_bytes wrote (for the same key type).

Threads

set_task_runner Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn set_task_runner(runner: Option<RunnerFn>, ctx: *mut c_void)

Runs Kwker's parallel work on your thread pool instead of its own threads, for example PyTorch's intra-op threads, so the two do not compete for the same cores.

Arguments

Notes

set_max_threads Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn set_max_threads(n: usize)

Caps the number of threads all parallel work in the process uses together, so many callers share one budget instead of each starting its own threads.

Arguments

Notes

Remarks: Threads change only the speed: the result follows the same rules on any thread count (rule 10).

max_threads Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn max_threads() -> usize

The cap set_max_threads set: the CPUs the process may run on when it is 0.

Remarks: Threads change only the speed: the result follows the same rules on any thread count (rule 10).

parallel_threads Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn parallel_threads(reset: bool) -> (usize, usize)

How many threads run parallel work now, and the most since the last reset.

Arguments

Returns

(now, peak).

set_worker_cpus Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn set_worker_cpus(cpus: Option<&[usize]>)

Pins Kwker's worker threads to the given CPUs (Linux only; ignored elsewhere).

Arguments

set_default_threads Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn set_default_threads(n: usize)

Sets how many threads multithreaded calls use when you pass threads = 0. The default is 1: Kwker starts no threads unless asked.

Arguments

Remarks: Threads change only the speed: the result follows the same rules on any thread count (rule 10).

default_threads Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn default_threads() -> usize

The thread count calls with threads = 0 use (see set_default_threads).

Remarks: Threads change only the speed: the result follows the same rules on any thread count (rule 10).

sort_mt Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_mt<T: Sortable + Send + Sync>(v: &mut [T], order: Order, threads: usize)

crate::sort_by_order on several threads; the result is the same.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Order;

let mut v: Vec<u32> = (0..1_000_000).rev().collect();
kwker::sort_mt(&mut v, Order::ASCENDING, 4);
assert!(v.windows(2).all(|w| w[0] <= w[1]));

Notes

Remarks: Not stable (rule 5): keys that are equal but can be told apart (NaNs with different bits) may change places. Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for. Threads change only the speed: the result follows the same rules on any thread count (rule 10).

Examples: Sorting: Big arrays: use more cores

sort_mt_with Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_mt_with<T: Sortable + Send + Sync>(
    v: &mut [T],
    order: Order,
    threads: usize,
    ctl: &Control<'_>,
) -> Result<(), Cancelled>

sort_mt with cancellation and progress reports (see Control).

Arguments

Returns

Ok(()), or Err(Cancelled): v then holds its keys in an unspecified order.

Remarks: Not stable (rule 5): keys that are equal but can be told apart (NaNs with different bits) may change places. Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for. Threads change only the speed: the result follows the same rules on any thread count (rule 10).

sort_indexed_mt Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_indexed_mt<T: Sortable + Send + Sync>(
    data: &[T],
    order: Order,
    values: Option<&mut [T]>,
    indices: &mut [u64],
    threads: usize,
)

Sorts on several threads and returns where each sorted key came from: crate::sort_with_indices without changing data.

Arguments

Examples: Large data: Use several cores

sort_indexed_mt_with Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_indexed_mt_with<T: Sortable + Send + Sync>(
    data: &[T],
    order: Order,
    values: Option<&mut [T]>,
    indices: &mut [u64],
    threads: usize,
    ctl: &Control<'_>,
) -> Result<(), Cancelled>

sort_indexed_mt with cancellation and progress reports (see Control).

Arguments

Returns

Ok(()), or Err(Cancelled): data is unchanged and the outputs are unspecified.

kth_mt Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn kth_mt<T: Sortable + Send + Sync>(
    v: &[T],
    k: usize,
    order: Order,
    nan_first: bool,
    threads: usize,
) -> (T, u64)

The key at sorted position k and its position in the input, on several threads.

Arguments

Returns

(key, position); among equal keys the earlier position counts first.

Panics

If k >= v.len().

sort_kv_mt Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_kv_mt<K: Sortable + Send + Sync, V: Copy + Send + Sync>(
    keys: &mut [K],
    values: &mut [V],
    order: Order,
    threads: usize,
)

crate::sort_kv_stable_by_order on several threads: sorts keys and moves values with them, equal keys keeping their input order. The result is the same as on one thread.

Arguments

Panics

If keys and values have different lengths.

Notes

Remarks: Unless the stable form is asked for, pairs with equal keys may come out in any order; the stable form keeps their input order (rule 6). Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for. Threads change only the speed: the result follows the same rules on any thread count (rule 10).

sort_kv_mt_with Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_kv_mt_with<K: Sortable + Send + Sync, V: Copy + Send + Sync>(
    keys: &mut [K],
    values: &mut [V],
    order: Order,
    threads: usize,
    ctl: &Control<'_>,
) -> Result<(), Cancelled>

sort_kv_mt with cancellation and progress reports (see Control).

Arguments

Returns

Ok(()), or Err(Cancelled) with keys and values unchanged.

Remarks: Unless the stable form is asked for, pairs with equal keys may come out in any order; the stable form keeps their input order (rule 6). Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for. Threads change only the speed: the result follows the same rules on any thread count (rule 10).

reduce_by_key_mt Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn reduce_by_key_mt<K: Sortable + Send + Sync, V: Reducible + Send + Sync>(
    keys: &[K],
    values: &[V],
    op: Reduction,
    order: Order,
    threads: usize,
) -> (Vec<K>, Vec<V>)

crate::reduce_by_key on several threads.

Arguments

Notes

MT_MIN Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const MT_MIN: usize = _;

Below this many keys the multithreaded sorts use one thread.

TaskFn Page

RustAdd kwker to Cargo.toml, then cargo run.
pub type TaskFn = unsafe fn(*mut c_void, usize);

One task of a parallel phase (C ABI): task(arg, i).

RunnerFn Page

RustAdd kwker to Cargo.toml, then cargo run.
pub type RunnerFn = unsafe fn(*mut c_void, usize, TaskFn, *mut c_void);

A thread-pool runner for set_task_runner (C ABI): runner(ctx, n, task, arg) must call task(arg, i) once for every i in 0..n, in any order and on any threads, and return when all have returned.

SELECT_MT_MIN Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const SELECT_MT_MIN: usize = _;

Below this many keys the multithreaded selections use one thread.

Plans and workspaces

argsort_into_with Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_into_with<T: Sortable>(v: &[T], order: Order, out: &mut [u64], ws: &mut Workspace)

crate::argsort_into with a Workspace you own, so repeated calls allocate nothing.

Arguments

Remarks: Stable (rule 6): equal keys keep their input order, so the same input always gives the same positions. Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

top_k_into_with Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_into_with<T: Sortable, I: Index>(
    v: &[T],
    order: Order,
    sorted: bool,
    values: &mut [T],
    indices: &mut [I],
    ws: &mut Workspace,
) -> usize

crate::top_k_into with a Workspace you own, so repeated calls allocate nothing.

Arguments

Returns

k, the number of entries written.

Remarks: The first k keys of the stable order and their positions; equal keys keep their input order (rule 9). Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

top_k_indices_into_with Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_indices_into_with<T: Sortable>(
    v: &[T],
    order: Order,
    sorted: bool,
    out: &mut [u64],
    ws: &mut Workspace,
) -> usize

crate::top_k_indices_into with a Workspace you own, so repeated calls allocate nothing.

Arguments

Returns

k, the number of positions written.

sort_kv_with Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_kv_with<K: Sortable, V: Copy>(
    keys: &mut [K],
    values: &mut [V],
    order: Order,
    ws: &mut Workspace,
)

crate::sort_kv_by_order with a Workspace you own, so repeated calls allocate nothing.

Arguments

Panics

If keys and values have different lengths.

Notes

Remarks: Unless the stable form is asked for, pairs with equal keys may come out in any order; the stable form keeps their input order (rule 6). Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

sort_kv_stable_with Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_kv_stable_with<K: Sortable, V: Copy>(
    keys: &mut [K],
    values: &mut [V],
    order: Order,
    ws: &mut Workspace,
)

crate::sort_kv_stable_by_order with a Workspace you own, so repeated calls allocate nothing.

Arguments

Panics

If keys and values have different lengths.

Remarks: Stable (rule 6): equal keys keep their input order, so the same input always gives the same positions. Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

select_nth_kv_with Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn select_nth_kv_with<K: Sortable, V: Copy>(
    keys: &mut [K],
    values: &mut [V],
    k: usize,
    order: Order,
    ws: &mut Workspace,
)

crate::select_nth_kv_by_order with a Workspace you own, so repeated calls allocate nothing.

Arguments

Panics

If k >= keys.len() or keys and values have different lengths.

partial_sort_kv_with Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partial_sort_kv_with<K: Sortable, V: Copy>(
    keys: &mut [K],
    values: &mut [V],
    k: usize,
    order: Order,
    ws: &mut Workspace,
)

crate::partial_sort_kv_by_order with a Workspace you own, so repeated calls allocate nothing.

Arguments

Panics

If keys and values have different lengths.

Remarks: The first k positions hold exactly what a full sort puts there; the rest hold the other keys in any order (rule 8). Unless the stable form is asked for, pairs with equal keys may come out in any order; the stable form keeps their input order (rule 6).

Workspace Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct Workspace {
    /* private fields */
}

Scratch buffers you own and pass to the _with functions; they are kept between calls, so repeated calls allocate nothing once the buffers have grown. Use one per thread.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::{Order, Workspace};

let mut ws = Workspace::with_capacity(1000);
let mut out = vec![0u64; 3];
for _ in 0..10 {
    kwker::argsort_into_with(&[30i64, 10, 20], Order::ASCENDING, &mut out, &mut ws);
}
assert_eq!(out, [1, 2, 0]);

Workspace::new Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn new() -> Self

An empty workspace (allocates on first use).

Workspace::with_capacity Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn with_capacity(n: usize) -> Self

A workspace sized for inputs of n keys (no allocation in calls up to that size).

Workspace::reserve_argsort Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn reserve_argsort(&mut self, n: usize)

Grows the buffers to what an argsort of 64-bit keys of up to n keys takes (argsort_into_with: its order keys, the small-input ranks), so that later calls allocate nothing - also under a scratch limit of 0, which otherwise leaves them the slower in-place merge sort of the indices.

Workspace::reserve_kv Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn reserve_kv(&mut self, n: usize, value_bytes: usize)

Grows the buffers for key-value calls of up to n pairs with value_bytes-byte values (sort_kv_with and the other _kv_with forms: then no allocation in them, also under a scratch limit of 0).

Workspace::capacity_bytes Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn capacity_bytes(&self) -> usize

The bytes held.

Workspace::release Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn release(&mut self)

Frees the buffers.

Plan Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct Plan {
    /* private fields */
}

Settings chosen once and applied to every call: an order, a thread count, a scratch limit and algorithm classes, plus a Workspace kept between calls. Results equal the free functions' with the same settings; a plan only changes where memory comes from and how many threads run.

Example

RustAdd kwker to Cargo.toml, then cargo run.
let mut plan = kwker::Plan::new(kwker::Order::DESCENDING).scratch_limit(Some(0));
let mut v = vec![3u64, 1, 2];
plan.sort(&mut v);  // descending, allocation-free
assert_eq!(v, [3, 2, 1]);
let mut ix = vec![0u64; 3];
plan.argsort_into(&[5i64, 7, 6], &mut ix);
assert_eq!(ix, [1, 2, 0]);

Plan::new Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn new(order: Order) -> Plan

A plan sorting in order, single-threaded, under the calling thread's own scratch limit.

Plan::threads Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn threads(self, threads: usize) -> Plan

Threads for Plan::sort (more than 1: crate::sort_mt; 0: the process default, crate::default_threads).

Plan::scratch_limit Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn scratch_limit(self, bytes: Option<usize>) -> Plan

The scratch limit every call of the plan runs under (crate::set_scratch_limit; the thread's own limit is restored afterwards). Some(0): allocation-free in-place operations.

Plan::algorithms Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn algorithms(self, a: Algorithms) -> Plan

The algorithm classes every call of the plan runs under (crate::set_algorithms; the thread's own setting is restored afterwards).

Plan::order Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn order(&self) -> Order

The plan's order.

Plan::thread_count Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn thread_count(&self) -> usize

The plan's thread count (0: the process default).

Plan::tune_threads Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn tune_threads<T: Sortable + Send + Sync>(
    &mut self,
    sample: &[T],
    max_threads: usize,
    reps: usize,
) -> usize

Picks the plan's thread count by timing: sorts copies of sample on 1, 2, 4, ... threads and keeps the fastest.

Arguments

Returns

The chosen thread count. Results never depend on it.

Plan::tune_algorithms Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn tune_algorithms<T: Sortable + Send + Sync>(
    &mut self,
    sample: &[T],
    reps: usize,
) -> Algorithms

Picks the plan's algorithm classes by timing: sorts copies of sample with every class set and keeps one only if it beats crate::Algorithms::ALL by 3%. Useful for inputs that mislead a shortcut.

Arguments

Returns

The chosen classes. Results never depend on them.

Plan::algorithm_set Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn algorithm_set(&self) -> Option<Algorithms>

The plan's algorithm classes (None: the calling thread's own).

Plan::workspace Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn workspace(&mut self) -> &mut Workspace

The plan's buffers (to pre-size or release them).

Plan::sort Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort<T: Sortable + Send + Sync>(&mut self, v: &mut [T])

Sorts v in the plan's order (on the plan's threads: crate::sort_mt).

Plan::select_nth Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn select_nth<T: Sortable>(&mut self, v: &mut [T], k: usize)

crate::select_nth_by_order in the plan's order.

Plan::partial_sort Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partial_sort<T: Sortable>(&mut self, v: &mut [T], k: usize)

crate::partial_sort_by_order in the plan's order.

Plan::sort_kv Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_kv<K: Sortable + Send + Sync, V: Copy + Send + Sync>(
    &mut self,
    keys: &mut [K],
    values: &mut [V],
)

crate::sort_kv_by_order in the plan's order, through the plan's workspace (sort_kv_with); on the plan's threads crate::sort_kv_mt (stable - also an order of the unstable sort).

Plan::sort_kv_stable Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_kv_stable<K: Sortable + Send + Sync, V: Copy + Send + Sync>(
    &mut self,
    keys: &mut [K],
    values: &mut [V],
)

crate::sort_kv_stable_by_order in the plan's order, through the plan's workspace (sort_kv_stable_with); on the plan's threads crate::sort_kv_mt.

Plan::select_nth_kv Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn select_nth_kv<K: Sortable, V: Copy>(&mut self, keys: &mut [K], values: &mut [V], k: usize)

crate::select_nth_kv_by_order in the plan's order, through the plan's workspace.

Plan::partial_sort_kv Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn partial_sort_kv<K: Sortable, V: Copy>(&mut self, keys: &mut [K], values: &mut [V], k: usize)

crate::partial_sort_kv_by_order in the plan's order, through the plan's workspace.

Plan::argsort_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn argsort_into<T: Sortable + Send + Sync>(&mut self, v: &[T], out: &mut [u64])

The stable permutation of v in the plan's order into out, through the plan's workspace; on the plan's threads crate::sort_indexed_mt (the same permutation).

Plan::top_k_into Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn top_k_into<T: Sortable, I: Index>(
    &mut self,
    v: &[T],
    sorted: bool,
    values: &mut [T],
    indices: &mut [I],
) -> usize

crate::top_k_into in the plan's order, through the plan's workspace (sorted: the k keys in order); returns k.

Cancellation and progress

sort_rows_with Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_rows_with<T: Sortable>(
    data: &mut [T],
    row_len: usize,
    order: Order,
    ctl: &Control<'_>,
) -> Result<(), Cancelled>

crate::sort_rows with cancellation and progress: rows in blocks of about 64K keys, a check before each block.

Remarks: Not stable (rule 5): keys that are equal but can be told apart (NaNs with different bits) may change places. Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

sort_segments_with Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn sort_segments_with<T: Sortable, I: Index>(
    data: &mut [T],
    offsets: &[I],
    order: Order,
    ctl: &Control<'_>,
) -> Result<(), Cancelled>

crate::sort_segments with cancellation and progress: a check before each segment and after each ~64K keys of small segments.

Remarks: Not stable (rule 5): keys that are equal but can be told apart (NaNs with different bits) may change places. Keys follow the key order: -0.0 before +0.0, every NaN in one block, last unless NaNs-first is asked for.

Cancelled Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct Cancelled;

The operation stopped at a cancellation check (Control::cancel_on).

Control Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct Control<'a> {
    /* private fields */
}

A cancellation flag and a progress callback for the _with operations (sort_rows_with, sort_segments_with, crate::sort_file_with); both optional, Control::new() = neither.

Control::new Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn new() -> Self

No cancellation, no progress.

Control::cancel_on Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn cancel_on(self, flag: &'a AtomicBool) -> Self

Stops the operation at its next check once flag is true.

Control::progress Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn progress(self, f: &'a dyn Fn(u64, u64) + Sync) -> Self

Calls f(done, total) after each block of work (keys; done reaches total when the operation completes).

Control::is_cancelled Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn is_cancelled(&self) -> bool

True once the cancellation flag is set (for callers driving their own blocks of work).

Control::report_progress Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn report_progress(&self, done: u64, total: u64)

Calls the progress callback, if any, with (done, total) (for callers driving their own blocks of work).

Engines, memory and algorithm classes

set_scratch_policy Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn set_scratch_policy(p: ScratchPolicy)

Sets how Kwker keeps its large scratch buffers between calls (process-wide).

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
let old = kwker::scratch_policy();
kwker::set_scratch_policy(kwker::ScratchPolicy { cache_bytes: 0, ..old });
let mut v: Vec<u64> = (0..1_000_000u64).map(|i| i.wrapping_mul(0x9E37_79B9_7F4A_7C15)).collect();
kwker::sort_mt(&mut v, kwker::Order::ASCENDING, 2);
assert_eq!(kwker::scratch_use(false).cached, 0); // nothing kept after the call
kwker::set_scratch_policy(old);

scratch_policy Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn scratch_policy() -> ScratchPolicy

The scratch policy in force.

set_scratch_allocator Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn set_scratch_allocator(a: Option<&'static dyn ScratchAllocator>)

Sends Kwker's large scratch buffers to your allocator (process-wide).

Arguments

Notes

scratch_use Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn scratch_use(reset_peak: bool) -> ScratchUse

How much scratch memory Kwker holds now (process-wide).

Arguments

Returns

A ScratchUse: bytes in use, bytes kept for later calls, and the peak.

buffer_alloc Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn buffer_alloc(bytes: usize) -> Option<(*mut u8, usize)>

Memory for large results that language bindings create on every call (for example a NumPy array), taken from Kwker's buffer cache so it does not have to be faulted in again. Linux only.

Arguments

Returns

(pointer, capacity) for buffer_free, uninitialized; None off Linux, below 4 MB, or with ScratchPolicy::mapped off (allocate as usual then).

buffer_free Page

RustAdd kwker to Cargo.toml, then cargo run.
pub unsafe fn buffer_free(p: *mut u8, cap: usize)

Gives a buffer_alloc block back to the cache.

Safety

p and cap must be as buffer_alloc returned them; give a block back once and do not use it after.

release_scratch Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn release_scratch()

Returns every kept scratch buffer to the system and frees this thread's argsort workspace.

capabilities Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn capabilities() -> Capabilities

The capabilities of this build on this machine (features and caches are read once and cached).

set_isa Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn set_isa(cap: Option<Isa>) -> Isa

Caps the engine (instruction set) this process's later calls run on, at run time. Results never change, only speed: use it for A/B timings, debugging, or matching another machine.

Arguments

Returns

The engine now in use.

Example

RustAdd kwker to Cargo.toml, then cargo run.
let best = kwker::set_isa(None);
assert_eq!(kwker::set_isa(Some(kwker::Isa::Portable)), kwker::Isa::Portable);
let mut v = vec![3u32, 1, 2];
kwker::sort(&mut v);
assert_eq!(v, [1, 2, 3]);
assert_eq!(kwker::set_isa(None), best);

Notes

Remarks: The engine changes only the speed, never a result (rule 11).

Examples: Runtime controls: Fallback switches

set_scratch_limit Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn set_scratch_limit(bytes: Option<usize>)

Limits the extra memory this thread's later sorts may allocate. A fast path that needs more is skipped: the results are the same, some inputs sort slower.

Arguments

Example

RustAdd kwker to Cargo.toml, then cargo run.
kwker::set_scratch_limit(Some(0));
let mut v: Vec<u64> = (0..100_000u64).map(|i| i * 7919 % 1000).collect();
kwker::sort(&mut v);  // no allocation: the counting path is skipped, the in-place recursion sorts
assert!(v.windows(2).all(|w| w[0] <= w[1]));
kwker::set_scratch_limit(None);

Notes

Remarks: The scratch limit changes only the speed and memory use, never a result (rule 12).

Examples: Large data: Limit the extra memory

scratch_limit Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn scratch_limit() -> Option<usize>

This thread's scratch limit (set_scratch_limit); None = no limit.

Remarks: The scratch limit changes only the speed and memory use, never a result (rule 12).

Examples: Large data: Limit the extra memory

set_algorithms Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn set_algorithms(a: Algorithms) -> Algorithms

Allows only the given algorithm classes in this thread's later calls. A skipped class changes only the time, never the result. Use it for predictable run times, or to isolate a path when a result looks wrong.

Arguments

Returns

The previous setting.

Example

RustAdd kwker to Cargo.toml, then cargo run.
use kwker::Algorithms;
let prev = kwker::set_algorithms(Algorithms::ALL - Algorithms::COUNTING);
let mut v: Vec<u32> = (0..100_000u32).map(|i| i % 7).collect();
kwker::sort(&mut v);  // seven values: sorted by partitioning, not counted
assert!(v.windows(2).all(|w| w[0] <= w[1]));
kwker::set_algorithms(prev);

Notes

algorithms Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn algorithms() -> Algorithms

This thread's permitted algorithm classes (set_algorithms).

isa Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn isa() -> Isa

The engine (instruction set) sorts run on, on this machine.

Notes

Remarks: The engine changes only the speed, never a result (rule 11).

Examples: Runtime controls: Fallback switches

is_accelerated Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn is_accelerated() -> bool

True if sorts run on one of the SIMD engines (false: the portable fallback).

build_info Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn build_info() -> &'static str

How this build was made: the engines compiled in and the compiler, or why only the portable fallback was built. isa says which engine this machine runs.

scratch_bound Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn scratch_bound(op: ScratchOp, n: usize, key_bytes: usize, value_bytes: usize) -> usize

The most scratch memory an operation allocates for a given input size on this machine, with no scratch limit. Use it to size set_scratch_limit or to check memory headroom before a call.

Arguments

Returns

An upper bound in bytes.

observe Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn observe<R>(f: impl FnOnce() -> R) -> (R, Observation)

Runs f and reports which internal stages its Kwker calls went through and how long each took: a look inside for performance questions.

Arguments

Returns

(f's result, the report); see Observation.

Example

RustAdd kwker to Cargo.toml, then cargo run.
let mut v: Vec<u32> = (0..100_000u32).map(|i| i.wrapping_mul(2654435761)).collect();
let ((), o) = kwker::observe(|| kwker::sort(&mut v));
assert!(v.windows(2).all(|w| w[0] <= w[1]));
if o.traced {
    assert!(!o.stages.is_empty());
}
println!("{o}");

Notes

ScratchPolicy Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct ScratchPolicy {
    pub cache_bytes: usize,
    pub mapped: bool,
    pub huge_pages: bool,
}

How Kwker keeps the large scratch buffers its calls allocate (process-wide; see set_scratch_policy).

Fields

ScratchAllocator Page

RustAdd kwker to Cargo.toml, then cargo run.
pub trait ScratchAllocator: Send + Sync {
    fn alloc(&self, bytes: usize, align: usize) -> *mut u8;
    unsafe fn free(&self, p: *mut u8, bytes: usize, align: usize);
}

Your allocator for Kwker's scratch buffers, such as a database's memory pool or an arena (see set_scratch_allocator). It is called from any thread, concurrently.

ScratchUse Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct ScratchUse {
    pub in_use: usize,
    pub cached: usize,
    pub peak: usize,
}

What the library's scratch buffers hold (scratch_use).

Fields

Capabilities Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct Capabilities {
    pub version: &'static str,
    pub isa: Isa,
    pub engines_built: Vec<Isa>,
    pub engines_usable: Vec<Isa>,
    pub features: Vec<&'static str>,
    pub sve_vector_bits: Option<u32>,
    pub l1d: Option<usize>,
    pub l2: Option<usize>,
    pub l3: Option<usize>,
    pub cpus: usize,
    pub default_threads: usize,
    pub scratch_limit: Option<usize>,
    pub build: &'static str,
}

What Kwker does on this machine. From capabilities.

Fields

Capabilities::to_json Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn to_json(&self) -> String

As one JSON object (the C API's kwker_capabilities_json, Python's kwker.capabilities()).

VERSION Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const VERSION: &str = "v26";

Version of the engine (shared numbering of the 32- and 64-bit sorts).

Isa Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum Isa {
    Avx512,
    Avx2,
    Portable,
    Neon,
    Simd128,
    Sse42,
}

The code that sorts on this machine.

Variants

Algorithms Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct Algorithms(_);

Classes of algorithms the sorts may use beyond their comparison core (set_algorithms). The core - in-place partitioning (sampled pivots or value midpoints), the sorting networks and the depth-guarded fallback - always runs; each class adds optional paths that a call takes only when its input suits them.

Algorithms::ADAPTIVE Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const ADAPTIVE: Algorithms;

Order detection: sorted, reversed, all-equal and nearly sorted inputs finish early, and runs of equal keys (timestamps, repeated readings) sort as one entry per run.

Algorithms::COUNTING Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const COUNTING: Algorithms;

Distribution paths: few distinct values (matched and counted), a dominant or a few heavy values, counting and rank-counting sorts of narrow or few-valued inputs, hashed counts, the varying-bits counting sort and key compaction. Without it, 8- and 16-bit keys sort by comparison too.

Algorithms::RADIX Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const RADIX: Algorithms;

Radix distribution passes: the MSD / LSD radix sorts and value-space bucket passes (ARM and the portable engine's large inputs, the 128-bit and stable key-value sorts' top levels).

Algorithms::ALL Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const ALL: Algorithms;

Every class (the default).

Algorithms::NONE Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const NONE: Algorithms;

The comparison core alone.

Algorithms::bits Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const fn bits(self) -> u32

The class bits (1 ADAPTIVE, 2 COUNTING, 4 RADIX).

Algorithms::from_bits Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const fn from_bits(bits: u32) -> Algorithms

From class bits; bits above ALL are ignored.

Algorithms::contains Page

RustAdd kwker to Cargo.toml, then cargo run.
pub const fn contains(self, other: Algorithms) -> bool

Whether every class of other is in self.

ScratchOp Page

RustAdd kwker to Cargo.toml, then cargo run.
pub enum ScratchOp {
    Sort,
    Select,
    SortKv,
    TopK,
    SortKvStable,
    Argsort,
    Rank,
    ReduceByKey,
    Sort128,
}

The operations scratch_bound covers.

Variants

Stage Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct Stage {
    pub id: u16,
    pub name: &'static str,
    pub about: &'static str,
    pub count: u64,
    pub cycles: u64,
}

One engine stage that ran under observe: its id and name in the engines' stage list (for example r32.vbits, the 32-bit root's varying-bits counting sort; rec64.comp.keys, keys the 64-bit recursion sorted on its composite path), what it is, how often it ran - for the .keys counting sites the keys it handled - and the CPU cycles spent in it (timed stages, nested stages included; 0 for the others).

Fields

Observation Page

RustAdd kwker to Cargo.toml, then cargo run.
pub struct Observation {
    pub isa: Isa,
    pub traced: bool,
    pub stages: Vec<Stage>,
    pub scratch_peak: usize,
}

What the calls inside observe did.

Fields

Observation::stage Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn stage(&self, name: &str) -> Option<&Stage>

The stage name if it ran.

Observation::to_json Page

RustAdd kwker to Cargo.toml, then cargo run.
pub fn to_json(&self) -> String

The report as JSON: {"isa":"avx512","traced":true,"scratch_peak":0,"stages":[{"id":40,"name":"r32.enter", "about":"...","count":1,"cycles":0},...]}.

Notes

Floating-point keys sort -0.0 before +0.0 and every NaN after the other values (positive NaNs first, then negative ones, each sign by f64::total_cmp), so the output depends only on the input's bit patterns. The full rules are in Behavior.

Applies to Kwker 0.1 · Rust
Last updated
Was this page helpful?
Kwker 0.1.x: the engines each platform chooses from at run time (details)
PlatformEngines
Linux x86-64AVX-512, AVX2, SSE4.2, portable
Linux ARM64SVE / SVE2 (64-bit keys), NEON, portable
Windows x64AVX-512, AVX2, SSE4.2, portable
Windows ARM64NEON, portable
macOS ARM64NEON, portable
macOS x86-64AVX2, SSE4.2, portable
Other CPUs (RISC-V, POWER, x86 without SSE4.2, ...)portable