1use crate::internal_prelude::*;
2
3#[derive(Copy, Clone, Debug)]
7#[repr(C)]
8pub struct JacobiRotation<T> {
9 pub c: T,
11 pub s: T,
13}
14
15#[allow(dead_code)]
16impl<T: ComplexField> JacobiRotation<T> {
17 #[math]
18 #[doc(hidden)]
19 pub fn make_givens(p: T, q: T) -> Self
20 where
21 T: RealField,
22 {
23 {
24 let p = real(p);
25 let q = real(q);
26
27 if q == zero() {
28 let c = if p < zero() { -one::<T>() } else { one() };
29 let s = zero();
30 let c = from_real(c);
31 let s = from_real(s);
32
33 Self { c, s }
34 } else if p == zero() {
35 let c = zero();
36 let s = if q < zero() { one() } else { -one::<T>() };
37 let c = from_real(c);
38 let s = from_real(s);
39
40 Self { c, s }
41 } else if abs(p) > abs(q) {
42 let t = q / p;
43 let mut u = hypot(one(), t);
44 if p < zero() {
45 u = -u;
46 }
47 let c = recip(u);
48 let s = -t * c;
49
50 let c = from_real(c);
51 let s = from_real(s);
52
53 Self { c, s }
54 } else {
55 let t = p / q;
56 let mut u = hypot(one(), t);
57 if q < zero() {
58 u = -u;
59 }
60 let s = -recip(u);
61 let c = -t * s;
62
63 let c = from_real(c);
64 let s = from_real(s);
65
66 Self { c, s }
67 }
68 }
69 }
70
71 #[math]
72 #[doc(hidden)]
73 pub fn rotg(p: T, q: T) -> (Self, T) {
74 if try_const! { T::IS_REAL } {
75 {
76 let p = real(p);
77 let q = real(q);
78
79 if q == zero() {
80 let c = one();
81 let s = zero();
82 let c = from_real(c);
83 let s = from_real(s);
84
85 (Self { c, s }, from_real(p))
86 } else if p == zero() {
87 let c = zero();
88 let s = one();
89 let c = from_real(c);
90 let s = from_real(s);
91
92 (Self { c, s }, from_real(q))
93 } else {
94 let safmin = min_positive();
95 let safmax = recip(safmin);
96 let a = p;
97 let b = q;
98
99 let scl = min(safmax, max(safmin, max(abs(a), abs(b))));
100 let r = scl * (sqrt(abs2(a / scl) + abs2(b / scl)));
101 let r = if abs(a) > abs(b) {
102 if a > zero() { r } else { -r }
103 } else {
104 if b > zero() { r } else { -r }
105 };
106 let c = from_real(a / r);
107 let s = from_real(b / r);
108 let r = from_real(r);
109
110 (Self { c, s }, r)
111 }
112 }
113 } else {
114 {
115 let a = p;
116 let b = q;
117
118 let eps = eps();
119 let sml = min_positive();
120 let big = max_positive();
121 let rtmin = sqrt(div(sml, eps));
122 let rtmax = recip(rtmin);
123
124 if b == zero() {
125 return (Self { c: one(), s: zero() }, one());
126 }
127
128 let (c, s, r);
129
130 if a == zero() {
131 c = zero();
132 let g1 = max(abs(real(b)), abs(imag(b)));
133 if g1 > rtmin && g1 < rtmax {
134 let g2 = abs2(b);
136
137 let d = sqrt(g2);
138 s = mul_real(conj(b), recip(d));
139 r = from_real(d);
140 } else {
141 let u = min(big, max(sml, g1));
143 let uu = recip(u);
144 let gs = mul_real(b, uu);
145 let g2 = abs2(gs);
146 let d = sqrt(g2);
147 s = mul_real(conj(gs), recip(d));
148 r = from_real(mul(d, u));
149 }
150 } else {
151 let f1 = max(abs(real(a)), abs(imag(a)));
152 let g1 = max(abs(real(b)), abs(imag(b)));
153 if f1 > rtmin && f1 < rtmax && g1 > rtmin && g1 < rtmax {
154 let f2 = abs2(a);
156 let g2 = abs2(b);
157 let h2 = add(f2, g2);
158 let d = if f2 > rtmin && h2 < rtmax {
159 sqrt(mul(f2, h2))
160 } else {
161 mul(sqrt(f2), sqrt(h2))
162 };
163 let p = recip(d);
164 c = from_real(mul(f2, p));
165 s = conj(b) * mul_real(a, p);
166
167 r = mul_real(a, mul(h2, p));
168 } else {
169 let u = min(big, max(sml, max(f1, g1)));
171 let uu = recip(u);
172 let gs = mul_real(b, uu);
173 let g2 = abs2(gs);
174 let (f2, h2, w);
175 let fs;
176 if mul(f1, uu) < rtmin {
177 let v = min(big, max(sml, f1));
179 let vv = recip(v);
180 w = mul(v, uu);
181 fs = mul_real(a, vv);
182 f2 = abs2(fs);
183 h2 = add(mul(mul(f2, w), w), g2);
184 } else {
185 w = one();
187 fs = mul_real(a, uu);
188 f2 = abs2(fs);
189 h2 = add(f2, g2);
190 }
191 let d = if f2 > rtmin && h2 < rtmax {
192 sqrt(mul(f2, h2))
193 } else {
194 mul(sqrt(f2), sqrt(h2))
195 };
196 let p = recip(d);
197 c = from_real(mul(mul(f2, p), w));
198 s = conj(gs) * mul_real(fs, p);
199 r = mul_real(mul_real(fs, mul(h2, p)), u);
200 }
201 }
202
203 (Self { c, s }, r)
204 }
205 }
206 }
207
208 #[inline]
212 #[math]
213 pub fn apply_on_the_left_2x2(&self, m00: T, m01: T, m10: T, m11: T) -> (T, T, T, T) {
214 let Self { c, s } = self;
215
216 (
217 m00 * *c + m10 * *s,
218 m01 * *c + m11 * *s,
219 *c * m10 - conj(*s) * m00,
220 *c * m11 - conj(*s) * m01,
221 )
222 }
223
224 #[inline]
228 pub fn apply_on_the_right_2x2(&self, m00: T, m01: T, m10: T, m11: T) -> (T, T, T, T) {
229 let (r00, r01, r10, r11) = self.transpose().apply_on_the_left_2x2(m00, m10, m01, m11);
230 (r00, r10, r01, r11)
231 }
232
233 #[inline]
234 fn apply_on_the_left_in_place_impl<'N>(&self, (x, y): (RowMut<'_, T, Dim<'N>>, RowMut<'_, T, Dim<'N>>)) {
235 let mut x = x;
236 let mut y = y;
237 if try_const! { T::SIMD_CAPABILITIES.is_simd() } {
238 struct Impl<'a, 'N, T: ComplexField> {
239 this: &'a JacobiRotation<T>,
240 x: RowMut<'a, T, Dim<'N>, ContiguousFwd>,
241 y: RowMut<'a, T, Dim<'N>, ContiguousFwd>,
242 }
243 impl<T: ComplexField> pulp::WithSimd for Impl<'_, '_, T> {
244 type Output = ();
245
246 #[inline(always)]
247 fn with_simd<S: pulp::Simd>(self, simd: S) -> Self::Output {
248 let Self { this, x, y } = self;
249 let simd = SimdCtx::new(T::simd_ctx(simd), x.ncols());
250 this.apply_on_the_left_in_place_with_simd(simd, x, y);
251 }
252 }
253
254 if x.col_stride() < 0 && y.col_stride() < 0 {
255 x = x.reverse_cols_mut();
256 y = y.reverse_cols_mut();
257 }
258
259 if let (Some(x), Some(y)) = (x.rb_mut().try_as_row_major_mut(), y.rb_mut().try_as_row_major_mut()) {
260 dispatch!(Impl { this: self, x, y }, Impl, T);
261 return;
262 }
263 }
264 self.apply_on_the_left_in_place_fallback(x, y);
265 }
266
267 #[inline]
269 pub fn apply_on_the_left_in_place<N: Shape>(&self, (x, y): (RowMut<'_, T, N>, RowMut<'_, T, N>)) {
270 with_dim!(N, x.ncols().unbound());
271 self.apply_on_the_left_in_place_impl((x.as_col_shape_mut(N), y.as_col_shape_mut(N)));
272 }
273
274 #[inline]
276 pub fn apply_on_the_right_in_place<N: Shape>(&self, (x, y): (ColMut<'_, T, N>, ColMut<'_, T, N>)) {
277 with_dim!(N, x.nrows().unbound());
278
279 let x = x.as_row_shape_mut(N);
280 let y = y.as_row_shape_mut(N);
281
282 self.transpose().apply_on_the_left_in_place((x.transpose_mut(), y.transpose_mut()));
283 }
284
285 #[inline(never)]
286 #[math]
287 fn apply_on_the_left_in_place_fallback<'N>(&self, x: RowMut<'_, T, Dim<'N>>, y: RowMut<'_, T, Dim<'N>>) {
288 let Self { c, s } = self;
289 zip!(x, y).for_each(move |unzip!(x, y)| {
290 let x_ = *c * *x - conj(*s) * *y;
291 let y_ = *c * *y + *s * *x;
292 *x = x_;
293 *y = y_;
294 });
295 }
296
297 #[inline(always)]
298 pub(crate) fn apply_on_the_right_in_place_with_simd<'N, S: pulp::Simd>(
299 &self,
300 simd: SimdCtx<'N, T, S>,
301 x: ColMut<'_, T, Dim<'N>, ContiguousFwd>,
302 y: ColMut<'_, T, Dim<'N>, ContiguousFwd>,
303 ) {
304 self.transpose()
305 .apply_on_the_left_in_place_with_simd(simd, x.transpose_mut(), y.transpose_mut());
306 }
307
308 #[math]
309 #[inline(always)]
310 pub(crate) fn apply_on_the_left_in_place_with_simd<'N, S: pulp::Simd>(
311 &self,
312 simd: SimdCtx<'N, T, S>,
313 x: RowMut<'_, T, Dim<'N>, ContiguousFwd>,
314 y: RowMut<'_, T, Dim<'N>, ContiguousFwd>,
315 ) {
316 let Self { c, s } = self;
317
318 if *c == one() && *s == zero() {
319 return;
320 };
321
322 let mut x = x.transpose_mut();
323 let mut y = y.transpose_mut();
324
325 let c = simd.splat_real(&real(*c));
326 let s = simd.splat(&s);
327
328 let (head, body, tail) = simd.indices();
329
330 if let Some(i) = head {
331 let mut xx = simd.read(x.rb(), i);
332 let mut yy = simd.read(y.rb(), i);
333
334 (xx, yy) = (
335 simd.conj_mul_add(simd.neg(s), yy, simd.mul_real(xx, c)),
336 simd.mul_add(s, xx, simd.mul_real(yy, c)),
337 );
338
339 simd.write(x.rb_mut(), i, xx);
340 simd.write(y.rb_mut(), i, yy);
341 }
342 for i in body {
343 let mut xx = simd.read(x.rb(), i);
344 let mut yy = simd.read(y.rb(), i);
345
346 (xx, yy) = (
347 simd.conj_mul_add(simd.neg(s), yy, simd.mul_real(xx, c)),
348 simd.mul_add(s, xx, simd.mul_real(yy, c)),
349 );
350
351 simd.write(x.rb_mut(), i, xx);
352 simd.write(y.rb_mut(), i, yy);
353 }
354 if let Some(i) = tail {
355 let mut xx = simd.read(x.rb(), i);
356 let mut yy = simd.read(y.rb(), i);
357
358 (xx, yy) = (
359 simd.conj_mul_add(simd.neg(s), yy, simd.mul_real(xx, c)),
360 simd.mul_add(s, xx, simd.mul_real(yy, c)),
361 );
362
363 simd.write(x.rb_mut(), i, xx);
364 simd.write(y.rb_mut(), i, yy);
365 }
366 }
367
368 #[inline]
370 #[math]
371 pub fn adjoint(&self) -> Self {
372 Self {
373 c: copy(self.c),
374 s: -conj(self.s),
375 }
376 }
377
378 #[inline]
380 #[math]
381 pub fn conjugate(&self) -> Self {
382 Self {
383 c: copy(self.c),
384 s: conj(self.s),
385 }
386 }
387
388 #[inline]
390 #[math]
391 pub fn transpose(&self) -> Self {
392 Self { c: copy(self.c), s: -self.s }
393 }
394}