{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# TOPIC 1 \n", "\n", "# Least squares: Cholesky, QR and Householder\n", "\n", "## 4 QR decomposition and Householder transformations\n", "\n", "***\n", "*Course:* [Math 535](http://www.math.wisc.edu/~roch/mmids/) - Mathematical Methods in Data Science (MMiDS) \n", "*Author:* [Sebastien Roch](http://www.math.wisc.edu/~roch/), Department of Mathematics, University of Wisconsin-Madison \n", "*Updated:* Sep 21, 2020 \n", "*Copyright:* © 2020 Sebastien Roch\n", "***\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### 4.1 Revisiting Gram-Schmidt\n", "\n", "Let $\\mathbf{a}_1,\\ldots,\\mathbf{a}_m$ be linearly independent. In a previous notebook, we discussed the Gram-Schmidt algorithm to obtain an orthonormal basis of $\\mathrm{span}(\\mathbf{a}_1,\\ldots,\\mathbf{a}_m)$. " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "We revisit it in matrix form. Let \n", "\n", "$$\n", "A =\n", "\\begin{pmatrix}\n", "| & & | \\\\\n", "\\mathbf{a}_1 & \\ldots & \\mathbf{a}_m \\\\\n", "| & & | \n", "\\end{pmatrix}\n", "\\quad\n", "\\text{and}\n", "\\quad\n", "Q =\n", "\\begin{pmatrix}\n", "| & & | \\\\\n", "\\mathbf{q}_1 & \\ldots & \\mathbf{q}_m \\\\\n", "| & & | \n", "\\end{pmatrix}.\n", "$$\n", "\n", "The output of the Gram-Schimdt algorithm can be written in the following compact form, known as a [QR decomposition](https://en.wikipedia.org/wiki/QR_decomposition),\n", "\n", "$$\n", "A = QR\n", "$$\n", "\n", "where column $i$ of the $m \\times m$ matrix $R$ contains the coefficients of the linear combination of the $\\mathbf{q}_j$'s that produce $\\mathbf{a}_i$." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "By the proof of Gram-Schmidt, $\\mathbf{a}_i \\in \\mathrm{span}(\\mathbf{q}_1,\\ldots,\\mathbf{q}_i)$. So column $i$ of $R$ has only zeros below the diagonal. Hence $R$ has a special structure we have previously encounteres: it is upper triangular.\n", "\n", "![QR](https://www.researchgate.net/profile/Alex_Townsend2/publication/270659665/figure/fig8/AS:668700940193794@1536442136069/QR-factorization-of-a-quasimatrix.png)\n", "\n", "([Source](https://www.researchgate.net/figure/QR-factorization-of-a-quasimatrix_fig8_270659665))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### 4.2 Least squares via QR" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Let $A \\in \\mathbb{R}^{n\\times m}$ be an $n\\times m$ matrix with linearly independent columns and let $\\mathbf{b} \\in \\mathbb{R}^n$ be a vector. Recall that a solution $\\mathbf{x}^*$ to the least-squares problem\n", "\n", "$$\n", "\\min_{\\mathbf{x} \\in \\mathbb{R}^m} \\|A \\mathbf{x} - \\mathbf{b}\\|\n", "$$\n", "\n", "satisfies the normal equations\n", "\n", "$$\n", "A^T A \\mathbf{x}^* = A^T \\mathbf{b}.\n", "$$\n", "\n", "As we will see later in the course, the normal equations approach via Cholesky decomposition has numerical issues. We present an alternative approach based on the QR decomposition. The QR decomposition approach to least squares proceeds as follows:" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "1. Construct an orthonormal basis of $\\mathrm{col}(A)$ through a QR decomposition\n", "\n", "$$\n", "A = QR.\n", "$$\n", "\n", "2. Form the orthogonal projection matrix\n", "\n", "$$\n", "P = Q Q^T.\n", "$$\n", "\n", "3. Apply the projection to $\\mathbf{b}$ and observe that, by the proof of the normal equations, $\\mathbf{x}$ satisfies\n", "\n", "$$\n", "A \\mathbf{x}^* = Q Q^T \\mathbf{b}. \n", "$$\n", "\n", "4. Plug in the QR decomposition for $A$ to get\n", "\n", "$$\n", "QR \\mathbf{x}^* = Q Q^T \\mathbf{b}. \n", "$$\n", "\n", "5. Multiply both sides by $Q^T$ and use $Q^T Q = I_{m \\times m}$\n", "\n", "$$\n", "R \\mathbf{x}^* = Q^T \\mathbf{b}. \n", "$$\n", "\n", "6. Solving this system for $\\mathbf{x}^*$ is straightforward because $R$ is upper triangular via back substitution." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "***\n", "**Theorem (Least Squares via QR):** Let $A \\in \\mathbb{R}^{n\\times m}$ be an $n\\times m$ matrix with linearly independent columns, let $\\mathbf{b} \\in \\mathbb{R}^n$ be a vector,\n", "and let $A = QR$ be a QR decomposition of $A$. The solution to the least-squares problem\n", "\n", "$$\n", "\\min_{\\mathbf{x} \\in \\mathbb{R}^m} \\|A \\mathbf{x} - \\mathbf{b}\\|.\n", "$$\n", "\n", "satisfies\n", "\n", "$$\n", "R \\mathbf{x}^* = Q^T \\mathbf{b}. \n", "$$\n", "\n", "***" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "**NUMERICAL CORNER** We implement the QR approach to least squares and return to our previous linear regression example." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [ { "data": { "text/plain": [ "mmids_backsubs (generic function with 1 method)" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Julia version: 1.5.1\n", "using Plots, LinearAlgebra\n", "\n", "function mmids_gramschmidt(A)\n", " n,m = size(A)\n", " Q = zeros(Float64,n,m)\n", " R = zeros(Float64,m,m)\n", " for j = 1:m\n", " v = A[:,j]\n", " for i = 1:j-1\n", " R[i,j] = dot(Q[:,i],A[:,j])\n", " v -= R[i,j]*Q[:,i]\n", " end\n", " R[j,j] = norm(v)\n", " Q[:,j] = v/R[j,j]\n", " end\n", " return Q,R\n", "end\n", "\n", "function mmids_backsubs(U,b)\n", " m = length(b)\n", " x = zeros(Float64,m)\n", " for i=m:-1:1\n", " x[i] = (b[i] - dot(U[i,i+1:m],x[i+1:m]))/U[i,i]\n", " end\n", " return x\n", "end" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "scrolled": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "ls_by_qr (generic function with 1 method)" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function ls_by_qr(A, b)\n", " Q,R = mmids_gramschmidt(A)\n", " return mmids_backsubs(R,Q'*b)\n", "end" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [ { "data": { "text/plain": [ "2-element Array{Float64,1}:\n", " -1.2341467593021789\n", " 1.0569731809683849" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n, b0, b1 = 100, -1, 1\n", "x = LinRange(0,10,n)\n", "y = b0 .+ b1*x .+ randn(n)\n", "A = hcat(ones(n),x)\n", "coeff = ls_by_qr(A,y)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "scatter(x,y,legend=false,alpha=0.5)\n", "plot!(x,coeff.+coeff*x,lw=2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### 4.3 Householder transformations\n", "\n", "While Gram-Schmidt gives a natural way to compute a QR decomposition, there are many other numerical algorithms for this purpose. Some have better numerical behavior, specifically in terms of how they handle roundoff error. Quoting [Wikipedia](https://en.wikipedia.org/wiki/Round-off_error):\n", "\n", "> A roundoff error, also called rounding error, is the difference between the result produced by a given algorithm using exact arithmetic and the result produced by the same algorithm using finite-precision, rounded arithmetic. Rounding errors are due to inexactness in the representation of real numbers and the arithmetic operations done with them. [...] When a sequence of calculations with an input involving roundoff error are made, errors may accumulate, sometimes dominating the calculation. \n", "\n", "We will not prove this here, but the following method based on Householder reflectors is numerically more [stable](https://en.wikipedia.org/wiki/Numerical_stability#Stability_in_numerical_linear_algebra)." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "First some preliminary definitions. \n", "\n", "**Definition (Orthogonal Matrix):** A square matrix $Q \\in \\mathbb{R}^{m\\times m}$ is orthogonal if $Q^T Q = Q Q^T = I_{m \\times m}$. $\\lhd$\n", "\n", "In words, the matrix inverse of $Q$ is its transpose. As we have seen before, this is equivalent to the columns of $Q$ forming an orthonormal basis of $\\mathbb{R}^m$.\n", "\n", "*Exercise:* Show that the product of two orthogonal matrices $Q_1$ and $Q_2$ is also orthogonal. $\\lhd$" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "An important property of orthogonal matrices is that they preserve inner products: if $Q \\in \\mathbb{R}^{m\\times m}$ is orthogonal, then for any $\\mathbf{x}, \\mathbf{y} \\in \\mathbb{R}^m$\n", "\n", "$$\n", "\\langle Q \\mathbf{x}, Q \\mathbf{y} \\rangle \n", "= (Q \\mathbf{x})^T Q \\mathbf{y}\n", "= \\mathbf{x}^T Q^T Q \\mathbf{y}\n", "= \\mathbf{x}^T \\mathbf{y}\n", "= \\langle \\mathbf{x}, \\mathbf{y} \\rangle.\n", "$$\n", "\n", "In particular, orthogonal matrices preserve norms and angles. " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Recall that the angle $\\theta$ between $\\mathbf{x}$ and $\\mathbf{y}$ satisfies\n", "\n", "$$\n", "\\cos \\theta\n", "= \\frac{\\langle \\mathbf{x}, \\mathbf{y} \\rangle}{\\|\\mathbf{x}\\| \\|\\mathbf{y}\\|}.\n", "$$\n", "\n", "![Angle between two vectors](https://upload.wikimedia.org/wikipedia/commons/thumb/0/05/Inner-product-angle.png/314px-Inner-product-angle.png)\n", "([Source](https://commons.wikimedia.org/wiki/File:Inner-product-angle.png))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#### 4.3.1 Reflections\n", "\n", "One such family of transformations are reflections. \n", "\n", "**Definition (Hyperplane):** A hyperplane $W$ is a linear subspace of $\\mathbb{R}^m$ of dimension $m-1$. $\\lhd$\n", "\n", "*Exercise:* Let $W \\subseteq \\mathbb{R}^m$ be a hyperplane. Show that there exists a unit vector $\\mathbf{z} \\in \\mathbb{R}^m$ such that \n", "\n", "$$\n", "\\mathbf{w} \\in W \\iff \\langle \\mathbf{z}, \\mathbf{w} \\rangle = 0.\n", "$$\n", "\n", "$\\lhd$" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "**Definition (Householder Reflection):** Let $\\mathbf{z} \\in \\mathbb{R}^m$ be a unit vector and let $W$ be the hyperplane orthogonal to it. The reflection across $W$ is given by\n", "\n", "$$\n", "H = I_{m \\times m} - 2 \\mathbf{z} \\mathbf{z}^T.\n", "$$\n", "\n", "This is referred to as a Householder reflection. $\\lhd$\n", "\n", "In words, we subtract twice the projection onto $\\mathbf{z}$, as depicted below." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "![Reflection](https://ccjou.files.wordpress.com/2009/08/householder-matrix.jpg)\n", "\n", "([Source](https://ccjou.wordpress.com/householder-matrix/))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "***\n", "\n", "**Lemma:** Let $H = I_{m\\times m} - 2\\mathbf{z}\\mathbf{z}^T$ be a Householder reflections. Then $H$ is an orthogonal matrix.\n", "\n", "***\n", "\n", "*Proof:* We check the definition:\n", "\n", "\n", "\\begin{align}\n", "H^T H \n", "&= (I_{m\\times m}^T - 2(\\mathbf{z}\\mathbf{z}^T)^T) (I_{m\\times m} - 2\\mathbf{z}\\mathbf{z}^T)\\\\\n", "&= (I_{m\\times m} - 2\\mathbf{z}\\mathbf{z}^T) (I_{m\\times m} - 2\\mathbf{z}\\mathbf{z}^T)\\\\\n", "&= I_{m\\times m} - 2\\mathbf{z}\\mathbf{z}^T - 2\\mathbf{z}\\mathbf{z}^T + 4 \\mathbf{z}\\mathbf{z}^T\n", "\\end{align}\n", "\n", "\n", "which is equal to $I_{m\\times m}$. The calculation for $H H^T$ is the same.$\\square$" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#### 4.3.2 QR decomposition by introducing zeros\n", "\n", "We return to QR decompositions. One way to construct a QR decomposition of a matrix $A \\in \\mathbb{R}^{n \\times m}$ is to find a sequence of orthogonal matrices $Q_1, \\ldots, Q_k$ that triangularize $A$:\n", "\n", "$$\n", "Q_k \\cdots Q_2 Q_1 A = R\n", "$$\n", "\n", "for an upper-triangular matrix $R$. Indeed, by the properties of orthogonal matrices, we then have\n", "\n", "$$\n", "A = Q_1^T Q_2^T \\cdots Q_{k}^T R\n", "$$\n", "\n", "where $Q = Q_1^T Q_2^T \\cdots Q_{k}^T$ is itself orthogonal. So to proceed we need to identify orthogonal matrices that have the effect of introducing zeros below the diagonal, as illustrated below." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "![Introducing zeros](https://hua-zhou.github.io/teaching/biostatm280-2017spring/slides/10-qr/householder_transform_diagram.png)\n", "\n", "[(Source)](https://hua-zhou.github.io/teaching/biostatm280-2017spring/slides/10-qr/householder_transform_diagram.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "It turns out that a well-chosen Householder reflection does the trick. Let $\\mathbf{a}_1$ be the first column of $A$ and take \n", "\n", "$$\n", "\\mathbf{z}_1 = \\frac{\\|\\mathbf{a}_1\\| \\,\\mathbf{e}_1 - \\mathbf{a}_1}{\\|\\|\\mathbf{a}_1\\| \\,\\mathbf{e}_1 - \\mathbf{a}_1\\|}\n", "\\quad\n", "\\text{and}\n", "\\quad\n", "H_1 = I_{n\\times n} - 2\\mathbf{z}_1\\mathbf{z}_1^T\n", "$$\n", "\n", "where recall that $\\mathbf{e}_1$ is the first element of the standard basis of $\\mathbb{R}^n$. As depicted below, this choice sends $\\mathbf{a}_1$ to \n", "\n", "$$\n", "\\|\\mathbf{a}_1\\| \\mathbf{e}_1 \n", "= \n", "\\begin{pmatrix}\n", "\\|\\mathbf{a}_1\\|\\\\\n", "0 \\\\\n", "\\vdots \\\\\n", "0\n", "\\end{pmatrix}.\n", "$$" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "![QR by Householder I](https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQPtIGW70euRIoKwOXwwNErCtqpV1Z_04oZy0rd2yk5ksVdVV1T)\n", "\n", "[(Source)](https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQPtIGW70euRIoKwOXwwNErCtqpV1Z_04oZy0rd2yk5ksVdVV1T)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "***\n", "\n", "**Lemma:** Let $\\mathbf{a}_1$, $\\mathbf{z}_1$ and $H_1$ be as above. Then\n", "\n", "$$\n", "H_1 \\mathbf{a}_1 = \\|\\mathbf{a}_1\\| \\mathbf{e}_1 .\n", "$$\n", "\n", "***\n", "\n", "*Proof idea:* The proof by picture is in the figure above." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "*Proof:* Note that\n", "\n", "\n", "\\begin{align}\n", "\\|\\|\\mathbf{a}_1\\| \\,\\mathbf{e}_1 - \\mathbf{a}_1\\|^2\n", "&= (\\|\\mathbf{a}_1\\| - a_{1,1})^2\n", "+ \\sum_{j=2}^n a_{1,j}^2\\\\\n", "&= \\|\\mathbf{a}_1\\|^2 -2 \\|\\mathbf{a}_1\\| a_{1,1} + a_{1,1}^2 + \\sum_{j=2}^n a_{1,j}^2\\\\\n", "&= 2(\\|\\mathbf{a}_1\\|^2 - \\|\\mathbf{a}_1\\| a_{1,1})\n", "\\end{align}\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "and\n", "\n", "\n", "\\begin{align}\n", "2 \\mathbf{z}_1 \\mathbf{z}_1^T \\mathbf{a}_1\n", "&= 2 \\mathbf{z}_1 \\frac{\\|\\mathbf{a}_1\\| \\,\\mathbf{e}_1^T \\mathbf{a}_1 - \\mathbf{a}_1^T \\mathbf{a}_1}{\\|\\|\\mathbf{a}_1\\| \\,\\mathbf{e}_1 - \\mathbf{a}_1\\|}\\\\\n", "&= 2 \\frac{\\|\\mathbf{a}_1\\| a_{1,1} - \\|\\mathbf{a}_1\\|^2}{\\|\\|\\mathbf{a}_1\\| \\,\\mathbf{e}_1 - \\mathbf{a}_1\\|^2} (\\|\\mathbf{a}_1\\| \\,\\mathbf{e}_1 - \\mathbf{a}_1)\\\\\n", "&= - (\\|\\mathbf{a}_1\\| \\,\\mathbf{e}_1 - \\mathbf{a}_1)\n", "\\end{align}\n", "\n", "\n", "where we used the previous equation. Hence\n", "\n", "$$\n", "H_1 \\mathbf{a}_1\n", "= (I_{n\\times n} - 2\\mathbf{z}_1\\mathbf{z}_1^T) \\,\\mathbf{a}_1\n", "= \\mathbf{a}_1 + (\\|\\mathbf{a}_1\\| \\,\\mathbf{e}_1 - \\mathbf{a}_1) = \\|\\mathbf{a}_1\\| \\,\\mathbf{e}_1.\n", "$$\n", "\n", "That establishes the claim. $\\square$" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "There is another valid choice, as the next exercise establishes.\n", "\n", "*Exercise:* Define \n", "\n", "$$\n", "\\tilde{\\mathbf{z}}_1 = \\frac{\\|\\mathbf{a}_1\\| \\,\\mathbf{e}_1 + \\mathbf{a}_1}{\\| \\|\\mathbf{a}_1\\| \\,\\mathbf{e}_1 + \\mathbf{a}_1\\|}\n", "\\quad\n", "\\text{and}\n", "\\quad\n", "\\tilde{H}_1 = I_{n\\times n} - 2\\tilde{\\mathbf{z}}_1 \\tilde{\\mathbf{z}}_1^T.\n", "$$\n", "\n", "Show that $\\tilde{H}_1 \\mathbf{a}_1 = - \\|\\mathbf{a}_1\\| \\,\\mathbf{e}_1$." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "![QR by Householder II](https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQ0lCpiodSnps555DzXtc5XSo2zvJWXfOjUZMuL6w4skmbpyEum)\n", "\n", "[(Source)](https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQ0lCpiodSnps555DzXtc5XSo2zvJWXfOjUZMuL6w4skmbpyEum)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#### 4.3.3 Putting everything together\n", "\n", "We have shown how to introduce zeros below the diagonal in the first column of a matrix $A \\in \\mathbb{R}^{n \\times m}$. To introduce zeros in the second column below the diagonal we use a block matrix\n", "\n", "$$\n", "H_2\n", "= \n", "\\begin{pmatrix}\n", "1 & \\mathbf{0} \\\\\n", "\\mathbf{0} & F_2\n", "\\end{pmatrix}\n", "$$\n", "\n", "where $F_2$ is the following Householder reflection. Write the second column of $H_1 A$ as $(y^{(2)}, \\mathbf{y}_2)^T$. That is, $\\mathbf{y}_2$ are the entries $2,\\ldots, n$ of that column.\n", "\n", "$$\n", "F_2 = I_{(n-1) \\times (n-1)} - 2 \\mathbf{z}_2 \\mathbf{z}_2^T\n", "\\quad\n", "\\text{with}\n", "\\quad\n", "\\mathbf{z}_2 \n", "= \\frac{\\|\\mathbf{y}_2\\| \\,\\mathbf{e}_1 - \\mathbf{y}_2}{\\|\\|\\mathbf{y}_2\\| \\,\\mathbf{e}_1 - \\mathbf{y}_2\\|}\n", "$$\n", "\n", "where now $\\mathbf{e}_1 \\in \\mathbb{R}^{n-1}$. Applying $H_2$ to $H_1 A$ preserves the first row and column, and introduces zeros under the diagonal on the second column." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "And so on. At Step $k$, we split the $k$-th column of $H_{k-1} \\cdots H_1 A$ into its first $k-1$ and last $n-k+1$ entries $(\\mathbf{y}^{(k)}, \\mathbf{y}_k)$ and form the matrix\n", "\n", "$$\n", "H_k\n", "= \n", "\\begin{pmatrix}\n", "I_{(k-1)\\times (k-1)} & \\mathbf{0} \\\\\n", "\\mathbf{0} & F_k\n", "\\end{pmatrix}\n", "$$\n", "\n", "where\n", "\n", "$$\n", "F_k = I_{(n-k+1) \\times (n-k+1)} - 2 \\mathbf{z}_k \\mathbf{z}_k^T\n", "\\quad\n", "\\text{with}\n", "\\quad\n", "\\mathbf{z}_k \n", "= \\frac{\\|\\mathbf{y}_k\\| \\,\\mathbf{e}_1 - \\mathbf{y}_k}{\\|\\|\\mathbf{y}_k\\| \\,\\mathbf{e}_1 - \\mathbf{y}_k\\|}.\n", "$$\n", "\n", "This time the first $k-1$ rows and columns are preserved, while zeros are introduced under the diagonal of the $k$-th column." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "**NUMERICAL CORNER** We implement the procedure above in Julia. We will need the following function. For $\\alpha \\in \\mathbb{R}$, let the sign of $\\alpha$ be\n", "\n", "$$\n", "\\mathrm{sign}(\\alpha)\n", "= \n", "\\begin{cases}\n", "1 & \\text{if \\alpha > 0}\\\\\n", "0 & \\text{if \\alpha = 0}\\\\\n", "-1 & \\text{if \\alpha < 0}\n", "\\end{cases}\n", "$$\n", "\n", "For example, in Julia, using the function sign:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "(-1, 1, 0)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sign(-10), sign(20), sign(0)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "The following function constructs the upper triangular matrix $R$ by iteratively modifying the relevant block of $A$. Computing $Q$ actually requires extra computational work that is often not needed. We saw that, in the context of the least-squares problem, we really only need to compute $Q^T \\mathbf{b}$ for some input vector $\\mathbf{b}$. This can be done as $R$ is constructed, as follows. \n", "\n", "See [here](https://docs.julialang.org/en/v1/base/base/#=) for an explanation of copy." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ "mmids_householder (generic function with 1 method)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function mmids_householder(A)\n", " n, m = size(A)\n", " Qt = Matrix{Float64}(I,n,n)\n", " R = copy(A)\n", " for k = 1:m\n", " # computing z\n", " y = R[k:n,k]\n", " e1 = zeros(n-k+1)\n", " e1 = 1\n", " z = sign(y)*norm(y)*e1 .+ y\n", " z = z/norm(z)\n", " \n", " # updating Qt\n", " Qt[k:n,1:n] = Qt[k:n,1:n] .- 2*z*z'*Qt[k:n,1:n]\n", " \n", " # updating R\n", " R[k:n,k:m] = R[k:n,k:m] .- 2*z*z'*R[k:n,k:m]\n", " end\n", " return Qt[1:m,1:n]', R[1:m,1:m]\n", "end" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "In mmids_householder, we use both reflections defined above. We will not prove this here, but the particular choice made has good numerical properties. Quoting [TB, Lecture 10]:\n", "\n", "> Mathematically, either choice of sign is satisfactory. However, this is a case where numerical stability -- insensitivity to rounding errors -- dictates that one choice should be taken rather than the other. For numerical stability, it is desirable to reflect $\\mathbf{x}$ to the vector $z \\|\\mathbf{x}\\| \\mathbf{e}_1$ that is not too close to $\\mathbf{x}$ itself. [...] Suppose that [in the figure above] the angle between $H^+$ and the $\\mathbf{e}_1$ axis is very small. Then the vector $\\mathbf{v} = \\|\\mathbf{x}\\| \\mathbf{e}_1 - \\mathbf{x}$ is much smaller than $\\mathbf{x}$ or $\\|\\mathbf{x}\\| \\mathbf{e}_1$. Thus the calculation of $\\mathbf{v}$ represents a subtraction of nearby quantities and will tend to suffer from cancellation errors. " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "We return to our regression example." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [ { "data": { "text/plain": [ "3-element Array{Float64,1}:\n", " 2.0282989895406263\n", " 0.2719746343547142\n", " 0.9204381318085032" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n, b0, b1, b2 = 100, 0, 0, 1\n", "x = LinRange(0,10,n)\n", "y = b0 .+ b1*x .+ b2*x.^2 .+ 10*randn(n)\n", "A = reduce(hcat, [ones(n), x, x.^2])\n", "Q, R = mmids_householder(A)\n", "coeff = mmids_backsubs(R, Q'*y)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "scrolled": false, "slideshow": { "slide_type": "skip" } }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "scatter(x,y,legend=false,alpha=0.5)\n", "plot!(x,coeff.+coeff*x.+coeff*x.^2,lw=2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "One advantage of the Householder approach is that it produces a matrix $Q$ with very good orthogonality, i.e., $Q^T Q \\approx I$. We give a quick example below comparing Gram-Schmidt and Householder. (The choice of matrix $A$ will become clearer when we discuss the singular value decomposition later in the course.)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "n = 50\n", "U, W = qr(randn(n,n))\n", "V, W = qr(randn(n,n))\n", "S = Diagonal((1/2).^(1:n))\n", "A = U*S*V';" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [ { "data": { "text/plain": [ "1.3619835091208436e-16" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Qgs, Rgs = mmids_gramschmidt(A)\n", "norm(A-Qgs*Rgs)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [ { "data": { "text/plain": [ "23.988875573848322" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "norm(Qgs'*Qgs - Matrix{Float64}(I,n,n))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "As you can see above, the $Q$ and $R$ factors produced by Gram-Schmidt do have the property that $QR \\approx A$. However, $Q$ is far from orthogonal. \n", "\n", "On the other hand, Householder reflections perform much better in that respect as we show next." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [ { "data": { "text/plain": [ "3.327807615972261e-16" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Qhh, Rhh = mmids_householder(A)\n", "norm(A-Qhh*Rhh)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [ { "data": { "text/plain": [ "6.643898557699989e-15" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "norm(Qhh'*Qhh - Matrix{Float64}(I,n,n))" ] } ], "metadata": { "kernelspec": { "display_name": "Julia 1.5.1", "language": "julia", "name": "julia-1.5" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.5.1" } }, "nbformat": 4, "nbformat_minor": 2 }