1#[cfg(feature = "serde-serialize-no-std")]
2use serde::{Deserialize, Serialize};
3
4use crate::allocator::Allocator;
5use crate::base::{Const, DefaultAllocator, OMatrix, OVector};
6use crate::dimension::Dim;
7use simba::scalar::RealField;
8
9#[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))]
11#[cfg_attr(
12 feature = "serde-serialize-no-std",
13 serde(bound(serialize = "OVector<T, D>: Serialize, OMatrix<T, D, D>: Serialize"))
14)]
15#[cfg_attr(
16 feature = "serde-serialize-no-std",
17 serde(bound(
18 deserialize = "OVector<T, D>: Deserialize<'de>, OMatrix<T, D, D>: Deserialize<'de>"
19 ))
20)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22#[derive(Clone, Debug)]
23pub struct UDU<T: RealField, D: Dim>
24where
25 DefaultAllocator: Allocator<D> + Allocator<D, D>,
26{
27 pub u: OMatrix<T, D, D>,
29 pub d: OVector<T, D>,
31}
32
33impl<T: RealField, D: Dim> Copy for UDU<T, D>
34where
35 DefaultAllocator: Allocator<D> + Allocator<D, D>,
36 OVector<T, D>: Copy,
37 OMatrix<T, D, D>: Copy,
38{
39}
40
41impl<T: RealField, D: Dim> UDU<T, D>
42where
43 DefaultAllocator: Allocator<D> + Allocator<D, D>,
44{
45 pub fn new(p: OMatrix<T, D, D>) -> Option<Self> {
52 let n = p.ncols();
53 let n_dim = p.shape_generic().1;
54
55 let mut d = OVector::zeros_generic(n_dim, Const::<1>);
56 let mut u = OMatrix::zeros_generic(n_dim, n_dim);
57
58 d[n - 1] = p[(n - 1, n - 1)].clone();
59
60 if d[n - 1].is_zero() {
61 return None;
62 }
63
64 u.column_mut(n - 1)
65 .axpy(T::one() / d[n - 1].clone(), &p.column(n - 1), T::zero());
66
67 for j in (0..n - 1).rev() {
68 let mut d_j = d[j].clone();
69 for k in j + 1..n {
70 d_j += d[k].clone() * u[(j, k)].clone().powi(2);
71 }
72
73 d[j] = p[(j, j)].clone() - d_j;
74
75 if d[j].is_zero() {
76 return None;
77 }
78
79 for i in (0..=j).rev() {
80 let mut u_ij = u[(i, j)].clone();
81 for k in j + 1..n {
82 u_ij += d[k].clone() * u[(j, k)].clone() * u[(i, k)].clone();
83 }
84
85 u[(i, j)] = (p[(i, j)].clone() - u_ij) / d[j].clone();
86 }
87
88 u[(j, j)] = T::one();
89 }
90
91 Some(Self { u, d })
92 }
93
94 #[must_use]
96 pub fn d_matrix(&self) -> OMatrix<T, D, D> {
97 OMatrix::from_diagonal(&self.d)
98 }
99}