Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

18) Householder QR

Last time

  • Gram-Schmidt orthogonalization

  • Classical vs Modified Gram-Schmidt

  • QR factorization

Today

  1. Recap from last time

  2. Householder QR

vander (generic function with 2 methods)

1. Recap Gram-Schmidt orthogonalization

For many applications, we find ourselves interested in the column spaces of a matrix AA:

⟨a1⟩⊆⟨a1,a2⟩⊆⟨a1,a2,a3⟩…\langle a_1 \rangle \subseteq \langle a_1, a_2 \rangle \subseteq \langle a_1, a_2, a_3 \rangle \ldots

The idea of QR factorization is the construction of a sequence of orthonormal vectors, q1,q2,…q_1, q_2, \ldots that span these successive spaces.

Thus, suppose we want to find an orthogonal basis for the span of the columns of AA:

[a1∣a2]=[q1∣q2][r11r120r22]\Bigg[ a_1 \Bigg| a_2 \Bigg] = \Bigg[ q_1 \Bigg| q_2 \Bigg] \begin{bmatrix} r_{11} & r_{12} \\ 0 & r_{22} \end{bmatrix}

Given a1,a2,…a_1, a_2, \dots, we can construct vectors q1,q2,…q_1, q_2, \ldots and entries rijr_{ij}, by an iterative process of successive orthogonalization.

Gram-Schmidt with more parallelism

We are performing the following (from right to left):

w=(I−q2q2T)(I−q1q1T)v=(I−q1q1T−q2q2T+q2q2Tq1q1T)v=(I−[q1∣q2][q1Tq2T])v\begin{align} w = (I - q_2 q_2^T) (I - q_1 q_1^T) v &= (I - q_1 q_1^T - q_2 q_2^T + q_2 q_2^T q_1 q_1^T) v \\ &= \Bigg( I - \Big[ q_1 \Big| q_2 \Big] \begin{bmatrix} q_1^T \\ q_2^T \end{bmatrix} \Bigg) v \end{align}

which can be factored in blocks to expoloit a bit of parallelism. Let’s call this classical Gram-Schmidt.

