It is possible to compute a thin QR factorization using the outer product formula (2.4.4), as we did with LU. However, to stably compute the factorization, a better strategy is to introduce zeros into the lower triangle, one column at a time, using orthogonal matrices. Thanks to Theorem 3.3.2, the product of orthogonal matrices will also be orthogonal.
The reason P is called a reflector is sketched in Figure 3.4.1.
Given a vector z, we can choose v so that P reflects z onto the x1-axis—i.e., so that Pz is nonzero only in the first element. Because orthogonal matrices preserve the 2-norm, we must have
(Recall that ek is the kth column of the identity matrix.) We choose the positive sign above for our discussion, but see Function 3.4.1 and Exercise 4 for important computational details. Let
The QR factorization is computed by using successive Householder reflections to introduce zeros in one column at a time. We first show the process for a small numerical example in Demo 3.4.1.
You may be wondering what happened to Q in Demo 3.4.1. Each Householder reflector is orthogonal but not full-size. We have to pad it out to represent algebraically the fact that a block of the first rows is left alone. Given a reflector Pk that is of square size m−k+1, we define
But QnQn−1⋯Q1 is orthogonal too, and we multiply on the left by its transpose to get A=QR, where Q=(QnQn−1⋯Q1)T. We don’t even need to form these matrices explicitly. Writing
we can build QT iteratively by starting with the identity and doing the same row operations as on A. That process uses much less memory than building the Qk matrices explicitly.
The algorithm we have described is encapsulated in Function 3.4.1. There is one more refinement in it, however. As indicated by (3.4.2), the application of a reflector P to a vector does not require the formation of the matrix P explicitly.
In Demo 3.3.1 it was seen that the Q output of Julia’s qr function is not a standard matrix. The reason is that Equation (3.3.8) shows that in order to solve the linear least-squares problem, all we need from Q is the computation of Q^Tb. Referring again to (3.4.10) and (3.4.2), the special structure of the reflectors is such that for this computation, we only need to apply code similar to lines 18 and 21 of Function 3.4.1 for each of the Householder vectors v that is constructed.
This observation leads to the idea of the Q-less QR factorization, in which the full or thin Q is never computed explicitly. This is the variant used by Julia’s qr. The returned value Q used within Function 3.3.2 is of a special type that allows Julia to perform Q'*b efficiently for the least-squares solution.
In Exercise 8 you are asked to derive the following result about the Q-less factorization.
The flop count quoted in Theorem 3.4.2 dominates the running time for least-squares solution via QR. Compared to the count from Theorem 3.2.3 for solution by the normal equations, the flops are essentially identical when m=n, but the QR solution is about twice the cost when m≫n. The redeeming quality of the QR route is better stability, which we do not discuss here.
(a) Find a vector u such that Pu=−u. (Figure 3.4.1 may be of help.)
(b) What algebraic condition is necessary and sufficient for a vector x to satisfy Px=x? In n dimensions, how many such linearly independent vectors are there?
✍ Under certain circumstances, computing the vector v in (3.4.4) could lead to subtractive cancellation, which is why line 12 of Function 3.4.1 reads as it does. Devise an example that causes subtractive cancellation if (3.4.4) is used.
✍ Suppose QR factorization is used to compute the solution of a square linear system, Ax=b, i.e., let m=n.
(a) Find an asymptotic flop count for this procedure, and compare it to the LU factorization algorithm.
(b) Show that κ2(A)=κ2(R).
✍ Prove that κ2(A)=κ2(R) when A is not square. (Be careful! You can’t take an inverse of A or R.)
Another algorithmic technique for orthogonally introducing zeros into a matrix is the Givens rotation. Given a 2-vector [α,β], it defines an angle θ such that
(a) ✍ Given α and β, show how to compute cosθ and sinθ without evaluating any trig functions.
(b) ⌨ Given the vector z=[12345]T, use Julia to find a sequence of Givens rotations that transforms z into the vector ∥z∥e1. (Hint: You can operate only on pairs of elements at a time, introducing a zero at the lower of the two positions.)
✍ Suppose m=Kn for constant K≥1 as both m and n go to infinity. Show that the flop counts from Theorem 3.4.2 and Theorem 3.2.3 have a ratio of 1 when K=1 and approaches 2 as K→∞.