#[derive(Clone, PartialEq)]
pub struct Hyper(Vec<f32>);
#[inline]
fn splitmix64(seed: u64) -> u64 {
let mut z = seed.wrapping_add(0x9E37_79B9_7F4A_7C15);
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^ (z >> 31)
}
impl Hyper {
#[inline]
pub fn from_vec(data: Vec<f32>) -> Self {
Hyper(data)
}
#[inline]
pub fn as_slice(&self) -> &[f32] {
&self.0
}
#[inline]
pub fn into_vec(self) -> Vec<f32> {
self.0
}
#[inline]
pub fn dim(&self) -> usize {
self.0.len()
}
pub fn zeros(dim: usize) -> Self {
Hyper(vec![0.0; dim])
}
pub fn atom(dim: usize, seed: u64, id: u64) -> Self {
let mut v = Vec::with_capacity(dim);
let base = splitmix64(seed ^ id.wrapping_mul(0xD1B5_4A32_D192_ED03));
for p in 0..dim {
let h = splitmix64(base.wrapping_add(p as u64));
v.push(if h >> 63 == 1 { 1.0 } else { -1.0 });
}
Hyper(v)
}
pub fn bind(&self, other: &Hyper) -> Hyper {
debug_assert_eq!(self.dim(), other.dim());
Hyper(self.0.iter().zip(&other.0).map(|(a, b)| a * b).collect())
}
pub fn bind_assign(&mut self, other: &Hyper) {
debug_assert_eq!(self.dim(), other.dim());
for (a, b) in self.0.iter_mut().zip(&other.0) {
*a *= b;
}
}
pub fn bundle_into(&mut self, other: &Hyper) {
debug_assert_eq!(self.dim(), other.dim());
for (a, b) in self.0.iter_mut().zip(&other.0) {
*a += b;
}
}
pub fn unbundle(&mut self, other: &Hyper) {
debug_assert_eq!(self.dim(), other.dim());
for (a, b) in self.0.iter_mut().zip(&other.0) {
*a -= b;
}
}
pub fn sign(&self) -> Hyper {
Hyper(
self.0
.iter()
.map(|&x| if x >= 0.0 { 1.0 } else { -1.0 })
.collect(),
)
}
pub fn permute(&self, shift: usize) -> Hyper {
let n = self.0.len();
if n == 0 {
return self.clone();
}
let s = shift % n;
let mut out = vec![0.0; n];
for (i, &x) in self.0.iter().enumerate() {
out[(i + s) % n] = x;
}
Hyper(out)
}
pub fn inverse_permute(&self, shift: usize) -> Hyper {
let n = self.0.len();
if n == 0 {
return self.clone();
}
self.permute(n - (shift % n))
}
pub fn dot(&self, other: &Hyper) -> f32 {
debug_assert_eq!(self.dim(), other.dim());
self.0.iter().zip(&other.0).map(|(a, b)| a * b).sum()
}
pub fn norm(&self) -> f32 {
self.dot(self).sqrt()
}
pub fn cosine(&self, other: &Hyper) -> f32 {
let denom = self.norm() * other.norm();
if denom == 0.0 {
0.0
} else {
self.dot(other) / denom
}
}
}
impl core::fmt::Debug for Hyper {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Hyper(dim={}, norm={:.2})", self.dim(), self.norm())
}
}