causal_hub/utils/
pseudo_inverse.rs1use ndarray::prelude::*;
2use ndarray_linalg::SVD;
3use ndarray_stats::QuantileExt;
4
5use crate::types::EPSILON;
6
7pub trait PseudoInverse {
9 fn pinv(&self) -> Self;
20}
21
22impl PseudoInverse for Array2<f64> {
23 fn pinv(&self) -> Self {
24 let a = *self.abs().max().unwrap_or(&1.);
26 let m = self / a;
27 let (u, s, vt) = m.svd(true, true).unwrap_or_else(|e| {
29 panic!(
30 "Failed to compute the SVD \n\
31 \t for the matrix: \n\
32 \t {m:?} \n\
33 \t with error: \n\
34 \t {e:?}."
35 )
36 });
37 let u = u.expect("Failed to get U from the SVD.");
38 let vt = vt.expect("Failed to get VT from the SVD.");
39 let s_max = s.max().unwrap_or(&0.);
41 let r_tol = f64::max(EPSILON, s.len() as f64 * s_max * EPSILON);
42 let s_inv = Array2::from_diag(&s.mapv(|x| if x > r_tol { 1. / x } else { 0. }));
43 vt.t().dot(&s_inv).dot(&u.t()) / a
45 }
46}