Skip to main content

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}