flow_pacmap/config.rs
1//! Configuration types for a PaCMAP embedding run.
2
3pub use flow_knn::{DistanceMetric, HnswParams, KnnMethod, Quantization};
4
5/// Initialisation strategy for the 2-D embedding.
6#[derive(Debug, Clone)]
7pub enum Init {
8 /// PCA projection onto the top-2 principal components (default).
9 Pca,
10 /// Draw from N(0, 10⁻⁴ · I) with an optional seed.
11 Random(Option<u64>),
12}
13
14/// Backend for the Adam + pair-gradient optimize loop.
15#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
16pub enum OptimizeBackend {
17 /// Rayon CPU path (default).
18 #[default]
19 Cpu,
20 /// cubeCL CSR gradients + Burn Adam via wgpu (requires the `cubecl` feature and a WGPU adapter).
21 #[cfg(feature = "cubecl")]
22 Gpu,
23}
24
25/// Full configuration for a `fit_transform` call.
26#[derive(Debug, Clone)]
27pub struct PaCMAPConfig {
28 /// Number of near-neighbour pairs per point. Default 10.
29 pub n_neighbors: usize,
30 /// Ratio nMN / n_neighbors. Default 0.5.
31 pub mn_ratio: f32,
32 /// Ratio nFP / n_neighbors. Default 2.0.
33 pub fp_ratio: f32,
34 /// Iteration counts for phases [1, 2, 3]. Sum = total iterations. Default [100, 100, 250].
35 pub phase_iters: [usize; 3],
36 /// Adam learning rate. Default 1.0.
37 pub learning_rate: f32,
38 /// Embedding initialisation. Default `Init::Pca`.
39 pub init: Init,
40 /// Random seed for reproducible runs.
41 pub seed: Option<u64>,
42 /// KNN method. Default HNSW when the `hnsw` feature is enabled.
43 pub knn_method: KnnMethod,
44 /// Distance metric. Default Euclidean.
45 pub distance_metric: DistanceMetric,
46 /// Optimize backend. Default [`OptimizeBackend::Cpu`].
47 pub optimize_backend: OptimizeBackend,
48}
49
50impl Default for PaCMAPConfig {
51 fn default() -> Self {
52 Self {
53 n_neighbors: 10,
54 mn_ratio: 0.5,
55 fp_ratio: 2.0,
56 phase_iters: [100, 100, 250],
57 learning_rate: 1.0,
58 init: Init::Pca,
59 seed: None,
60 knn_method: KnnMethod::default(),
61 distance_metric: DistanceMetric::default(),
62 optimize_backend: OptimizeBackend::default(),
63 }
64 }
65}
66
67impl PaCMAPConfig {
68 /// Derived: number of mid-near pairs per point = floor(n_neighbors * mn_ratio).
69 pub fn n_mn(&self) -> usize {
70 (self.n_neighbors as f32 * self.mn_ratio).floor() as usize
71 }
72 /// Derived: number of further pairs per point = floor(n_neighbors * fp_ratio).
73 pub fn n_fp(&self) -> usize {
74 (self.n_neighbors as f32 * self.fp_ratio).floor() as usize
75 }
76 /// Total optimization iterations across all phases.
77 pub fn total_iters(&self) -> usize {
78 self.phase_iters.iter().sum()
79 }
80}