Skip to main content

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}