hydroplane 0.1.0

Floating but fast: float-agnostic, ISPC-style SPMD/SIMD infrastructure — write one kernel generic over the scalar element (f32/f64/f16/bf16) and run it with runtime ISA dispatch.
Documentation
//! Micro-kernels: tiny SIMD functions called in a hot loop, here a robot joint-limit check over
//! a 6-DOF configuration. `out_of_limits` composes the two sub-kernels via their `_on`
//! companions, so the whole check is one dispatch.

use hydroplane::{Gang, kernel};

/// Any `a[i] > b[i]`? The remainder pads with `-inf` (lhs) / `+inf` (rhs): `-inf > +inf` is false,
/// so padding never trips the reduction.
#[kernel(tiny)]
fn any_gt<'a>(ctx: Gang, a: &'a [f32], b: &'a [f32]) -> bool {
    let n = ctx.lanes::<f32>();
    for off in ctx.chunks_exact::<f32>(a.len()) {
        if ctx.load(&a[off..off + n]).gt(ctx.load(&b[off..off + n])).any() {
            return true;
        }
    }
    if let Some((off, cnt)) = ctx.remainder::<f32>(a.len()) {
        let x = ctx.load_partial(&a[off..off + cnt], f32::NEG_INFINITY);
        let y = ctx.load_partial(&b[off..off + cnt], f32::INFINITY);
        return x.gt(y).any();
    }
    false
}

/// Any `a[i] < b[i]`? Sentinels swapped: `+inf < -inf` is false.
#[kernel(tiny)]
fn any_lt<'a>(ctx: Gang, a: &'a [f32], b: &'a [f32]) -> bool {
    let n = ctx.lanes::<f32>();
    for off in ctx.chunks_exact::<f32>(a.len()) {
        if ctx.load(&a[off..off + n]).lt(ctx.load(&b[off..off + n])).any() {
            return true;
        }
    }
    if let Some((off, cnt)) = ctx.remainder::<f32>(a.len()) {
        let x = ctx.load_partial(&a[off..off + cnt], f32::INFINITY);
        let y = ctx.load_partial(&b[off..off + cnt], f32::NEG_INFINITY);
        return x.lt(y).any();
    }
    false
}

/// Below `lo` or above `hi` anywhere? One dispatch at entry; the sub-kernels reuse the chosen
/// backend via their `_on` companions.
#[kernel(tiny)]
fn out_of_limits<'a>(ctx: Gang, q: &'a [f32], lo: &'a [f32], hi: &'a [f32]) -> bool {
    any_lt_on(ctx, q, lo) || any_gt_on(ctx, q, hi)
}

/// Squared distance between two joint configs: `Σ (q[i] - p[i])²`. `zip_sum` supplies the zero
/// identity, masked tail, chain combine, and per-core unroll factor.
#[kernel(tiny)]
fn dist_sq<'a>(ctx: Gang, q: &'a [f32], p: &'a [f32]) -> f32 {
    ctx.zip_sum(q, p, |acc, a, b| {
        let d = a - b;
        d.fma(d, acc)
    })
}

fn main() {
    let lo = [-3.2_f32, -2.0, -2.8, -3.2, -2.0, -6.4];
    let hi = [3.2_f32, 2.0, 2.8, 3.2, 2.0, 6.4];

    let inside = [0.1_f32, 0.5, -1.0, 1.2, 0.0, 3.0];
    let high = [0.1_f32, 0.5, -1.0, 1.2, 0.0, 7.0]; // joint 5 past its upper bound
    let low = [0.1_f32, -2.5, -1.0, 1.2, 0.0, 3.0]; // joint 1 below its lower bound

    println!("inside limits?  {}", !out_of_limits(&inside, &lo, &hi)); // true
    println!("high  in limits {}", !out_of_limits(&high, &lo, &hi)); // false
    println!("low   in limits {}", !out_of_limits(&low, &lo, &hi)); // false
    println!("dist² inside→high: {}", dist_sq(&inside, &high)); // (3.0-7.0)² = 16
}