csm_core_lib/
hyperdim_ops.rs1use serde::{Deserialize, Serialize};
7use std::fmt::Debug;
8use std::hash::Hash;
9
10use crate::error::Result;
11use crate::hyperdim::HVec10240;
12
13pub trait Hypervector:
15 Debug + Clone + Copy + PartialEq + Eq + Hash + Send + Sync + Serialize + for<'de> Deserialize<'de>
16{
17 const DIMENSION: usize;
18 const FORMAT_NAME: &'static str;
19 fn zero() -> Self;
20 fn random() -> Self;
21 fn new_seeded(seed: u64) -> Self;
22 fn bundle(vectors: &[&Self]) -> Result<Self>;
23 fn bind(&self, other: &Self) -> Self;
24 fn cosine_similarity(&self, other: &Self) -> f32;
25 fn hamming_distance(&self, other: &Self) -> u32;
26 fn permute(&self, shift: usize) -> Self;
27 fn to_bytes(&self) -> Vec<u8>;
28 fn from_bytes(bytes: &[u8]) -> Result<Self>;
29}
30
31impl Hypervector for HVec10240 {
32 const DIMENSION: usize = 10240;
33 const FORMAT_NAME: &'static str = "f32";
34
35 fn zero() -> Self {
36 Self::zero()
37 }
38
39 fn random() -> Self {
40 Self::random()
41 }
42
43 fn new_seeded(seed: u64) -> Self {
44 Self::new_seeded(seed)
45 }
46
47 fn bundle(vectors: &[&Self]) -> Result<Self> {
48 let owned_vecs: Vec<Self> = vectors.iter().map(|&v| *v).collect();
50 Self::bundle(&owned_vecs)
51 }
52
53 fn bind(&self, other: &Self) -> Self {
54 self.bind(other)
55 }
56
57 fn cosine_similarity(&self, other: &Self) -> f32 {
58 self.cosine_similarity(other)
59 }
60
61 fn hamming_distance(&self, other: &Self) -> u32 {
62 self.hamming_distance(other)
63 }
64
65 fn permute(&self, shift: usize) -> Self {
66 self.permute(shift)
67 }
68
69 fn to_bytes(&self) -> Vec<u8> {
70 self.to_bytes()
71 }
72
73 fn from_bytes(bytes: &[u8]) -> Result<Self> {
74 Self::from_bytes(bytes)
75 }
76}
77
78pub const BUNDLE_MAX_PLANES: usize = 64;
83
84#[allow(dead_code)]
90pub fn bundle_word_scalar(
91 vectors: &[HVec10240],
92 word_idx: usize,
93 threshold: usize,
94 num_planes: usize,
95) -> u128 {
96 debug_assert!(
97 num_planes <= BUNDLE_MAX_PLANES,
98 "num_planes={num_planes} exceeds BUNDLE_MAX_PLANES={BUNDLE_MAX_PLANES}"
99 );
100 let mut planes = [0u128; BUNDLE_MAX_PLANES];
101 for v in vectors {
102 let mut carry = v.data[word_idx];
103 for plane in planes.iter_mut().take(num_planes) {
104 let next_carry = *plane & carry;
105 *plane ^= carry;
106 carry = next_carry;
107 if carry == 0 {
108 break;
109 }
110 }
111 }
112 let (mut current_eq, mut current_gt) = (!0u128, 0u128);
113 for p in (0..num_planes).rev() {
114 if ((threshold >> p) & 1) == 1 {
115 current_eq &= planes[p];
116 } else {
117 current_gt |= current_eq & planes[p];
118 current_eq &= !planes[p];
119 }
120 }
121 current_gt | current_eq
122}
123
124pub fn bundle_word_u64(
129 words: impl IntoIterator<Item = u64>,
130 threshold: usize,
131 num_planes: usize,
132) -> u64 {
133 debug_assert!(
134 num_planes <= BUNDLE_MAX_PLANES,
135 "num_planes={num_planes} exceeds BUNDLE_MAX_PLANES={BUNDLE_MAX_PLANES}"
136 );
137 let mut planes = [0u64; BUNDLE_MAX_PLANES];
138 for word in words {
139 let mut carry = word;
140 for plane in planes.iter_mut().take(num_planes) {
141 let next_carry = *plane & carry;
142 *plane ^= carry;
143 carry = next_carry;
144 if carry == 0 {
145 break;
146 }
147 }
148 }
149 let (mut current_eq, mut current_gt) = (!0u64, 0u64);
150 for p in (0..num_planes).rev() {
151 if ((threshold >> p) & 1) == 1 {
152 current_eq &= planes[p];
153 } else {
154 current_gt |= current_eq & planes[p];
155 current_eq &= !planes[p];
156 }
157 }
158 current_gt | current_eq
159}