1#[cfg(feature = "serde-serialize-no-std")]
2use serde::{Deserialize, Serialize};
3use std::any::TypeId;
4
5use approx::AbsDiffEq;
6use num::{One, Zero};
7
8use crate::allocator::Allocator;
9use crate::base::{DefaultAllocator, Matrix, Matrix2x3, OMatrix, OVector, Vector2};
10use crate::constraint::{SameNumberOfRows, ShapeConstraint};
11use crate::dimension::{Dim, DimDiff, DimMin, DimMinimum, DimSub, U1};
12use crate::storage::Storage;
13use crate::{Matrix2, Matrix3, RawStorage, U2, U3};
14use simba::scalar::{ComplexField, RealField};
15
16use crate::linalg::givens::GivensRotation;
17use crate::linalg::symmetric_eigen;
18use crate::linalg::Bidiagonal;
19
20#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
22#[cfg_attr(
23 feature = "serde-serialize-no-std",
24 serde(bound(
25 serialize = "DefaultAllocator: Allocator<T::RealField, DimMinimum<R, C>> +
26 Allocator<T, DimMinimum<R, C>, C> +
27 Allocator<T, R, DimMinimum<R, C>>,
28 OMatrix<T, R, DimMinimum<R, C>>: Serialize,
29 OMatrix<T, DimMinimum<R, C>, C>: Serialize,
30 OVector<T::RealField, DimMinimum<R, C>>: Serialize"
31 ))
32)]
33#[cfg_attr(
34 feature = "serde-serialize-no-std",
35 serde(bound(
36 deserialize = "DefaultAllocator: Allocator<T::RealField, DimMinimum<R, C>> +
37 Allocator<T, DimMinimum<R, C>, C> +
38 Allocator<T, R, DimMinimum<R, C>>,
39 OMatrix<T, R, DimMinimum<R, C>>: Deserialize<'de>,
40 OMatrix<T, DimMinimum<R, C>, C>: Deserialize<'de>,
41 OVector<T::RealField, DimMinimum<R, C>>: Deserialize<'de>"
42 ))
43)]
44#[derive(Clone, Debug)]
45pub struct SVD<T: ComplexField, R: DimMin<C>, C: Dim>
46where
47 DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>
48 + Allocator<T, R, DimMinimum<R, C>>
49 + Allocator<T::RealField, DimMinimum<R, C>>,
50{
51 pub u: Option<OMatrix<T, R, DimMinimum<R, C>>>,
53 pub v_t: Option<OMatrix<T, DimMinimum<R, C>, C>>,
55 pub singular_values: OVector<T::RealField, DimMinimum<R, C>>,
57}
58
59impl<T: ComplexField, R: DimMin<C>, C: Dim> Copy for SVD<T, R, C>
60where
61 DefaultAllocator: Allocator<T, DimMinimum<R, C>, C>
62 + Allocator<T, R, DimMinimum<R, C>>
63 + Allocator<T::RealField, DimMinimum<R, C>>,
64 OMatrix<T, R, DimMinimum<R, C>>: Copy,
65 OMatrix<T, DimMinimum<R, C>, C>: Copy,
66 OVector<T::RealField, DimMinimum<R, C>>: Copy,
67{
68}
69
70impl<T: ComplexField, R: DimMin<C>, C: Dim> SVD<T, R, C>
71where
72 DimMinimum<R, C>: DimSub<U1>, DefaultAllocator: Allocator<T, R, C>
74 + Allocator<T, C>
75 + Allocator<T, R>
76 + Allocator<T, DimDiff<DimMinimum<R, C>, U1>>
77 + Allocator<T, DimMinimum<R, C>, C>
78 + Allocator<T, R, DimMinimum<R, C>>
79 + Allocator<T, DimMinimum<R, C>>
80 + Allocator<T::RealField, DimMinimum<R, C>>
81 + Allocator<T::RealField, DimDiff<DimMinimum<R, C>, U1>>,
82{
83 fn use_special_always_ordered_svd2() -> bool {
84 TypeId::of::<OMatrix<T, R, C>>() == TypeId::of::<Matrix2<T::RealField>>()
85 && TypeId::of::<Self>() == TypeId::of::<SVD<T::RealField, U2, U2>>()
86 }
87
88 fn use_special_always_ordered_svd3() -> bool {
89 TypeId::of::<OMatrix<T, R, C>>() == TypeId::of::<Matrix3<T::RealField>>()
90 && TypeId::of::<Self>() == TypeId::of::<SVD<T::RealField, U3, U3>>()
91 }
92
93 pub fn new_unordered(matrix: OMatrix<T, R, C>, compute_u: bool, compute_v: bool) -> Self {
97 Self::try_new_unordered(
98 matrix,
99 compute_u,
100 compute_v,
101 T::RealField::default_epsilon(),
102 0,
103 )
104 .unwrap()
105 }
106
107 pub fn try_new_unordered(
120 mut matrix: OMatrix<T, R, C>,
121 compute_u: bool,
122 compute_v: bool,
123 eps: T::RealField,
124 max_niter: usize,
125 ) -> Option<Self> {
126 assert!(
127 !matrix.is_empty(),
128 "Cannot compute the SVD of an empty matrix."
129 );
130 let (nrows, ncols) = matrix.shape_generic();
131 let min_nrows_ncols = nrows.min(ncols);
132
133 if Self::use_special_always_ordered_svd2() {
134 let matrix: &Matrix2<T::RealField> = unsafe { std::mem::transmute(&matrix) };
136 let result = super::svd2::svd_ordered2(matrix, compute_u, compute_v);
137 let typed_result: &Self = unsafe { std::mem::transmute(&result) };
138 return Some(typed_result.clone());
139 } else if Self::use_special_always_ordered_svd3() {
140 let matrix: &Matrix3<T::RealField> = unsafe { std::mem::transmute(&matrix) };
142 let result = super::svd3::svd_ordered3(matrix, compute_u, compute_v, eps, max_niter);
143 let typed_result: &Self = unsafe { std::mem::transmute(&result) };
144 return Some(typed_result.clone());
145 }
146
147 let dim = min_nrows_ncols.value();
148
149 let m_amax = matrix.camax();
150
151 if !m_amax.is_zero() {
152 matrix.unscale_mut(m_amax.clone());
153 }
154
155 let bi_matrix = Bidiagonal::new(matrix);
156 let mut u = if compute_u { Some(bi_matrix.u()) } else { None };
157 let mut v_t = if compute_v {
158 Some(bi_matrix.v_t())
159 } else {
160 None
161 };
162 let mut diagonal = bi_matrix.diagonal();
163 let mut off_diagonal = bi_matrix.off_diagonal();
164
165 let mut niter = 0;
166 let (mut start, mut end) = Self::delimit_subproblem(
167 &mut diagonal,
168 &mut off_diagonal,
169 &mut u,
170 &mut v_t,
171 bi_matrix.is_upper_diagonal(),
172 dim - 1,
173 eps.clone(),
174 );
175
176 while end != start {
177 let subdim = end - start + 1;
178
179 #[allow(clippy::comparison_chain)]
181 if subdim > 2 {
182 let m = end - 1;
183 let n = end;
184
185 let mut vec;
186 {
187 let dm = diagonal[m].clone();
188 let dn = diagonal[n].clone();
189 let fm = off_diagonal[m].clone();
190
191 let tmm = dm.clone() * dm.clone()
192 + off_diagonal[m - 1].clone() * off_diagonal[m - 1].clone();
193 let tmn = dm * fm.clone();
194 let tnn = dn.clone() * dn + fm.clone() * fm;
195
196 let shift = symmetric_eigen::wilkinson_shift(tmm, tnn, tmn);
197
198 vec = Vector2::new(
199 diagonal[start].clone() * diagonal[start].clone() - shift,
200 diagonal[start].clone() * off_diagonal[start].clone(),
201 );
202 }
203
204 for k in start..n {
205 let m12 = if k == n - 1 {
206 T::RealField::zero()
207 } else {
208 off_diagonal[k + 1].clone()
209 };
210
211 let mut subm = Matrix2x3::new(
212 diagonal[k].clone(),
213 off_diagonal[k].clone(),
214 T::RealField::zero(),
215 T::RealField::zero(),
216 diagonal[k + 1].clone(),
217 m12,
218 );
219
220 if let Some((rot1, norm1)) = GivensRotation::cancel_y(&vec) {
221 rot1.inverse()
222 .rotate_rows(&mut subm.fixed_columns_mut::<2>(0));
223 let rot1 = GivensRotation::new_unchecked(rot1.c(), T::from_real(rot1.s()));
224
225 if k > start {
226 off_diagonal[k - 1] = norm1;
228 }
229
230 let v = Vector2::new(subm[(0, 0)].clone(), subm[(1, 0)].clone());
231 let (rot2, norm2) = GivensRotation::cancel_y(&v)
233 .unwrap_or((GivensRotation::identity(), subm[(0, 0)].clone()));
234
235 rot2.rotate(&mut subm.fixed_columns_mut::<2>(1));
236 let rot2 = GivensRotation::new_unchecked(rot2.c(), T::from_real(rot2.s()));
237
238 subm[(0, 0)] = norm2;
239
240 if let Some(ref mut v_t) = v_t {
241 if bi_matrix.is_upper_diagonal() {
242 rot1.rotate(&mut v_t.fixed_rows_mut::<2>(k));
243 } else {
244 rot2.rotate(&mut v_t.fixed_rows_mut::<2>(k));
245 }
246 }
247
248 if let Some(ref mut u) = u {
249 if bi_matrix.is_upper_diagonal() {
250 rot2.inverse().rotate_rows(&mut u.fixed_columns_mut::<2>(k));
251 } else {
252 rot1.inverse().rotate_rows(&mut u.fixed_columns_mut::<2>(k));
253 }
254 }
255
256 diagonal[k] = subm[(0, 0)].clone();
257 diagonal[k + 1] = subm[(1, 1)].clone();
258 off_diagonal[k] = subm[(0, 1)].clone();
259
260 if k != n - 1 {
261 off_diagonal[k + 1] = subm[(1, 2)].clone();
262 }
263
264 vec.x = subm[(0, 1)].clone();
265 vec.y = subm[(0, 2)].clone();
266 } else {
267 break;
268 }
269 }
270 } else if subdim == 2 {
271 let (u2, s, v2) = compute_2x2_uptrig_svd(
273 diagonal[start].clone(),
274 off_diagonal[start].clone(),
275 diagonal[start + 1].clone(),
276 compute_u && bi_matrix.is_upper_diagonal()
277 || compute_v && !bi_matrix.is_upper_diagonal(),
278 compute_v && bi_matrix.is_upper_diagonal()
279 || compute_u && !bi_matrix.is_upper_diagonal(),
280 );
281 let u2 = u2.map(|u2| GivensRotation::new_unchecked(u2.c(), T::from_real(u2.s())));
282 let v2 = v2.map(|v2| GivensRotation::new_unchecked(v2.c(), T::from_real(v2.s())));
283
284 diagonal[start] = s[0].clone();
285 diagonal[start + 1] = s[1].clone();
286 off_diagonal[start] = T::RealField::zero();
287
288 if let Some(ref mut u) = u {
289 let rot = if bi_matrix.is_upper_diagonal() {
290 u2.clone().unwrap()
291 } else {
292 v2.clone().unwrap()
293 };
294 rot.rotate_rows(&mut u.fixed_columns_mut::<2>(start));
295 }
296
297 if let Some(ref mut v_t) = v_t {
298 let rot = if bi_matrix.is_upper_diagonal() {
299 v2.unwrap()
300 } else {
301 u2.unwrap()
302 };
303 rot.inverse().rotate(&mut v_t.fixed_rows_mut::<2>(start));
304 }
305
306 end -= 1;
307 }
308
309 let sub = Self::delimit_subproblem(
311 &mut diagonal,
312 &mut off_diagonal,
313 &mut u,
314 &mut v_t,
315 bi_matrix.is_upper_diagonal(),
316 end,
317 eps.clone(),
318 );
319 start = sub.0;
320 end = sub.1;
321
322 niter += 1;
323 if niter == max_niter {
324 return None;
325 }
326 }
327
328 diagonal *= m_amax;
329
330 for i in 0..dim {
332 let sval = diagonal[i].clone();
333
334 if sval < T::RealField::zero() {
335 diagonal[i] = -sval;
336
337 if let Some(ref mut u) = u {
338 u.column_mut(i).neg_mut();
339 }
340 }
341 }
342
343 Some(Self {
344 u,
345 v_t,
346 singular_values: diagonal,
347 })
348 }
349
350 fn delimit_subproblem(
366 diagonal: &mut OVector<T::RealField, DimMinimum<R, C>>,
367 off_diagonal: &mut OVector<T::RealField, DimDiff<DimMinimum<R, C>, U1>>,
368 u: &mut Option<OMatrix<T, R, DimMinimum<R, C>>>,
369 v_t: &mut Option<OMatrix<T, DimMinimum<R, C>, C>>,
370 is_upper_diagonal: bool,
371 end: usize,
372 eps: T::RealField,
373 ) -> (usize, usize) {
374 let mut n = end;
375
376 while n > 0 {
377 let m = n - 1;
378
379 if off_diagonal[m].is_zero()
380 || off_diagonal[m].clone().norm1()
381 <= eps.clone() * (diagonal[n].clone().norm1() + diagonal[m].clone().norm1())
382 {
383 off_diagonal[m] = T::RealField::zero();
384 } else if diagonal[m].clone().norm1() <= eps {
385 diagonal[m] = T::RealField::zero();
386 Self::cancel_horizontal_off_diagonal_elt(
387 diagonal,
388 off_diagonal,
389 u,
390 v_t,
391 is_upper_diagonal,
392 m,
393 m + 1,
394 );
395
396 if m != 0 {
397 Self::cancel_vertical_off_diagonal_elt(
398 diagonal,
399 off_diagonal,
400 u,
401 v_t,
402 is_upper_diagonal,
403 m - 1,
404 );
405 }
406 } else if diagonal[n].clone().norm1() <= eps {
407 diagonal[n] = T::RealField::zero();
408 Self::cancel_vertical_off_diagonal_elt(
409 diagonal,
410 off_diagonal,
411 u,
412 v_t,
413 is_upper_diagonal,
414 m,
415 );
416 } else {
417 break;
418 }
419
420 n -= 1;
421 }
422
423 if n == 0 {
424 return (0, 0);
425 }
426
427 let mut new_start = n - 1;
428 while new_start > 0 {
429 let m = new_start - 1;
430
431 if off_diagonal[m].clone().norm1()
432 <= eps.clone() * (diagonal[new_start].clone().norm1() + diagonal[m].clone().norm1())
433 {
434 off_diagonal[m] = T::RealField::zero();
435 break;
436 }
437 else if diagonal[m].clone().norm1() <= eps {
439 diagonal[m] = T::RealField::zero();
440 Self::cancel_horizontal_off_diagonal_elt(
441 diagonal,
442 off_diagonal,
443 u,
444 v_t,
445 is_upper_diagonal,
446 m,
447 n,
448 );
449
450 if m != 0 {
451 Self::cancel_vertical_off_diagonal_elt(
452 diagonal,
453 off_diagonal,
454 u,
455 v_t,
456 is_upper_diagonal,
457 m - 1,
458 );
459 }
460 break;
461 }
462
463 new_start -= 1;
464 }
465
466 (new_start, n)
467 }
468
469 fn cancel_horizontal_off_diagonal_elt(
471 diagonal: &mut OVector<T::RealField, DimMinimum<R, C>>,
472 off_diagonal: &mut OVector<T::RealField, DimDiff<DimMinimum<R, C>, U1>>,
473 u: &mut Option<OMatrix<T, R, DimMinimum<R, C>>>,
474 v_t: &mut Option<OMatrix<T, DimMinimum<R, C>, C>>,
475 is_upper_diagonal: bool,
476 i: usize,
477 end: usize,
478 ) {
479 let mut v = Vector2::new(off_diagonal[i].clone(), diagonal[i + 1].clone());
480 off_diagonal[i] = T::RealField::zero();
481
482 for k in i..end {
483 if let Some((rot, norm)) = GivensRotation::cancel_x(&v) {
484 let rot = GivensRotation::new_unchecked(rot.c(), T::from_real(rot.s()));
485 diagonal[k + 1] = norm;
486
487 if is_upper_diagonal {
488 if let Some(ref mut u) = *u {
489 rot.inverse()
490 .rotate_rows(&mut u.fixed_columns_with_step_mut::<2>(i, k - i));
491 }
492 } else if let Some(ref mut v_t) = *v_t {
493 rot.rotate(&mut v_t.fixed_rows_with_step_mut::<2>(i, k - i));
494 }
495
496 if k + 1 != end {
497 v.x = -rot.s().real() * off_diagonal[k + 1].clone();
498 v.y = diagonal[k + 2].clone();
499 off_diagonal[k + 1] *= rot.c();
500 }
501 } else {
502 break;
503 }
504 }
505 }
506
507 fn cancel_vertical_off_diagonal_elt(
509 diagonal: &mut OVector<T::RealField, DimMinimum<R, C>>,
510 off_diagonal: &mut OVector<T::RealField, DimDiff<DimMinimum<R, C>, U1>>,
511 u: &mut Option<OMatrix<T, R, DimMinimum<R, C>>>,
512 v_t: &mut Option<OMatrix<T, DimMinimum<R, C>, C>>,
513 is_upper_diagonal: bool,
514 i: usize,
515 ) {
516 let mut v = Vector2::new(diagonal[i].clone(), off_diagonal[i].clone());
517 off_diagonal[i] = T::RealField::zero();
518
519 for k in (0..i + 1).rev() {
520 if let Some((rot, norm)) = GivensRotation::cancel_y(&v) {
521 let rot = GivensRotation::new_unchecked(rot.c(), T::from_real(rot.s()));
522 diagonal[k] = norm;
523
524 if is_upper_diagonal {
525 if let Some(ref mut v_t) = *v_t {
526 rot.rotate(&mut v_t.fixed_rows_with_step_mut::<2>(k, i - k));
527 }
528 } else if let Some(ref mut u) = *u {
529 rot.inverse()
530 .rotate_rows(&mut u.fixed_columns_with_step_mut::<2>(k, i - k));
531 }
532
533 if k > 0 {
534 v.x = diagonal[k - 1].clone();
535 v.y = rot.s().real() * off_diagonal[k - 1].clone();
536 off_diagonal[k - 1] *= rot.c();
537 }
538 } else {
539 break;
540 }
541 }
542 }
543
544 #[must_use]
547 pub fn rank(&self, eps: T::RealField) -> usize {
548 assert!(
549 eps >= T::RealField::zero(),
550 "SVD rank: the epsilon must be non-negative."
551 );
552 self.singular_values.iter().filter(|e| **e > eps).count()
553 }
554
555 pub fn recompose(self) -> Result<OMatrix<T, R, C>, &'static str> {
561 match (self.u, self.v_t) {
562 (Some(mut u), Some(v_t)) => {
563 for i in 0..self.singular_values.len() {
564 let val = self.singular_values[i].clone();
565 u.column_mut(i).scale_mut(val);
566 }
567 Ok(u * v_t)
568 }
569 (None, None) => Err("SVD recomposition: U and V^t have not been computed."),
570 (None, _) => Err("SVD recomposition: U has not been computed."),
571 (_, None) => Err("SVD recomposition: V^t has not been computed."),
572 }
573 }
574
575 pub fn pseudo_inverse(mut self, eps: T::RealField) -> Result<OMatrix<T, C, R>, &'static str>
581 where
582 DefaultAllocator: Allocator<T, C, R>,
583 {
584 if eps < T::RealField::zero() {
585 Err("SVD pseudo inverse: the epsilon must be non-negative.")
586 } else {
587 for i in 0..self.singular_values.len() {
588 let val = self.singular_values[i].clone();
589
590 if val > eps {
591 self.singular_values[i] = T::RealField::one() / val;
592 } else {
593 self.singular_values[i] = T::RealField::zero();
594 }
595 }
596
597 self.recompose().map(|m| m.adjoint())
598 }
599 }
600
601 pub fn solve<R2: Dim, C2: Dim, S2>(
607 &self,
608 b: &Matrix<T, R2, C2, S2>,
609 eps: T::RealField,
610 ) -> Result<OMatrix<T, C, C2>, &'static str>
611 where
612 S2: Storage<T, R2, C2>,
613 DefaultAllocator: Allocator<T, C, C2> + Allocator<T, DimMinimum<R, C>, C2>,
614 ShapeConstraint: SameNumberOfRows<R, R2>,
615 {
616 if eps < T::RealField::zero() {
617 Err("SVD solve: the epsilon must be non-negative.")
618 } else {
619 match (&self.u, &self.v_t) {
620 (Some(u), Some(v_t)) => {
621 let mut ut_b = u.ad_mul(b);
622
623 for j in 0..ut_b.ncols() {
624 let mut col = ut_b.column_mut(j);
625
626 for i in 0..self.singular_values.len() {
627 let val = self.singular_values[i].clone();
628 if val > eps {
629 col[i] = col[i].clone().unscale(val);
630 } else {
631 col[i] = T::zero();
632 }
633 }
634 }
635
636 Ok(v_t.ad_mul(&ut_b))
637 }
638 (None, None) => Err("SVD solve: U and V^t have not been computed."),
639 (None, _) => Err("SVD solve: U has not been computed."),
640 (_, None) => Err("SVD solve: V^t has not been computed."),
641 }
642 }
643 }
644
645 pub fn to_polar(&self) -> Option<(OMatrix<T, R, R>, OMatrix<T, R, C>)>
650 where
651 DefaultAllocator: Allocator<T, R, C> + Allocator<T, DimMinimum<R, C>, R> + Allocator<T, DimMinimum<R, C>> + Allocator<T, R, R> + Allocator<T, DimMinimum<R, C>, DimMinimum<R, C>>, {
657 match (&self.u, &self.v_t) {
658 (Some(u), Some(v_t)) => Some((
659 u * OMatrix::from_diagonal(&self.singular_values.map(|e| T::from_real(e)))
660 * u.adjoint(),
661 u * v_t,
662 )),
663 _ => None,
664 }
665 }
666}
667
668impl<T: ComplexField, R: DimMin<C>, C: Dim> SVD<T, R, C>
669where
670 DimMinimum<R, C>: DimSub<U1>, DefaultAllocator: Allocator<T, R, C>
672 + Allocator<T, C>
673 + Allocator<T, R>
674 + Allocator<T, DimDiff<DimMinimum<R, C>, U1>>
675 + Allocator<T, DimMinimum<R, C>, C>
676 + Allocator<T, R, DimMinimum<R, C>>
677 + Allocator<T, DimMinimum<R, C>>
678 + Allocator<T::RealField, DimMinimum<R, C>>
679 + Allocator<T::RealField, DimDiff<DimMinimum<R, C>, U1>>
680 + Allocator<(usize, usize), DimMinimum<R, C>> + Allocator<(T::RealField, usize), DimMinimum<R, C>>, {
683 pub fn new(matrix: OMatrix<T, R, C>, compute_u: bool, compute_v: bool) -> Self {
687 let mut svd = Self::new_unordered(matrix, compute_u, compute_v);
688
689 if !Self::use_special_always_ordered_svd3() && !Self::use_special_always_ordered_svd2() {
690 svd.sort_by_singular_values();
691 }
692
693 svd
694 }
695
696 pub fn try_new(
709 matrix: OMatrix<T, R, C>,
710 compute_u: bool,
711 compute_v: bool,
712 eps: T::RealField,
713 max_niter: usize,
714 ) -> Option<Self> {
715 Self::try_new_unordered(matrix, compute_u, compute_v, eps, max_niter).map(|mut svd| {
716 if !Self::use_special_always_ordered_svd3() && !Self::use_special_always_ordered_svd2()
717 {
718 svd.sort_by_singular_values();
719 }
720
721 svd
722 })
723 }
724
725 pub fn sort_by_singular_values(&mut self) {
729 const VALUE_PROCESSED: usize = usize::MAX;
730
731 let mut singular_values = self.singular_values.map_with_location(|r, _, e| (e, r));
733 assert_ne!(
734 singular_values.data.shape().0.value(),
735 VALUE_PROCESSED,
736 "Too many singular values"
737 );
738
739 singular_values
741 .as_mut_slice()
742 .sort_unstable_by(|(a, _), (b, _)| b.partial_cmp(a).expect("Singular value was NaN"));
743
744 self.singular_values
746 .zip_apply(&singular_values, |value, (new_value, _)| {
747 value.clone_from(&new_value)
748 });
749
750 let mut permutations =
753 crate::PermutationSequence::identity_generic(singular_values.data.shape().0);
754
755 for i in 0..singular_values.len() {
756 let mut index_1 = i;
757 let mut index_2 = singular_values[i].1;
758
759 while index_2 != VALUE_PROCESSED && singular_values[index_2].1 != VALUE_PROCESSED
762 {
763 permutations.append_permutation(index_1, index_2);
765 singular_values[index_1].1 = VALUE_PROCESSED;
767
768 index_1 = index_2;
769 index_2 = singular_values[index_1].1;
770 }
771 }
772
773 if let Some(u) = self.u.as_mut() {
775 permutations.permute_columns(u);
776 }
777
778 if let Some(v_t) = self.v_t.as_mut() {
779 permutations.permute_rows(v_t);
780 }
781 }
782}
783
784impl<T: ComplexField, R: DimMin<C>, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S>
785where
786 DimMinimum<R, C>: DimSub<U1>, DefaultAllocator: Allocator<T, R, C>
788 + Allocator<T, C>
789 + Allocator<T, R>
790 + Allocator<T, DimDiff<DimMinimum<R, C>, U1>>
791 + Allocator<T, DimMinimum<R, C>, C>
792 + Allocator<T, R, DimMinimum<R, C>>
793 + Allocator<T, DimMinimum<R, C>>
794 + Allocator<T::RealField, DimMinimum<R, C>>
795 + Allocator<T::RealField, DimDiff<DimMinimum<R, C>, U1>>,
796{
797 #[must_use]
801 pub fn singular_values_unordered(&self) -> OVector<T::RealField, DimMinimum<R, C>> {
802 SVD::new_unordered(self.clone_owned(), false, false).singular_values
803 }
804
805 #[must_use]
809 pub fn rank(&self, eps: T::RealField) -> usize {
810 let svd = SVD::new_unordered(self.clone_owned(), false, false);
811 svd.rank(eps)
812 }
813
814 pub fn pseudo_inverse(self, eps: T::RealField) -> Result<OMatrix<T, C, R>, &'static str>
818 where
819 DefaultAllocator: Allocator<T, C, R>,
820 {
821 SVD::new_unordered(self.clone_owned(), true, true).pseudo_inverse(eps)
822 }
823}
824
825impl<T: ComplexField, R: DimMin<C>, C: Dim, S: Storage<T, R, C>> Matrix<T, R, C, S>
826where
827 DimMinimum<R, C>: DimSub<U1>,
828 DefaultAllocator: Allocator<T, R, C>
829 + Allocator<T, C>
830 + Allocator<T, R>
831 + Allocator<T, DimDiff<DimMinimum<R, C>, U1>>
832 + Allocator<T, DimMinimum<R, C>, C>
833 + Allocator<T, R, DimMinimum<R, C>>
834 + Allocator<T, DimMinimum<R, C>>
835 + Allocator<T::RealField, DimMinimum<R, C>>
836 + Allocator<T::RealField, DimDiff<DimMinimum<R, C>, U1>>
837 + Allocator<(usize, usize), DimMinimum<R, C>>
838 + Allocator<(T::RealField, usize), DimMinimum<R, C>>,
839{
840 #[must_use]
844 pub fn singular_values(&self) -> OVector<T::RealField, DimMinimum<R, C>> {
845 SVD::new(self.clone_owned(), false, false).singular_values
846 }
847}
848
849fn compute_2x2_uptrig_svd<T: RealField>(
853 m11: T,
854 m12: T,
855 m22: T,
856 compute_u: bool,
857 compute_v: bool,
858) -> (
859 Option<GivensRotation<T>>,
860 Vector2<T>,
861 Option<GivensRotation<T>>,
862) {
863 let two: T::RealField = crate::convert(2.0f64);
864 let half: T::RealField = crate::convert(0.5f64);
865
866 let denom = (m11.clone() + m22.clone()).hypot(m12.clone())
867 + (m11.clone() - m22.clone()).hypot(m12.clone());
868
869 let mut v1 = m11.clone() * m22.clone() * two / denom.clone();
874 let mut v2 = half * denom;
875
876 let mut u = None;
877 let mut v_t = None;
878
879 if compute_u || compute_v {
880 let (csv, sgn_v) = GivensRotation::new(
881 m11.clone() * m12.clone(),
882 v1.clone() * v1.clone() - m11.clone() * m11.clone(),
883 );
884 v1 *= sgn_v.clone();
885 v2 *= sgn_v;
886
887 if compute_v {
888 v_t = Some(csv.clone());
889 }
890
891 if compute_u {
892 let cu = (m11.scale(csv.c()) + m12 * csv.s()) / v1.clone();
893 let su = (m22 * csv.s()) / v1.clone();
894 let (csu, sgn_u) = GivensRotation::new(cu, su);
895
896 v1 *= sgn_u.clone();
897 v2 *= sgn_u;
898 u = Some(csu);
899 }
900 }
901
902 (u, Vector2::new(v1, v2), v_t)
903}