#![allow(
clippy::cast_precision_loss,
clippy::cast_possible_truncation,
clippy::needless_range_loop,
clippy::many_single_char_names
)]
use std::sync::OnceLock;
pub const GOLDRAT: f64 = 0.381_966_011_250_105_2;
pub const UNIVEC_N: usize = 255;
pub const UNIVEC_LEN: usize = 256;
static UNIVEC: OnceLock<[[f32; 3]; UNIVEC_LEN]> = OnceLock::new();
static IUNIVEC: OnceLock<[[i16; 4]; UNIVEC_LEN]> = OnceLock::new();
fn build_univec() -> [[f32; 3]; UNIVEC_LEN] {
let mut out = [[0.0f32; 3]; UNIVEC_LEN];
let n = UNIVEC_N as f32;
let zmulk = 2.0_f32 / n;
let zaddk = zmulk * 0.5_f32 - 1.0_f32;
let goldrat_2pi: f64 = GOLDRAT * std::f64::consts::PI * 2.0;
for i in 0..UNIVEC_N {
let z = (i as f32) * zmulk + zaddk;
let r = (1.0_f32 - z * z).sqrt();
let a = ((i as f64) * goldrat_2pi) as f32;
let x = a.cos() * r;
let y = a.sin() * r;
out[i] = [x, y, z];
}
out[UNIVEC_N] = [0.0, 0.0, 0.0];
out
}
fn build_iunivec(univec: &[[f32; 3]; UNIVEC_LEN]) -> [[i16; 4]; UNIVEC_LEN] {
let mut out = [[0i16; 4]; UNIVEC_LEN];
for i in 0..UNIVEC_LEN {
out[i][0] = (univec[i][0] * 4096.0) as i16;
out[i][1] = (univec[i][1] * 4096.0) as i16;
out[i][2] = (univec[i][2] * 4096.0) as i16;
out[i][3] = 4096;
}
out
}
#[must_use]
pub fn univec() -> &'static [[f32; 3]; UNIVEC_LEN] {
UNIVEC.get_or_init(build_univec)
}
#[must_use]
pub fn iunivec() -> &'static [[i16; 4]; UNIVEC_LEN] {
IUNIVEC.get_or_init(|| build_iunivec(univec()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn univec_endpoints_are_polar() {
let u = univec();
assert!(u[0][2] < -0.99, "got z = {}", u[0][2]);
assert!(u[254][2] > 0.99, "got z = {}", u[254][2]);
}
#[test]
fn univec_unit_length_for_active_slots() {
let u = univec();
for (i, v) in u.iter().enumerate().take(UNIVEC_N) {
let len2 = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
assert!((len2 - 1.0).abs() < 1e-5, "slot {i} len² = {len2}");
}
let v = u[UNIVEC_N];
assert_eq!(v[0].to_bits(), 0);
assert_eq!(v[1].to_bits(), 0);
assert_eq!(v[2].to_bits(), 0);
}
#[test]
fn iunivec_lane3_is_4096() {
let iu = iunivec();
for (i, v) in iu.iter().enumerate() {
assert_eq!(v[3], 4096, "iunivec[{i}][3] should be 4096");
}
}
#[test]
fn iunivec_matches_quantised_univec() {
let u = univec();
let iu = iunivec();
for i in 0..UNIVEC_LEN {
assert_eq!(iu[i][0], (u[i][0] * 4096.0) as i16);
assert_eq!(iu[i][1], (u[i][1] * 4096.0) as i16);
assert_eq!(iu[i][2], (u[i][2] * 4096.0) as i16);
}
}
}