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.

17) Gram-Schmidt and QR

Last time

  • Linear Algebra

  • Polynomial evaluation

  • Orthogonality

Today

  1. Revisit orthogonality

  2. Constructing orthogonal bases
    2.1 Orthogonal matrices
    2.2 Gram-Schmidt orthogonalization

  3. QR factorization

    Updating registry at `~/.julia/registries/General.toml`
   Resolving package versions...
    Updating `~/.julia/environments/v1.10/Project.toml`
  [b964fa9f] + LaTeXStrings v1.4.1
    Updating `~/.julia/environments/v1.10/Manifest.toml`
 
 [b964fa9f] ↑ LaTeXStrings v1.4.0 ⇒ v1.4.1
Precompiling packages...
    770.3 ms  ✓ LaTeXStrings
   2517.9 ms  ✓ Latexify
    692.6 ms  ✓ Latexify → SparseArraysExt
  3 dependencies successfully precompiled in 6 seconds. 195 already precompiled.
vander (generic function with 2 methods)

1. Revisit orthogonality

Polynomials can be orthogonal too!

Loading...
  • Which inner product will be zero?

    • Which functions are even and odd?

Pairwise inner product

The pairwise inner products between two sets of vectors can be expressed by collecting the sets as columns in matrices and writing A=XTYA = X^T Y where Ai,j=xiTyjA_{i,j} = x_i^T y_j. It follows from this definition that

(XTY)T=YTX.(X^T Y)^T = Y^T X .
3×3 Matrix{Float64}: 12.5 -1.11022e-15 8.67347 -1.11022e-15 17.3469 -2.22045e-16 8.67347 -2.22045e-16 10.8272

Normalization and orthogonalization

Loading...
3×3 Matrix{Float64}: 1.0 -1.94289e-16 2.45323 -1.94289e-16 17.3469 -2.22045e-16 2.45323 -2.22045e-16 10.8272

2. Orthogonality

2.1 Orthogonal matrices

If two vectors xx and yy are such that xTy=0x^T y = 0 then we say xx and yy are orthogonal (or “xx is orthogonal to yy”).

A vector is said to be normalized if ∥x∥=1\lVert x \rVert = 1. If xx is orthogonal to yy and ∥x∥=∥y∥=1\lVert x \rVert = \lVert y \rVert = 1 then we say xx and yy are orthonormal.

A square matrix with orthonormal columns is said to be an orthogonal matrix (or orthonormal matrix).

We typically use QQ or UU and VV for matrices that are known/constructed to be orthogonal.

Orthogonal matrices are always full rank -- the columns are linearly independent.

The inverse of an orthogonal matrix is its transpose:

QTQ=QQT=I.Q^T Q = Q Q^T = I .

Orthogonal matrices are a powerful building block for robust numerical algorithms.

2.2 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.

A naive algorithm

gram_schmidt_naive (generic function with 1 method)
norm(Q' * Q - I) = 6.609184312080184e-16
norm(Q * R - A) = 
2.500206551829073e-16
2.500206551829073e-16

What do orthogonal polynomials look like?

Computations with orthogonal polynomials form the basis of spectral methods, one of the most powerful techniques for the numerical solution of partial differential equations (PDE).

Loading...

What happens if we use more than 50 values of xx?

Theorem:

Every full-rank m×nm\times n matrix (m≥nm \ge n) has a unique reduced QRQ R factorization with Rj,j>0R_{j,j} > 0

The algorithm we’re using generates this positive matrix due to the line:

        R[j,j] = norm(v)

Solving equations using QR=AQR = A

If Ax=bA x = b then Rx=QTbRx = Q^T b (because Q is orthogonal, and it is easy to solve with RR since is triangular).

Loading...

How accurate is it?

norm(Q' * Q - I) = 1.073721107832196e-8
norm(Q * R - A) = 8.268821431611631e-16
8.268821431611631e-16

A variant 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}

Here I−qiqiTI-q_iq_i^T removes the component of a vector in the direction qiq_i, assuming qiq_i is a unit vector. From right to left, we are first applying I−q1q1TI-q_1q_1^T, which removes the q1q_1 component. Then we apply I−q2q2TI-q_2q_2^T, which removes the q2q_2 component. In the above, the cross term vanishe as q1⊥q2q_1 \perp q_2.

This operation 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

The order of operations matter!

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) = 2.2760345477368898e-15
2.2760345477368898e-15