computer science and mathematics

QR decomposition using Householder transformations

It's been a while since my last post. A project I have in the works requires some matrix decompositions, so I thought this would be a good opportunity to get a post out about QR decompositions using Householder transformations. For the moment we will focus on the field of real numbers, though we can extend these concepts to the complex field if necessary.

Theorem.

A real matrix, \(\mathbf{A} \in \mathbf{M}_{m,n}\), can be decomposed as \(\mathbf{A}=\mathbf{Q}\mathbf{R}\), where \(\mathbf{Q} \in \mathbf{M}_{m,m}\) is an orthogonal matrix and \(\mathbf{R} \in \mathbf{M}_{m,n}\) is an upper triangular matrix.

The proof of this theorem has been omitted but could be constructed using Householder transformations. We'll discuss the Householder transformation and see how it can be applied to perform the QR decomposition. We'll review the decomposition algorithm and, lastly, have a look at some C++ code.

A Householder transformation is a linear transformation given by the matrix, \(\mathbf{P}\),

where \(\mathbf{I}\) is the identity matrix and \(\hat{v}\) is a unit vector. \(\mathbf{P}\vec{x}\) is the reflection of \(\vec{x}\) about the hyperplane passing through the origin with normal vector, \(\hat{v}\).

If \(\hat{v}\hat{v}^T\vec{x}\) is the projection of \(\vec{x}\) onto \(\hat{v}\), then \(\mathbf{P}\vec{x}\) should reflect \(\vec{x}\) about the hyperplane with normal, \(\hat{v}\). See the diagram below.

thus, \(1\) is an eigenvalue of \(\mathbf{P}\) with multiplicity \(m-1\), since there are \(m-1\) vectors orthogonal to \(\vec{v}\).

Now that we have touched on the Householder transformation, we'll see how the transformation can be applied to decompose a matrix into the product of an orthogonal matrix and an upper triangular matrix. The basic idea is to apply multiple transformations to successively zap the entries below the main diagonal column by column. We will then have something of the form,

Clearly, from the properties above, \(\mathbf{Q}_i\mathbf{Q}_i = \mathbf{I}\), so this is a valid statement. Additionally, \(\mathbf{Q}_1\mathbf{Q}_2\ldots\mathbf{Q}_n\) is the product of orthogonal matrices and is itself orthogonal. What is maybe not so clear at this point is that the product, \(\mathbf{Q}_n\mathbf{Q}_{n-1}\ldots\mathbf{Q}_1\mathbf{A}\), is an upper triangular matrix.

The first step is to find the Householder transformation, \(\mathbf{Q}_1 = \mathbf{I} - 2\hat{v_1}\hat{v_1}^T\), that rotates the vector, \(\vec{a_1}\), to the vector, \(\|\vec{a_1}\|\hat{e_1} = \begin{pmatrix}\|\vec{a_1}\| & 0 & \cdots & 0\end{pmatrix}^T\), which amounts to finding the appropriate unit vector, \(\hat{v_1}\). Note that we could also rotate the vector, \(\vec{a_1}\), to the vector, \(-\|\vec{a_1}\|\hat{e_1} = \begin{pmatrix}-\|\vec{a_1}\| & 0 & \cdots & 0\end{pmatrix}^T\). In our implementation we will choose the sign to improve numerical stability. For the vector, \(\vec{a_1}\), we will choose the sign to be \(-\text{sgn}(\hat{e_1}^T\vec{a_1})\).

We proceed in this fashion until all entries below the main diagonal are zero. Thus, \(\mathbf{Q}_n\mathbf{Q}_{n-1}\ldots\mathbf{Q}_1\mathbf{A}\) will be an upper triangular matrix.

We can now write out an algorithm for performing the QR decomposition using Householder transformations. This algorithm is rather straightforward but naive in the sense that a more efficient algorithm could be written.

Below we have a C++ implementation of the decomposition algorithm above. The householderDecomposition method is a member of the cMatrix object. The cMatrix object is a rather simple object to perform a few matrix operations. It has a few operator overloads and the ability to transpose a matrix. Download the project at the end of this post to see the details. Here is the Householder decomposition.