1use crate::{convert::*, error::*, layout::*, types::*};
6use ndarray::*;
7
8pub 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
20pub 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
32pub 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}