Coverage Report

Created: 2026-10-28 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}