a/math/matrix/qr.rs
1//! The QR decomposition by Householder reflections.
2//!
3//! # The decomposition
4//!
5//! A matrix of at most [`SMALL`] elements, and a complex one of at most 64 columns and 32768
6//! elements, is decomposed one reflection at a time ([`unblocked`], LAPACK's `geqr2`): each column's
7//! reflection taken from it, then applied to the columns right of it four at a time, each read for
8//! its products with the reflection's vector and again, from the cache, for the update
9//! ([`kernels::reflect`]). Larger matrices go by blocks of `nb` columns ([`block_width`]): a panel
10//! of `nb` columns is decomposed and gives the triangular factor `T` of its block of reflections,
11//! `H_0·…·H_nb-1 = I - V·T·V*` (the compact WY form), and the rest of the matrix takes the block
12//! by three products, `C -= V·(T*·(V*·C))`, with `V` read where the panel left it, its unit
13//! triangle written over `R` for the time ([`with_v`]).
14//!
15//! A panel is halved down to leaves of [`LEAF`] columns as LAPACK's `geqrt3` does ([`panel`]):
16//! the left half, its block applied to the right half by products of blocks, the right half, and
17//! the halves' factors joined, `T12 = -T1·V1*·V2·T2`. A leaf is decomposed one reflection at a time,
18//! and each reflection's products with the columns left of it, which make its column of `T`, are
19//! taken in the pass that applies it to those right of it.
20//!
21//! The block widens with the work of the update against that of the panel: 8 columns up to 384
22//! columns of `f64` (192 of `f32`, 96 complex), then 16, 24 and 32, measured with each width from
23//! 8 to 64 on square matrices and ones of twice and eight times as many rows as columns. At
24//! `1024 × 1024` 24 took 30.3 ms, 16 30.9, 8 32.1 and 64 32.3, and 32 as 24 in other runs; at
25//! `256 × 256` 8 took 556 µs and 32 610. A matrix of four times as many rows as columns takes at
26//! least 16 columns from 512 rows, 48 from 2048 and 64 from 4096: the product `V*·C` of so tall
27//! a block of 32 columns or fewer ran at 41 GFLOP/s against 54 for 64, and an `8192 × 1024`
28//! decomposition took 337 ms with 64 against 372 with 32.
29//!
30//! The decomposition keeps the blocks' `T` with the reflections: forming `Q` and the least
31//! squares reuse them.
32//!
33//! # `Q`
34//!
35//! `Q` is formed from the last block back, as LAPACK's `orgqr` ([`Qr::form_q`]): each block gives
36//! its own columns directly, `[I; 0] - V·T·E1*` (`E1` the block's unit triangle), and updates
37//! those right of it, whose rows of the block are still zeros, by three products. The columns
38//! right of the last block are those of the identity, so that their product with `V*` is a copy
39//! of it. The whole `Q` of a matrix of at least four times as many rows as columns is formed in
40//! one block of all the reflections, whose `T` is built from `V*·V` ([`Qr::whole_t`]): most of
41//! the work is the columns right of the reflections, and in one block it is the copy and one
42//! product, half of the work of applying the blocks in turn: the whole `Q` of a `1024 × 128`
43//! matrix took 6.4 ms, against 12.3 by blocks of 32 before and faer's 10.9. A decomposition
44//! without blocks forms `Q` one reflection at a time.
45//!
46//! # Least squares
47//!
48//! `Q*·B` takes the blocks' `T` for more than [`FOURS`] columns of `B`, by products of blocks;
49//! for up to four, each column takes four reflections at a time by the diagonal blocks of their
50//! blocks' `T`, `w = T*·V*·y` in one pass over the column and `y -= V·w` in another
51//! ([`Qr::reflect_fours`]), half the passes of one reflection at a time. `R·X = Q*·B` is solved
52//! by columns of `R` for one column of `B` or an `R` of at most [`SUBSTITUTE`] columns
53//! ([`back_substitute`]), and by the blocked triangular solve otherwise.
54//!
55//! # Speed
56//!
57//! Measured on an Apple M4 Max, one core, the median of interleaved runs while other processes
58//! ran, against faer 0.24 (`Par::Seq`), nalgebra 0.35 and Accelerate (`dgeqrf`, `dorgqr`,
59//! `dgels`, `dormqr` with `dtrtrs`; on the matrix unit); `f64`, µs unless ms. The largest varied
60//! by up to 10 % from run to run, their ratios by less. `solve(b)` is of one column, given the
61//! decomposition; `qr().solve(b)` includes it. nalgebra has no whole `Q` of a non-square matrix.
62//!
63//! | `f64` | ours | faer | nalgebra | Accelerate |
64//! | --- | --- | --- | --- | --- |
65//! | `qr()` 2 × 2 | 0.05 | 0.15 | 0.07 | 0.11 |
66//! | `qr()` 8 × 8 | 0.22 | 0.50 | 0.35 | 0.48 |
67//! | `qr()` 32 × 32 | 2.52 | 7.18 | 4.40 | 4.20 |
68//! | `qr()` 128 × 128 | 82.2 | 147 | 176 | 109 |
69//! | `qr()` 512 × 512 | 4.44 ms | 5.15 ms | 13.56 ms | 2.30 ms |
70//! | `qr()` 1024 × 1024 | 32.47 ms | 35.42 ms | 102.36 ms | 12.25 ms |
71//! | `qr()` 2048 × 1024 | 79.24 ms | 83.14 ms | 247.62 ms | 27.22 ms |
72//! | `qr()` 8192 × 1024 | 365.6 ms | 381.5 ms | 1259.7 ms | 114.7 ms |
73//! | `q()` 32 × 32 | 2.18 | 5.24 | 3.56 | 4.08 |
74//! | `q()` 1024 × 1024 | 28.12 ms | 44.29 ms | 95.46 ms | 11.12 ms |
75//! | `q()` 8192 × 1024 | 310.3 ms | 601.5 ms | 1189.7 ms | 106.3 ms |
76//! | `q_full()` 1024 × 128 | 6.39 ms | 10.85 ms | - | 8.84 ms |
77//! | `q_full()` 8192 × 1024 | 2.93 s | 4.72 s | - | 3.85 s |
78//! | `qr().solve(b)` 32 × 32 | 2.94 | 8.60 | 5.77 | 6.82 |
79//! | `qr().solve(b)` 1024 × 1024 | 30.16 ms | 32.87 ms | 96.37 ms | 12.76 ms |
80//! | `qr().solve(b)` 8192 × 1024 | 347.4 ms | 369.9 ms | 1181.6 ms | 124.2 ms |
81//! | `solve(b)` 16 × 16 | 0.23 | 0.30 | 0.56 | 0.83 |
82//! | `solve(b)` 1024 × 1024 | 229 | 389 | 2.00 ms | 1.06 ms |
83//! | `solve(b)` 8192 × 1024 | 1.87 ms | 2.63 ms | 3.95 ms | 6.22 ms |
84//!
85//! `f32` and complex matrices compare alike: `qr()` of `512 × 512` took 2.18 ms in `f32` against
86//! faer's 2.63 and nalgebra's 7.36, and 15.9 ms in `Complex<f64>` against 19.3 and 55.1.
87
88mod kernels;
89
90use super::blas::{Op, Side, Uplo, gemm, trsm};
91use super::{Matrix, Scalar};
92use kernels::{axpy, axpys4, dots, dots4, reflect, reflector};
93
94/// The QR decomposition `A = Q·R` of an `m × n` matrix by Householder reflections: `Q` of
95/// `m × min(m, n)` with orthonormal columns (unitary for complex elements), `R` of
96/// `min(m, n) × n` upper triangular with a real diagonal. From [`Matrix::qr`].
97///
98/// # Examples
99///
100/// ```
101/// use a::math::matrix::Matrix;
102///
103/// let a: Matrix<f64> = Matrix::from_rows(&[[3.0, 1.0], [4.0, 2.0]]);
104/// let qr = a.qr();
105/// let (q, r) = (qr.q(), qr.r());
106/// assert!((&q * &r - &a).as_slice().iter().all(|x| x.abs() < 1e-15));
107/// assert!((&q.transpose() * &q - Matrix::identity(2)).as_slice().iter().all(|x| x.abs() < 1e-15));
108/// assert!((r[(0, 0)].abs() - 5.0).abs() < 1e-15);
109/// ```
110#[derive(Clone, Debug)]
111pub struct Qr<T> {
112 /// `R` on and above the diagonal, the reflections' vectors below it.
113 qr: Matrix<T>,
114 /// The reflections' factors.
115 taus: Vec<T>,
116 /// The triangular factors of the blocks of reflections, `H_j0·…·H_j1-1 = I - V·T·V*` for
117 /// the block of columns `j0..j1`, whose `T` starts at `j0 · nb` with the leading dimension
118 /// `nb`; empty when the decomposition was not blocked.
119 ts: Vec<T>,
120 /// The width `nb` of the blocks, 0 when the decomposition was not blocked.
121 nb: usize,
122}
123
124/// The most elements of a matrix decomposed one reflection at a time. Beyond, blocks of 8
125/// columns were faster: `f64` matrices of `64 × 64` took 14.3 µs by them against 14.6, of
126/// `256 × 32` 22.7 against 25.8, while `48 × 48` took 7.3 against 7.5 and `128 × 16` 3.6 against
127/// 4.2; `f32` and complex ones of the same shapes broke even at about the same size, but complex
128/// ones of few columns stayed faster one reflection at a time up to `512 × 64`.
129const SMALL: usize = 4096;
130
131/// The columns of the leaves of a panel, decomposed one reflection at a time: 4 and 16 were as
132/// fast as 8 within 5 % from `64 × 64` to `8192 × 1024`, 32 up to 10 % slower.
133const LEAF: usize = 8;
134
135/// The most columns of `B` whose `Q*·B` goes a column at a time, four reflections at a time;
136/// with more, products of blocks were faster: for 8 columns of 1024 rows 916 µs against 963.
137const FOURS: usize = 4;
138
139/// The most columns of `R` solved for by columns for any number of columns of `B`: for 4 columns
140/// of 128 rows 9.4 µs against 10.2 by the triangular solve, of 192 rows 22.7 against 20.5.
141const SUBSTITUTE: usize = 128;
142
143/// The fewest rows of a matrix whose whole `Q` is formed in one block: `16 × 4` took 0.41 µs so
144/// against 0.25 one reflection at a time, `64 × 16` 6.5 against 8.8.
145const ONE_BLOCK: usize = 48;
146
147/// The reflections whose triangular factor [`Qr::whole_t`] builds from `V*·V` directly, before
148/// joining them by products of blocks.
149const LEAF_T: usize = 64;
150
151/// The width of the blocks of the decomposition of an `m × n` matrix, 0 for none: see the
152/// module's documentation.
153fn block_width<T: Scalar>(m: usize, n: usize) -> usize {
154 let size = m * n;
155 if size <= SMALL || (T::IS_COMPLEX && n <= 64 && size <= 8 * SMALL) {
156 return 0;
157 }
158 // A complex element takes four times the work of a real one, and an `f32` half the time of
159 // an `f64`, at the same speed of the products of blocks.
160 let e = n * if T::IS_COMPLEX {
161 4
162 } else if core::mem::size_of::<T>() == 4 {
163 2
164 } else {
165 1
166 };
167 let nb = match e {
168 0..=384 => 8,
169 385..=640 => 16,
170 641..=896 => 24,
171 _ => 32,
172 };
173 if m >= 4 * n {
174 let tall = match m {
175 0..=511 => 8,
176 512..=2047 => 16,
177 2048..=4095 => 48,
178 _ => 64,
179 };
180 nb.max(tall)
181 } else {
182 nb
183 }
184}
185
186impl<T: Scalar> Matrix<T> {
187 /// The QR decomposition `A = Q·R`: see [`Qr`]. About `2mn² - 2n³/3` operations for
188 /// `m ≥ n`, most of them, for large matrices, in products of blocks of reflections.
189 pub fn qr(&self) -> Qr<T> {
190 let (m, n) = self.shape();
191 let mut qr = self.clone();
192 let k = m.min(n);
193 let mut taus = vec![T::zero(); k];
194 let nb = block_width::<T>(m, n);
195 if nb == 0 {
196 unblocked(&mut qr.data, m, m, n, &mut taus, None, &mut []);
197 return Qr {
198 qr,
199 taus,
200 ts: Vec::new(),
201 nb: 0,
202 };
203 }
204 let mut ts = vec![T::zero(); nb * k];
205 let mut work = Work::new(nb, n);
206 let mut j0 = 0;
207 while j0 < k {
208 let kb = nb.min(k - j0);
209 let j1 = j0 + kb;
210 let (left, right) = qr.data.split_at_mut(j1 * m);
211 let block = &mut left[j0 + j0 * m..];
212 panel(
213 block,
214 m,
215 m - j0,
216 kb,
217 &mut taus[j0..j1],
218 &mut ts[j0 * nb..],
219 nb,
220 &mut work,
221 );
222 if j1 < n {
223 let Work { save, w, .. } = &mut work;
224 let t = &ts[j0 * nb..];
225 with_v(block, m, kb, save, |v| {
226 apply_block(v, m, m - j0, kb, t, nb, &mut right[j0..], m, n - j1, w);
227 });
228 }
229 j0 = j1;
230 }
231 Qr { qr, taus, ts, nb }
232 }
233}
234
235impl<T: Scalar> Qr<T> {
236 /// `Q`, `m × min(m, n)`, with orthonormal columns.
237 pub fn q(&self) -> Matrix<T> {
238 self.form_q(self.taus.len())
239 }
240
241 /// The whole `m × m` unitary `Q`, whose first `min(m, n)` columns are [`q`](Qr::q).
242 pub fn q_full(&self) -> Matrix<T> {
243 self.form_q(self.qr.rows())
244 }
245
246 /// `R`, `min(m, n) × n`, upper triangular.
247 pub fn r(&self) -> Matrix<T> {
248 let (m, n) = self.qr.shape();
249 let k = m.min(n);
250 let mut r = vec![T::zero(); k * n];
251 for (j, col) in r.chunks_exact_mut(k.max(1)).take(n).enumerate() {
252 let h = k.min(j + 1);
253 col[..h].copy_from_slice(&self.qr.data[j * m..j * m + h]);
254 }
255 Matrix::from_column_major(k, n, r)
256 }
257
258 /// The `X` of the least squares, which makes `‖A·X - B‖` the smallest, for `m ≥ n`: the
259 /// solution of `R·X = Q*·B`, or `None` when a diagonal element of `R` is zero, the
260 /// columns of `A` dependent. For a square matrix it solves `A·X = B`.
261 ///
262 /// # Panics
263 ///
264 /// Panics if the matrix has fewer rows than columns, or `B` not as many rows as it.
265 #[track_caller]
266 pub fn solve(&self, b: &Matrix<T>) -> Option<Matrix<T>> {
267 let (m, n) = self.qr.shape();
268 assert!(m >= n, "the matrix has fewer rows than columns");
269 assert_eq!(b.rows(), m, "the right-hand side has not as many rows");
270 if (0..n).any(|i| self.qr[(i, i)] == T::zero()) {
271 return None;
272 }
273 let cols = b.cols();
274 let mut y = b.clone();
275 let a = &self.qr.data;
276 if cols == 0 {
277 } else if self.nb == 0 {
278 // One reflection at a time, `y ← H_j*·y`.
279 for (j, &tau) in self.taus.iter().enumerate() {
280 if tau != T::zero() {
281 let v = &a[j * m + j + 1..(j + 1) * m];
282 reflect(v, tau.conj(), &mut y.data[j..], m, cols);
283 }
284 }
285 } else if cols <= FOURS {
286 for y in y.data.chunks_exact_mut(m) {
287 self.reflect_fours(y);
288 }
289 } else {
290 self.apply_blocks(&mut y.data, cols);
291 }
292 // The first `n` rows of `y`, moved up in place.
293 for j in 1..cols {
294 y.data.copy_within(j * m..j * m + n, j * n);
295 }
296 y.data.truncate(n * cols);
297 let mut x = Matrix::from_column_major(n, cols, y.data);
298 if n == 0 {
299 } else if cols == 1 || n <= SUBSTITUTE {
300 for x in x.data.chunks_exact_mut(n) {
301 back_substitute(a, m, n, x);
302 }
303 } else {
304 trsm(
305 Side::Left,
306 Uplo::Upper,
307 Op::N,
308 false,
309 n,
310 cols,
311 a,
312 m,
313 &mut x.data,
314 n,
315 );
316 }
317 Some(x)
318 }
319
320 /// `Y ← Q*·Y` for the `m × cols` block `y` (leading dimension `m`), a block of reflections at
321 /// a time: `W = V*·Y` by the block's unit triangle and the rows below it, `W ← T*·W`, and
322 /// `Y -= V·W`.
323 fn apply_blocks(&self, y: &mut [T], cols: usize) {
324 let m = self.qr.rows();
325 let (k, nb) = (self.taus.len(), self.nb);
326 let a = &self.qr.data;
327 let mut e1 = vec![T::zero(); nb * nb];
328 let mut w = vec![T::zero(); 2 * nb * cols];
329 let mut j0 = 0;
330 while j0 < k {
331 let kb = nb.min(k - j0);
332 let j1 = j0 + kb;
333 unit_lower(&a[j0 + j0 * m..], m, kb, &mut e1);
334 let v2 = &a[j1 + j0 * m..];
335 let t = &self.ts[j0 * nb..];
336 let (w1, w2) = w.split_at_mut(kb * cols);
337 let w2 = &mut w2[..kb * cols];
338 gemm(
339 kb,
340 cols,
341 kb,
342 T::one(),
343 &e1,
344 kb,
345 Op::C,
346 &y[j0..],
347 m,
348 Op::N,
349 T::zero(),
350 w1,
351 kb,
352 );
353 gemm(
354 kb,
355 cols,
356 m - j1,
357 T::one(),
358 v2,
359 m,
360 Op::C,
361 &y[j1..],
362 m,
363 Op::N,
364 T::one(),
365 w1,
366 kb,
367 );
368 gemm(
369 kb,
370 cols,
371 kb,
372 T::one(),
373 t,
374 nb,
375 Op::C,
376 w1,
377 kb,
378 Op::N,
379 T::zero(),
380 w2,
381 kb,
382 );
383 gemm(
384 kb,
385 cols,
386 kb,
387 -T::one(),
388 &e1,
389 kb,
390 Op::N,
391 w2,
392 kb,
393 Op::N,
394 T::one(),
395 &mut y[j0..],
396 m,
397 );
398 gemm(
399 m - j1,
400 cols,
401 kb,
402 -T::one(),
403 v2,
404 m,
405 Op::N,
406 w2,
407 kb,
408 Op::N,
409 T::one(),
410 &mut y[j1..],
411 m,
412 );
413 j0 = j1;
414 }
415 }
416
417 /// `y ← Q*·y` for a column `y`, four reflections at a time by the diagonal blocks of their
418 /// blocks' `T`, `I - V·T·V*` of four: `w = T*·V*·y` in one pass over `y` and `y -= V·w` in
419 /// another, the rows below the four's triangle by kernels; the reflections left over one at a
420 /// time.
421 fn reflect_fours(&self, y: &mut [T]) {
422 let m = self.qr.rows();
423 let (k, nb) = (self.taus.len(), self.nb);
424 let a = &self.qr.data;
425 let mut j0 = 0;
426 while j0 < k {
427 let j1 = (j0 + nb).min(k);
428 let t = &self.ts[j0 * nb..];
429 let mut j = j0;
430 while j + 4 <= j1 && j + 4 <= m {
431 // `V`'s rows `j..j + 4`, unit lower triangular, and the rows below them.
432 let at = |r: usize, c: usize| a[j + r + (j + c) * m];
433 let col = |c: usize| &a[(j + c) * m + j + 4..(j + c + 1) * m];
434 let cols = [col(0), col(1), col(2), col(3)];
435 let (top, bottom) = y[j..].split_at_mut(4);
436 let mut w = dots4(bottom, cols);
437 for (c, w) in w.iter_mut().enumerate() {
438 *w += top[c];
439 for (r, &y) in top.iter().enumerate().skip(c + 1) {
440 *w += at(r, c).conj() * y;
441 }
442 }
443 // `w ← T*·w` for the four's block of `T`, upper triangular.
444 let d = j - j0;
445 let tt = |r: usize, c: usize| t[d + r + (d + c) * nb];
446 for c in (0..4).rev() {
447 let mut x = T::zero();
448 for (r, &w) in w.iter().enumerate().take(c + 1) {
449 x += tt(r, c).conj() * w;
450 }
451 w[c] = x;
452 }
453 for r in 0..4 {
454 let mut x = w[r];
455 for (c, &w) in w.iter().enumerate().take(r) {
456 x += at(r, c) * w;
457 }
458 top[r] -= x;
459 }
460 axpys4(bottom, cols, w);
461 j += 4;
462 }
463 for j in j..j1 {
464 let tau = self.taus[j];
465 if tau != T::zero() {
466 reflect(
467 &a[j * m + j + 1..(j + 1) * m],
468 tau.conj(),
469 &mut y[j..],
470 m,
471 1,
472 );
473 }
474 }
475 j0 = j1;
476 }
477 }
478
479 /// The triangular factor of all the `k` reflections in one block, `k × k`: `S = V*·V` by
480 /// products of blocks, the factors of blocks of up to [`LEAF_T`] reflections from it as
481 /// LAPACK's `larft` builds them, `T[0..j, j] = -τ_j·T[0..j, 0..j]·S[0..j, j]`, and those
482 /// joined from the left by products of blocks, `T12 = -T1·S12·T2`.
483 fn whole_t(&self) -> Vec<T> {
484 let m = self.qr.rows();
485 let k = self.taus.len();
486 let a = &self.qr.data;
487 let mut s = vec![T::zero(); k * k];
488 {
489 let mut e = vec![T::zero(); k * k];
490 unit_lower(a, m, k, &mut e);
491 gemm(
492 k,
493 k,
494 k,
495 T::one(),
496 &e,
497 k,
498 Op::C,
499 &e,
500 k,
501 Op::N,
502 T::zero(),
503 &mut s,
504 k,
505 );
506 gemm(
507 k,
508 k,
509 m - k,
510 T::one(),
511 &a[k..],
512 m,
513 Op::C,
514 &a[k..],
515 m,
516 Op::N,
517 T::one(),
518 &mut s,
519 k,
520 );
521 }
522 let mut t = vec![T::zero(); k * k];
523 let mut y = vec![T::zero(); k * LEAF_T];
524 let mut z = vec![T::zero(); k * LEAF_T];
525 let mut j0 = 0;
526 while j0 < k {
527 let j1 = (j0 + LEAF_T).min(k);
528 let kb = j1 - j0;
529 for j in j0..j1 {
530 let tau = self.taus[j];
531 t[j + j * k] = tau;
532 if tau == T::zero() {
533 continue;
534 }
535 for i in j0..j {
536 let mut x = T::zero();
537 for p in i..j {
538 x += t[i + p * k] * s[p + j * k];
539 }
540 t[i + j * k] = -tau * x;
541 }
542 }
543 if j0 > 0 {
544 let (y, z) = (&mut y[..j0 * kb], &mut z[..j0 * kb]);
545 gemm(
546 j0,
547 kb,
548 j0,
549 T::one(),
550 &t,
551 k,
552 Op::N,
553 &s[j0 * k..],
554 k,
555 Op::N,
556 T::zero(),
557 y,
558 j0,
559 );
560 gemm(
561 j0,
562 kb,
563 kb,
564 -T::one(),
565 y,
566 j0,
567 Op::N,
568 &t[j0 + j0 * k..],
569 k,
570 Op::N,
571 T::zero(),
572 z,
573 j0,
574 );
575 for (c, z) in z.chunks_exact(j0).enumerate() {
576 t[(j0 + c) * k..(j0 + c) * k + j0].copy_from_slice(z);
577 }
578 }
579 j0 = j1;
580 }
581 t
582 }
583
584 /// The first `cols` columns of `Q = H_0·H_1·…·H_k-1`, `cols` either `k` or `m`, from the
585 /// last reflection back, as LAPACK's `orgqr`: each block of reflections gives its own columns
586 /// directly and updates those right of it. The matrix starts as zeros: the identity's columns
587 /// from `k` on are taken in by the last block, or set for the reflections one at a time.
588 fn form_q(&self, cols: usize) -> Matrix<T> {
589 let m = self.qr.rows();
590 let k = self.taus.len();
591 let a = &self.qr.data;
592 let mut q = Matrix::from_column_major(m, cols, vec![T::zero(); m * cols]);
593 // The whole `Q` of a tall matrix: all the reflections in one block, whose product with
594 // the columns of the identity right of them, most of the work, is a copy.
595 let one = cols > k && m >= 4 * k && m >= ONE_BLOCK;
596 let nb = if one { k } else { self.nb };
597 if nb == 0 || k == 0 {
598 for j in k..cols {
599 q.data[j + j * m] = T::one();
600 }
601 for j in (0..k).rev() {
602 let tau = self.taus[j];
603 let v = &a[j * m + j + 1..(j + 1) * m];
604 let (left, right) = q.data.split_at_mut((j + 1) * m);
605 let rest = cols - j - 1;
606 if rest > 0 && tau != T::zero() {
607 // Row `j` of the columns right of `j` is still zero.
608 reflect(v, tau, &mut right[j..], m, rest);
609 }
610 left[j + j * m] = T::one() - tau;
611 for (q, &v) in left[j * m + j + 1..].iter_mut().zip(v) {
612 *q = -tau * v;
613 }
614 }
615 return q;
616 }
617 let built;
618 let ts: &[T] = if one {
619 built = self.whole_t();
620 &built
621 } else {
622 &self.ts
623 };
624 let mut e1 = vec![T::zero(); nb * nb];
625 let mut y = vec![T::zero(); nb * nb];
626 let mut w = vec![T::zero(); 2 * nb * cols];
627 let mut end = k;
628 while end > 0 {
629 let j0 = (end - 1) / nb * nb;
630 let j1 = end;
631 let kb = j1 - j0;
632 unit_lower(&a[j0 + j0 * m..], m, kb, &mut e1);
633 let v2 = &a[j1 + j0 * m..];
634 let t = &ts[j0 * nb..];
635 let (left, right) = q.data.split_at_mut(j1 * m);
636 let rest = cols - j1;
637 // The last block, whose columns right of it are still those of the identity.
638 let last = j1 == k;
639 if rest > 0 {
640 // The columns right of the block, zeros in its rows: `W = T·V2*·C2`, then
641 // `C1 = -E1·W` and `C2 -= V2·W`.
642 let (w1, w2) = w.split_at_mut(kb * rest);
643 let w2 = &mut w2[..kb * rest];
644 if last {
645 // `V2*·I`.
646 for (c, w) in w1.chunks_exact_mut(kb).enumerate() {
647 for (i, w) in w.iter_mut().enumerate() {
648 *w = v2[c + i * m].conj();
649 }
650 }
651 } else {
652 gemm(
653 kb,
654 rest,
655 m - j1,
656 T::one(),
657 v2,
658 m,
659 Op::C,
660 &right[j1..],
661 m,
662 Op::N,
663 T::zero(),
664 w1,
665 kb,
666 );
667 }
668 gemm(
669 kb,
670 rest,
671 kb,
672 T::one(),
673 t,
674 nb,
675 Op::N,
676 w1,
677 kb,
678 Op::N,
679 T::zero(),
680 w2,
681 kb,
682 );
683 gemm(
684 kb,
685 rest,
686 kb,
687 -T::one(),
688 &e1,
689 kb,
690 Op::N,
691 w2,
692 kb,
693 Op::N,
694 T::zero(),
695 &mut right[j0..],
696 m,
697 );
698 // `C2 = I - V2·W` for the last block, the identity not held yet.
699 gemm(
700 m - j1,
701 rest,
702 kb,
703 -T::one(),
704 v2,
705 m,
706 Op::N,
707 w2,
708 kb,
709 Op::N,
710 if last { T::zero() } else { T::one() },
711 &mut right[j1..],
712 m,
713 );
714 if last {
715 for c in 0..rest.min(m - j1) {
716 right[j1 + c + c * m] += T::one();
717 }
718 }
719 }
720 // The block's own columns, `[I; 0] - V·T·E1*`.
721 gemm(
722 kb,
723 kb,
724 kb,
725 T::one(),
726 t,
727 nb,
728 Op::N,
729 &e1,
730 kb,
731 Op::C,
732 T::zero(),
733 &mut y,
734 kb,
735 );
736 gemm(
737 kb,
738 kb,
739 kb,
740 -T::one(),
741 &e1,
742 kb,
743 Op::N,
744 &y,
745 kb,
746 Op::N,
747 T::zero(),
748 &mut left[j0 + j0 * m..],
749 m,
750 );
751 gemm(
752 m - j1,
753 kb,
754 kb,
755 -T::one(),
756 v2,
757 m,
758 Op::N,
759 &y,
760 kb,
761 Op::N,
762 T::zero(),
763 &mut left[j1 + j0 * m..],
764 m,
765 );
766 for i in j0..j1 {
767 left[i + i * m] += T::one();
768 }
769 end = j0;
770 }
771 q
772 }
773}
774
775/// `x ← R⁻¹·x` for the upper triangle `R` of the `n × n` block `r`, its diagonal real, and a
776/// column `x`, by columns of `R`: each element of `x`, once known, taken from those above it.
777fn back_substitute<T: Scalar>(r: &[T], ldr: usize, n: usize, x: &mut [T]) {
778 for j in (0..n).rev() {
779 let d = r[j + j * ldr].re();
780 let xj = T::from_parts(x[j].re() / d, x[j].im() / d);
781 x[j] = xj;
782 axpy(&r[j * ldr..j * ldr + j], xj, &mut x[..j]);
783 }
784}
785
786/// Scratch of the blocked decomposition.
787struct Work<T> {
788 /// The elements of `R` a block's unit triangle stands in for while it is used.
789 save: Vec<T>,
790 /// Products of blocks of reflections with the rest of the matrix.
791 w: Vec<T>,
792 /// The products of a reflection's vector with the columns of a leaf.
793 u: Vec<T>,
794}
795
796impl<T: Scalar> Work<T> {
797 /// Scratch for blocks of `nb` reflections of a matrix of `n` columns.
798 fn new(nb: usize, n: usize) -> Work<T> {
799 Work {
800 save: vec![T::zero(); nb * nb],
801 w: vec![T::zero(); 2 * nb * n.max(nb)],
802 u: vec![T::zero(); nb],
803 }
804 }
805}
806
807/// Factors the `m × n` panel `a`, `m ≥ n`, into its reflections and the triangular factor `T`
808/// (`ldt`, zeros below its diagonal on entry) of their block, as LAPACK's `geqrt3`: the left
809/// half, then its block applied to the right half, the right half, and the two halves' `T`
810/// joined by products of blocks; leaves of [`LEAF`] columns one reflection at a time.
811#[allow(clippy::too_many_arguments)]
812fn panel<T: Scalar>(
813 a: &mut [T],
814 lda: usize,
815 m: usize,
816 n: usize,
817 taus: &mut [T],
818 t: &mut [T],
819 ldt: usize,
820 work: &mut Work<T>,
821) {
822 if n <= LEAF {
823 unblocked(a, lda, m, n, taus, Some((t, ldt)), &mut work.u);
824 return;
825 }
826 let n1 = n / 2;
827 let n2 = n - n1;
828 panel(a, lda, m, n1, &mut taus[..n1], t, ldt, work);
829 let (l, r) = a.split_at_mut(n1 * lda);
830 {
831 let Work { save, w, .. } = &mut *work;
832 let t1: &[T] = t;
833 with_v(l, lda, n1, save, |v| {
834 apply_block(v, lda, m, n1, t1, ldt, r, lda, n2, w);
835 });
836 }
837 let (t1, t2) = t.split_at_mut(n1 * ldt);
838 panel(
839 &mut r[n1..],
840 lda,
841 m - n1,
842 n2,
843 &mut taus[n1..],
844 &mut t2[n1..],
845 ldt,
846 work,
847 );
848 // `T12 = -T1·(V1*·V2)·T2`, `V1` from row `n1` on, where `V2` starts.
849 let Work { save, w, .. } = work;
850 let (x, y) = w.split_at_mut(n1 * n2);
851 let y = &mut y[..n1 * n2];
852 let l: &[T] = l;
853 with_v(&mut r[n1..], lda, n2, save, |v2| {
854 gemm(
855 n1,
856 n2,
857 m - n1,
858 T::one(),
859 &l[n1..],
860 lda,
861 Op::C,
862 v2,
863 lda,
864 Op::N,
865 T::zero(),
866 x,
867 n1,
868 );
869 });
870 gemm(
871 n1,
872 n2,
873 n1,
874 T::one(),
875 t1,
876 ldt,
877 Op::N,
878 x,
879 n1,
880 Op::N,
881 T::zero(),
882 y,
883 n1,
884 );
885 gemm(
886 n1,
887 n2,
888 n2,
889 -T::one(),
890 y,
891 n1,
892 Op::N,
893 &t2[n1..],
894 ldt,
895 Op::N,
896 T::zero(),
897 x,
898 n1,
899 );
900 for (t, x) in t2.chunks_mut(ldt).zip(x.chunks(n1)) {
901 t[..n1].copy_from_slice(x);
902 }
903}
904
905/// Factors the `m × n` block `a` by `min(m, n)` reflections, one at a time, as LAPACK's
906/// `geqr2`, and with `t` (`ldt`, zeros below its diagonal on entry) also the triangular factor
907/// of their block, as `larft`, from the same kind of products: for the reflection of column `j`,
908/// the products of its vector with the columns right of it, which apply it, and with those left
909/// of it, the reflections' vectors, which make the column `j` of `T`. `u` holds `n` elements of
910/// scratch when `t` is given.
911fn unblocked<T: Scalar>(
912 a: &mut [T],
913 lda: usize,
914 m: usize,
915 n: usize,
916 taus: &mut [T],
917 mut t: Option<(&mut [T], usize)>,
918 u: &mut [T],
919) {
920 let k = m.min(n);
921 for j in 0..k {
922 let (left, right) = a.split_at_mut(((j + 1) * lda).min(a.len()));
923 let col = &mut left[j * lda..j * lda + m];
924 let (tau, beta) = reflector(col[j], &mut col[j + 1..]);
925 col[j] = beta;
926 taus[j] = tau;
927 if tau == T::zero() {
928 continue;
929 }
930 let v = &left[j * lda + j + 1..j * lda + m];
931 let rest = n - j - 1;
932 if rest > 0 {
933 reflect(v, tau.conj(), &mut right[j..], lda, rest);
934 }
935 if let Some((t, ldt)) = &mut t {
936 let ldt = *ldt;
937 t[j + j * ldt] = tau;
938 if j > 0 {
939 // `T[0..j, j] = -τ·T[0..j, 0..j]·V[:, 0..j]*·v_j`, the products from row `j`,
940 // where `v_j` starts.
941 let s = &mut u[..j];
942 dots(v, &left[j + 1..], lda, j, s);
943 for (i, s) in s.iter_mut().enumerate() {
944 *s = (left[j + i * lda] + *s).conj();
945 }
946 for i in 0..j {
947 let mut x = T::zero();
948 for p in i..j {
949 x += t[i + p * ldt] * s[p];
950 }
951 t[i + j * ldt] = -tau * x;
952 }
953 }
954 }
955 }
956}
957
958/// `c ← (I - V·T·V*)*·c` for the `m × n` block `c`: `V` of `m × k` with its unit lower triangle
959/// held, `T` of `k × k` upper triangular with zeros below; `W = V*·c`, `W ← T*·W`, `c -= V·W`.
960/// `w` holds `2·k·n` elements of scratch.
961#[allow(clippy::too_many_arguments)]
962fn apply_block<T: Scalar>(
963 v: &[T],
964 ldv: usize,
965 m: usize,
966 k: usize,
967 t: &[T],
968 ldt: usize,
969 c: &mut [T],
970 ldc: usize,
971 n: usize,
972 w: &mut [T],
973) {
974 if n == 0 || k == 0 {
975 return;
976 }
977 let (w1, w2) = w[..2 * k * n].split_at_mut(k * n);
978 gemm(
979 k,
980 n,
981 m,
982 T::one(),
983 v,
984 ldv,
985 Op::C,
986 c,
987 ldc,
988 Op::N,
989 T::zero(),
990 w1,
991 k,
992 );
993 gemm(
994 k,
995 n,
996 k,
997 T::one(),
998 t,
999 ldt,
1000 Op::C,
1001 w1,
1002 k,
1003 Op::N,
1004 T::zero(),
1005 w2,
1006 k,
1007 );
1008 gemm(
1009 m,
1010 n,
1011 k,
1012 -T::one(),
1013 v,
1014 ldv,
1015 Op::N,
1016 w2,
1017 k,
1018 Op::N,
1019 T::one(),
1020 c,
1021 ldc,
1022 );
1023}
1024
1025/// Runs `f` on the `m × k` block `a` of reflections' vectors as `V`, its top `k × k` made the
1026/// unit lower triangle for the time: the elements of `R` there are kept in `save` and put back.
1027fn with_v<T: Scalar, X>(
1028 a: &mut [T],
1029 lda: usize,
1030 k: usize,
1031 save: &mut [T],
1032 f: impl FnOnce(&[T]) -> X,
1033) -> X {
1034 for j in 0..k {
1035 let col = &mut a[j * lda..j * lda + j + 1];
1036 save[j * k..j * k + j + 1].copy_from_slice(col);
1037 col[..j].fill(T::zero());
1038 col[j] = T::one();
1039 }
1040 let x = f(a);
1041 for j in 0..k {
1042 a[j * lda..j * lda + j + 1].copy_from_slice(&save[j * k..j * k + j + 1]);
1043 }
1044 x
1045}
1046
1047/// The unit lower triangle of the top `k × k` of the reflections' vectors `a`, into `e`, `k × k`.
1048fn unit_lower<T: Scalar>(a: &[T], lda: usize, k: usize, e: &mut [T]) {
1049 for j in 0..k {
1050 let col = &mut e[j * k..(j + 1) * k];
1051 col[..j].fill(T::zero());
1052 col[j] = T::one();
1053 col[j + 1..].copy_from_slice(&a[j * lda + j + 1..j * lda + k]);
1054 }
1055}