1pub const VECTOR_DIM: usize = 384;
5
6#[derive(Clone, Debug)]
8pub struct Md5 {
9 state: [u32; 4],
10 count: [u32; 2],
11 buffer: [u8; 64],
12}
13
14impl Default for Md5 {
15 fn default() -> Self {
16 Self::new()
17 }
18}
19
20impl Md5 {
21 pub fn new() -> Self {
22 Self {
23 state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476],
24 count: [0, 0],
25 buffer: [0u8; 64],
26 }
27 }
28
29 pub fn update(&mut self, input: &[u8]) {
30 let mut index = ((self.count[0] >> 3) & 0x3f) as usize;
31 let input_len = input.len();
32
33 let shift = (input_len as u32) << 3;
34 self.count[0] = self.count[0].wrapping_add(shift);
35 if self.count[0] < shift {
36 self.count[1] = self.count[1].wrapping_add(1);
37 }
38 self.count[1] = self.count[1].wrapping_add((input_len as u32) >> 29);
39
40 let part_len = 64 - index;
41 let mut i = 0;
42
43 if input_len >= part_len {
44 self.buffer[index..index + part_len].copy_from_slice(&input[0..part_len]);
45 let buf = self.buffer;
46 self.transform(&buf);
47
48 i = part_len;
49 while i + 63 < input_len {
50 let mut chunk = [0u8; 64];
51 chunk.copy_from_slice(&input[i..i + 64]);
52 self.transform(&chunk);
53 i += 64;
54 }
55 index = 0;
56 }
57
58 if i < input_len {
59 self.buffer[index..index + (input_len - i)].copy_from_slice(&input[i..input_len]);
60 }
61 }
62
63 pub fn finalize(mut self) -> [u8; 16] {
64 let mut bits = [0u8; 8];
65 for i in 0..4 {
66 bits[i] = ((self.count[0] >> (i * 8)) & 0xff) as u8;
67 bits[i + 4] = ((self.count[1] >> (i * 8)) & 0xff) as u8;
68 }
69
70 let index = ((self.count[0] >> 3) & 0x3f) as usize;
71 let pad_len = if index < 56 { 56 - index } else { 120 - index };
72 let mut padding = [0u8; 64];
73 padding[0] = 0x80;
74
75 self.update(&padding[..pad_len]);
76 self.update(&bits);
77
78 let mut digest = [0u8; 16];
79 for i in 0..4 {
80 digest[i * 4] = (self.state[i] & 0xff) as u8;
81 digest[i * 4 + 1] = ((self.state[i] >> 8) & 0xff) as u8;
82 digest[i * 4 + 2] = ((self.state[i] >> 16) & 0xff) as u8;
83 digest[i * 4 + 3] = ((self.state[i] >> 24) & 0xff) as u8;
84 }
85 digest
86 }
87
88 pub fn digest(data: &[u8]) -> [u8; 16] {
89 let mut md5 = Self::new();
90 md5.update(data);
91 md5.finalize()
92 }
93
94 fn transform(&mut self, block: &[u8; 64]) {
95 let mut a = self.state[0];
96 let mut b = self.state[1];
97 let mut c = self.state[2];
98 let mut d = self.state[3];
99 let mut x = [0u32; 16];
100
101 for i in 0..16 {
102 let j = i * 4;
103 x[i] = (block[j] as u32)
104 | ((block[j + 1] as u32) << 8)
105 | ((block[j + 2] as u32) << 16)
106 | ((block[j + 3] as u32) << 24);
107 }
108
109 #[inline(always)]
110 fn f(x: u32, y: u32, z: u32) -> u32 {
111 (x & y) | (!x & z)
112 }
113 #[inline(always)]
114 fn g(x: u32, y: u32, z: u32) -> u32 {
115 (x & z) | (y & !z)
116 }
117 #[inline(always)]
118 fn h(x: u32, y: u32, z: u32) -> u32 {
119 x ^ y ^ z
120 }
121 #[inline(always)]
122 fn i_func(x: u32, y: u32, z: u32) -> u32 {
123 y ^ (x | !z)
124 }
125 #[inline(always)]
126 fn rotl(x: u32, n: u32) -> u32 {
127 (x << n) | (x >> (32 - n))
128 }
129
130 macro_rules! step {
131 ($func:ident, $a:expr, $b:expr, $c:expr, $d:expr, $k:expr, $s:expr, $t:expr) => {
132 $a = $a.wrapping_add($func($b, $c, $d).wrapping_add(x[$k]).wrapping_add($t));
133 $a = rotl($a, $s).wrapping_add($b);
134 };
135 }
136
137 step!(f, a, b, c, d, 0, 7, 0xd76aa478);
139 step!(f, d, a, b, c, 1, 12, 0xe8c7b756);
140 step!(f, c, d, a, b, 2, 17, 0x242070db);
141 step!(f, b, c, d, a, 3, 22, 0xc1bdceee);
142 step!(f, a, b, c, d, 4, 7, 0xf57c0faf);
143 step!(f, d, a, b, c, 5, 12, 0x4787c62a);
144 step!(f, c, d, a, b, 6, 17, 0xa8304613);
145 step!(f, b, c, d, a, 7, 22, 0xfd469501);
146 step!(f, a, b, c, d, 8, 7, 0x698098d8);
147 step!(f, d, a, b, c, 9, 12, 0x8b44f7af);
148 step!(f, c, d, a, b, 10, 17, 0xffff5bb1);
149 step!(f, b, c, d, a, 11, 22, 0x895cd7be);
150 step!(f, a, b, c, d, 12, 7, 0x6b901122);
151 step!(f, d, a, b, c, 13, 12, 0xfd987193);
152 step!(f, c, d, a, b, 14, 17, 0xa679438e);
153 step!(f, b, c, d, a, 15, 22, 0x49b40821);
154
155 step!(g, a, b, c, d, 1, 5, 0xf61e2562);
157 step!(g, d, a, b, c, 6, 9, 0xc040b340);
158 step!(g, c, d, a, b, 11, 14, 0x265e5a51);
159 step!(g, b, c, d, a, 0, 20, 0xe9b6c7aa);
160 step!(g, a, b, c, d, 5, 5, 0xd62f105d);
161 step!(g, d, a, b, c, 10, 9, 0x02441453);
162 step!(g, c, d, a, b, 15, 14, 0xd8a1e681);
163 step!(g, b, c, d, a, 4, 20, 0xe7d3fbc8);
164 step!(g, a, b, c, d, 9, 5, 0x21e1cde6);
165 step!(g, d, a, b, c, 14, 9, 0xc33707d6);
166 step!(g, c, d, a, b, 3, 14, 0xf4d50d87);
167 step!(g, b, c, d, a, 8, 20, 0x455a14ed);
168 step!(g, a, b, c, d, 13, 5, 0xa9e3e905);
169 step!(g, d, a, b, c, 2, 9, 0xfcefa3f8);
170 step!(g, c, d, a, b, 7, 14, 0x676f02d9);
171 step!(g, b, c, d, a, 12, 20, 0x8d2a4c8a);
172
173 step!(h, a, b, c, d, 5, 4, 0xfffa3942);
175 step!(h, d, a, b, c, 8, 11, 0x8771f681);
176 step!(h, c, d, a, b, 11, 16, 0x6d9d6122);
177 step!(h, b, c, d, a, 14, 23, 0xfde5380c);
178 step!(h, a, b, c, d, 1, 4, 0xa4beea44);
179 step!(h, d, a, b, c, 4, 11, 0x4bdecfa9);
180 step!(h, c, d, a, b, 7, 16, 0xf6bb4b60);
181 step!(h, b, c, d, a, 10, 23, 0xbebfbc70);
182 step!(h, a, b, c, d, 13, 4, 0x289b7ec6);
183 step!(h, d, a, b, c, 0, 11, 0xeaa127fa);
184 step!(h, c, d, a, b, 3, 16, 0xd4ef3085);
185 step!(h, b, c, d, a, 6, 23, 0x04881d05);
186 step!(h, a, b, c, d, 9, 4, 0xd9d4d039);
187 step!(h, d, a, b, c, 12, 11, 0xe6db99e5);
188 step!(h, c, d, a, b, 15, 16, 0x1fa27cf8);
189 step!(h, b, c, d, a, 2, 23, 0xc4ac5665);
190
191 step!(i_func, a, b, c, d, 0, 6, 0xf4292244);
193 step!(i_func, d, a, b, c, 7, 10, 0x432aff97);
194 step!(i_func, c, d, a, b, 14, 15, 0xab9423a7);
195 step!(i_func, b, c, d, a, 5, 21, 0xfc93a039);
196 step!(i_func, a, b, c, d, 12, 6, 0x655b59c3);
197 step!(i_func, d, a, b, c, 3, 10, 0x8f0ccc92);
198 step!(i_func, c, d, a, b, 10, 15, 0xffeff47d);
199 step!(i_func, b, c, d, a, 1, 21, 0x85845dd1);
200 step!(i_func, a, b, c, d, 8, 6, 0x6fa87e4f);
201 step!(i_func, d, a, b, c, 15, 10, 0xfe2ce6e0);
202 step!(i_func, c, d, a, b, 6, 15, 0xa3014314);
203 step!(i_func, b, c, d, a, 13, 21, 0x4e0811a1);
204 step!(i_func, a, b, c, d, 4, 6, 0xf7537e82);
205 step!(i_func, d, a, b, c, 11, 10, 0xbd3af235);
206 step!(i_func, c, d, a, b, 2, 15, 0x2ad7d2bb);
207 step!(i_func, b, c, d, a, 9, 21, 0xeb86d391);
208
209 self.state[0] = self.state[0].wrapping_add(a);
210 self.state[1] = self.state[1].wrapping_add(b);
211 self.state[2] = self.state[2].wrapping_add(c);
212 self.state[3] = self.state[3].wrapping_add(d);
213 }
214}
215
216pub fn cosine_similarity(a: &[f32], b: &[f32]) -> f32 {
218 assert_eq!(a.len(), b.len(), "Vector lengths must match");
219 a.iter().zip(b.iter()).map(|(x, y)| x * y).sum()
220}
221
222#[derive(Clone, Debug, Default)]
224pub struct SemanticVectorEncoder;
225
226impl SemanticVectorEncoder {
227 pub fn new() -> Self {
228 Self
229 }
230
231 pub fn encode(&self, text: &str) -> [f32; VECTOR_DIM] {
233 let mut vec = [0.0f32; VECTOR_DIM];
234 let lower = text.to_lowercase();
235
236 let tokens: Vec<&str> = lower
238 .split(|c: char| !(c.is_alphanumeric() || c == '_'))
239 .filter(|s| !s.is_empty())
240 .collect();
241
242 if tokens.is_empty() {
243 return vec;
244 }
245
246 for (i, &tok) in tokens.iter().enumerate() {
248 Self::hash_into_vector(tok, &mut vec, 1.0);
249 if i + 1 < tokens.len() {
250 let bigram = format!("{}_{}", tok, tokens[i + 1]);
251 Self::hash_into_vector(&bigram, &mut vec, 1.4);
252 }
253 }
254
255 for &tok in &tokens {
257 if tok.len() >= 3 {
258 for j in 0..=tok.len() - 3 {
259 let sub = &tok[j..j + 3];
260 let sub_key = format!("sub_{}", sub);
261 Self::hash_into_vector(&sub_key, &mut vec, 0.5);
262 }
263 }
264 }
265
266 let sum_sq: f32 = vec.iter().map(|x| x * x).sum();
268 let norm = sum_sq.sqrt();
269 if norm > 1e-9 {
270 for val in vec.iter_mut() {
271 *val /= norm;
272 }
273 }
274
275 vec
276 }
277
278 fn hash_into_vector(token: &str, vec: &mut [f32; VECTOR_DIM], weight: f32) {
279 let digest = Md5::digest(token.as_bytes());
280 let h = ((digest[0] as u64) << 40)
282 | ((digest[1] as u64) << 32)
283 | ((digest[2] as u64) << 24)
284 | ((digest[3] as u64) << 16)
285 | ((digest[4] as u64) << 8)
286 | (digest[5] as u64);
287
288 let idx = (h % (VECTOR_DIM as u64)) as usize;
289 let sign = if (h >> 16) % 2 == 0 { 1.0f32 } else { -1.0f32 };
290 vec[idx] += sign * weight;
291 }
292}