ndarray_linalg/
svd.rs

1//! Singular-value decomposition (SVD)
2//!
3//! [Wikipedia article on SVD](https://en.wikipedia.org/wiki/Singular_value_decomposition)
4
5use crate::{convert::*, error::*, layout::*, types::*};
6use ndarray::*;
7
8/// singular-value decomposition of matrix reference
9pub trait SVD {
10    type U;
11    type VT;
12    type Sigma;
13    fn svd(
14        &self,
15        calc_u: bool,
16        calc_vt: bool,
17    ) -> Result<(Option<Self::U>, Self::Sigma, Option<Self::VT>)>;
18}
19
20/// singular-value decomposition
21pub trait SVDInto {
22    type U;
23    type VT;
24    type Sigma;
25    fn svd_into(
26        self,
27        calc_u: bool,
28        calc_vt: bool,
29    ) -> Result<(Option<Self::U>, Self::Sigma, Option<Self::VT>)>;
30}
31
32/// singular-value decomposition for mutable reference of matrix
33pub trait SVDInplace {
34    type U;
35    type VT;
36    type Sigma;
37    fn svd_inplace(
38        &mut self,
39        calc_u: bool,
40        calc_vt: bool,
41    ) -> Result<(Option<Self::U>, Self::Sigma, Option<Self::VT>)>;
42}
43
44impl<A, S> SVDInto for ArrayBase<S, Ix2>
45where
46    A: Scalar + Lapack,
47    S: DataMut<Elem = A>,
48{
49    type U = Array2<A>;
50    type VT = Array2<A>;
51    type Sigma = Array1<A::Real>;
52
53    fn svd_into(
54        mut self,
55        calc_u: bool,
56        calc_vt: bool,
57    ) -> Result<(Option<Self::U>, Self::Sigma, Option<Self::VT>)> {
58        self.svd_inplace(calc_u, calc_vt)
59    }
60}
61
62impl<A> SVD for ArrayRef<A, Ix2>
63where
64    A: Scalar + Lapack,
65{
66    type U = Array2<A>;
67    type VT = Array2<A>;
68    type Sigma = Array1<A::Real>;
69
70    fn svd(
71        &self,
72        calc_u: bool,
73        calc_vt: bool,
74    ) -> Result<(Option<Self::U>, Self::Sigma, Option<Self::VT>)> {
75        let a = self.to_owned();
76        a.svd_into(calc_u, calc_vt)
77    }
78}
79
80impl<A> SVDInplace for ArrayRef<A, Ix2>
81where
82    A: Scalar + Lapack,
83{
84    type U = Array2<A>;
85    type VT = Array2<A>;
86    type Sigma = Array1<A::Real>;
87
88    fn svd_inplace(
89        &mut self,
90        calc_u: bool,
91        calc_vt: bool,
92    ) -> Result<(Option<Self::U>, Self::Sigma, Option<Self::VT>)> {
93        let l = self.layout()?;
94        let svd_res = A::svd(l, calc_u, calc_vt, self.as_allocated_mut()?)?;
95        let (n, m) = l.size();
96
97        let u = svd_res.u.map(|u| into_matrix(l.resized(n, n), u).unwrap());
98        let vt = svd_res
99            .vt
100            .map(|vt| into_matrix(l.resized(m, m), vt).unwrap());
101        let s = ArrayBase::from(svd_res.s);
102        Ok((u, s, vt))
103    }
104}