gram_schmidt_classical (generic function with 1 method)
norm(Q' * Q - I) = 1.4985231287367549
norm(Q * R - A) = 
7.350692433565389e-16
7.350692433565389e-16

Classical Vs Modified Gram-Schmidt

Why does the order of operations matter?

We are performing the following (from right to left):

w=(I−q2q2T)(I−q1q1T)v=(I−q1q1T−q2q2T+q2q2Tq1q1T)v=(I−[q1∣q2][q1Tq2T])v\begin{align} w = (I - q_2 q_2^T) (I - q_1 q_1^T) v &= (I - q_1 q_1^T - q_2 q_2^T + q_2 q_2^T q_1 q_1^T) v \\ &= \Bigg( I - \Big[ q_1 \Big| q_2 \Big] \begin{bmatrix} q_1^T \\ q_2^T \end{bmatrix} \Bigg) v \end{align}

which can be factored in blocks and is not exact in finite arithmetic.

Let’s look at this a bit more closely. In the classical Gram-Schmidt (CGS), we take each vector, one at a time, and make it orthogonal to all previous vectors. If an error is made in computing q2q_2 in CGS, so that q1Tq2=δq^T_1q_2=\delta is small, but non-zero in finite arithmetic, this will not be corrected for in any of the computations that follow, and it will actually be propagated. In this case, v3v_3 will not be orthogonal to q1q_1 or q2q_2.

Because of rounding errors, in classical Gram-Schmidt, Qk−1Q_{k−1} does not have truly orthogonal columns. In modified Gram–Schmidt (MGS) we compute the length of the projection of w=vkw = v_k onto q1q_1 and subtract that projection (and the rounding errors) from ww. Next, we compute the length of the projection of the computed ww onto q2q_2 and subtract that projection (and the rounding errors) from ww, and so on, but always orthogonalizing against the computed version of ww.

We can look at the size of what’s left over

We project out the components of our vectors in the directions of each qjq_j.

Loading...

The next vector is almost linearly dependent

norm(v) = 1.4245900685395503
Loading...

We can see that vv has substantial components in some QQ-directions, while it is nearly orthogonal to the other directions.

Right-looking modified Gram-Schmidt

Each outer step of the modified Gram-Schmidt algorithm can be interpreted as a right-multiplication by a square upper-triangular matrix.

gram_schmidt_modified (generic function with 1 method)
norm(Q' * Q - I) = 8.486718528276085e-9
norm(Q * R - A) = 8.709998074379606e-16
8.709998074379606e-16

Classical versus modified?

  • Classical

    • Really unstable, orthogonality error of size 1≫ϵmachine1 \gg \epsilon_{\text{machine}}

    • Don’t need to know all the vectors in advance

  • Modified

    • Needs to be right-looking for efficiency

    • Less unstable, but orthogonality error 10−9≫ϵmachine10^{-9} \gg \epsilon_{\text{machine}}

norm(Q' * Q - I) = 3.216006485393791e-15
3.216006485393791e-15

2. Householder triangularization

Householder triangularization is numerically more stable than Gram-Schmidt orthogonaliztion, though it lacks the latter’s applicability as a basis for iterative methods. The Householder algorithm is a process of “orthogonal triangularization”, making a matrix triangular by a sequence of unitary matrix operations.

Gram-Schmidt constructed a triangular matrix RR to orthogonalize AA into QQ. Each step was an orthogonal projector, which is a rank-deficient operation.

Oblique projector (Trefethen and Bau, 1997)Orthogonal projector (Trefethen and Bau, 1997)

Image credits: Pictures taken from the reference book: Trefethen and Bau (1997), Numerical Linear Algebra (available at the library).

Householder uses orthogonal transformations (reflectors) to triangularize.

Qn⋯Q1⏟QTA=R\underbrace{Q_{n} \dotsb Q_1}_{Q^T} A = R
Householder Reflector (Trefethen and Bau, 1997)

The reflection, as depicted above by Trefethen and Bau (1997) can be written F=I−2vvTvTvF = I - 2 \frac{v v^T}{v^T v}.

The structure of the algorithm is

[∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗]⏟A→[∗∗∗0∗∗0∗∗0∗∗0∗∗]⏟Q1A→[∗∗∗0∗∗00∗00∗00∗]⏟Q2Q1A→[∗∗∗0∗∗00∗000000]⏟Q3Q2Q1A\underbrace{\begin{bmatrix} * & * & * \\ * & * & * \\ * & * & * \\ * & * & * \\ * & * & * \\ \end{bmatrix}}_{A} \to \underbrace{\begin{bmatrix} * & * & * \\ 0 & * & * \\ 0 & * & * \\ 0 & * & * \\ 0 & * & * \\ \end{bmatrix}}_{Q_1 A} \to \underbrace{\begin{bmatrix} * & * & * \\ 0 & * & * \\ 0 & 0 & * \\ 0 & 0 & * \\ 0 & 0 & * \\ \end{bmatrix}}_{Q_2 Q_1 A} \to \underbrace{\begin{bmatrix} * & * & * \\ 0 & * & * \\ 0 & 0 & * \\ 0 & 0 & 0 \\ 0 & 0 & 0 \\ \end{bmatrix}}_{Q_3 Q_2 Q_1 A}

Constructing the QjQ_j

Qn−1⋯Q0⏟QTA=R\underbrace{Q_{n-1} \dotsb Q_0}_{Q^T} A = R

Each of our QjQ_j will have the form

Qj=[Ij00F]Q_j = \begin{bmatrix} I_j & 0 \\ 0 & F \end{bmatrix}

where FF is a “reflection” that achieves

Fx=[∥x∥00⋮]F x = \begin{bmatrix} \lVert x \rVert \\ 0 \\ 0 \\ \vdots \end{bmatrix}

where xx is the column of RR from the diagonal down. This transformation is a reflection across a plane with normal v=Fx−x=∥x∥e1−xv = Fx - x = \lVert x \rVert e_1 - x.

The two methods can be summarized as follows:

  • Gram-Schmidt: a triangular orthogonalization

  • Householder: an orthogonal triangularization

Adventures in reflection

norm(v) = 1.9143500566953007
4×4 Matrix{Float64}: 1.91435 1.90727 1.74837 1.50921 -2.35196e-16 -0.314783 0.966541 1.51907 -3.65311e-16 0.80021 0.549617 0.814576 -5.06571e-16 0.829846 0.314388 0.339815
4×4 Matrix{Float64}: 1.91435 1.90727 1.74837 1.50921 -2.35196e-16 1.19502 0.331753 0.38129 -3.65311e-16 -1.66533e-16 0.886061 1.41761 -5.06571e-16 -1.11022e-16 0.663291 0.965183

Householder: A naive algorithm

qr_householder_naive (generic function with 1 method)
4×4 Matrix{Float64}: -2.0 0.0 -1.11111 0.0 0.0 1.49071 1.38778e-17 1.3582 0.0 0.0 0.888889 9.71445e-17 0.0 0.0 0.0 0.397523

How to interpret VV as QQ?

The following two programs compute a matrix containing vectors that generate the Householder reflectors whose product is Q.

reflectors_to_dense (generic function with 1 method)
norm(Q' * Q - I) = 3.7994490775439526e-15
norm(Q * R - A) = 7.562760794606217e-15

Great, but we can still break it

(Any[[NaN, NaN], [NaN]], [NaN NaN; NaN NaN])

We had the lines

    v = copy(R[j:end, j])
    v[1] -= norm(v)
    v = normalize(v)

What happens when R is already upper triangular?

In this case

v=[10]v = \begin{bmatrix}1 \\ 0 \end{bmatrix}
Choosing the better of two Householder reflectors (Trefethen and Bau, 1999).

In general, there are two possible reflections. For numerical stability, it is important to choose the one that moves xx the largest distance, so that it is not too close to xx itself.

In fact, suppose that in the above figure, the angle of H+H^{+} and the e1e_1 axis is much smaller than xx or ∣∣x∣∣e1|| x || e_1. Thus, the calculation of vv represents a subtraction of nearby quantities and will tend to suffer from cancellation errors. We can pick the sign of vv so that we can avoid such effects by ensuring that ∣∣v∣∣||v|| is never smaller than ∣∣x∣∣||x||.

Householder: An improved algorithm

qr_householder (generic function with 1 method)
tau = [2.0, 2.0]
V1 = 
[[1.0, 0.0], [1.0]]
2×2 Matrix{Int64}: -1 0 0 -1

Householder is backward stable

norm(Q' * Q - I) = 5.949301496893686e-15
norm(Q * R - A) = 1.2090264267288813e-14
LinearAlgebra.QRCompactWY{Float64, Matrix{Float64}, Matrix{Float64}} Q factor: 2×2 LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}, Matrix{Float64}} R factor: 2×2 Matrix{Float64}: 1.0 0.0 0.0 1.0

Orthogonality is preserved

norm(Q' * Q - I) = 1.4985231287367549
norm(v) = 1.4245900685395503
Loading...
norm(Q' * Q - I) = 3.840520021608235e-15
Loading...

Summary:

  • Classic Gram-Schmidt: Usually very poor orthogonality.

  • Modified Gram-Schmidt: Depends upon condition of AA. Fails completely when AA is singular.

  • Householder triangularization: Always good orthogonality and backward stable.