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};
6
7pub fn determine_chunk_size(nrows: usize) -> usize {
8 let num_threads = rayon::current_num_threads();
9
10 let min_rows_per_thread = 16;
11 let desired_chunks_per_thread = 4;
12
13 let target_total_chunks = num_threads * desired_chunks_per_thread;
14 let chunk_size = nrows.div_ceil(target_total_chunks);
15
16 chunk_size.max(min_rows_per_thread)
17}
18
19pub trait SMat<T: Float>: Sync {
20 fn nrows(&self) -> usize;
21 fn ncols(&self) -> usize;
22 fn nnz(&self) -> usize;
23 fn svd_opa(&self, x: &[T], y: &mut [T], transposed: bool); }
25
26#[derive(Debug, Clone, PartialEq)]
35pub struct SvdRec<T: Float> {
36 pub d: usize,
37 pub u: Array2<T>,
38 pub s: Array1<T>,
39 pub vt: Array2<T>,
40 pub diagnostics: Diagnostics<T>,
41}
42
43#[derive(Debug, Clone, PartialEq)]
58pub struct Diagnostics<T: Float> {
59 pub non_zero: usize,
60 pub dimensions: usize,
61 pub iterations: usize,
62 pub transposed: bool,
63 pub lanczos_steps: usize,
64 pub ritz_values_stabilized: usize,
65 pub significant_values: usize,
66 pub singular_values: usize,
67 pub end_interval: [T; 2],
68 pub kappa: T,
69 pub random_seed: u32,
70}
71
72pub trait SvdFloat:
73 Float
74 + FromPrimitive
75 + Debug
76 + Send
77 + Sync
78 + Zero
79 + One
80 + AddAssign
81 + SubAssign
82 + MulAssign
83 + Neg<Output = Self>
84 + Sum
85{
86 fn eps() -> Self;
87 fn eps34() -> Self;
88 fn compare(a: Self, b: Self) -> bool;
89}
90
91impl SvdFloat for f32 {
92 fn eps() -> Self {
93 f32::EPSILON
94 }
95
96 fn eps34() -> Self {
97 f32::EPSILON.powf(0.75)
98 }
99
100 fn compare(a: Self, b: Self) -> bool {
101 (b - a).abs() < f32::EPSILON
102 }
103}
104
105impl SvdFloat for f64 {
106 fn eps() -> Self {
107 f64::EPSILON
108 }
109
110 fn eps34() -> Self {
111 f64::EPSILON.powf(0.75)
112 }
113
114 fn compare(a: Self, b: Self) -> bool {
115 (b - a).abs() < f64::EPSILON
116 }
117}