/rust/registry/src/index.crates.io-1949cf8c6b5b557f/nalgebra-0.35.0/src/linalg/givens.rs
Line | Count | Source |
1 | | //! Construction of givens rotations. |
2 | | |
3 | | use num::{One, Zero}; |
4 | | use simba::scalar::ComplexField; |
5 | | |
6 | | use crate::base::constraint::{DimEq, ShapeConstraint}; |
7 | | use crate::base::dimension::{Dim, U2}; |
8 | | use crate::base::storage::{Storage, StorageMut}; |
9 | | use crate::base::{Matrix, Vector}; |
10 | | |
11 | | /// A Givens rotation. |
12 | | #[derive(Debug, Clone, Copy)] |
13 | | pub struct GivensRotation<T: ComplexField> { |
14 | | c: T::RealField, |
15 | | s: T, |
16 | | } |
17 | | |
18 | | // Matrix = UnitComplex * Matrix |
19 | | impl<T: ComplexField> GivensRotation<T> { |
20 | | /// The Givens rotation that does nothing. |
21 | 0 | pub fn identity() -> Self { |
22 | 0 | Self { |
23 | 0 | c: T::RealField::one(), |
24 | 0 | s: T::zero(), |
25 | 0 | } |
26 | 0 | } |
27 | | |
28 | | /// Initializes a Givens rotation from its components. |
29 | | /// |
30 | | /// The components are copies as-is. It is not checked whether they describe |
31 | | /// an actually valid Givens rotation. |
32 | 0 | pub const fn new_unchecked(c: T::RealField, s: T) -> Self { |
33 | 0 | Self { c, s } |
34 | 0 | } |
35 | | |
36 | | /// Initializes a Givens rotation from its non-normalized cosine an sine components. |
37 | 0 | pub fn new(c: T, s: T) -> (Self, T) { |
38 | 0 | Self::try_new(c, s, T::RealField::zero()) |
39 | 0 | .unwrap_or_else(|| (GivensRotation::identity(), T::zero())) |
40 | 0 | } |
41 | | |
42 | | /// Initializes a Givens rotation form its non-normalized cosine an sine components. |
43 | 0 | pub fn try_new(c: T, s: T, eps: T::RealField) -> Option<(Self, T)> { |
44 | 0 | let (mod0, sign0) = c.to_exp(); |
45 | 0 | let denom = (mod0.clone() * mod0.clone() + s.clone().modulus_squared()).sqrt(); |
46 | | |
47 | 0 | if denom > eps { |
48 | 0 | let norm = sign0.scale(denom.clone()); |
49 | 0 | let c = mod0 / denom; |
50 | 0 | let s = s / norm.clone(); |
51 | 0 | Some((Self { c, s }, norm)) |
52 | | } else { |
53 | 0 | None |
54 | | } |
55 | 0 | } |
56 | | |
57 | | /// Computes the rotation `R` required such that the `y` component of `R * v` is zero. |
58 | | /// |
59 | | /// Returns `None` if no rotation is needed (i.e. if `v.y == 0`). Otherwise, this returns the norm |
60 | | /// of `v` and the rotation `r` such that `R * v = [ |v|, 0.0 ]^t` where `|v|` is the norm of `v`. |
61 | 0 | pub fn cancel_y<S: Storage<T, U2>>(v: &Vector<T, U2, S>) -> Option<(Self, T)> { |
62 | 0 | if !v[1].is_zero() { |
63 | 0 | let (mod0, sign0) = v[0].clone().to_exp(); |
64 | 0 | let denom = (mod0.clone() * mod0.clone() + v[1].clone().modulus_squared()).sqrt(); |
65 | 0 | let c = mod0 / denom.clone(); |
66 | 0 | let s = -v[1].clone() / sign0.clone().scale(denom.clone()); |
67 | 0 | let r = sign0.scale(denom); |
68 | 0 | Some((Self { c, s }, r)) |
69 | | } else { |
70 | 0 | None |
71 | | } |
72 | 0 | } |
73 | | |
74 | | /// Computes the rotation `R` required such that the `x` component of `R * v` is zero. |
75 | | /// |
76 | | /// Returns `None` if no rotation is needed (i.e. if `v.x == 0`). Otherwise, this returns the norm |
77 | | /// of `v` and the rotation `r` such that `R * v = [ 0.0, |v| ]^t` where `|v|` is the norm of `v`. |
78 | | pub fn cancel_x<S: Storage<T, U2>>(v: &Vector<T, U2, S>) -> Option<(Self, T)> { |
79 | | if !v[0].is_zero() { |
80 | | let (mod1, sign1) = v[1].clone().to_exp(); |
81 | | let denom = (mod1.clone() * mod1.clone() + v[0].clone().modulus_squared()).sqrt(); |
82 | | let c = mod1 / denom.clone(); |
83 | | let s = (v[0].clone().conjugate() * sign1.clone()).unscale(denom.clone()); |
84 | | let r = sign1.scale(denom); |
85 | | Some((Self { c, s }, r)) |
86 | | } else { |
87 | | None |
88 | | } |
89 | | } |
90 | | |
91 | | /// The cos part of this rotation. |
92 | | #[must_use] |
93 | 0 | pub fn c(&self) -> T::RealField { |
94 | 0 | self.c.clone() |
95 | 0 | } |
96 | | |
97 | | /// The sin part of this rotation. |
98 | | #[must_use] |
99 | 0 | pub fn s(&self) -> T { |
100 | 0 | self.s.clone() |
101 | 0 | } |
102 | | |
103 | | /// The inverse of this givens rotation. |
104 | | #[must_use = "This function does not mutate self."] |
105 | 0 | pub fn inverse(&self) -> Self { |
106 | 0 | Self { |
107 | 0 | c: self.c.clone(), |
108 | 0 | s: -self.s.clone(), |
109 | 0 | } |
110 | 0 | } |
111 | | |
112 | | /// Performs the multiplication `rhs = self * rhs` in-place. |
113 | 0 | pub fn rotate<R2: Dim, C2: Dim, S2: StorageMut<T, R2, C2>>( |
114 | 0 | &self, |
115 | 0 | rhs: &mut Matrix<T, R2, C2, S2>, |
116 | 0 | ) where |
117 | 0 | ShapeConstraint: DimEq<R2, U2>, |
118 | | { |
119 | 0 | assert_eq!( |
120 | 0 | rhs.nrows(), |
121 | | 2, |
122 | 0 | "Unit complex rotation: the input matrix must have exactly two rows." |
123 | | ); |
124 | 0 | let s = self.s.clone(); |
125 | 0 | let c = self.c.clone(); |
126 | | |
127 | 0 | for j in 0..rhs.ncols() { |
128 | 0 | unsafe { |
129 | 0 | let a = rhs.get_unchecked((0, j)).clone(); |
130 | 0 | let b = rhs.get_unchecked((1, j)).clone(); |
131 | 0 |
|
132 | 0 | *rhs.get_unchecked_mut((0, j)) = |
133 | 0 | a.clone().scale(c.clone()) - s.clone().conjugate() * b.clone(); |
134 | 0 | *rhs.get_unchecked_mut((1, j)) = s.clone() * a + b.scale(c.clone()); |
135 | 0 | } |
136 | | } |
137 | 0 | } Unexecuted instantiation: <nalgebra::linalg::givens::GivensRotation<f64>>::rotate::<nalgebra::base::dimension::Const<2>, nalgebra::base::dimension::Const<2>, nalgebra::base::matrix_view::ViewStorageMut<f64, nalgebra::base::dimension::Const<2>, nalgebra::base::dimension::Const<2>, nalgebra::base::dimension::Const<1>, nalgebra::base::dimension::Const<2>>> Unexecuted instantiation: <nalgebra::linalg::givens::GivensRotation<f64>>::rotate::<nalgebra::base::dimension::Const<2>, nalgebra::base::dimension::Dyn, nalgebra::base::matrix_view::ViewStorageMut<f64, nalgebra::base::dimension::Const<2>, nalgebra::base::dimension::Dyn, nalgebra::base::dimension::Const<1>, nalgebra::base::dimension::Const<2>>> |
138 | | |
139 | | /// Performs the multiplication `lhs = lhs * self` in-place. |
140 | 0 | pub fn rotate_rows<R2: Dim, C2: Dim, S2: StorageMut<T, R2, C2>>( |
141 | 0 | &self, |
142 | 0 | lhs: &mut Matrix<T, R2, C2, S2>, |
143 | 0 | ) where |
144 | 0 | ShapeConstraint: DimEq<C2, U2>, |
145 | | { |
146 | 0 | assert_eq!( |
147 | 0 | lhs.ncols(), |
148 | | 2, |
149 | 0 | "Unit complex rotation: the input matrix must have exactly two columns." |
150 | | ); |
151 | 0 | let s = self.s.clone(); |
152 | 0 | let c = self.c.clone(); |
153 | | |
154 | | // TODO: can we optimize that to iterate on one column at a time ? |
155 | 0 | for j in 0..lhs.nrows() { |
156 | 0 | unsafe { |
157 | 0 | let a = lhs.get_unchecked((j, 0)).clone(); |
158 | 0 | let b = lhs.get_unchecked((j, 1)).clone(); |
159 | 0 |
|
160 | 0 | *lhs.get_unchecked_mut((j, 0)) = a.clone().scale(c.clone()) + s.clone() * b.clone(); |
161 | 0 | *lhs.get_unchecked_mut((j, 1)) = -s.clone().conjugate() * a + b.scale(c.clone()); |
162 | 0 | } |
163 | | } |
164 | 0 | } Unexecuted instantiation: <nalgebra::linalg::givens::GivensRotation<f64>>::rotate_rows::<nalgebra::base::dimension::Const<2>, nalgebra::base::dimension::Const<2>, nalgebra::base::matrix_view::ViewStorageMut<f64, nalgebra::base::dimension::Const<2>, nalgebra::base::dimension::Const<2>, nalgebra::base::dimension::Const<1>, nalgebra::base::dimension::Const<2>>> Unexecuted instantiation: <nalgebra::linalg::givens::GivensRotation<f64>>::rotate_rows::<nalgebra::base::dimension::Const<6>, nalgebra::base::dimension::Const<2>, nalgebra::base::matrix_view::ViewStorageMut<f64, nalgebra::base::dimension::Const<6>, nalgebra::base::dimension::Const<2>, nalgebra::base::dimension::Const<1>, nalgebra::base::dimension::Const<6>>> Unexecuted instantiation: <nalgebra::linalg::givens::GivensRotation<f64>>::rotate_rows::<nalgebra::base::dimension::Dyn, nalgebra::base::dimension::Const<2>, nalgebra::base::matrix_view::ViewStorageMut<f64, nalgebra::base::dimension::Dyn, nalgebra::base::dimension::Const<2>, nalgebra::base::dimension::Const<1>, nalgebra::base::dimension::Const<2>>> |
165 | | } |