single_svdlib/
utils.rs

1use ndarray::{Array1, Array2};
2use num_traits::{Float, FromPrimitive, One, Zero};
3use std::fmt::Debug;
4use std::iter::Sum;
5use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
6use single_utilities::traits::FloatOpsTS;
7
8pub fn determine_chunk_size(nrows: usize) -> usize {
9    let num_threads = rayon::current_num_threads();
10
11    let min_rows_per_thread = 16;
12    let desired_chunks_per_thread = 4;
13
14    let target_total_chunks = num_threads * desired_chunks_per_thread;
15    let chunk_size = nrows.div_ceil(target_total_chunks);
16
17    chunk_size.max(min_rows_per_thread)
18}
19
20pub trait SMat<T: Float>: Sync {
21    fn nrows(&self) -> usize;
22    fn ncols(&self) -> usize;
23    fn nnz(&self) -> usize;
24    fn svd_opa(&self, x: &[T], y: &mut [T], transposed: bool); // y = A*x
25    
26    fn compute_column_means(&self) -> Vec<T>;
27}
28
29/// Singular Value Decomposition Components
30///
31/// # Fields
32/// - d:  Dimensionality (rank), the number of rows of both `ut`, `vt` and the length of `s`
33/// - ut: Transpose of left singular vectors, the vectors are the rows of `ut`
34/// - s:  Singular values (length `d`)
35/// - vt: Transpose of right singular vectors, the vectors are the rows of `vt`
36/// - diagnostics: Computational diagnostics
37#[derive(Debug, Clone, PartialEq)]
38pub struct SvdRec<T: Float> {
39    pub d: usize,
40    pub u: Array2<T>,
41    pub s: Array1<T>,
42    pub vt: Array2<T>,
43    pub diagnostics: Diagnostics<T>,
44}
45
46/// Computational Diagnostics
47///
48/// # Fields
49/// - non_zero:  Number of non-zeros in the matrix
50/// - dimensions: Number of dimensions attempted (bounded by matrix shape)
51/// - iterations: Number of iterations attempted (bounded by dimensions and matrix shape)
52/// - transposed:  True if the matrix was transposed internally
53/// - lanczos_steps: Number of Lanczos steps performed
54/// - ritz_values_stabilized: Number of ritz values
55/// - significant_values: Number of significant values discovered
56/// - singular_values: Number of singular values returned
57/// - end_interval: left, right end of interval containing unwanted eigenvalues
58/// - kappa: relative accuracy of ritz values acceptable as eigenvalues
59/// - random_seed: Random seed provided or the seed generated
60#[derive(Debug, Clone, PartialEq)]
61pub struct Diagnostics<T: Float> {
62    pub non_zero: usize,
63    pub dimensions: usize,
64    pub iterations: usize,
65    pub transposed: bool,
66    pub lanczos_steps: usize,
67    pub ritz_values_stabilized: usize,
68    pub significant_values: usize,
69    pub singular_values: usize,
70    pub end_interval: [T; 2],
71    pub kappa: T,
72    pub random_seed: u32,
73}
74
75pub trait SvdFloat:
76    FloatOpsTS
77{
78    fn eps() -> Self;
79    fn eps34() -> Self;
80    fn compare(a: Self, b: Self) -> bool;
81}
82
83impl SvdFloat for f32 {
84    fn eps() -> Self {
85        f32::EPSILON
86    }
87
88    fn eps34() -> Self {
89        f32::EPSILON.powf(0.75)
90    }
91
92    fn compare(a: Self, b: Self) -> bool {
93        (b - a).abs() < f32::EPSILON
94    }
95}
96
97impl SvdFloat for f64 {
98    fn eps() -> Self {
99        f64::EPSILON
100    }
101
102    fn eps34() -> Self {
103        f64::EPSILON.powf(0.75)
104    }
105
106    fn compare(a: Self, b: Self) -> bool {
107        (b - a).abs() < f64::EPSILON
108    }
109}