1#![forbid(unsafe_code)]
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum Ternary {
11 Neg,
12 Zero,
13 Pos,
14}
15
16impl Ternary {
17 pub fn to_f64(self) -> f64 {
18 match self {
19 Ternary::Neg => -1.0,
20 Ternary::Zero => 0.0,
21 Ternary::Pos => 1.0,
22 }
23 }
24
25 pub fn from_i8(v: i8) -> Option<Self> {
26 match v {
27 -1 => Some(Ternary::Neg),
28 0 => Some(Ternary::Zero),
29 1 => Some(Ternary::Pos),
30 _ => None,
31 }
32 }
33
34 pub fn values() -> [Ternary; 3] {
35 [Ternary::Neg, Ternary::Zero, Ternary::Pos]
36 }
37}
38
39use std::f64::consts::{PI, E};
40
41pub struct TernaryWavelet {
45 pub levels: usize,
46}
47
48impl TernaryWavelet {
49 pub fn new(levels: usize) -> Self {
50 TernaryWavelet { levels }
51 }
52
53 pub fn forward(&self, data: &[f64]) -> Vec<f64> {
55 let n = data.len();
56 if n < 2 {
57 return data.to_vec();
58 }
59 let mut result = data.to_vec();
60 let mut current_n = n;
61
62 for _ in 0..self.levels.min(log2_floor(n)) {
63 let half = current_n / 2;
64 let mut approx = vec![0.0; half];
65 let mut detail = vec![0.0; half];
66
67 for i in 0..half {
68 let a = result[2 * i];
70 let b = result[2 * i + 1];
71 approx[i] = (a + b) / 2.0;
72 detail[i] = (a - b) / 2.0;
73 }
74
75 for i in 0..half {
77 result[i] = approx[i];
78 }
79 for i in 0..half {
80 result[half + i] = detail[i];
81 }
82 current_n = half;
83 }
84
85 result
86 }
87
88 pub fn inverse(&self, coeffs: &[f64]) -> Vec<f64> {
90 let n = coeffs.len();
91 if n < 2 {
92 return coeffs.to_vec();
93 }
94
95 let levels = self.levels.min(log2_floor(n));
96 let mut result = coeffs.to_vec();
97
98 for _ in 0..levels {
99 let current_n = smallest_reconstruct(n, levels);
100 let half = current_n / 2;
101 let mut reconstructed = vec![0.0; current_n];
102
103 for i in 0..half {
104 let a = result[i];
105 let d = result[half + i];
106 reconstructed[2 * i] = a + d;
107 reconstructed[2 * i + 1] = a - d;
108 }
109
110 for i in 0..current_n {
111 result[i] = reconstructed[i];
112 }
113 }
114
115 result
116 }
117
118 pub fn energy_per_level(&self, coeffs: &[f64]) -> Vec<f64> {
120 let n = coeffs.len();
121 let levels = self.levels.min(log2_floor(n));
122 let mut energies = Vec::new();
123 let mut current_n = n;
124
125 for _level in 0..levels {
126 let half = current_n / 2;
127 let start = half;
128 let energy: f64 = coeffs[start..current_n]
129 .iter()
130 .map(|&c| c * c)
131 .sum();
132 energies.push(energy);
133 current_n = half;
134 }
135
136 energies
137 }
138
139 pub fn denoise(&self, data: &[f64], threshold: f64) -> Vec<f64> {
141 let coeffs = self.forward(data);
142 let n = coeffs.len();
143 let levels = self.levels.min(log2_floor(n));
144
145 let mut denoised = coeffs.clone();
146 let mut current_n = n;
147
148 for _ in 0..levels {
149 let half = current_n / 2;
150 for i in half..current_n {
151 if denoised[i].abs() < threshold {
152 denoised[i] = 0.0;
153 }
154 }
155 current_n = half;
156 }
157
158 self.inverse(&denoised)
159 }
160}
161
162fn log2_floor(n: usize) -> usize {
163 if n == 0 { 0 } else { (n as f64).log2() as usize }
164}
165
166fn smallest_reconstruct(n: usize, levels: usize) -> usize {
167 n / (1 << (levels - 1).max(0))
169}
170
171pub struct TernaryFourier {
175 pub n_features: usize,
176 pub frequencies: Vec<f64>,
177}
178
179impl TernaryFourier {
180 pub fn new(n_features: usize) -> Self {
181 let frequencies: Vec<f64> = (1..=n_features).map(|i| i as f64).collect();
182 TernaryFourier {
183 n_features,
184 frequencies,
185 }
186 }
187
188 pub fn transform(&self, data: &[Ternary]) -> Vec<f64> {
190 let n = data.len() as f64;
191 let mut features = Vec::with_capacity(self.n_features * 2);
192
193 for &freq in &self.frequencies {
194 let mut cos_sum = 0.0;
195 let mut sin_sum = 0.0;
196 for (t, &val) in data.iter().enumerate() {
197 let x = val.to_f64();
198 let phase = 2.0 * PI * freq * t as f64 / n;
199 cos_sum += x * phase.cos();
200 sin_sum += x * phase.sin();
201 }
202 features.push(cos_sum / n);
203 features.push(sin_sum / n);
204 }
205
206 features
207 }
208
209 pub fn power_spectrum(&self, data: &[Ternary]) -> Vec<f64> {
211 let features = self.transform(data);
212 features
213 .chunks(2)
214 .map(|chunk| {
215 let cos_v = chunk[0];
216 let sin_v = if chunk.len() > 1 { chunk[1] } else { 0.0 };
217 cos_v * cos_v + sin_v * sin_v
218 })
219 .collect()
220 }
221
222 pub fn reconstruct(&self, features: &[f64], length: usize) -> Vec<f64> {
224 let mut result = vec![0.0; length];
225 let n = length as f64;
226
227 for (i, chunk) in features.chunks(2).enumerate() {
228 let cos_v = chunk[0];
229 let sin_v = if chunk.len() > 1 { chunk[1] } else { 0.0 };
230 let freq = (i + 1) as f64;
231 for t in 0..length {
232 let phase = 2.0 * PI * freq * t as f64 / n;
233 result[t] += cos_v * phase.cos() + sin_v * phase.sin();
234 }
235 }
236
237 result
238 }
239}
240
241pub struct RandomFeatures {
245 pub n_features: usize,
246 pub dim: usize,
247 pub weights: Vec<Vec<f64>>,
248 pub biases: Vec<f64>,
249}
250
251impl RandomFeatures {
252 pub fn new(n_features: usize, dim: usize, seed: u64) -> Self {
253 let weights: Vec<Vec<f64>> = (0..n_features)
254 .map(|i| {
255 (0..dim)
256 .map(|j| {
257 let s = seed.wrapping_add((i * dim + j) as u64);
259 pseudo_random(s)
260 })
261 .collect()
262 })
263 .collect();
264
265 let biases: Vec<f64> = (0..n_features)
266 .map(|i| pseudo_random(seed.wrapping_add(n_features as u64 * dim as u64 + i as u64)) * 2.0 * PI)
267 .collect();
268
269 RandomFeatures {
270 n_features,
271 dim,
272 weights,
273 biases,
274 }
275 }
276
277 pub fn transform(&self, input: &[f64]) -> Vec<f64> {
279 self.weights
280 .iter()
281 .zip(self.biases.iter())
282 .map(|(w, &b)| {
283 let dot: f64 = w.iter().zip(input.iter()).map(|(&a, &x)| a * x).sum();
284 (dot + b).cos()
285 })
286 .collect()
287 }
288
289 pub fn kernel_approx(&self, a: &[f64], b: &[f64]) -> f64 {
291 let fa = self.transform(a);
292 let fb = self.transform(b);
293 let dot: f64 = fa.iter().zip(fb.iter()).map(|(&x, &y)| x * y).sum();
294 dot / self.n_features as f64
295 }
296}
297
298fn pseudo_random(seed: u64) -> f64 {
299 let s = seed.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407);
301 ((s >> 33) as i64 as f64) / (1i64 << 31) as f64
302}
303
304pub struct TernaryKernel {
308 pub sigma: f64,
309}
310
311impl TernaryKernel {
312 pub fn new(sigma: f64) -> Self {
313 TernaryKernel { sigma }
314 }
315
316 pub fn rbf(&self, a: &[Ternary], b: &[Ternary]) -> f64 {
318 let dist_sq: f64 = a.iter()
319 .zip(b.iter())
320 .map(|(&x, &y)| {
321 let d = x.to_f64() - y.to_f64();
322 d * d
323 })
324 .sum();
325 (-dist_sq / (2.0 * self.sigma * self.sigma)).exp()
326 }
327
328 pub fn matching(&self, a: &[Ternary], b: &[Ternary]) -> f64 {
330 let matches = a.iter().zip(b.iter()).filter(|(&x, &y)| x == y).count();
331 matches as f64 / a.len().max(1) as f64
332 }
333
334 pub fn agreement(&self, a: &[Ternary], b: &[Ternary]) -> f64 {
336 let score: f64 = a.iter()
337 .zip(b.iter())
338 .map(|(&x, &y)| {
339 let xv = x.to_f64();
340 let yv = y.to_f64();
341 xv * yv
342 })
343 .sum();
344 score / a.len().max(1) as f64
345 }
346
347 pub fn polynomial(&self, a: &[Ternary], b: &[Ternary], degree: i32, offset: f64) -> f64 {
349 let dot: f64 = a.iter()
350 .zip(b.iter())
351 .map(|(&x, &y)| x.to_f64() * y.to_f64())
352 .sum();
353 (dot + offset).powi(degree)
354 }
355
356 pub fn kernel_matrix(&self, data: &[Vec<Ternary>], kernel_type: KernelType) -> Vec<Vec<f64>> {
358 let n = data.len();
359 let mut matrix = vec![vec![0.0; n]; n];
360 for i in 0..n {
361 for j in 0..n {
362 matrix[i][j] = match kernel_type {
363 KernelType::Rbf => self.rbf(&data[i], &data[j]),
364 KernelType::Matching => self.matching(&data[i], &data[j]),
365 KernelType::Agreement => self.agreement(&data[i], &data[j]),
366 KernelType::Polynomial(d, o) => self.polynomial(&data[i], &data[j], d, o),
367 };
368 }
369 }
370 matrix
371 }
372}
373
374#[derive(Debug, Clone, Copy)]
376pub enum KernelType {
377 Rbf,
378 Matching,
379 Agreement,
380 Polynomial(i32, f64),
381}
382
383pub struct TernaryRBFSimilarity {
387 pub gamma: f64,
388}
389
390impl TernaryRBFSimilarity {
391 pub fn new(gamma: f64) -> Self {
392 TernaryRBFSimilarity { gamma }
393 }
394
395 pub fn similarity(&self, a: &[Ternary], b: &[Ternary]) -> f64 {
397 let dist = self.hamming_distance(a, b) as f64;
398 (-self.gamma * dist).exp()
399 }
400
401 pub fn hamming_distance(&self, a: &[Ternary], b: &[Ternary]) -> usize {
403 a.iter().zip(b.iter()).filter(|(&x, &y)| x != y).count()
404 }
405
406 pub fn weighted_distance(&self, a: &[Ternary], b: &[Ternary]) -> f64 {
408 a.iter().zip(b.iter())
409 .map(|(&x, &y)| {
410 let xv = x.to_f64();
411 let yv = y.to_f64();
412 (xv - yv).abs()
413 })
414 .sum()
415 }
416
417 pub fn similarity_matrix(&self, data: &[Vec<Ternary>]) -> Vec<Vec<f64>> {
419 let n = data.len();
420 let mut matrix = vec![vec![0.0; n]; n];
421 for i in 0..n {
422 matrix[i][i] = 1.0;
423 for j in (i + 1)..n {
424 let s = self.similarity(&data[i], &data[j]);
425 matrix[i][j] = s;
426 matrix[j][i] = s;
427 }
428 }
429 matrix
430 }
431
432 pub fn knn(&self, query: &[Ternary], data: &[Vec<Ternary>], k: usize) -> Vec<(usize, f64)> {
434 let mut scored: Vec<(usize, f64)> = data.iter()
435 .enumerate()
436 .map(|(i, d)| (i, self.similarity(query, d)))
437 .collect();
438 scored.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
439 scored.truncate(k);
440 scored
441 }
442}
443
444#[cfg(test)]
445mod tests {
446 use super::*;
447
448 #[test]
449 fn test_wavelet_forward() {
450 let w = TernaryWavelet::new(1);
451 let data = vec![1.0, -1.0, 1.0, -1.0];
452 let coeffs = w.forward(&data);
453 assert_eq!(coeffs.len(), 4);
454 assert!(coeffs[0].abs() < 1e-10);
456 assert!(coeffs[1].abs() < 1e-10);
457 }
458
459 #[test]
460 fn test_wavelet_inverse() {
461 let w = TernaryWavelet::new(1);
462 let data = vec![3.0, 1.0, -1.0, 5.0];
463 let coeffs = w.forward(&data);
464 let reconstructed = w.inverse(&coeffs);
465 for i in 0..data.len() {
467 assert!((reconstructed[i] - data[i]).abs() < 1e-10);
468 }
469 }
470
471 #[test]
472 fn test_wavelet_energy() {
473 let w = TernaryWavelet::new(2);
474 let data = vec![1.0, -1.0, 1.0, -1.0];
475 let coeffs = w.forward(&data);
476 let energy = w.energy_per_level(&coeffs);
477 assert_eq!(energy.len(), 2);
478 }
479
480 #[test]
481 fn test_wavelet_denoise() {
482 let w = TernaryWavelet::new(1);
483 let data = vec![1.0, 0.01, -1.0, 0.01];
484 let denoised = w.denoise(&data, 0.05);
485 assert_eq!(denoised.len(), 4);
486 }
487
488 #[test]
489 fn test_wavelet_single_element() {
490 let w = TernaryWavelet::new(1);
491 let data = vec![5.0];
492 let coeffs = w.forward(&data);
493 assert_eq!(coeffs, vec![5.0]);
494 }
495
496 #[test]
497 fn test_fourier_transform() {
498 let f = TernaryFourier::new(3);
499 let data = vec![Ternary::Pos, Ternary::Neg, Ternary::Pos, Ternary::Neg];
500 let features = f.transform(&data);
501 assert_eq!(features.len(), 6); }
503
504 #[test]
505 fn test_fourier_power_spectrum() {
506 let f = TernaryFourier::new(4);
507 let data = vec![Ternary::Pos, Ternary::Neg, Ternary::Pos, Ternary::Neg];
508 let spectrum = f.power_spectrum(&data);
509 assert_eq!(spectrum.len(), 4);
510 assert!(spectrum[1] > spectrum[0]);
512 }
513
514 #[test]
515 fn test_fourier_reconstruct() {
516 let f = TernaryFourier::new(2);
517 let data = vec![Ternary::Pos, Ternary::Zero, Ternary::Neg, Ternary::Zero];
518 let features = f.transform(&data);
519 let reconstructed = f.reconstruct(&features, 4);
520 assert_eq!(reconstructed.len(), 4);
521 }
522
523 #[test]
524 fn test_fourier_constant_signal() {
525 let f = TernaryFourier::new(2);
526 let data = vec![Ternary::Zero, Ternary::Zero, Ternary::Zero, Ternary::Zero];
527 let features = f.transform(&data);
528 for &v in &features {
530 assert!(v.abs() < 1e-10);
531 }
532 }
533
534 #[test]
535 fn test_random_features_transform() {
536 let rf = RandomFeatures::new(10, 3, 42);
537 let input = vec![1.0, 0.0, -1.0];
538 let features = rf.transform(&input);
539 assert_eq!(features.len(), 10);
540 for &v in &features {
542 assert!(v >= -1.0 && v <= 1.0);
543 }
544 }
545
546 #[test]
547 fn test_random_features_kernel() {
548 let rf = RandomFeatures::new(100, 3, 42);
549 let a = vec![1.0, 0.0, -1.0];
550 let b = vec![1.0, 0.0, -1.0];
551 let k = rf.kernel_approx(&a, &b);
552 assert!(k > 0.5);
554 }
555
556 #[test]
557 fn test_ternary_kernel_rbf() {
558 let k = TernaryKernel::new(1.0);
559 let a = vec![Ternary::Pos, Ternary::Pos];
560 let b = vec![Ternary::Pos, Ternary::Pos];
561 let rbf = k.rbf(&a, &b);
562 assert!((rbf - 1.0).abs() < 1e-10);
563 }
564
565 #[test]
566 fn test_ternary_kernel_matching() {
567 let k = TernaryKernel::new(1.0);
568 let a = vec![Ternary::Pos, Ternary::Neg];
569 let b = vec![Ternary::Pos, Ternary::Zero];
570 let m = k.matching(&a, &b);
571 assert!((m - 0.5).abs() < 1e-10);
572 }
573
574 #[test]
575 fn test_ternary_kernel_agreement() {
576 let k = TernaryKernel::new(1.0);
577 let a = vec![Ternary::Pos, Ternary::Neg];
578 let b = vec![Ternary::Neg, Ternary::Pos];
579 let ag = k.agreement(&a, &b);
580 assert!((ag - (-1.0)).abs() < 1e-10);
581 }
582
583 #[test]
584 fn test_ternary_kernel_polynomial() {
585 let k = TernaryKernel::new(1.0);
586 let a = vec![Ternary::Pos, Ternary::Pos];
587 let b = vec![Ternary::Pos, Ternary::Pos];
588 let p = k.polynomial(&a, &b, 2, 1.0);
589 assert!((p - 9.0).abs() < 1e-10); }
591
592 #[test]
593 fn test_kernel_matrix() {
594 let k = TernaryKernel::new(1.0);
595 let data = vec![
596 vec![Ternary::Pos, Ternary::Pos],
597 vec![Ternary::Neg, Ternary::Neg],
598 ];
599 let m = k.kernel_matrix(&data, KernelType::Matching);
600 assert!((m[0][0] - 1.0).abs() < 1e-10);
601 assert!((m[1][1] - 1.0).abs() < 1e-10);
602 assert!(m[0][1] < 1.0);
603 }
604
605 #[test]
606 fn test_rbf_similarity() {
607 let sim = TernaryRBFSimilarity::new(1.0);
608 let a = vec![Ternary::Pos, Ternary::Pos];
609 let b = vec![Ternary::Pos, Ternary::Pos];
610 assert!((sim.similarity(&a, &b) - 1.0).abs() < 1e-10);
611 }
612
613 #[test]
614 fn test_rbf_hamming() {
615 let sim = TernaryRBFSimilarity::new(1.0);
616 let a = vec![Ternary::Pos, Ternary::Neg, Ternary::Zero];
617 let b = vec![Ternary::Pos, Ternary::Zero, Ternary::Zero];
618 assert_eq!(sim.hamming_distance(&a, &b), 1);
619 }
620
621 #[test]
622 fn test_rbf_weighted_distance() {
623 let sim = TernaryRBFSimilarity::new(1.0);
624 let a = vec![Ternary::Pos];
625 let b = vec![Ternary::Neg];
626 let d = sim.weighted_distance(&a, &b);
627 assert!((d - 2.0).abs() < 1e-10);
628 }
629
630 #[test]
631 fn test_rbf_similarity_matrix() {
632 let sim = TernaryRBFSimilarity::new(1.0);
633 let data = vec![
634 vec![Ternary::Pos],
635 vec![Ternary::Neg],
636 ];
637 let m = sim.similarity_matrix(&data);
638 assert!((m[0][0] - 1.0).abs() < 1e-10);
639 assert!((m[0][1] - m[1][0]).abs() < 1e-10);
640 }
641
642 #[test]
643 fn test_rbf_knn() {
644 let sim = TernaryRBFSimilarity::new(1.0);
645 let query = vec![Ternary::Pos, Ternary::Pos];
646 let data = vec![
647 vec![Ternary::Pos, Ternary::Pos],
648 vec![Ternary::Neg, Ternary::Neg],
649 vec![Ternary::Zero, Ternary::Zero],
650 ];
651 let knn = sim.knn(&query, &data, 2);
652 assert_eq!(knn.len(), 2);
653 assert_eq!(knn[0].0, 0); }
655}