Skip to main content

apex_solver/linearizer/cpu/
mod.rs

1//! CPU linearizer implementations.
2//!
3//! Provides sparse and dense Jacobian assembly for CPU computation.
4//! GPU equivalent lives in the sibling [`super::gpu`] module.
5//!
6//! This module also owns the [`LinearizationMode`] marker trait and its two
7//! implementations ([`SparseMode`], [`DenseMode`]), which define the matrix
8//! types used throughout the solver pipeline.
9
10pub mod dense;
11pub mod sparse;
12
13use faer::{Mat, sparse::SparseColMat};
14
15// ============================================================================
16// LinearizationMode — static dispatch between sparse and dense paths
17// ============================================================================
18
19/// Marker trait that defines the matrix types for a linear algebra path.
20///
21/// Enables zero-cost static dispatch between sparse and dense linear algebra
22/// backends. Optimizers are generic over `LinearizationMode`, so the compiler
23/// generates one specialization per concrete mode at no runtime cost.
24///
25/// Two implementations are provided:
26/// - [`SparseMode`]: Jacobian and Hessian are `SparseColMat<usize, f64>`
27/// - [`DenseMode`]: Jacobian and Hessian are `Mat<f64>`
28pub trait LinearizationMode: 'static {
29    /// The Jacobian matrix type (`SparseColMat` or `Mat`)
30    type Jacobian: Send + Sync;
31    /// The Hessian matrix type (`SparseColMat` or `Mat`)
32    type Hessian: Send + Sync;
33}
34
35/// Sparse linear algebra mode.
36///
37/// Uses `SparseColMat<usize, f64>` for Jacobians and Hessians.
38/// Optimal for large-scale problems with sparse structure (e.g., pose graphs).
39pub struct SparseMode;
40
41impl LinearizationMode for SparseMode {
42    type Jacobian = SparseColMat<usize, f64>;
43    type Hessian = SparseColMat<usize, f64>;
44}
45
46/// Dense linear algebra mode.
47///
48/// Uses `Mat<f64>` for Jacobians and Hessians.
49/// Optimal for small-to-medium problems (< 500 DOF) or dense Jacobians.
50pub struct DenseMode;
51
52impl LinearizationMode for DenseMode {
53    type Jacobian = Mat<f64>;
54    type Hessian = Mat<f64>;
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use faer::{Mat, sparse::SparseColMat};
61
62    type TestResult = Result<(), Box<dyn std::error::Error>>;
63
64    #[test]
65    fn test_sparse_mode_jacobian_is_sparse_col_mat() -> TestResult {
66        let j: <SparseMode as LinearizationMode>::Jacobian = SparseColMat::try_new_from_triplets(
67            1,
68            1,
69            &[faer::sparse::Triplet::new(0usize, 0usize, 1.0f64)],
70        )?;
71        assert_eq!(j.ncols(), 1);
72        Ok(())
73    }
74
75    #[test]
76    fn test_sparse_mode_hessian_is_sparse_col_mat() -> TestResult {
77        let h: <SparseMode as LinearizationMode>::Hessian = SparseColMat::try_new_from_triplets(
78            2,
79            2,
80            &[
81                faer::sparse::Triplet::new(0usize, 0usize, 1.0f64),
82                faer::sparse::Triplet::new(1usize, 1usize, 2.0f64),
83            ],
84        )?;
85        assert_eq!(h.nrows(), 2);
86        Ok(())
87    }
88
89    #[test]
90    fn test_dense_mode_jacobian_is_mat() {
91        let j: <DenseMode as LinearizationMode>::Jacobian = Mat::zeros(3, 4);
92        assert_eq!(j.nrows(), 3);
93        assert_eq!(j.ncols(), 4);
94    }
95
96    #[test]
97    fn test_dense_mode_hessian_is_mat() {
98        let h: <DenseMode as LinearizationMode>::Hessian =
99            Mat::from_fn(2, 2, |i, j| if i == j { 1.0 } else { 0.0 });
100        assert!((h[(0, 0)] - 1.0).abs() < 1e-12);
101        assert!(h[(0, 1)].abs() < 1e-12);
102    }
103}