|
9 | 9 | //! Based on ArrowSpace's start_clustering_dim_reduce algorithm [file:6] |
10 | 10 |
|
11 | 11 | use crate::centroid::CentroidState; |
| 12 | +use crate::reduction::{ImplicitProjection, compute_jl_dimension}; |
12 | 13 | use burn::prelude::*; |
13 | 14 | use rayon::prelude::*; |
14 | 15 |
|
@@ -66,62 +67,6 @@ impl ClusteringConfig { |
66 | 67 | } |
67 | 68 | } |
68 | 69 |
|
69 | | -/// JL Projection matrix (implicit, seed-based) [file:6] |
70 | | -pub struct ImplicitProjection { |
71 | | - pub original_dim: usize, |
72 | | - pub target_dim: usize, |
73 | | - pub seed: u64, |
74 | | -} |
75 | | - |
76 | | -impl ImplicitProjection { |
77 | | - pub(crate) fn new(original_dim: usize, target_dim: usize, seed: Option<u64>) -> Self { |
78 | | - Self { |
79 | | - original_dim, |
80 | | - target_dim, |
81 | | - seed: seed.unwrap_or(42), |
82 | | - } |
83 | | - } |
84 | | - |
85 | | - /// Project a single row: x (F) -> y (R) |
86 | | - pub(crate) fn project(&self, row: &[f32]) -> Vec<f32> { |
87 | | - use rand::{Rng, SeedableRng}; |
88 | | - use rand_chacha::ChaCha8Rng; |
89 | | - |
90 | | - assert_eq!(row.len(), self.original_dim); |
91 | | - |
92 | | - let scale = 1.0 / (self.target_dim as f32).sqrt(); |
93 | | - let mut result = vec![0.0f32; self.target_dim]; |
94 | | - |
95 | | - // Generate random Gaussian projection on-the-fly (memory efficient) |
96 | | - let mut rng = ChaCha8Rng::seed_from_u64(self.seed); |
97 | | - |
98 | | - for j in 0..self.target_dim { |
99 | | - let mut sum = 0.0f32; |
100 | | - for i in 0..self.original_dim { |
101 | | - // Sample from N(0, 1) |
102 | | - let rand_val: f32 = rng.sample(rand_distr::StandardNormal); |
103 | | - sum += row[i] * rand_val; |
104 | | - } |
105 | | - result[j] = sum * scale; |
106 | | - } |
107 | | - |
108 | | - result |
109 | | - } |
110 | | -} |
111 | | - |
112 | | -/// Compute JL target dimension [file:6] |
113 | | -pub(crate) fn compute_jl_dimension(n_points: usize, original_dim: usize, epsilon: f32) -> usize { |
114 | | - if original_dim < 32 { |
115 | | - return original_dim; |
116 | | - } |
117 | | - |
118 | | - let log_n = (n_points as f32).ln(); |
119 | | - let eps_sq = epsilon.powi(2); |
120 | | - let jl_bound = (8.0 * log_n / eps_sq).ceil() as usize; |
121 | | - |
122 | | - jl_bound.clamp(32, original_dim) |
123 | | -} |
124 | | - |
125 | 70 | /// Output of the clustering stage |
126 | 71 | pub struct ClusteringOutput<B: Backend> { |
127 | 72 | pub state: CentroidState<B>, |
|
0 commit comments