├── .gitignore ├── .travis.yml ├── Chap1 ├── Julia Essentials.ipynb ├── PlotlyJS.ipynb ├── plot1.pdf ├── plot10.pdf ├── plot11.pdf ├── plot12.pdf ├── plot2.pdf ├── plot3.pdf ├── plot3_1.pdf ├── plot4.pdf ├── plot5.pdf ├── plot6.pdf ├── plot7.pdf ├── plot8.pdf ├── plot8_1.pdf ├── plot8_2.pdf └── plot8_3.pdf ├── Chap2 ├── Balls.ipynb ├── Gershgorin.ipynb ├── Linear Algebra Preliminaries.ipynb ├── Matrix Norm.ipynb └── SVD.ipynb ├── Chap3 ├── Cholesky.ipynb ├── Floating_Point.ipynb ├── Homework │ ├── rook_pivoting.jl │ └── starter_code.ipynb ├── LU_Fail.ipynb ├── LU_Pivoting.ipynb ├── LU_Rank_Revealing.ipynb ├── LU_Solve.ipynb └── Triangular_Solve.ipynb ├── Chap4 ├── Homework │ └── accuracy.ipynb ├── QR.mp4 ├── QR_Animation.ipynb ├── QR_GS.ipynb ├── QR_Givens.ipynb ├── QR_Householder.ipynb └── QR_Viewer.ipynb ├── Chap5 ├── Inverse_Iteration.ipynb ├── Orthogonal_Iteration.ipynb ├── Power_Iteration.ipynb ├── QR_Iteration.ipynb ├── QR_Iteration_With_Shift.ipynb ├── QR_homework.ipynb ├── QR_homework_matrix_data.ipynb ├── QR_hwk_matrix_data.h5 ├── QR_iteration.mp4 ├── QR_iteration_unsym.mp4 ├── Rayleigh_Quotient.ipynb └── Schur_Iteration.ipynb ├── Chap6 ├── Arnoldi.ipynb ├── Lanczos.ipynb └── Lanczos_CRO.ipynb ├── Chap7 ├── gs.jl ├── jacobi.jl └── sor.jl ├── Chap8 ├── IterativeMethods.jl ├── bicgstab.jl ├── cg.jl ├── cr.jl ├── gmres.jl ├── minres.jl └── qmr.jl ├── Chap9 ├── .gitignore ├── Elimination_Tree.ipynb ├── Lower_Triangular_Solve.ipynb ├── Reach.ipynb ├── Sparse.jl ├── Sparse_Matrix_Demo.ipynb ├── Trefethen_150 │ └── Trefethen_150.mtx ├── example_A.mtx └── reach_example.mtx ├── Demo.ipynb ├── README.md ├── load_plot_pkg.jl ├── src ├── gees.jl ├── gees_test.jl ├── geqrf.jl ├── getrf.jl ├── potrf.jl └── trtrs.jl └── test └── runtests.jl /.gitignore: -------------------------------------------------------------------------------- 1 | *.jl.cov 2 | *.jl.*.cov 3 | *.jl.mem 4 | deps/deps.jl 5 | .ipynb_checkpoints 6 | test/data.h5 7 | test.h5 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: julia 2 | julia: 3 | - 1.0 4 | script: 5 | - julia test/runtests.jl 6 | -------------------------------------------------------------------------------- /Chap1/plot1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap1/plot1.pdf -------------------------------------------------------------------------------- /Chap1/plot10.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap1/plot10.pdf -------------------------------------------------------------------------------- /Chap1/plot11.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap1/plot11.pdf -------------------------------------------------------------------------------- /Chap1/plot12.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap1/plot12.pdf -------------------------------------------------------------------------------- /Chap1/plot2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap1/plot2.pdf -------------------------------------------------------------------------------- /Chap1/plot3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap1/plot3.pdf -------------------------------------------------------------------------------- /Chap1/plot3_1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap1/plot3_1.pdf -------------------------------------------------------------------------------- /Chap1/plot4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap1/plot4.pdf -------------------------------------------------------------------------------- /Chap1/plot5.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap1/plot5.pdf -------------------------------------------------------------------------------- /Chap1/plot6.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap1/plot6.pdf -------------------------------------------------------------------------------- /Chap1/plot7.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap1/plot7.pdf -------------------------------------------------------------------------------- /Chap1/plot8.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap1/plot8.pdf -------------------------------------------------------------------------------- /Chap1/plot8_1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap1/plot8_1.pdf -------------------------------------------------------------------------------- /Chap1/plot8_2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap1/plot8_2.pdf -------------------------------------------------------------------------------- /Chap1/plot8_3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap1/plot8_3.pdf -------------------------------------------------------------------------------- /Chap3/Cholesky.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "using LinearAlgebra\n", 10 | "using Random\n", 11 | "rng = MersenneTwister()\n", 12 | "Random.seed!(rng, 2018)\n", 13 | ";" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 2, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "# Size of the matrix\n", 23 | "n = 512;\n", 24 | "\n", 25 | "# Random initialization of matrix A\n", 26 | "G = zeros(Float64,n,n)\n", 27 | "for i=1:n\n", 28 | " G[i,i] = rand(rng, 1:2)\n", 29 | " G[i+1:n,i] = rand(rng, -2:2, n-i)\n", 30 | "end\n", 31 | "A = G * transpose(G)\n", 32 | "A0 = copy(A);" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": 3, 38 | "metadata": {}, 39 | "outputs": [ 40 | { 41 | "data": { 42 | "text/plain": [ 43 | "1×512 Adjoint{Float64,Array{Float64,1}}:\n", 44 | " 164.0 276.0 -609.0 298.0 1225.0 … -6754.0 894.0 4969.0 -983.0" 45 | ] 46 | }, 47 | "execution_count": 3, 48 | "metadata": {}, 49 | "output_type": "execute_result" 50 | } 51 | ], 52 | "source": [ 53 | "# Initializing the right-hand side\n", 54 | "xe = rand(rng, 0:9, n) # This will be our solution\n", 55 | "b = A * xe\n", 56 | "b'" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": 4, 62 | "metadata": {}, 63 | "outputs": [ 64 | { 65 | "data": { 66 | "text/plain": [ 67 | "potrs (generic function with 1 method)" 68 | ] 69 | }, 70 | "execution_count": 4, 71 | "metadata": {}, 72 | "output_type": "execute_result" 73 | } 74 | ], 75 | "source": [ 76 | "include(\"../src/getrf.jl\")\n", 77 | "include(\"../src/potrf.jl\")" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": 5, 83 | "metadata": {}, 84 | "outputs": [ 85 | { 86 | "name": "stdout", 87 | "output_type": "stream", 88 | "text": [ 89 | " 0.065163 seconds (29.09 k allocations: 1.493 MiB)\n" 90 | ] 91 | }, 92 | { 93 | "data": { 94 | "text/plain": [ 95 | "\"TEST PASSED\"" 96 | ] 97 | }, 98 | "execution_count": 5, 99 | "metadata": {}, 100 | "output_type": "execute_result" 101 | } 102 | ], 103 | "source": [ 104 | "A = copy(A0)\n", 105 | "@time potrf!(A)\n", 106 | "# Solve\n", 107 | "x = potrs(A, b)\n", 108 | "norm(x - xe) == 0 ? \"TEST PASSED\" : \"TEST FAILED\"" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": 6, 114 | "metadata": {}, 115 | "outputs": [ 116 | { 117 | "name": "stdout", 118 | "output_type": "stream", 119 | "text": [ 120 | " 0.213301 seconds (344.08 k allocations: 19.801 MiB)\n", 121 | " 0.024932 seconds\n" 122 | ] 123 | } 124 | ], 125 | "source": [ 126 | "# Compare with LU factorization\n", 127 | "A = copy(A0)\n", 128 | "@time getrf!(A);\n", 129 | "A = copy(A0)\n", 130 | "@time potrf!(A)" 131 | ] 132 | } 133 | ], 134 | "metadata": { 135 | "@webio": { 136 | "lastCommId": null, 137 | "lastKernelId": null 138 | }, 139 | "kernelspec": { 140 | "display_name": "Julia 1.5.1", 141 | "language": "julia", 142 | "name": "julia-1.5" 143 | }, 144 | "language_info": { 145 | "file_extension": ".jl", 146 | "mimetype": "application/julia", 147 | "name": "julia", 148 | "version": "1.5.1" 149 | } 150 | }, 151 | "nbformat": 4, 152 | "nbformat_minor": 4 153 | } 154 | -------------------------------------------------------------------------------- /Chap3/Homework/rook_pivoting.jl: -------------------------------------------------------------------------------- 1 | function getrfRook!(A) 2 | # Rook pivoting for rank-revealing LU 3 | end 4 | -------------------------------------------------------------------------------- /Chap3/Homework/starter_code.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "using Random\n", 10 | "using Printf\n", 11 | "using LinearAlgebra\n", 12 | "\n", 13 | "# Initialize the random number generator\n", 14 | "rng = MersenneTwister(2018)\n", 15 | "\n", 16 | "# Your answer is implemented in this file\n", 17 | "include(\"rook_pivoting.jl\")\n", 18 | ";" 19 | ] 20 | }, 21 | { 22 | "cell_type": "markdown", 23 | "metadata": {}, 24 | "source": [ 25 | "### Initialization" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 2, 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "n = 64 # Size of matrix\n", 35 | "r = 32 # Rank\n", 36 | "\n", 37 | "A = rand(rng,n,n)\n", 38 | "\n", 39 | "F = lu(A) # LU factorization\n", 40 | "L = F.L # Lower triangular part\n", 41 | "U = F.U # Upper triangular part\n", 42 | "L = L[:,1:r] # Keep the first r columns\n", 43 | "U = U[1:r,:] # Keep the first r rows\n", 44 | "\n", 45 | "# You can replace this by equivalent Matlab/Python code\n", 46 | "\n", 47 | "A = L*U # Rank r matrix\n", 48 | "A0 = copy(A) # Save a copy\n", 49 | ";" 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": {}, 55 | "source": [ 56 | "### Factorization" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": 3, 62 | "metadata": {}, 63 | "outputs": [], 64 | "source": [ 65 | "# Calling your factorization algorithm\n", 66 | "P_row, P_col = getrfRook!(A0)\n", 67 | "\n", 68 | "# Rook pivoting LU:\n", 69 | "# function getrfRook!\n", 70 | "# Input: matrix A0\n", 71 | "# Ouput: returns the row and column permutations\n", 72 | "# The L and U factors are stored in the lower and upper triangular parts of A0\n", 73 | ";" 74 | ] 75 | }, 76 | { 77 | "cell_type": "markdown", 78 | "metadata": {}, 79 | "source": [ 80 | "### Test" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": 4, 86 | "metadata": {}, 87 | "outputs": [ 88 | { 89 | "name": "stdout", 90 | "output_type": "stream", 91 | "text": [ 92 | "The error is 4.02146e-14" 93 | ] 94 | }, 95 | { 96 | "data": { 97 | "text/plain": [ 98 | "\"PASS\"" 99 | ] 100 | }, 101 | "execution_count": 4, 102 | "metadata": {}, 103 | "output_type": "execute_result" 104 | } 105 | ], 106 | "source": [ 107 | "L0 = UniformScaling(1.0) + tril(A0,-1) # Extract L matrix\n", 108 | "U0 = triu(A0) # Extract U matrix\n", 109 | "\n", 110 | "L = zeros(n,r)\n", 111 | "for i=1:n\n", 112 | " L[P_row[i],:] = L0[i,1:r] # Undo the row permutations\n", 113 | "end\n", 114 | "\n", 115 | "U = zeros(r,n)\n", 116 | "for j=1:n\n", 117 | " U[:,P_col[j]] = U0[1:r,j] # Undo the column permutations\n", 118 | "end\n", 119 | "\n", 120 | "err = norm(L*U - A)\n", 121 | "@printf \"The error is %g\" err # Test the accuracy\n", 122 | "err < 1e-13 ? \"PASS\" : \"FAIL\"" 123 | ] 124 | } 125 | ], 126 | "metadata": { 127 | "kernelspec": { 128 | "display_name": "Julia 1.0.0", 129 | "language": "julia", 130 | "name": "julia-1.0" 131 | }, 132 | "language_info": { 133 | "file_extension": ".jl", 134 | "mimetype": "application/julia", 135 | "name": "julia", 136 | "version": "1.0.0" 137 | } 138 | }, 139 | "nbformat": 4, 140 | "nbformat_minor": 1 141 | } 142 | -------------------------------------------------------------------------------- /Chap3/LU_Fail.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "using LinearAlgebra\n", 10 | "using Random\n", 11 | "rng = MersenneTwister();" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 2, 17 | "metadata": {}, 18 | "outputs": [ 19 | { 20 | "data": { 21 | "text/plain": [ 22 | "\"L,U =\"" 23 | ] 24 | }, 25 | "metadata": {}, 26 | "output_type": "display_data" 27 | }, 28 | { 29 | "data": { 30 | "text/plain": [ 31 | "4×4 Array{Float64,2}:\n", 32 | " 1.0 0.0 0.0 0.0\n", 33 | " 0.0 1.0 0.0 0.0\n", 34 | " 1.0 0.0 0.0 1.0\n", 35 | " 0.0 0.0 1.0 0.0" 36 | ] 37 | }, 38 | "metadata": {}, 39 | "output_type": "display_data" 40 | }, 41 | { 42 | "data": { 43 | "text/plain": [ 44 | "4×4 Array{Float64,2}:\n", 45 | " 1.0 3.0 4.0 0.0\n", 46 | " 0.0 1.0 3.0 1.0\n", 47 | " 0.0 0.0 1.0 7.0\n", 48 | " 0.0 0.0 0.0 1.0" 49 | ] 50 | }, 51 | "metadata": {}, 52 | "output_type": "display_data" 53 | }, 54 | { 55 | "name": "stdout", 56 | "output_type": "stream", 57 | "text": [ 58 | "n = 4\n", 59 | "det(A) = -1.0\n", 60 | "A:\n", 61 | "\n" 62 | ] 63 | }, 64 | { 65 | "data": { 66 | "text/plain": [ 67 | "4×4 Array{Float64,2}:\n", 68 | " 1.0 3.0 4.0 0.0\n", 69 | " 0.0 1.0 3.0 1.0\n", 70 | " 1.0 3.0 4.0 1.0\n", 71 | " 0.0 0.0 1.0 7.0" 72 | ] 73 | }, 74 | "execution_count": 2, 75 | "metadata": {}, 76 | "output_type": "execute_result" 77 | } 78 | ], 79 | "source": [ 80 | "Random.seed!(rng, 2018)\n", 81 | "\n", 82 | "# Size of the matrix\n", 83 | "n = 4;\n", 84 | "\n", 85 | "# Initialization of matrix A\n", 86 | "@show n\n", 87 | "L = zeros(Float64,n,n)\n", 88 | "U = zeros(Float64,n,n)\n", 89 | "for i=1:n\n", 90 | " L[i,i] = 1\n", 91 | " U[i,i] = 1\n", 92 | " U[i,i+1:n] = rand(rng, 0:9, n-i)\n", 93 | "end\n", 94 | "L[3, [1,3,4]] = [1,0,1]\n", 95 | "L[4,[3,4]] = [1,0]\n", 96 | "display(\"L,U =\")\n", 97 | "display(L)\n", 98 | "display(U)\n", 99 | "A = L * U\n", 100 | "@show det(A)\n", 101 | "println(\"A:\\n\")\n", 102 | "A" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": 3, 108 | "metadata": {}, 109 | "outputs": [ 110 | { 111 | "data": { 112 | "text/plain": [ 113 | "getrs (generic function with 3 methods)" 114 | ] 115 | }, 116 | "execution_count": 3, 117 | "metadata": {}, 118 | "output_type": "execute_result" 119 | } 120 | ], 121 | "source": [ 122 | "include(\"../src/getrf.jl\")" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": 4, 128 | "metadata": {}, 129 | "outputs": [ 130 | { 131 | "name": "stdout", 132 | "output_type": "stream", 133 | "text": [ 134 | "One of the pivots A[k,k] was 0. The algorithm could not proceed.\n" 135 | ] 136 | } 137 | ], 138 | "source": [ 139 | "# This call is expected to fail\n", 140 | "try\n", 141 | " getrfOuter!(A)\n", 142 | " println(\"The algorithm completed successfully.\")\n", 143 | "catch\n", 144 | " println(\"One of the pivots A[k,k] was 0. The algorithm could not proceed.\")\n", 145 | "end " 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": 5, 151 | "metadata": {}, 152 | "outputs": [ 153 | { 154 | "name": "stdout", 155 | "output_type": "stream", 156 | "text": [ 157 | "L:\n", 158 | "[1.0 0.0; 1.0e17 1.0]\n", 159 | "U:\n", 160 | "[1.0e-17 1.0; 0.0 -1.0e17]\n", 161 | "LU:\n", 162 | "[1.0e-17 1.0; 1.0 0.0]\n", 163 | "A:\n", 164 | "[1.0e-17 1.0; 1.0 3.141592653589793]\n" 165 | ] 166 | } 167 | ], 168 | "source": [ 169 | "n = 2\n", 170 | "ϵ = 1e-17\n", 171 | "# ϵ = 1e-17 # Type \\epsilon [TAB]\n", 172 | "# ϵ = 64.0 * eps(Float64) / π \n", 173 | "# ϵ = eps(Float64) / π \n", 174 | "# ϵ = 0.25 * eps(Float64) / π\n", 175 | "A = [ϵ 1; 1 π] # Type \\pi [TAB]\n", 176 | "A0 = copy(A)\n", 177 | "\n", 178 | "getrfOuter!(A)\n", 179 | "L = tril(A,-1) + UniformScaling(1)\n", 180 | "U = triu(A)\n", 181 | "println(\"L:\\n\",L)\n", 182 | "println(\"U:\\n\",U)\n", 183 | "println(\"LU:\\n\",L*U)\n", 184 | "println(\"A:\\n\",A0)" 185 | ] 186 | } 187 | ], 188 | "metadata": { 189 | "@webio": { 190 | "lastCommId": null, 191 | "lastKernelId": null 192 | }, 193 | "anaconda-cloud": {}, 194 | "kernelspec": { 195 | "display_name": "Julia 1.8.1", 196 | "language": "julia", 197 | "name": "julia-1.8" 198 | }, 199 | "language_info": { 200 | "file_extension": ".jl", 201 | "mimetype": "application/julia", 202 | "name": "julia", 203 | "version": "1.8.1" 204 | } 205 | }, 206 | "nbformat": 4, 207 | "nbformat_minor": 4 208 | } 209 | -------------------------------------------------------------------------------- /Chap3/LU_Solve.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# Initialize the random number generator\n", 10 | "using Random\n", 11 | "rng = MersenneTwister(0);" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 2, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "# Size of the matrix\n", 21 | "n = 512;" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 3, 27 | "metadata": {}, 28 | "outputs": [ 29 | { 30 | "data": { 31 | "text/plain": [ 32 | "6×6 Array{Float64,2}:\n", 33 | " 2.0 -2.0 -2.0 -1.0 1.0 2.0\n", 34 | " 2.0 -1.0 -4.0 -3.0 0.0 4.0\n", 35 | " -4.0 3.0 8.0 3.0 0.0 -4.0\n", 36 | " 0.0 -1.0 -2.0 6.0 1.0 -5.0\n", 37 | " -4.0 6.0 2.0 -1.0 1.0 1.0\n", 38 | " 4.0 -5.0 -2.0 4.0 9.0 4.0" 39 | ] 40 | }, 41 | "execution_count": 3, 42 | "metadata": {}, 43 | "output_type": "execute_result" 44 | } 45 | ], 46 | "source": [ 47 | "# Random initialization of matrix A\n", 48 | "L = zeros(Float64,n,n)\n", 49 | "U = zeros(Float64,n,n)\n", 50 | "for i=1:n\n", 51 | " L[i,i] = 1\n", 52 | " L[i+1:n,i] = rand(rng, -2:2, n-i)\n", 53 | " U[i,i] = rand(rng, 1:2)\n", 54 | " U[i,i+1:n] = rand(rng, -2:2, n-i)\n", 55 | "end\n", 56 | "A = L * U\n", 57 | "A0 = copy(A);\n", 58 | "A0[1:6,1:6]" 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": 4, 64 | "metadata": {}, 65 | "outputs": [ 66 | { 67 | "data": { 68 | "text/plain": [ 69 | "1×512 LinearAlgebra.Adjoint{Float64,Array{Float64,1}}:\n", 70 | " 249.0 278.0 -487.0 -33.0 -159.0 890.0 … 233.0 -4087.0 975.0 2038.0" 71 | ] 72 | }, 73 | "execution_count": 4, 74 | "metadata": {}, 75 | "output_type": "execute_result" 76 | } 77 | ], 78 | "source": [ 79 | "# Initializing the right-hand side\n", 80 | "xe = rand(rng, 0:9, n) # This will be our solution\n", 81 | "b = A * xe\n", 82 | "b'" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 5, 88 | "metadata": {}, 89 | "outputs": [ 90 | { 91 | "data": { 92 | "text/plain": [ 93 | "getrs (generic function with 3 methods)" 94 | ] 95 | }, 96 | "execution_count": 5, 97 | "metadata": {}, 98 | "output_type": "execute_result" 99 | } 100 | ], 101 | "source": [ 102 | "include(\"../src/getrf.jl\")" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": 6, 108 | "metadata": {}, 109 | "outputs": [ 110 | { 111 | "name": "stdout", 112 | "output_type": "stream", 113 | "text": [ 114 | "getrfOuter!: PASSED\n", 115 | "getrfAxpy!: PASSED\n", 116 | "getrfDot!: PASSED\n" 117 | ] 118 | } 119 | ], 120 | "source": [ 121 | "# Test our solvers\n", 122 | "map([getrfOuter!, getrfAxpy!, getrfDot!]) do solver\n", 123 | " A = copy(A0)\n", 124 | " solver(A)\n", 125 | " # Solve\n", 126 | " x = getrs(A, b)\n", 127 | " @assert x == xe\n", 128 | " println(string(solver) * \": PASSED\")\n", 129 | "end \n", 130 | ";" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": 7, 136 | "metadata": {}, 137 | "outputs": [ 138 | { 139 | "name": "stdout", 140 | "output_type": "stream", 141 | "text": [ 142 | " 0.235425 seconds\n", 143 | " 0.035208 seconds\n", 144 | " 0.120560 seconds\n" 145 | ] 146 | } 147 | ], 148 | "source": [ 149 | "# Time the solvers\n", 150 | "map([getrfOuter!, getrfAxpy!, getrfDot!]) do solver\n", 151 | " A = copy(A0); @time solver(A)\n", 152 | "end\n", 153 | ";" 154 | ] 155 | } 156 | ], 157 | "metadata": { 158 | "@webio": { 159 | "lastCommId": null, 160 | "lastKernelId": null 161 | }, 162 | "anaconda-cloud": {}, 163 | "kernelspec": { 164 | "display_name": "Julia 1.5.1", 165 | "language": "julia", 166 | "name": "julia-1.5" 167 | }, 168 | "language_info": { 169 | "file_extension": ".jl", 170 | "mimetype": "application/julia", 171 | "name": "julia", 172 | "version": "1.5.1" 173 | } 174 | }, 175 | "nbformat": 4, 176 | "nbformat_minor": 4 177 | } 178 | -------------------------------------------------------------------------------- /Chap3/Triangular_Solve.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# Initialize the random number generator\n", 10 | "using Random\n", 11 | "rng = MersenneTwister(2018);" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 2, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | "# Size of the matrix\n", 21 | "n = 4000;" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 3, 27 | "metadata": {}, 28 | "outputs": [ 29 | { 30 | "data": { 31 | "text/plain": [ 32 | "6×6 Array{Float64,2}:\n", 33 | " 1.0 0.0 0.0 0.0 0.0 0.0\n", 34 | " -1.0 1.0 0.0 0.0 0.0 0.0\n", 35 | " 0.0 2.0 1.0 0.0 0.0 0.0\n", 36 | " -2.0 0.0 2.0 1.0 0.0 0.0\n", 37 | " -1.0 -2.0 2.0 -2.0 1.0 0.0\n", 38 | " -2.0 -1.0 2.0 1.0 0.0 1.0" 39 | ] 40 | }, 41 | "execution_count": 3, 42 | "metadata": {}, 43 | "output_type": "execute_result" 44 | } 45 | ], 46 | "source": [ 47 | "# Lower triangular matrix\n", 48 | "L = zeros(Float64,n,n)\n", 49 | "# Filling the matrix with random integer entries\n", 50 | "for j=1:n # Column j\n", 51 | " L[j,j] = 1 # Should be non-zero\n", 52 | " L[j+1:n,j] = rand(rng, -2:2, n-j) \n", 53 | "end\n", 54 | "L[1:6,1:6]" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": 4, 60 | "metadata": {}, 61 | "outputs": [ 62 | { 63 | "data": { 64 | "text/plain": [ 65 | "1×4000 LinearAlgebra.Adjoint{Float64,Array{Float64,1}}:\n", 66 | " 3.0 1.0 8.0 0.0 -18.0 -2.0 21.0 … 251.0 743.0 922.0 178.0 399.0" 67 | ] 68 | }, 69 | "execution_count": 4, 70 | "metadata": {}, 71 | "output_type": "execute_result" 72 | } 73 | ], 74 | "source": [ 75 | "# Initializing the right-hand side\n", 76 | "xe = rand(rng, 0:9, n) # This will be our solution\n", 77 | "b = L * xe\n", 78 | "b'" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": 5, 84 | "metadata": { 85 | "scrolled": false 86 | }, 87 | "outputs": [ 88 | { 89 | "data": { 90 | "text/plain": [ 91 | "trtrsRow (generic function with 1 method)" 92 | ] 93 | }, 94 | "execution_count": 5, 95 | "metadata": {}, 96 | "output_type": "execute_result" 97 | } 98 | ], 99 | "source": [ 100 | "# Load our triangular solvers\n", 101 | "include(\"../src/trtrs.jl\")" 102 | ] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": 6, 107 | "metadata": {}, 108 | "outputs": [], 109 | "source": [ 110 | "x = trtrsRow(L, b)\n", 111 | "# Let's check the result\n", 112 | "@assert x == xe\n", 113 | "\n", 114 | "x = trtrs(L, b)\n", 115 | "@assert x == xe" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": 7, 121 | "metadata": {}, 122 | "outputs": [ 123 | { 124 | "name": "stdout", 125 | "output_type": "stream", 126 | "text": [ 127 | " 0.043279 seconds (2 allocations: 31.328 KiB)\n", 128 | " 0.008398 seconds (2 allocations: 31.328 KiB)\n" 129 | ] 130 | } 131 | ], 132 | "source": [ 133 | "@time x = trtrsRow(L, b) # Takes about 4x longer!\n", 134 | "@time x = trtrs(L, b)\n", 135 | ";" 136 | ] 137 | } 138 | ], 139 | "metadata": { 140 | "@webio": { 141 | "lastCommId": null, 142 | "lastKernelId": null 143 | }, 144 | "anaconda-cloud": {}, 145 | "kernelspec": { 146 | "display_name": "Julia 1.5.1", 147 | "language": "julia", 148 | "name": "julia-1.5" 149 | }, 150 | "language_info": { 151 | "file_extension": ".jl", 152 | "mimetype": "application/julia", 153 | "name": "julia", 154 | "version": "1.5.1" 155 | } 156 | }, 157 | "nbformat": 4, 158 | "nbformat_minor": 4 159 | } 160 | -------------------------------------------------------------------------------- /Chap4/Homework/accuracy.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "using LinearAlgebra\n", 10 | "using Random\n", 11 | "using Printf\n", 12 | "using Plots" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 2, 18 | "metadata": {}, 19 | "outputs": [ 20 | { 21 | "name": "stdout", 22 | "output_type": "stream", 23 | "text": [ 24 | "Size of matrix 128\n", 25 | "Qe should be orthogonal; let's check: 1.06528e-14\n", 26 | "Q is also orthogonal: 1.06814e-14\n" 27 | ] 28 | } 29 | ], 30 | "source": [ 31 | "n = 128\n", 32 | "println(\"Size of matrix \", n)\n", 33 | "\n", 34 | "# Initialize the matrix\n", 35 | "F = qr(rand(n,n))\n", 36 | "Qe = Matrix(F.Q)\n", 37 | "Re = F.R\n", 38 | "# Qe is orthogonal, Re is upper triangular\n", 39 | "for i = 1 : n\n", 40 | " # Multiply row i by 1/2^i\n", 41 | " Re[i,:] = 1.0/2.0^(i-1) * Re[i,:]\n", 42 | "end\n", 43 | "\n", 44 | "@printf \"Qe should be orthogonal; let's check: %g\\n\" norm(transpose(Qe)*Qe - UniformScaling(1.0))\n", 45 | "\n", 46 | "A = Qe * Re\n", 47 | "\n", 48 | "# Compute QR factorization of A\n", 49 | "F = qr(A)\n", 50 | "Q = Matrix(F.Q)\n", 51 | "R = F.R\n", 52 | "\n", 53 | "@printf \"Q is also orthogonal: %g\\n\" norm(transpose(Q)*Q - UniformScaling(1.0))\n", 54 | "\n", 55 | "# Fix possible differences in the sign of the diagonal entries of R\n", 56 | "for i = 1 : n\n", 57 | " if R[i,i] * Re[i,i] < 0\n", 58 | " R[i,:] = -R[i,:]\n", 59 | " Q[:,i] = -Q[:,i]\n", 60 | " end\n", 61 | "end\n", 62 | "\n", 63 | "# We now expect that Q=Qe and R=Re.\n", 64 | "\n", 65 | "# Calculate the error in Q\n", 66 | "err = zeros(n)\n", 67 | "for j = 1 : n\n", 68 | " # Processing column j\n", 69 | " err[j] = norm(Q[:,j] - Qe[:,j])\n", 70 | "end" 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": 3, 76 | "metadata": {}, 77 | "outputs": [ 78 | { 79 | "data": { 80 | "image/png": "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" 81 | }, 82 | "execution_count": 3, 83 | "metadata": {}, 84 | "output_type": "execute_result" 85 | } 86 | ], 87 | "source": [ 88 | "pyplot()\n", 89 | "\n", 90 | "# Plot the error in Q\n", 91 | "plot(err, yscale=:log10)\n", 92 | "xlabel!(\"Column index\")\n", 93 | "ylabel!(\"Error in Q\")" 94 | ] 95 | } 96 | ], 97 | "metadata": { 98 | "anaconda-cloud": {}, 99 | "kernelspec": { 100 | "display_name": "Julia 1.0.0", 101 | "language": "julia", 102 | "name": "julia-1.0" 103 | }, 104 | "language_info": { 105 | "file_extension": ".jl", 106 | "mimetype": "application/julia", 107 | "name": "julia", 108 | "version": "1.0.0" 109 | } 110 | }, 111 | "nbformat": 4, 112 | "nbformat_minor": 1 113 | } 114 | -------------------------------------------------------------------------------- /Chap4/QR.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap4/QR.mp4 -------------------------------------------------------------------------------- /Chap4/QR_Givens.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "include(\"../src/geqrf.jl\")\n", 10 | "using Random\n", 11 | "rng = MersenneTwister(2018)\n", 12 | "import LinearAlgebra.dot\n", 13 | "import LinearAlgebra.norm\n", 14 | "import LinearAlgebra.triu\n", 15 | ";" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": 2, 21 | "metadata": {}, 22 | "outputs": [ 23 | { 24 | "data": { 25 | "text/plain": [ 26 | "6×6 Array{Float64,2}:\n", 27 | " 0.654539 0.151455 0.970956 0.40543 0.379994 0.29234\n", 28 | " 0.108906 0.612651 0.966637 0.540992 0.740725 0.497368\n", 29 | " 0.0 0.982534 0.34616 0.00765431 0.960489 0.339104\n", 30 | " 0.0 0.0 0.249169 0.501108 0.585616 0.0791543\n", 31 | " 0.0 0.0 0.0 0.602202 0.191024 0.658122\n", 32 | " 0.0 0.0 0.0 0.0 0.422507 0.0184764" 33 | ] 34 | }, 35 | "execution_count": 2, 36 | "metadata": {}, 37 | "output_type": "execute_result" 38 | } 39 | ], 40 | "source": [ 41 | "n = 6\n", 42 | "A = triu(rand(rng,n,n),-1)\n", 43 | "\n", 44 | "# A is a matrix with non-zero entries only above the first sub-diagonal.\n", 45 | "# Such a matrix is also called an upper Hessenberg matrix.\n", 46 | "A" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": 3, 52 | "metadata": {}, 53 | "outputs": [ 54 | { 55 | "data": { 56 | "text/plain": [ 57 | "6×6 Array{Float64,2}:\n", 58 | " 0.663538 0.249955 1.11644 0.488725 0.496415 0.370008\n", 59 | " 1.38778e-17 -1.14069 -0.701611 -0.243892 -1.16683 -0.516954\n", 60 | " 0.0 0.0 0.565998 0.578373 0.336559 0.222505\n", 61 | " 0.0 0.0 0.0 -0.661824 -0.375907 -0.590149\n", 62 | " 0.0 0.0 0.0 0.0 -0.557731 0.176641\n", 63 | " 0.0 0.0 0.0 0.0 0.0 -0.233295" 64 | ] 65 | }, 66 | "execution_count": 3, 67 | "metadata": {}, 68 | "output_type": "execute_result" 69 | } 70 | ], 71 | "source": [ 72 | "for k=1:n-1\n", 73 | " c, s = givens(A[k,k], A[k+1,k])\n", 74 | " # Apply the Givens rotation to row k and k+1\n", 75 | " for j=k:n\n", 76 | " A[k,j], A[k+1,j] =\n", 77 | " ( c * A[k,j] - s * A[k+1,j],\n", 78 | " s * A[k,j] + c * A[k+1,j] )\n", 79 | " end\n", 80 | "end\n", 81 | "# A is now upper triangular\n", 82 | "A" 83 | ] 84 | } 85 | ], 86 | "metadata": { 87 | "@webio": { 88 | "lastCommId": null, 89 | "lastKernelId": null 90 | }, 91 | "kernelspec": { 92 | "display_name": "Julia 1.5.1", 93 | "language": "julia", 94 | "name": "julia-1.5" 95 | }, 96 | "language_info": { 97 | "file_extension": ".jl", 98 | "mimetype": "application/julia", 99 | "name": "julia", 100 | "version": "1.5.1" 101 | } 102 | }, 103 | "nbformat": 4, 104 | "nbformat_minor": 1 105 | } 106 | -------------------------------------------------------------------------------- /Chap5/Inverse_Iteration.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "using Printf\n", 10 | "using Random\n", 11 | "using LinearAlgebra\n", 12 | "rng = MersenneTwister(18);" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 2, 18 | "metadata": {}, 19 | "outputs": [ 20 | { 21 | "data": { 22 | "text/plain": [ 23 | "8×8 Diagonal{Float32,Array{Float32,1}}:\n", 24 | " 1.0 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ \n", 25 | " ⋅ 0.5 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ \n", 26 | " ⋅ ⋅ 0.25 ⋅ ⋅ ⋅ ⋅ ⋅ \n", 27 | " ⋅ ⋅ ⋅ 0.125 ⋅ ⋅ ⋅ ⋅ \n", 28 | " ⋅ ⋅ ⋅ ⋅ 0.0625 ⋅ ⋅ ⋅ \n", 29 | " ⋅ ⋅ ⋅ ⋅ ⋅ 0.03125 ⋅ ⋅ \n", 30 | " ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 0.015625 ⋅ \n", 31 | " ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 0.0078125" 32 | ] 33 | }, 34 | "execution_count": 2, 35 | "metadata": {}, 36 | "output_type": "execute_result" 37 | } 38 | ], 39 | "source": [ 40 | "# Size of matrix\n", 41 | "n = 8\n", 42 | "X = rand(rng, n, n)\n", 43 | "for i=1:n\n", 44 | " X[:,i] /= norm(X[:,i])\n", 45 | "end\n", 46 | "\n", 47 | "Λ = diagm(0 => Float32[2.0^(-i) for i=0:n-1])\n", 48 | "\n", 49 | "A = X * Λ / X\n", 50 | "Diagonal(Λ)" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 3, 56 | "metadata": {}, 57 | "outputs": [ 58 | { 59 | "name": "stdout", 60 | "output_type": "stream", 61 | "text": [ 62 | "Exact answer: 0.25\n", 63 | "Initial guess: 0.225\n", 64 | "Iteration: 1 | e-value: 0.22458631564985737\n", 65 | "Iteration: 2 | e-value: 0.25714423465121167\n", 66 | "Iteration: 3 | e-value: 0.24907485989915507\n", 67 | "Iteration: 4 | e-value: 0.25021854613948735\n", 68 | "Iteration: 5 | e-value: 0.2499526593945788\n", 69 | "Iteration: 6 | e-value: 0.25001182249103904\n", 70 | "Iteration: 7 | e-value: 0.24999707148221273\n", 71 | "Iteration: 8 | e-value: 0.25000073930927985\n" 72 | ] 73 | } 74 | ], 75 | "source": [ 76 | "qk = rand(rng, n)\n", 77 | "qk /= norm(qk)\n", 78 | "\n", 79 | "μ0 = Λ[3,3]\n", 80 | "μ = μ0 * 0.9\n", 81 | "# Our initial approximation of an eigenvalue of interest\n", 82 | "\n", 83 | "println(\"Exact answer: \", μ0)\n", 84 | "println(\"Initial guess: \", μ)\n", 85 | "\n", 86 | "for k=1:8\n", 87 | " zk = (A - μ * I) \\ qk\n", 88 | " qk = zk/norm(zk) # Normalize e-vector\n", 89 | " ev = dot(qk, A * qk) # E-value approximation\n", 90 | " println(\"Iteration: \",k,\" | e-value: \", ev)\n", 91 | "end" 92 | ] 93 | } 94 | ], 95 | "metadata": { 96 | "anaconda-cloud": {}, 97 | "kernelspec": { 98 | "display_name": "Julia 1.5.1", 99 | "language": "julia", 100 | "name": "julia-1.5" 101 | }, 102 | "language_info": { 103 | "file_extension": ".jl", 104 | "mimetype": "application/julia", 105 | "name": "julia", 106 | "version": "1.5.1" 107 | } 108 | }, 109 | "nbformat": 4, 110 | "nbformat_minor": 4 111 | } 112 | -------------------------------------------------------------------------------- /Chap5/QR_hwk_matrix_data.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap5/QR_hwk_matrix_data.h5 -------------------------------------------------------------------------------- /Chap5/QR_iteration.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap5/QR_iteration.mp4 -------------------------------------------------------------------------------- /Chap5/QR_iteration_unsym.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EricDarve/numerical_linear_algebra/506741a849fc871f2d9471a3c7a55ffcceaa15f3/Chap5/QR_iteration_unsym.mp4 -------------------------------------------------------------------------------- /Chap7/gs.jl: -------------------------------------------------------------------------------- 1 | using LinearAlgebra 2 | 3 | function gs(A, b; 4 | tol = sqrt(eps(real(eltype(b)))), # tolerance 5 | maxiter = length(b)) # maximum number of iterations 6 | 7 | n = size(b, 1) 8 | x = zeros(n) 9 | nb = norm(b) 10 | res = zeros(maxiter + 1) 11 | res[1] = nb 12 | for k = 1:maxiter 13 | for i = 1:n 14 | sigma = 0. 15 | for j = 1:n 16 | if j != i 17 | sigma += A[i,j] * x[j] 18 | end 19 | end 20 | x[i] = (b[i] - sigma) / A[i,i] 21 | end 22 | # Check residual and error 23 | res[k + 1] = norm(A * x - b) 24 | print_residual(k, maxiter, res[k + 1], nb) 25 | if res[k + 1] / nb < tol 26 | success_message(k) 27 | return (x, res[1:k + 1]) 28 | end 29 | end 30 | failure_message(maxiter) 31 | return (x, res) 32 | end 33 | -------------------------------------------------------------------------------- /Chap7/jacobi.jl: -------------------------------------------------------------------------------- 1 | using LinearAlgebra 2 | 3 | function jacobi(A, b; 4 | tol = sqrt(eps(real(eltype(b)))), # tolerance 5 | maxiter = length(b)) # maximum number of iterations 6 | n = size(b, 1) 7 | x = zeros(n) 8 | nb = norm(b) 9 | res = zeros(maxiter + 1) 10 | res[1] = nb 11 | for k = 1:maxiter 12 | xnew = zeros(n) 13 | for i = 1:n 14 | for j = 1:n 15 | if j != i 16 | xnew[i] += A[i,j] * x[j] 17 | end 18 | end 19 | xnew[i] = (b[i] - xnew[i]) / A[i,i] 20 | end 21 | x = xnew 22 | # Check residual and error 23 | res[k + 1] = norm(A * x - b) 24 | print_residual(k, maxiter, res[k + 1], nb) 25 | if res[k + 1] / nb < tol 26 | success_message(k) 27 | return (x, res[1:k + 1]) 28 | end 29 | end 30 | failure_message(maxiter) 31 | return (x, res) 32 | end 33 | -------------------------------------------------------------------------------- /Chap7/sor.jl: -------------------------------------------------------------------------------- 1 | using LinearAlgebra 2 | 3 | function sor(A, b; 4 | tol = sqrt(eps(real(eltype(b)))), # tolerance 5 | maxiter = length(b), # maximum number of iterations 6 | omega = 1.5) 7 | 8 | n = size(b, 1) 9 | x = zeros(n) 10 | nb = norm(b) 11 | res = zeros(maxiter + 1) 12 | res[1] = nb 13 | for k = 1:maxiter 14 | for i = 1:n 15 | sigma = 0. 16 | for j = 1:n 17 | if j != i 18 | sigma += A[i,j] * x[j] 19 | end 20 | end 21 | sigma = (b[i] - sigma) / A[i,i] 22 | x[i] += omega * (sigma - x[i]) 23 | end 24 | # Check residual and error 25 | res[k + 1] = norm(A * x - b) 26 | print_residual(k, maxiter, res[k + 1], nb) 27 | if res[k + 1] / nb < tol 28 | success_message(k) 29 | return (x, res[1:k + 1]) 30 | end 31 | end 32 | failure_message(maxiter) 33 | return (x, res) 34 | end 35 | -------------------------------------------------------------------------------- /Chap8/IterativeMethods.jl: -------------------------------------------------------------------------------- 1 | module IterativeMethods 2 | 3 | import Printf 4 | 5 | function success_message(i) 6 | @Printf.printf "Converged after %d iterations\n" i 7 | end 8 | 9 | function failure_message(i) 10 | @Printf.printf "Failure to converge after %d iterations\n" i 11 | end 12 | 13 | function print_residual(i, maxiter, res, nb) 14 | @Printf.printf "Iteration %3d/%d, " i maxiter 15 | @Printf.printf "residual %1.2e; |r|/|b| %1.2e\n" res res / nb 16 | end 17 | 18 | include("cg.jl") 19 | include("minres.jl") 20 | include("cr.jl") 21 | include("qmr.jl") 22 | include("bicgstab.jl") 23 | include("gmres.jl") 24 | 25 | include("jacobi.jl") 26 | include("gs.jl") 27 | include("sor.jl") 28 | 29 | export cg, minres, cg, qmr, bicgstab, gmres, jacobi, gs, sor 30 | 31 | end 32 | -------------------------------------------------------------------------------- /Chap8/bicgstab.jl: -------------------------------------------------------------------------------- 1 | using LinearAlgebra 2 | 3 | function bicgstab(A, b; 4 | tol = sqrt(eps(real(eltype(b)))), # tolerance 5 | maxiter = length(b), # maximum number of iterations 6 | precond = UniformScaling(1.0)) # preconditioner 7 | 8 | # It is assumed that the preconditioner supports the operator \ 9 | # If you pass a matrix, we advise that you call lufact() before 10 | # calling this routine such that \ can be computed efficiently, 11 | # without having to refactor the matrix for every call of \. 12 | 13 | n = size(b, 1) 14 | x = zeros(n) 15 | nb = norm(b) 16 | res = zeros(maxiter + 1) 17 | res[1] = nb 18 | 19 | r = b 20 | rtilde = b 21 | 22 | M = precond # shorter name 23 | 24 | rho = 1. 25 | alpha = 0. 26 | omega = 1. 27 | p = zeros(n) 28 | v = p 29 | 30 | for i = 1:maxiter 31 | rhoold, rho = rho, dot(rtilde, r) 32 | if rho == 0. || omega == 0. 33 | failure_message(i) 34 | return (x, res[1:i]) 35 | end 36 | p = r + (rho / rhoold) * (alpha / omega) * (p - omega * v) 37 | phat = M \ p 38 | v = A * phat 39 | alpha = rho / dot(rtilde, v) 40 | s = r - alpha * v 41 | if norm(s) / nb < tol 42 | res[i + 1] = norm(s) 43 | print_residual(i, maxiter, res[i + 1], nb) 44 | success_message(i) 45 | x += alpha * phat 46 | return (x, res[1:i + 1]) 47 | end 48 | shat = M \ s 49 | t = A * shat 50 | omega = dot(t, s) / dot(t, t) 51 | x += alpha * phat + omega * shat 52 | r = s - omega * t 53 | res[i + 1] = norm(r) 54 | @show res[i + 1] / nb, tol 55 | print_residual(i, maxiter, res[i + 1], nb) 56 | if res[i + 1] / nb < tol 57 | success_message(i) 58 | return (x, res[1:i + 1]) 59 | end 60 | end 61 | failure_message(maxiter) 62 | return (x, res) 63 | end 64 | -------------------------------------------------------------------------------- /Chap8/cg.jl: -------------------------------------------------------------------------------- 1 | using LinearAlgebra 2 | 3 | function cg(A, b; 4 | tol = sqrt(eps(real(eltype(b)))), # tolerance 5 | maxiter = length(b), # maximum number of iterations 6 | precond = UniformScaling(1.0)) # preconditioner 7 | 8 | # It is assumed that the preconditioner supports the operator \ 9 | # If you pass a matrix, we advise that you call lufact() before 10 | # calling this routine such that \ can be computed efficiently, 11 | # without having to refactor the matrix for every call of \. 12 | 13 | n = size(b, 1) 14 | x = zeros(n) 15 | nb = norm(b) 16 | res = zeros(maxiter + 1) 17 | res[1] = nb 18 | 19 | r = b 20 | 21 | M = precond # shorter name 22 | 23 | p = zeros(n) 24 | rho = 1. 25 | 26 | for i = 1:maxiter 27 | z = M \ r 28 | rhoold, rho = rho, dot(r, z) 29 | p = z + (rho / rhoold) * p 30 | q = A * p 31 | alpha = rho / dot(p, q) 32 | x += alpha * p 33 | r -= alpha * q 34 | res[i + 1] = norm(r) 35 | print_residual(i, maxiter, res[i + 1], nb) 36 | if res[i + 1] / nb < tol 37 | success_message(i) 38 | return (x, res[1:i + 1]) 39 | end 40 | end 41 | failure_message(maxiter) 42 | return (x, res) 43 | end 44 | -------------------------------------------------------------------------------- /Chap8/cr.jl: -------------------------------------------------------------------------------- 1 | using LinearAlgebra 2 | 3 | function cr(A, b; 4 | tol = sqrt(eps(real(eltype(b)))), # tolerance 5 | maxiter = length(b), # maximum number of iterations 6 | precond = UniformScaling(1.0)) # preconditioner 7 | 8 | # It is assumed that the preconditioner supports the operator \ 9 | # If you pass a matrix, we advise that you call lufact() before 10 | # calling this routine such that \ can be computed efficiently, 11 | # without having to refactor the matrix for every call of \. 12 | 13 | n = size(b, 1) 14 | x = zeros(n) 15 | nb = norm(b) 16 | res = zeros(maxiter + 1) 17 | res[1] = nb 18 | 19 | M = precond # shorter name 20 | 21 | r = M \ b 22 | 23 | rho = 1. 24 | p = zeros(n) 25 | q = p 26 | 27 | for i = 1:maxiter 28 | s = A * r 29 | rhoold, rho = rho, dot(r, s) 30 | beta = rho / rhoold 31 | p = r + beta * p 32 | q = s + beta * q 33 | z = M \ q 34 | alpha = rho / dot(q, z) 35 | x += alpha * p 36 | r -= alpha * z 37 | res[i + 1] = norm(r) 38 | print_residual(i, maxiter, res[i + 1], nb) 39 | if res[i + 1] / nb < tol 40 | success_message(i) 41 | return (x, res[1:i + 1]) 42 | end 43 | end 44 | failure_message(maxiter) 45 | return (x, res) 46 | end 47 | -------------------------------------------------------------------------------- /Chap8/gmres.jl: -------------------------------------------------------------------------------- 1 | using LinearAlgebra 2 | using Printf 3 | 4 | function gmres_update(x, s, q, i, H) 5 | y = H[1:i,1:i] \ s[1:i] 6 | for k in eachindex(y) 7 | x += q[k] * y[k] 8 | end 9 | return x 10 | end 11 | 12 | function gmres(A, b; 13 | tol = sqrt(eps(real(eltype(b)))), # tolerance 14 | restart = length(b), # maximum number of inner iterations between restarts 15 | maxiter = min(20, length(b)), # maximum number of outer iterations 16 | precond = UniformScaling(1.0)) # preconditioner 17 | 18 | # It is assumed that the preconditioner supports the operator \ 19 | # If you pass a matrix, we advise that you call lufact() before 20 | # calling this routine such that \ can be computed efficiently, 21 | # without having to refactor the matrix for every call of \. 22 | 23 | n = length(b) 24 | m = restart # variable with shorter name 25 | x = zeros(n) 26 | nb = norm(b) 27 | res = zeros(1 + maxiter * m) 28 | res[1] = nb 29 | 30 | M = precond # shorter name 31 | 32 | it = 0 33 | 34 | for j = 1:maxiter 35 | 36 | residual = b - A * x 37 | q = Vector{Any}(undef, m + 1) 38 | J = Vector{Any}(undef, m) 39 | H = zeros(m + 1, m) 40 | 41 | @printf "Outer iteration %d/%d, residual %1.2e\n" j maxiter norm(residual) 42 | 43 | r = M \ residual 44 | normr = norm(r) 45 | q[1] = r / normr 46 | s = zeros(m + 1) 47 | s[1] = normr 48 | 49 | for i = 1:m 50 | z = M \ (A * q[i]) 51 | # Arnoldi iteration 52 | for k = 1:i 53 | H[k,i] = dot(z, q[k]) 54 | z -= H[k,i] * q[k] 55 | end 56 | H[i + 1,i] = norm(z) 57 | q[i + 1] = z / H[i + 1,i] 58 | 59 | # Apply previous Givens rotations to solve least squares 60 | for k = 1:i - 1 61 | H[1:i + 1,i] = J[k] * H[1:i + 1,i] 62 | end 63 | J[i], = givens(H[i,i], H[i + 1,i], i, i + 1) 64 | # Update s and H 65 | H[1:i + 1,i] = J[i] * H[1:i + 1,i] 66 | s = J[i] * s 67 | 68 | it += 1 69 | # Norm of residual 70 | res[it + 1] = abs(s[i + 1]) 71 | print_residual(i, maxiter, res[it + 1], nb) 72 | 73 | # Check residual, compute x, and stop if possible 74 | if res[it + 1] / nb < tol 75 | x = gmres_update(x, s, q, i, H) 76 | @printf "Converged after %d outer and %d inner iterations\n" j i 77 | return (x, res[1:it + 1]) 78 | end 79 | end 80 | 81 | # Update x before the restart 82 | x = gmres_update(x, s, q, m, H) 83 | end 84 | failure_message(maxiter) 85 | return (x, res) 86 | end 87 | -------------------------------------------------------------------------------- /Chap8/minres.jl: -------------------------------------------------------------------------------- 1 | using LinearAlgebra 2 | 3 | function symortho(a, b) 4 | if (b == 0) 5 | s = 0 6 | r = abs(a) 7 | if a == 0 8 | c = 1 9 | else 10 | c = sign(a) 11 | end 12 | elseif a == 0 13 | c = 0 14 | r = abs(b) 15 | s = sign(b) 16 | elseif abs(b) > abs(a) 17 | tau = a / b 18 | s = sign(b) / sqrt(1 + tau^2) 19 | c = s * tau 20 | r = b / s 21 | else 22 | tau = b / a 23 | c = sign(a) / sqrt(1 + tau^2) 24 | s = c * tau 25 | r = a / c 26 | end 27 | return (c, s, r) 28 | end 29 | 30 | function minres(A, b; 31 | tol = sqrt(eps(real(eltype(b)))), # tolerance 32 | maxiter = length(b), # maximum number of iterations 33 | precond = UniformScaling(1.0)) # preconditioner 34 | 35 | # It is assumed that the preconditioner supports the operator \ 36 | # If you pass a matrix, we advise that you call lufact() before 37 | # calling this routine such that \ can be computed efficiently, 38 | # without having to refactor the matrix for every call of \. 39 | 40 | n = size(b, 1) 41 | x = zeros(n) 42 | nb = norm(b) 43 | res = zeros(maxiter + 1) 44 | res[1] = nb 45 | 46 | M = precond # shorter name 47 | 48 | q = M \ b 49 | beta = norm(q) 50 | q /= beta 51 | qold = zeros(n) 52 | 53 | phi = beta 54 | 55 | c, s = -1., 0. 56 | delta = 0. 57 | 58 | eps = 0. 59 | pold, p = zeros(n), zeros(n) 60 | 61 | for i = 1:maxiter 62 | # Lanczos step 63 | z = M \ (A * q) 64 | alpha = dot(q, z) # Diagonal entry in Tk 65 | qold, q = q, z - alpha * q - beta * qold 66 | 67 | beta = norm(q) # Off-diagonal entry in Tk 68 | if beta == 0. 69 | failure_message(i) 70 | return (x, res[1:i]) 71 | end 72 | 73 | q /= beta # Normalize q vector 74 | 75 | # Solve min ||Tk' y - beta0 e1|| 76 | tau = c * delta + s * alpha 77 | gamma = s * delta - c * alpha 78 | 79 | delta = - c * beta 80 | epsold, eps = eps, s * beta 81 | 82 | # Build rotation 83 | c, s, eta = symortho(gamma, beta) 84 | 85 | mu = c * phi 86 | phi = s * phi 87 | 88 | # Update search direction p 89 | pold, p = p, (qold - tau * p - epsold * pold) / eta 90 | 91 | # Update solution 92 | x += mu * p 93 | 94 | # Check residual 95 | res[i + 1] = abs(phi) 96 | print_residual(i, maxiter, res[i + 1], nb) 97 | if res[i + 1] / nb < tol 98 | success_message(i) 99 | return (x, res[1:i + 1]) 100 | end 101 | end 102 | failure_message(maxiter) 103 | return (x, res) 104 | end 105 | -------------------------------------------------------------------------------- /Chap8/qmr.jl: -------------------------------------------------------------------------------- 1 | using LinearAlgebra 2 | 3 | function qmr(A, b; 4 | tol = sqrt(eps(real(eltype(b)))), # tolerance 5 | maxiter = length(b), # maximum number of iterations 6 | precond1 = UniformScaling(1), # preconditioner M1 7 | precond2 = UniformScaling(1)) # preconditioner M2 8 | 9 | # Preconditioner is defined as M = M1 M2. 10 | # It is assumed that the preconditioners M1 and M2 support the operator \ 11 | # If you pass a matrix, we advise that you call lufact() before 12 | # calling this routine such that \ can be computed efficiently, 13 | # without having to refactor the matrix for every call of \. 14 | 15 | n = size(b, 1) 16 | x = zeros(n) 17 | nb = norm(b) 18 | res = zeros(1 + maxiter) 19 | res[1] = nb 20 | 21 | M1 = precond1 # shorter name 22 | M2 = precond2 # shorter name 23 | 24 | vtilde = b 25 | y = M1 \ vtilde 26 | rho = norm(y) 27 | 28 | wtilde = b 29 | z = (M2') \ wtilde 30 | xi = norm(z) 31 | 32 | gamma = 1. 33 | eta = -1. 34 | 35 | r = b 36 | 37 | epsilon = 1. 38 | theta = 0. 39 | p = zeros(n) 40 | q = zeros(n) 41 | d = zeros(n) 42 | s = zeros(n) 43 | 44 | for i = 1:maxiter 45 | if rho == 0. || xi == 0. 46 | failure_message(i) 47 | return (x, res[1:i]) 48 | end 49 | 50 | y /= rho 51 | z /= xi 52 | delta = dot(z, y) 53 | 54 | y = M2 \ y 55 | z = (M1') \ z 56 | p = y - (xi * delta / epsilon) * p 57 | q = z - (rho * delta / epsilon) * q 58 | 59 | ptilde = A * p 60 | epsilon = dot(q, ptilde) 61 | if delta == 0. || epsilon == 0. 62 | failure_message(i) 63 | return (x, res[1:i]) 64 | end 65 | beta = epsilon / delta 66 | 67 | vtilde = ptilde - (beta / rho) * vtilde 68 | y = M1 \ vtilde 69 | rhoold, rho = rho, norm(y) 70 | 71 | wtilde = A' * q - (beta / xi) * wtilde 72 | z = (M2') \ wtilde 73 | xi = norm(z) 74 | 75 | thetaold, theta = theta, rho / (gamma * abs(beta)) 76 | gammaold, gamma = gamma, 1. / sqrt(1. + theta^2) 77 | 78 | eta *= - (rhoold / beta) / (gammaold / gamma)^2 79 | 80 | d = eta * p + (thetaold * gamma)^2 * d 81 | s = eta * ptilde + (thetaold * gamma)^2 * s 82 | x += d 83 | r -= s 84 | 85 | res[i + 1] = norm(r) 86 | print_residual(i, maxiter, res[i + 1], nb) 87 | if res[i + 1] / nb < tol 88 | success_message(i) 89 | return (x, res[1:i + 1]) 90 | end 91 | end 92 | failure_message(maxiter) 93 | return (x, res) 94 | end 95 | -------------------------------------------------------------------------------- /Chap9/.gitignore: -------------------------------------------------------------------------------- 1 | *.dot 2 | -------------------------------------------------------------------------------- /Chap9/Elimination_Tree.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stderr", 10 | "output_type": "stream", 11 | "text": [ 12 | "┌ Info: Precompiling MatrixMarket [4d4711f2-db25-561a-b6b3-d35e7d4047d3]\n", 13 | "└ @ Base loading.jl:1278\n" 14 | ] 15 | }, 16 | { 17 | "data": { 18 | "text/plain": [ 19 | "11" 20 | ] 21 | }, 22 | "execution_count": 1, 23 | "metadata": {}, 24 | "output_type": "execute_result" 25 | } 26 | ], 27 | "source": [ 28 | "using MatrixMarket\n", 29 | "using LinearAlgebra\n", 30 | "using SparseArrays\n", 31 | "using Plots\n", 32 | "using Printf\n", 33 | "\n", 34 | "# Read the matrix data\n", 35 | "file_name = \"example_A.mtx\"\n", 36 | "A_CSC = SparseMatrixCSC{Float64,Int64}( MatrixMarket.mmread(file_name) )\n", 37 | "# A is symmetric; we only read the lower triangular part\n", 38 | "\n", 39 | "include(\"Sparse.jl\")\n", 40 | "A = SparseMatrixCSR(A_CSC)\n", 41 | "n = A.m # Size of matrix" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 2, 47 | "metadata": {}, 48 | "outputs": [ 49 | { 50 | "data": { 51 | "image/png": "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RWnVfUe07t5bdd80B4HVpC6//PJYvXp1fP/734+IiEceeSTa29ujvb292MGIcrkc1Wp1wpNNtVotent7W2L9orTqviNad++tum+aQ5b/X/eVKNSWLVti27Zt8eKLL8a8efPikksuiQMHDkRExLPPPht/+qd/GidPnozf+73fiwceeOC8l8ZHR0eju7s7RkZGoqurq9FbAICWI7BagMACgMZyixAAIDGBBQCQmMACAEhMYAEAJCawAAASE1gAAIkJLACAxAQWAEBiAgsAIDGBBQCQmMACAEhMYAEAJCawAAASE1gAAIkJLACAxAQWAEBiAgsAIDGBBQCQmMACAEhMYAEAJCawAAASE1gAAIkJrCZw9913R3t7e2RZFvv27XvPX6M49Xo9SqVStLW1RalUinq9XvRIDdOqey9630WvX5Qi992q55z3KGfa2717dz4+Pp4vWrQof/rpp9/z194yMjKSR0Q+MjLSiHFbXq1WyyNiwl9ZluW1Wq3o0aZcq+696H0XvX5Ritx3q55z3jtXsJrAunXrYv78+Rf8NYrR398/6Vie5zEwMFDANI3Vqnsvet9Fr1+UIvfdquec905gtZC+vr7o6emJoaGhokeZ0cbGxi7o+EzSqnsvet9Fr1+UIvfdquec905gtZDBwcHYvn17bNy4sehRZrSOjo4LOj6TtOrei9530esXpch9t+o5570TWJBYpVKJLMsmHMuyLCqVSkETNU6r7r3ofRe9flGK3HernnPeO4EFiZXL5ahWqxOeLqrVatHb21v0aFOuVfde9L6LXr8oRe67Vc85712W53le9BC8uy1btsS2bdvixRdfjHnz5sUll1wSBw4c+D+/9pbR0dHo7u6OkZGR6OrqKmILANBSBFYLEFgA0FhuEQIAJCawAAASE1gAAIkJLACAxAQWAEBiAgsAIDGBBQCQmMACAEhMYAEAJCawAAASE1gAAIkJLACAxAQWAEBiAgsAIDGBBQCQmMACAEhMYAEAJCawAAASE1gAAIkJLACAxAQWAEBiAgsAIDGBRUMMDQ1Zu8XWt3brrW9t+DWBRUO06ptf0W+8rbr3Vl276PWtDb82u+gBmHqvvfZaRET813/9V2EznDp1KkZHR63dQutbuxituvdWXfsty5cvjw996EOFzsBEWZ7nedFDMLX++Z//OTZt2lT0GABMkZGRkejq6ip6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" 52 | }, 53 | "execution_count": 2, 54 | "metadata": {}, 55 | "output_type": "execute_result" 56 | } 57 | ], 58 | "source": [ 59 | "pyplot()\n", 60 | "plot(spy(A_CSC), xaxis=((0,n+1), 1:n), yaxis=((0,n+1), 1:n), \n", 61 | " markersize = 5, clims = (1,2)) " 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 3, 67 | "metadata": {}, 68 | "outputs": [ 69 | { 70 | "data": { 71 | "text/plain": [ 72 | "etree" 73 | ] 74 | }, 75 | "execution_count": 3, 76 | "metadata": {}, 77 | "output_type": "execute_result" 78 | } 79 | ], 80 | "source": [ 81 | "\"\"\"Function that calculates the elimination tree given a CSR structure\"\"\"\n", 82 | "function etree(rowptr::Vector{Int}, colval::Vector{Int})\n", 83 | " n = length(rowptr) - 1\n", 84 | " parent = fill(-1,n) # e-tree information\n", 85 | " ancestor = fill(-1,n) # ancestor information to reduce the running time\n", 86 | "\n", 87 | " # We compute the elimination tree\n", 88 | " for i=1:n\n", 89 | " parent[i] = -1 # Initialize to -1\n", 90 | " ancestor[i] = -1\n", 91 | "\n", 92 | " for p = rowptr[i]:rowptr[i+1]-1\n", 93 | " j = colval[p] # column index\n", 94 | " # Traverse row i and stop before the diagonal\n", 95 | " while j != -1 && j < i\n", 96 | " jnext = ancestor[j] # Search for the root\n", 97 | " ancestor[j] = i # Update ancestor for efficiency\n", 98 | " if jnext == -1 # We have found a root\n", 99 | " parent[j] = i # Connect to i\n", 100 | " end\n", 101 | " j = jnext\n", 102 | " end\n", 103 | " end\n", 104 | " end\n", 105 | " return parent\n", 106 | "end" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": 4, 112 | "metadata": {}, 113 | "outputs": [ 114 | { 115 | "data": { 116 | "text/plain": [ 117 | "row_sparsity (generic function with 1 method)" 118 | ] 119 | }, 120 | "execution_count": 4, 121 | "metadata": {}, 122 | "output_type": "execute_result" 123 | } 124 | ], 125 | "source": [ 126 | "function row_sparsity(rowptr, colval, parent, i)\n", 127 | " n = length(rowptr) - 1\n", 128 | " s = Vector{Int64}(undef,n)\n", 129 | " w = fill(false,n) # Used to mark points as visited\n", 130 | " w[i] = true\n", 131 | " len = 1\n", 132 | "\n", 133 | " for p = rowptr[i]:rowptr[i+1]-1\n", 134 | " j = colval[p] # column index\n", 135 | " # Traverse row i and stop before the diagonal\n", 136 | " while !w[j] && j < i # Stop when marked node is found\n", 137 | " s[len] = j # Add column j to row i\n", 138 | " w[j] = true # Mark node j\n", 139 | " len += 1\n", 140 | " j = parent[j] # Move to parent in e-tree\n", 141 | " end\n", 142 | " end\n", 143 | " \n", 144 | " len -= 1\n", 145 | " return s[1:len]\n", 146 | "end" 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": 5, 152 | "metadata": {}, 153 | "outputs": [ 154 | { 155 | "name": "stdout", 156 | "output_type": "stream", 157 | "text": [ 158 | "parent_tree = [6, 3, 8, 6, 8, 7, 9, 10, 10, 11, -1]\n" 159 | ] 160 | } 161 | ], 162 | "source": [ 163 | "# Compute the elimination tree\n", 164 | "parent_tree = etree(A.rowptr, A.colval)\n", 165 | "\n", 166 | "@show parent_tree\n", 167 | "\n", 168 | "# We write the elimination tree to a DOT file.\n", 169 | "# Use Graphviz to see the graph of the tree.\n", 170 | "# Open the file \"etree.dot\" using Graphviz.\n", 171 | "# http://www.graphviz.org/\n", 172 | "# Command line:\n", 173 | "# xdot, or\n", 174 | "# dot -Tpng etree.dot > etree.png\n", 175 | "#\n", 176 | "n = A.m # Size of matrix\n", 177 | "open(\"etree.dot\", \"w\") do f\n", 178 | " @printf f \"digraph G {\\n\"\n", 179 | " for k=1:n\n", 180 | " @printf f \"%d;\\n\" k\n", 181 | " if parent_tree[k] != -1\n", 182 | " @printf f \"%d -> %d;\\n\" k parent_tree[k]\n", 183 | " end\n", 184 | " end\n", 185 | " @printf f \"label=\\\"Elimination tree of A\\\";\\n\"\n", 186 | " @printf f \"labelloc=\\\"t\\\";\\n\" \n", 187 | " @printf f \"}\"\n", 188 | "end" 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": 6, 194 | "metadata": {}, 195 | "outputs": [], 196 | "source": [ 197 | "n = A.m # Size of matrix\n", 198 | "\n", 199 | "# Select the index of the row subtree\n", 200 | "k = 8\n", 201 | "@assert k>=1\n", 202 | "@assert k<=n\n", 203 | "\n", 204 | "# Compute the row sparsity pattern\n", 205 | "s = row_sparsity(A.rowptr, A.colval, parent_tree, k)\n", 206 | "\n", 207 | "# We write the row sub-tree to a DOT file.\n", 208 | "# Use Graphviz to see the graph of the row sub-tree.\n", 209 | "# Open the file \"row_subtree.dot\".\n", 210 | "open(\"row_subtree.dot\", \"w\") do f\n", 211 | " @printf f \"digraph G {\\n\"\n", 212 | " @printf f \"%d; \\n\" k\n", 213 | " for i=1:length(s)\n", 214 | " @printf f \"%d -> %d;\\n\" s[i] parent_tree[s[i]]\n", 215 | " end\n", 216 | " @printf f \"label=\\\"Row sub-tree of node %d\\\";\\n\" k\n", 217 | " @printf f \"labelloc=\\\"t\\\";\\n\" \n", 218 | " @printf f \"}\"\n", 219 | "end" 220 | ] 221 | } 222 | ], 223 | "metadata": { 224 | "@webio": { 225 | "lastCommId": null, 226 | "lastKernelId": null 227 | }, 228 | "anaconda-cloud": {}, 229 | "kernelspec": { 230 | "display_name": "Julia 1.5.1", 231 | "language": "julia", 232 | "name": "julia-1.5" 233 | }, 234 | "language_info": { 235 | "file_extension": ".jl", 236 | "mimetype": "application/julia", 237 | "name": "julia", 238 | "version": "1.5.1" 239 | } 240 | }, 241 | "nbformat": 4, 242 | "nbformat_minor": 4 243 | } 244 | -------------------------------------------------------------------------------- /Chap9/Lower_Triangular_Solve.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "using LinearAlgebra\n", 10 | "using SparseArrays\n", 11 | "using Plots\n", 12 | "using Random\n", 13 | "using MatrixMarket" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 2, 19 | "metadata": {}, 20 | "outputs": [ 21 | { 22 | "name": "stdout", 23 | "output_type": "stream", 24 | "text": [ 25 | "MatrixMarket.mmread(file_name, true) = (150, 150, 1095, \"coordinate\", \"integer\", \"symmetric\")\n", 26 | "Number of rows = 150\n", 27 | "Number of columns = 150\n", 28 | "Number of entries = 1095\n" 29 | ] 30 | }, 31 | { 32 | "data": { 33 | "text/plain": [ 34 | "150×150 SparseMatrixCSC{Int64, Int64} with 1095 stored entries:\n", 35 | "⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n", 36 | "⠑⢝⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n", 37 | "⠱⣄⠱⣽⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n", 38 | "⠀⠈⠳⣌⠓⢝⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n", 39 | "⠲⡀⠀⠈⠓⣄⠑⣝⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n", 40 | "⠀⠈⠢⡀⠀⠈⠳⣌⠻⢝⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n", 41 | "⠀⠀⠀⠈⠢⡀⠀⠈⠳⣀⠑⣝⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n", 42 | "⠀⠀⠀⠀⠀⠈⠢⡀⠀⠈⠳⣌⠻⢝⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n", 43 | "⢤⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠈⠳⢄⠑⢝⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n", 44 | "⠀⠑⢄⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠈⠳⣌⠻⣟⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n", 45 | "⠀⠀⠀⠑⢄⡀⠀⠀⠀⠀⠀⠈⠢⣀⠀⠈⠳⣄⠑⢝⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n", 46 | "⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠳⣄⠳⣿⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n", 47 | "⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠈⠳⣌⠑⢝⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n", 48 | "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢄⠀⠀⠀⠀⠀⠀⠈⠣⡀⠀⠈⠱⣄⠱⣽⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n", 49 | "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠈⠳⣌⠓⢝⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n", 50 | "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢄⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠈⠣⣄⠱⣽⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀\n", 51 | "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠈⠳⣌⠓⢝⢷⣄⠀⠀⠀⠀⠀⠀\n", 52 | "⠙⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢆⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠈⠓⣄⠑⣝⣷⣄⠀⠀⠀⠀\n", 53 | "⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠈⠳⣌⠻⢝⢷⣄⠀⠀\n", 54 | "⠀⠀⠀⠀⠑⢦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢤⠀⠀⠀⠀⠀⠀⠈⠢⡄⠀⠈⠳⢄⠑⢝⢷⣄" 55 | ] 56 | }, 57 | "execution_count": 2, 58 | "metadata": {}, 59 | "output_type": "execute_result" 60 | } 61 | ], 62 | "source": [ 63 | "file_name = \"Trefethen_150/Trefethen_150.mtx\"\n", 64 | "# The entries are zero everywhere except for the prime numbers\n", 65 | "# 2, 3, 5, 7, ..., 863 along the main diagonal.\n", 66 | "# Then, we add the number 1 in all the positions A[i,j] with\n", 67 | "# |i-j| = 1, 2, 4, 8, ..., 128.\n", 68 | "\n", 69 | "# Load the matrix using the matrix market format (this is an optional step).\n", 70 | "# Information data for the matrix\n", 71 | "@show MatrixMarket.mmread(file_name,true)\n", 72 | "rows, cols, entries, mat_format, field, symm = MatrixMarket.mmread(file_name,true)\n", 73 | "\n", 74 | "println(\"Number of rows = \", rows)\n", 75 | "println(\"Number of columns = \", cols)\n", 76 | "println(\"Number of entries = \", entries)\n", 77 | "\n", 78 | "# Read the matrix data\n", 79 | "Amm = MatrixMarket.mmread(file_name)\n", 80 | "\n", 81 | "# Keep only the lower triangular part\n", 82 | "Lmm = tril(Amm)" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 3, 88 | "metadata": {}, 89 | "outputs": [ 90 | { 91 | "data": { 92 | "image/png": "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fr3bzeoRn8+H119/HQ899BCCwSBKSkqwatUq9O3b1+2m2RaJRJCbm4s+fTp+L/X5fAgEAmhubna5ZfZ59fsc0ON7nfTGAouusGTJEtTX1+MHP/iB203pkdraWmzevBlPPPGE201x5MKFCzh48CBGjx6NLVu24KWXXsI3vvENHDt2zO2mWdbe3o5nn30Wb7zxBpqamrB+/Xo89thjou4naEd8RDHOy+s0e/X7HNDne530xgKLLvP8889j7dq1WLduncWbm8rx3nvvYc+ePcjPz0coFEI0GsU999yDdevWud20HgkGg8jKysKjjz4KACgqKkJ+fj527drlcsus27ZtG1paWjB16lQAwO23347c3Fxs377d5ZbZl5eXh2g0ivb2dgAdxVUkEvHkbU28/H0O6PO9TnpjgUUJL7zwAqqqqvD222/jxhtvdLs5PbZw4UK0tLSgsbERjY2N8Pv9qK6uxn333ed203okJycHd999N6qrqwEATU1NaGhowMiRI11umXXxYmTv3r0AgP379+PAgQMoKChwuWX2DRo0COPGjcPq1asBAGvWrEEoFEIoFHK3YT3k9e9zQJ/vddKcQco98cQTxtChQ41rrrnGGDx4sHHLLbe43aSrikQiBgBj2LBhRlFRkVFUVGQUFxcn9nvxmoLBoLFjx47En710DQcOHDDuvPNOo7Cw0CgqKjLWrl2b2OeV63jttdeMwsJC4ytf+Ypx2223GVVVVYl9kq8hVdv27NljTJ482RgxYoQxYcIEY+fOnZZe19u6a4vXvs+ttsfL3+ukL97smYiIiEgxThESERERKcYCi4iIiEgxFlhEREREirHAIiIiIlKMBRYRERGRYv8fAOswXF7YoCAAAAAASUVORK5CYII=" 93 | }, 94 | "execution_count": 3, 95 | "metadata": {}, 96 | "output_type": "execute_result" 97 | } 98 | ], 99 | "source": [ 100 | "# Plot the matrix\n", 101 | "pyplot()\n", 102 | "n = Lmm.m # Size of matrix\n", 103 | "plot(spy(Lmm), xaxis=((0,n+1), 1:20:n), yaxis=((0,n+1), 1:20:n), \n", 104 | " markersize = 5, clims = (1,2))" 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": 4, 110 | "metadata": {}, 111 | "outputs": [], 112 | "source": [ 113 | "include(\"Sparse.jl\")\n", 114 | ";" 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": 5, 120 | "metadata": {}, 121 | "outputs": [ 122 | { 123 | "name": "stdout", 124 | "output_type": "stream", 125 | "text": [ 126 | "Error should be equal to 0: 0.0\n" 127 | ] 128 | }, 129 | { 130 | "data": { 131 | "text/plain": [ 132 | "\"PASS\"" 133 | ] 134 | }, 135 | "execution_count": 5, 136 | "metadata": {}, 137 | "output_type": "execute_result" 138 | } 139 | ], 140 | "source": [ 141 | "L = SparseMatrixCSR(Lmm);\n", 142 | "\n", 143 | "# Matrix-vector product using the CSR format\n", 144 | "Random.seed!(2018)\n", 145 | "b = Float64[ rand(-9:9) for _=1:L.n ]\n", 146 | "b = L*b\n", 147 | "\n", 148 | "x = Vector{Float64}(undef,L.m)\n", 149 | "# Solving: L x = b\n", 150 | "# L is lower triangular\n", 151 | "for i=1:L.m\n", 152 | " x[i] = b[i]\n", 153 | " for k=L.rowptr[i]:L.rowptr[i+1]-2\n", 154 | " x[i] -= L.nzval[k] * x[L.colval[k]]\n", 155 | " end\n", 156 | " x[i] /= L.nzval[L.rowptr[i+1]-1]\n", 157 | "end \n", 158 | "\n", 159 | "println(\"Error should be equal to 0: \", norm(b - L * x))\n", 160 | "norm(b - L * x) == 0 ? \"PASS\" : \"FAIL\"" 161 | ] 162 | } 163 | ], 164 | "metadata": { 165 | "@webio": { 166 | "lastCommId": null, 167 | "lastKernelId": null 168 | }, 169 | "anaconda-cloud": {}, 170 | "kernelspec": { 171 | "display_name": "Julia 1.6.3", 172 | "language": "julia", 173 | "name": "julia-1.6" 174 | }, 175 | "language_info": { 176 | "file_extension": ".jl", 177 | "mimetype": "application/julia", 178 | "name": "julia", 179 | "version": "1.6.3" 180 | } 181 | }, 182 | "nbformat": 4, 183 | "nbformat_minor": 4 184 | } 185 | -------------------------------------------------------------------------------- /Chap9/Reach.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "data": { 10 | "image/png": "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L//yLzF79uyyxwAA/p8rWHAUeZ6XPUISrbIfAM1GYLWAG2+8MS688ML40z/909i3b98xnzcwMBB9fX1Rq9UaOF3zyfM8qtVq08dJq+wHQDOqFEVRlD0EH9+LL74Y06ZNi3feeSe++c1vxrPPPhtPPvnkB55Tr9ejt7c3hoaGoqenp6RJm0ue55FlWdljfGKtsh8AzcY9WE1u2rRpERFx8sknx8DAQHR1dZU8UWtolShplf0AaDY+Imxib7zxRuzfv//I97VaLebOnVveQABARLiC1dR++ctfxuLFi+N///d/oyiKmD59enz3u98teywAmPAEVhObPn16/OxnPyt7DADgQ3xECACQmMACAEhMYAEAJCawAAASE1gAAIkJLACAxAQWAEBiAgsAIDGBBQCQmMACAEhMYAEAJCawAAASE1gAAIkJLACAxAQWAEBiAgsAIDGB1cQOHToU3/jGN2LmzJlxwQUXxNKlS8seCQCIiEllD8DHt3Llymhra4tf/OIXUalU4qWXXip7JAAgBFbTeuONN2LVqlUxOjoalUolIiLOPvvskqdiIsrzPLIsK3sMgHHFR4RNaufOndHe3h533HFHXHzxxXH55ZfHj3/84+P+zsDAQPT19UWtVmvQlLS6PM+jWq1GnudljwIwrriC1aTeeeed2LVrV5x//vlx9913x7Zt22LBggXx3HPPxRlnnHHU3xkcHIyenp4GT0ory7IsRkZGXMEC+BBXsJpUZ2dntLW1xY033hgRERdddFFUq9X47//+75InY6IRVwAfJbCa1Oc+97m46qqrYt26dRERsXv37hgZGYlzzz235MkAAB8RNrEHHnggbr755virv/qrOOmkk+If/uEf3OgOAOOAwGpi06dPj6effrrsMQCAD/ERIQBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQmlT0AH9/+/fvjD//wD498/+abb8auXbvilVdeiSlTppQ3GABMcAKriU2ePDm2bt165Pt77rknNm7cKK4AoGQ+Imwhq1atiltuuaXsMcZcnudlj0CDec2BZiOwWsTmzZvj1VdfjUWLFh3zOQMDA9HX1xe1Wq2Bk6WV53lUq1VvuBOI1xxoRj4ibBEPP/xwLFu2LCZNOvZLOjg4GD09PQ2cKr0sy2JkZCSyLCt7FBrEaw40I4HVAt54441Ys2ZN/PSnPy17lIbwRjvxeM2BZuMjwhbw6KOPxpw5c2LWrFlljwIAhMBqCQ899NCEuLkdAJqFjwhbwE9+8pOyRwAA3scVLACAxAQWAEBiAgsAIDGBBQCQmMACAEhMYAEAJCawAAASE1gAAIkJLACAxAQWAEBiAgsAIDGBBQCQmMACAEhMYAEAJCawAAASE1gAAIkJrCa2bt266O3tjblz58bs2bNj9erVZY8EAETEpLIH4OMpiiL+5E/+JDZs2BBz5syJPM9j1qxZcf3118fpp59e9ngAMKG5gtXk9u/fHxERBw8ejPb29jjllFPKHahF5Hle9ghJtMp+NIJjBaQksJpUpVKJRx55JK6//vro7OyMyy67LFavXh2f+tSnjvk7AwMD0dfXF7VarYGTNp88z6NarTb9G26r7EcjOFZAapWiKIqyh+B3d/jw4Vi4cGHcfvvt8eUvfzm2bNkS1113XTz77LMxZcqUDzy3Xq9Hb29vDA0NRU9PT0kTN5c8zyPLsrLH+MRaZT8awbECUnIFq0lt3bo19u7dG1/+8pcjIuKSSy6Jc845J7Zt21byZK2hVd5oW2U/GsGxAlISWE1q6tSpMTo6Gs8//3xERLzwwguxc+fO6OrqKnkyAMDfImxSZ511Vjz44IOxZMmSaGtri6Io4v7774/Pf/7zZY8GABOewGpiN9xwQ9xwww1ljwEAfIiPCAEAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsJrYU089FRdffHHMmTMn5s2bF9u2bSt7JAAgIiaVPQAfz2uvvRZLly6Nn/zkJ3HeeefFxo0b48Ybb4zh4eGyRwOACc8VrCa1c+fOOPPMM+O8886LiIgrrrgidu/eHfV6veTJxl6e52WPkIT9mHgcK5g4BFaTmjlzZuzbty+eeeaZiIhYu3ZtvP7668f9A3xgYCD6+vqiVqs1aMr08jyParXa9G9U9mPicaxgYvERYZP67Gc/G4899lisXLky/ud//icuu+yyOP/88+Pkk08+5u8MDg5GT09PA6dML8uyGBkZiSzLyh7lE7EfE49jBRNLpSiKouwh+OQOHToUf/AHfxBbtmyJGTNmfOCxer0evb29MTQ01PSBBQDNwEeETeyll1468vW3vvWt+MpXvvKRuAIAGk9gNbG//uu/jlmzZsWMGTNi9+7d8dBDD5U9EgAQ7sFqav/4j/9Y9ggAwFG4ggUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgTXOrVixIrIsi0qlEsPDwx94bMeOHfGlL30purq64tJLL43nnnuupCkBgPcTWOPckiVLYtOmTdHZ2fmRx/7sz/4sli9fHr/4xS/iL//yL+OWW24pYUIA4MME1jg3f/786Ojo+MjPX3nllajX67F06dKIiFi8eHGMjIxEnucNnpCJrhH/zbXKGo3QKvsBzU5gNak9e/bEOeecE5MmTYqIiEqlEtOmTYsXX3zxmL8zMDAQfX19UavVGjUmLS7P86hWq2P6pt4qazRCq+wHtIJJZQ/Ax1epVD7wfVEUx33+4OBg9PT0jOVITDBZlsXIyEhkWWaNcaBV9gNagStYTWrq1KkxOjoahw8fjojfxNWePXti2rRpJU/GRNOIN/NWWaMRWmU/oNkJrCZ15plnxty5c+N73/teREQ89thjkWWZP1wBYBwQWONcf39/dHR0xOjoaCxYsCBmzJhx5LEHH3wwHnzwwejq6oq77747HnrooRInBQDeUyl+2407NL16vR69vb0xNDTkHiwAaABXsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsJrAihUrIsuyqFQqMTw8fMKPAQDlEFhNYMmSJbFp06bo7Oz8nR4DAMohsJrA/Pnzo6Oj43d+DFpFnudlj9A0GnGsvB7w2wmsCWRgYCD6+vqiVquVPQqcsDzPo1qtelM/AY04Vl4PODGTyh6AxhkcHIyenp6yx4DfSZZlMTIyElmWlT3KuNeIY+X1gBPjChYw7nkzP3GNOFZeD/jtBBYAQGICqwn09/dHR0dHjI6OxoIFC2LGjBkn9BgAUI5KURRF2UMwtur1evT29sbQ0JB7sACgAVzBAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAagIrVqyILMuiUqnE8PDwkZ+//fbbcd1110VXV1d0d3fHwoULI8/z8gYFACJCYDWFJUuWxKZNm6Kzs/Mjjy1fvjyef/752Lp1ayxatCiWL19ewoQAwPsJrCYwf/786Ojo+MjPTz311LjmmmuiUqlERMS8efNi165djR4POEGtcoW5EfvRKseKiUtgtZD77rsvrr322mM+PjAwEH19fVGr1Ro4FRDxm2CoVqtNHw6N2I9WOVZMbJPKHoA07rzzztixY0c88MADx3zO4OBg9PT0NHAq4D1ZlsXIyEhkWVb2KJ9II/ajVY4VE5vAagH33HNPPP7447F+/fo47bTTyh4HOIZWCYZG7EerHCsmLoHV5O69996o1Wqxfv36mDx5ctnjAADhHqym0N/fHx0dHTE6OhoLFiyIGTNmRETE6Oho3HrrrbF///648soro7u7O774xS+WPC0AUCmKoih7CMZWvV6P3t7eGBoacg8WADSAK1gAAIkJLACAxAQWAEBiAgsAIDGBBQCQmMACAEhMYAEAJCawAAASE1gAAIkJLACAxAQWAEBiAgsAIDGBBQCQmMACAEhMYAEAJCawAAASE1jj3IoVKyLLsqhUKjE8PPyBx66++uqYM2dOdHd3x+WXXx5bt24tZ0gA4AME1ji3ZMmS2LRpU3R2dn7ksUceeST+67/+K7Zu3Rq33npr3HzzzSVMCAB8mMAa5+bPnx8dHR1HfWzy5MlHvj5w4EC0tXk5YTzL89waE2wNJi7vyE1u2bJlMXXq1PjmN78Zq1evPu5zBwYGoq+vL2q1WoOmA96T53lUq9UxfVO3xvhag4mtUhRFUfYQ/HZZlsUTTzwRs2fPPurjq1evjjVr1sSTTz75kcfq9Xr09vbG0NBQ9PT0jPWowDHkeR5ZllljAq3BxOUKVou46aabYsOGDfHqq6+WPQpwDI14M7fG+FqDiUtgNamDBw/G3r17j3y/du3aaG9vjylTppQ4FQAQETGp7AE4vv7+/vjBD34QL7/8cixYsCA+85nPxAsvvBAHDhyIxYsXx1tvvRVtbW1xxhlnxBNPPBGVSqXskQFgwnMP1gTgHiwAaCwfEQIAJCawAAASE1gAAIkJLACAxAQWAEBiAgsAIDGBBQCQmMACAEhMYAEAJCawAAASE1gAAIkJLACAxAQWAEBiAgsAIDGBBQCQmMACAEhMYI1zK1asiCzLolKpxPDw8FGfc/vttx/3cQCgsQTWOLdkyZLYtGlTdHZ2HvXxer0ezzzzTEybNq3BkwEAxyKwxrn58+dHR0fHUR87dOhQ9Pf3x/333x+VSqXBkwHjUZ7nZY/QNBpxrLweE5fAamK33XZbLF26NKrV6gk9f2BgIPr6+qJWq43xZEAZ8jyParXqTf0ENOJYeT0mtkllD8DHs3nz5tiyZUvcfffdJ/w7g4OD0dPTM4ZTAWXKsixGRkYiy7KyRxn3GnGsvB4TmytYTWrjxo2xffv2qFarkWVZjI6Oxle/+tX40Y9+VPZoQIm8mZ+4Rhwrr8fEJbCa1MqVK2Pv3r2R53nkeR4dHR2xbt26+NrXvlb2aAAw4Qmsca6/vz86OjpidHQ0FixYEDNmzCh7JADgt6gURVGUPQRjq16vR29vbwwNDbkHCwAawBUsAIDEBBYAQGICCwAgMYEFAJCYwAIASExgAQAkJrAAABITWAAAiQksAIDEBBYAQGICCwAgMYEFAJCYwAIASExgAQAkJrAAABITWAAAiQkskqrVatawhjWsYY0GrsH4JLBIqlX+wLKGNaxhjWZZg/FpUtkDMPbeeuutiIj4+c9/PuZr7d+/P+r1ujWsYQ1rWKNBa0REzJo1K0477bQxX4cTVymKoih7CMbWP/3TP8XSpUvLHgOAMTI0NBQ9PT1lj8H7CKwJ4Fe/+lWsW7cusiyLT3/602WPA0BirmCNPwILACAxN7kDACQmsAAAEhNYAACJCSwAgMQEFkmsWLEisiyLSqUSw8PDybf/9ttvx3XXXRddXV3R3d0dCxcujDzPk65x9dVXx5w5c6K7uzsuv/zy2Lp1a9Ltv9/tt98+ZscqIiLLspg1a1Z0d3dHd3d3rFmzJun2Dx06FN/4xjdi5syZccEFF4zJPwOyf//+I/N3d3dHV1dXTJo0KX79618nW2PdunXR29sbc+fOjdmzZ8fq1auTbfs9Tz31VFx88cUxZ86cmDdvXmzbti3Jdo93zu3YsSO+9KUvRVdXV1x66aXx3HPPJV8j1Tl/rO2kPOePN2uq8/5EjsdYn/eMMwUksHHjxmLPnj1FZ2dn8eyzzybf/ltvvVX88Ic/LN59992iKIriO9/5TvFHf/RHSdd47bXXjny9du3aYu7cuUm3/56hoaFi4cKFxbRp08bkWBVFMWavw3sGBgaKP//zPz/yeuzdu3fM1nrPt7/97WLRokXJtvfuu+8WU6ZMKbZt21YURVGMjIwUp5xySnHw4MFka/z6178u2tvbi+eee64oiqJ4+umniwsuuCDJto93zl155ZXFqlWriqIoikcffbSYN29e8jVSnfPH2k7Kc/54s6Y673/b8WjEec/44goWScyfPz86OjrGbPunnnpqXHPNNVGpVCIiYt68ebFr166ka0yePPnI1wcOHIi2tvSnx6FDh6K/vz/uv//+I/vSbN54441YtWpV3HnnnUf24eyzzx7zdVetWhW33HJL8u3u378/IiIOHjwY7e3tccoppyTb9s6dO+PMM8+M8847LyIirrjiiti9e3eSf9n7WOfcK6+8EvV6/chVxcWLF8fIyMjHuvpzvPM61Tl/rO2kPOePN2uq8/54a7TCec/vzv8qh6Z03333xbXXXpt8u8uWLYsNGzZExG8+2knttttui6VLl0a1Wk2+7Q+78cYb4913340vfvGLcdddd8UZZ5yRZLs7d+6M9vb2uOOOO2L9+vXx6U9/Ov7mb/4mrrrqqiTbP5rNmzfHq6++GosWLUq2zUqlEo888khcf/318Xu/93vx2muvxeOPPx6f+tSnkq0xc+bM2LdvXzzzzDMxb968WLt2bbz++uuR5/mY/avbe/bsiXPOOScmTfrNH++VSiWmTZsWL774YmRZNiZrNsJYnfMRrXXeM364gkXTufPOO2PHjh3xt3/7t8m3/d3vfjf27NkTd9xxR/zFX/xF0m1v3rw5tmzZEl//+teTbvdo/v3f/z22bdsW9Xo92tvb46abbkq27XfeeSd27doV559/fvznf/5n/N3f/V388R//cezbty/ZGh/28MMPx7Jly45EQwqHDx+Ou+66K37wgx/E7t2748c//nHcdNNNSe/x+uxnPxuPPfZYrFy5Mnp7e+Ppp5+O888/P04++eRkaxzNh6+SFE3+70mP5Tkf0TrnPeNM2Z9R0lrG+t6fb3/720Vvb+8H7psYK6eeemrxq1/9Ktn27rrrruLss88uOjs7i87OzuKkk04qzjnnnOLJJ59MtsbR7N27t/jMZz6TbHv79u0r2traisOHDx/52SWXXFJs2LAh2Rrv9/rrrxenn3568fOf/zzpdrds2VKcd955H/jZxRdfXPzbv/1b0nXe7+233y4mT55c7NixI9k2P3zO/fKXvyx+//d/v3jnnXeKovjNvWZnnXVWMTIykmyNE30sxRopz/kTmfWTnvcfXqOs857yuYJF07j33nujVqvFv/7rv37gvokUDh48GHv37j3y/dq1a6O9vT2mTJmSbI2VK1fG3r17I8/zyPM8Ojo6Yt26dfG1r30t2RoRv7lH6r37iiIiarVazJ07N9n2P/e5z8VVV10V69ati4iI3bt3x8jISJx77rnJ1ni/Rx99NObMmROzZs1Kut2pU6fG6OhoPP/88xER8cILL8TOnTujq6sr6TovvfTSka+/9a1vxVe+8pWYMWNG0jXe78wzz4y5c+fG9773vYiIeOyxxyLLsqb8eHAsz/mI1jrvGYfKLjxaw9e//vXi85//fHHSSScVZ511VvGFL3wh6fb37NlTREQxffr04qKLLiouuuii4tJLL022/RdffLG45JJLitmzZxdz5swprrrqquJnP/tZsu0fzVhd7du5c2fR3d1dXHjhhcXs2bOLvr6+T3T14lhrXHHFFcXs2bOLiy66qHj88ceTbv/9LrvssuLhhx8ek23/8z//85HX/MILLyxqtVryNW655Zbi3HPPLb7whS8US5cuTXb19Xjn3Pbt24t58+YVM2fOLHp7e4vh4eHka6Q654+1nZTn/LHWSHnen+jxGOur/Iwf/mfPAACJ+YgQACAxgQUAkJjAAgBITGABACQmsAAAEvs/fZlnwIo8v1QAAAAASUVORK5CYII=" 11 | }, 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "output_type": "execute_result" 15 | } 16 | ], 17 | "source": [ 18 | "using SparseArrays\n", 19 | "using Plots\n", 20 | "using MatrixMarket\n", 21 | "\n", 22 | "# Read the matrix data\n", 23 | "file_name = \"reach_example.mtx\"\n", 24 | "L = MatrixMarket.mmread(file_name)\n", 25 | "\n", 26 | "pyplot()\n", 27 | "n = L.m # Size of matrix\n", 28 | "plot(spy(L), xaxis=((0,n+1), 1:n), yaxis=((0,n+1), 1:n), \n", 29 | " markersize = 5, clims = (1,2))" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 2, 35 | "metadata": {}, 36 | "outputs": [ 37 | { 38 | "data": { 39 | "text/plain": [ 40 | "dfs" 41 | ] 42 | }, 43 | "execution_count": 2, 44 | "metadata": {}, 45 | "output_type": "execute_result" 46 | } 47 | ], 48 | "source": [ 49 | "\"\"\"\n", 50 | "dfs: depth-first search construction of the reach. The ordering\n", 51 | "of the nodes is important for correctness of the lower triangular solve.\n", 52 | "\n", 53 | "input j: index of node for which reach is computed\n", 54 | "input/output xi: reach set of node\n", 55 | "input/output top: pointer that locates where the data\n", 56 | " is stored in xi.\n", 57 | "input/output w: used to mark nodes already visited\n", 58 | "input Lp: indexing array of L\n", 59 | "input Li: row index array for L\n", 60 | "\"\"\"\n", 61 | "function dfs(j, xi, top, w, Lp, Li)\n", 62 | " # Mark the current node\n", 63 | " w[j] = true\n", 64 | "\n", 65 | " # Loop over non-zero entries in column j of L\n", 66 | " for k=Lp[j]:Lp[j+1]-1\n", 67 | " if !w[Li[k]] # Skip node that was marked\n", 68 | " xi, top, w = dfs(Li[k], xi, top, w, Lp, Li)\n", 69 | " # Call dfs recursively for all nodes in column j\n", 70 | " end\n", 71 | " end\n", 72 | "\n", 73 | " # Insert j before all nodes inserted so far\n", 74 | " xi[top] = j\n", 75 | " # Move top one position up\n", 76 | " top = top-1\n", 77 | "\n", 78 | " return xi, top, w\n", 79 | "end" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": 3, 85 | "metadata": {}, 86 | "outputs": [ 87 | { 88 | "name": "stdout", 89 | "output_type": "stream", 90 | "text": [ 91 | "Reach of node 6\n", 92 | "[6, 10, 11, 9, 12, 13, 14]\n" 93 | ] 94 | } 95 | ], 96 | "source": [ 97 | "n = L.m # Size of matrix\n", 98 | "\n", 99 | "# Starting node\n", 100 | "node = 6\n", 101 | "@assert node>=1\n", 102 | "@assert node<=n\n", 103 | "\n", 104 | "top = n\n", 105 | "\n", 106 | "xi = zeros(Int64,n)\n", 107 | "w = fill(false,n) # Flag whether a node was visited or not\n", 108 | "xi, top, w = dfs(node, xi, top, w, L.colptr, L.rowval)\n", 109 | "xi = xi[top+1:end] # Keeping only the relevant data\n", 110 | "\n", 111 | "println(\"Reach of node \", node)\n", 112 | "println(xi)" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": 6, 118 | "metadata": {}, 119 | "outputs": [ 120 | { 121 | "name": "stdout", 122 | "output_type": "stream", 123 | "text": [ 124 | "Reach of nodes 4 and 6\n", 125 | "[6, 10, 11, 4, 9, 12, 13, 14]\n" 126 | ] 127 | } 128 | ], 129 | "source": [ 130 | "top = n\n", 131 | "xi = zeros(Int64,n)\n", 132 | "w = fill(false,n) # Flag whether a node was visited or not\n", 133 | "xi, top, w = dfs(4, xi, top, w, L.colptr, L.rowval)\n", 134 | "xi, top, w = dfs(6, xi, top, w, L.colptr, L.rowval)\n", 135 | "xi = xi[top+1:end] # Keeping only the relevant data\n", 136 | "println(\"Reach of nodes 4 and 6\")\n", 137 | "println(xi)" 138 | ] 139 | } 140 | ], 141 | "metadata": { 142 | "@webio": { 143 | "lastCommId": null, 144 | "lastKernelId": null 145 | }, 146 | "anaconda-cloud": {}, 147 | "kernelspec": { 148 | "display_name": "Julia 1.6.3", 149 | "language": "julia", 150 | "name": "julia-1.6" 151 | }, 152 | "language_info": { 153 | "file_extension": ".jl", 154 | "mimetype": "application/julia", 155 | "name": "julia", 156 | "version": "1.6.3" 157 | } 158 | }, 159 | "nbformat": 4, 160 | "nbformat_minor": 4 161 | } 162 | -------------------------------------------------------------------------------- /Chap9/Sparse.jl: -------------------------------------------------------------------------------- 1 | mutable struct SparseMatrixCSR 2 | m::Int # Number of rows 3 | n::Int # Number of columns 4 | rowptr::Vector{Int} # Starting index for each row 5 | colval::Vector{Int} # Column indices 6 | nzval::Vector{Float64} # Matrix entries 7 | end 8 | 9 | # Convert a CSC matrix to CSR format 10 | # CSC = compressed sparse column 11 | # CSR = compressed sparse row 12 | function SparseMatrixCSR(A_CSC::SparseMatrixCSC) 13 | m = A_CSC.m 14 | n = A_CSC.n 15 | 16 | # Counting the number of entries in each row 17 | rowptr = zeros(Int,m+1) 18 | for j=1:A_CSC.n 19 | for k=A_CSC.colptr[j]:A_CSC.colptr[j+1]-1 20 | rowptr[A_CSC.rowval[k]] += 1 21 | end 22 | end 23 | 24 | # Beginning index for each row 25 | rowptr = cumsum(rowptr) .+ 1 26 | rowptr = vcat([1],rowptr[1:end-1]) 27 | 28 | colval = Vector{Int}(undef,rowptr[end]-1) 29 | nzval = Vector{Float64}(undef,rowptr[end]-1) 30 | for j=1:A_CSC.n 31 | for k=A_CSC.colptr[j]:A_CSC.colptr[j+1]-1 32 | i = A_CSC.rowval[k] 33 | k_CSR = rowptr[i] 34 | colval[k_CSR] = j 35 | nzval[k_CSR] = A_CSC.nzval[k] 36 | rowptr[i] += 1 37 | end 38 | end 39 | # Reset to correct value 40 | rowptr = vcat([1],rowptr[1:end-1]) 41 | 42 | return SparseMatrixCSR(m,n,rowptr,colval,nzval) 43 | end 44 | 45 | """Multiplication operator for a sparse matrix A and a dense vector x""" 46 | function Base.:*(A::SparseMatrixCSR, x::Array{Float64,1}) 47 | # y = A * x 48 | y = Vector{Float64}(undef,A.m) 49 | for i=1:A.m 50 | y[i] = 0.0 51 | for k=A.rowptr[i]:A.rowptr[i+1]-1 52 | y[i] += A.nzval[k] * x[A.colval[k]] 53 | end 54 | end 55 | return y 56 | end 57 | -------------------------------------------------------------------------------- /Chap9/Trefethen_150/Trefethen_150.mtx: -------------------------------------------------------------------------------- 1 | %%MatrixMarket matrix coordinate integer symmetric 2 | %------------------------------------------------------------------------------- 3 | % UF Sparse Matrix Collection, Tim Davis 4 | % http://www.cise.ufl.edu/research/sparse/matrices/JGD_Trefethen/Trefethen_150 5 | % name: JGD_Trefethen/Trefethen_150 6 | % [Diagonal matrices with primes, Nick Trefethen, Oxford Univ.] 7 | % id: 2205 8 | % date: 2008 9 | % author: N. Trefethen 10 | % ed: J.-G. Dumas 11 | % fields: name title A id date author ed kind notes 12 | % kind: combinatorial problem 13 | %------------------------------------------------------------------------------- 14 | % notes: 15 | % Diagonal matrices with primes, Nick Trefethen, Oxford Univ. 16 | % From Jean-Guillaume Dumas' Sparse Integer Matrix Collection, 17 | % http://ljk.imag.fr/membres/Jean-Guillaume.Dumas/simc.html 18 | % 19 | % Problem 7 of the Hundred-dollar, Hundred-digit Challenge Problems, 20 | % SIAM News, vol 35, no. 1. 21 | % 22 | % 7. Let A be the 20,000 x 20,000 matrix whose entries are zero 23 | % everywhere except for the primes 2, 3, 5, 7, . . . , 224737 along the 24 | % main diagonal and the number 1 in all the positions A(i,j) with 25 | % |i-j| = 1,2,4,8, . . . ,16384. What is the (1,1) entry of inv(A)? 26 | % 27 | % http://www.siam.org/news/news.php?id=388 28 | % 29 | % Filename in JGD collection: Trefethen/trefethen_150.sms 30 | %------------------------------------------------------------------------------- 31 | 150 150 1095 32 | 1 1 2 33 | 2 1 1 34 | 3 1 1 35 | 5 1 1 36 | 9 1 1 37 | 17 1 1 38 | 33 1 1 39 | 65 1 1 40 | 129 1 1 41 | 2 2 3 42 | 3 2 1 43 | 4 2 1 44 | 6 2 1 45 | 10 2 1 46 | 18 2 1 47 | 34 2 1 48 | 66 2 1 49 | 130 2 1 50 | 3 3 5 51 | 4 3 1 52 | 5 3 1 53 | 7 3 1 54 | 11 3 1 55 | 19 3 1 56 | 35 3 1 57 | 67 3 1 58 | 131 3 1 59 | 4 4 7 60 | 5 4 1 61 | 6 4 1 62 | 8 4 1 63 | 12 4 1 64 | 20 4 1 65 | 36 4 1 66 | 68 4 1 67 | 132 4 1 68 | 5 5 11 69 | 6 5 1 70 | 7 5 1 71 | 9 5 1 72 | 13 5 1 73 | 21 5 1 74 | 37 5 1 75 | 69 5 1 76 | 133 5 1 77 | 6 6 13 78 | 7 6 1 79 | 8 6 1 80 | 10 6 1 81 | 14 6 1 82 | 22 6 1 83 | 38 6 1 84 | 70 6 1 85 | 134 6 1 86 | 7 7 17 87 | 8 7 1 88 | 9 7 1 89 | 11 7 1 90 | 15 7 1 91 | 23 7 1 92 | 39 7 1 93 | 71 7 1 94 | 135 7 1 95 | 8 8 19 96 | 9 8 1 97 | 10 8 1 98 | 12 8 1 99 | 16 8 1 100 | 24 8 1 101 | 40 8 1 102 | 72 8 1 103 | 136 8 1 104 | 9 9 23 105 | 10 9 1 106 | 11 9 1 107 | 13 9 1 108 | 17 9 1 109 | 25 9 1 110 | 41 9 1 111 | 73 9 1 112 | 137 9 1 113 | 10 10 29 114 | 11 10 1 115 | 12 10 1 116 | 14 10 1 117 | 18 10 1 118 | 26 10 1 119 | 42 10 1 120 | 74 10 1 121 | 138 10 1 122 | 11 11 31 123 | 12 11 1 124 | 13 11 1 125 | 15 11 1 126 | 19 11 1 127 | 27 11 1 128 | 43 11 1 129 | 75 11 1 130 | 139 11 1 131 | 12 12 37 132 | 13 12 1 133 | 14 12 1 134 | 16 12 1 135 | 20 12 1 136 | 28 12 1 137 | 44 12 1 138 | 76 12 1 139 | 140 12 1 140 | 13 13 41 141 | 14 13 1 142 | 15 13 1 143 | 17 13 1 144 | 21 13 1 145 | 29 13 1 146 | 45 13 1 147 | 77 13 1 148 | 141 13 1 149 | 14 14 43 150 | 15 14 1 151 | 16 14 1 152 | 18 14 1 153 | 22 14 1 154 | 30 14 1 155 | 46 14 1 156 | 78 14 1 157 | 142 14 1 158 | 15 15 47 159 | 16 15 1 160 | 17 15 1 161 | 19 15 1 162 | 23 15 1 163 | 31 15 1 164 | 47 15 1 165 | 79 15 1 166 | 143 15 1 167 | 16 16 53 168 | 17 16 1 169 | 18 16 1 170 | 20 16 1 171 | 24 16 1 172 | 32 16 1 173 | 48 16 1 174 | 80 16 1 175 | 144 16 1 176 | 17 17 59 177 | 18 17 1 178 | 19 17 1 179 | 21 17 1 180 | 25 17 1 181 | 33 17 1 182 | 49 17 1 183 | 81 17 1 184 | 145 17 1 185 | 18 18 61 186 | 19 18 1 187 | 20 18 1 188 | 22 18 1 189 | 26 18 1 190 | 34 18 1 191 | 50 18 1 192 | 82 18 1 193 | 146 18 1 194 | 19 19 67 195 | 20 19 1 196 | 21 19 1 197 | 23 19 1 198 | 27 19 1 199 | 35 19 1 200 | 51 19 1 201 | 83 19 1 202 | 147 19 1 203 | 20 20 71 204 | 21 20 1 205 | 22 20 1 206 | 24 20 1 207 | 28 20 1 208 | 36 20 1 209 | 52 20 1 210 | 84 20 1 211 | 148 20 1 212 | 21 21 73 213 | 22 21 1 214 | 23 21 1 215 | 25 21 1 216 | 29 21 1 217 | 37 21 1 218 | 53 21 1 219 | 85 21 1 220 | 149 21 1 221 | 22 22 79 222 | 23 22 1 223 | 24 22 1 224 | 26 22 1 225 | 30 22 1 226 | 38 22 1 227 | 54 22 1 228 | 86 22 1 229 | 150 22 1 230 | 23 23 83 231 | 24 23 1 232 | 25 23 1 233 | 27 23 1 234 | 31 23 1 235 | 39 23 1 236 | 55 23 1 237 | 87 23 1 238 | 24 24 89 239 | 25 24 1 240 | 26 24 1 241 | 28 24 1 242 | 32 24 1 243 | 40 24 1 244 | 56 24 1 245 | 88 24 1 246 | 25 25 97 247 | 26 25 1 248 | 27 25 1 249 | 29 25 1 250 | 33 25 1 251 | 41 25 1 252 | 57 25 1 253 | 89 25 1 254 | 26 26 101 255 | 27 26 1 256 | 28 26 1 257 | 30 26 1 258 | 34 26 1 259 | 42 26 1 260 | 58 26 1 261 | 90 26 1 262 | 27 27 103 263 | 28 27 1 264 | 29 27 1 265 | 31 27 1 266 | 35 27 1 267 | 43 27 1 268 | 59 27 1 269 | 91 27 1 270 | 28 28 107 271 | 29 28 1 272 | 30 28 1 273 | 32 28 1 274 | 36 28 1 275 | 44 28 1 276 | 60 28 1 277 | 92 28 1 278 | 29 29 109 279 | 30 29 1 280 | 31 29 1 281 | 33 29 1 282 | 37 29 1 283 | 45 29 1 284 | 61 29 1 285 | 93 29 1 286 | 30 30 113 287 | 31 30 1 288 | 32 30 1 289 | 34 30 1 290 | 38 30 1 291 | 46 30 1 292 | 62 30 1 293 | 94 30 1 294 | 31 31 127 295 | 32 31 1 296 | 33 31 1 297 | 35 31 1 298 | 39 31 1 299 | 47 31 1 300 | 63 31 1 301 | 95 31 1 302 | 32 32 131 303 | 33 32 1 304 | 34 32 1 305 | 36 32 1 306 | 40 32 1 307 | 48 32 1 308 | 64 32 1 309 | 96 32 1 310 | 33 33 137 311 | 34 33 1 312 | 35 33 1 313 | 37 33 1 314 | 41 33 1 315 | 49 33 1 316 | 65 33 1 317 | 97 33 1 318 | 34 34 139 319 | 35 34 1 320 | 36 34 1 321 | 38 34 1 322 | 42 34 1 323 | 50 34 1 324 | 66 34 1 325 | 98 34 1 326 | 35 35 149 327 | 36 35 1 328 | 37 35 1 329 | 39 35 1 330 | 43 35 1 331 | 51 35 1 332 | 67 35 1 333 | 99 35 1 334 | 36 36 151 335 | 37 36 1 336 | 38 36 1 337 | 40 36 1 338 | 44 36 1 339 | 52 36 1 340 | 68 36 1 341 | 100 36 1 342 | 37 37 157 343 | 38 37 1 344 | 39 37 1 345 | 41 37 1 346 | 45 37 1 347 | 53 37 1 348 | 69 37 1 349 | 101 37 1 350 | 38 38 163 351 | 39 38 1 352 | 40 38 1 353 | 42 38 1 354 | 46 38 1 355 | 54 38 1 356 | 70 38 1 357 | 102 38 1 358 | 39 39 167 359 | 40 39 1 360 | 41 39 1 361 | 43 39 1 362 | 47 39 1 363 | 55 39 1 364 | 71 39 1 365 | 103 39 1 366 | 40 40 173 367 | 41 40 1 368 | 42 40 1 369 | 44 40 1 370 | 48 40 1 371 | 56 40 1 372 | 72 40 1 373 | 104 40 1 374 | 41 41 179 375 | 42 41 1 376 | 43 41 1 377 | 45 41 1 378 | 49 41 1 379 | 57 41 1 380 | 73 41 1 381 | 105 41 1 382 | 42 42 181 383 | 43 42 1 384 | 44 42 1 385 | 46 42 1 386 | 50 42 1 387 | 58 42 1 388 | 74 42 1 389 | 106 42 1 390 | 43 43 191 391 | 44 43 1 392 | 45 43 1 393 | 47 43 1 394 | 51 43 1 395 | 59 43 1 396 | 75 43 1 397 | 107 43 1 398 | 44 44 193 399 | 45 44 1 400 | 46 44 1 401 | 48 44 1 402 | 52 44 1 403 | 60 44 1 404 | 76 44 1 405 | 108 44 1 406 | 45 45 197 407 | 46 45 1 408 | 47 45 1 409 | 49 45 1 410 | 53 45 1 411 | 61 45 1 412 | 77 45 1 413 | 109 45 1 414 | 46 46 199 415 | 47 46 1 416 | 48 46 1 417 | 50 46 1 418 | 54 46 1 419 | 62 46 1 420 | 78 46 1 421 | 110 46 1 422 | 47 47 211 423 | 48 47 1 424 | 49 47 1 425 | 51 47 1 426 | 55 47 1 427 | 63 47 1 428 | 79 47 1 429 | 111 47 1 430 | 48 48 223 431 | 49 48 1 432 | 50 48 1 433 | 52 48 1 434 | 56 48 1 435 | 64 48 1 436 | 80 48 1 437 | 112 48 1 438 | 49 49 227 439 | 50 49 1 440 | 51 49 1 441 | 53 49 1 442 | 57 49 1 443 | 65 49 1 444 | 81 49 1 445 | 113 49 1 446 | 50 50 229 447 | 51 50 1 448 | 52 50 1 449 | 54 50 1 450 | 58 50 1 451 | 66 50 1 452 | 82 50 1 453 | 114 50 1 454 | 51 51 233 455 | 52 51 1 456 | 53 51 1 457 | 55 51 1 458 | 59 51 1 459 | 67 51 1 460 | 83 51 1 461 | 115 51 1 462 | 52 52 239 463 | 53 52 1 464 | 54 52 1 465 | 56 52 1 466 | 60 52 1 467 | 68 52 1 468 | 84 52 1 469 | 116 52 1 470 | 53 53 241 471 | 54 53 1 472 | 55 53 1 473 | 57 53 1 474 | 61 53 1 475 | 69 53 1 476 | 85 53 1 477 | 117 53 1 478 | 54 54 251 479 | 55 54 1 480 | 56 54 1 481 | 58 54 1 482 | 62 54 1 483 | 70 54 1 484 | 86 54 1 485 | 118 54 1 486 | 55 55 257 487 | 56 55 1 488 | 57 55 1 489 | 59 55 1 490 | 63 55 1 491 | 71 55 1 492 | 87 55 1 493 | 119 55 1 494 | 56 56 263 495 | 57 56 1 496 | 58 56 1 497 | 60 56 1 498 | 64 56 1 499 | 72 56 1 500 | 88 56 1 501 | 120 56 1 502 | 57 57 269 503 | 58 57 1 504 | 59 57 1 505 | 61 57 1 506 | 65 57 1 507 | 73 57 1 508 | 89 57 1 509 | 121 57 1 510 | 58 58 271 511 | 59 58 1 512 | 60 58 1 513 | 62 58 1 514 | 66 58 1 515 | 74 58 1 516 | 90 58 1 517 | 122 58 1 518 | 59 59 277 519 | 60 59 1 520 | 61 59 1 521 | 63 59 1 522 | 67 59 1 523 | 75 59 1 524 | 91 59 1 525 | 123 59 1 526 | 60 60 281 527 | 61 60 1 528 | 62 60 1 529 | 64 60 1 530 | 68 60 1 531 | 76 60 1 532 | 92 60 1 533 | 124 60 1 534 | 61 61 283 535 | 62 61 1 536 | 63 61 1 537 | 65 61 1 538 | 69 61 1 539 | 77 61 1 540 | 93 61 1 541 | 125 61 1 542 | 62 62 293 543 | 63 62 1 544 | 64 62 1 545 | 66 62 1 546 | 70 62 1 547 | 78 62 1 548 | 94 62 1 549 | 126 62 1 550 | 63 63 307 551 | 64 63 1 552 | 65 63 1 553 | 67 63 1 554 | 71 63 1 555 | 79 63 1 556 | 95 63 1 557 | 127 63 1 558 | 64 64 311 559 | 65 64 1 560 | 66 64 1 561 | 68 64 1 562 | 72 64 1 563 | 80 64 1 564 | 96 64 1 565 | 128 64 1 566 | 65 65 313 567 | 66 65 1 568 | 67 65 1 569 | 69 65 1 570 | 73 65 1 571 | 81 65 1 572 | 97 65 1 573 | 129 65 1 574 | 66 66 317 575 | 67 66 1 576 | 68 66 1 577 | 70 66 1 578 | 74 66 1 579 | 82 66 1 580 | 98 66 1 581 | 130 66 1 582 | 67 67 331 583 | 68 67 1 584 | 69 67 1 585 | 71 67 1 586 | 75 67 1 587 | 83 67 1 588 | 99 67 1 589 | 131 67 1 590 | 68 68 337 591 | 69 68 1 592 | 70 68 1 593 | 72 68 1 594 | 76 68 1 595 | 84 68 1 596 | 100 68 1 597 | 132 68 1 598 | 69 69 347 599 | 70 69 1 600 | 71 69 1 601 | 73 69 1 602 | 77 69 1 603 | 85 69 1 604 | 101 69 1 605 | 133 69 1 606 | 70 70 349 607 | 71 70 1 608 | 72 70 1 609 | 74 70 1 610 | 78 70 1 611 | 86 70 1 612 | 102 70 1 613 | 134 70 1 614 | 71 71 353 615 | 72 71 1 616 | 73 71 1 617 | 75 71 1 618 | 79 71 1 619 | 87 71 1 620 | 103 71 1 621 | 135 71 1 622 | 72 72 359 623 | 73 72 1 624 | 74 72 1 625 | 76 72 1 626 | 80 72 1 627 | 88 72 1 628 | 104 72 1 629 | 136 72 1 630 | 73 73 367 631 | 74 73 1 632 | 75 73 1 633 | 77 73 1 634 | 81 73 1 635 | 89 73 1 636 | 105 73 1 637 | 137 73 1 638 | 74 74 373 639 | 75 74 1 640 | 76 74 1 641 | 78 74 1 642 | 82 74 1 643 | 90 74 1 644 | 106 74 1 645 | 138 74 1 646 | 75 75 379 647 | 76 75 1 648 | 77 75 1 649 | 79 75 1 650 | 83 75 1 651 | 91 75 1 652 | 107 75 1 653 | 139 75 1 654 | 76 76 383 655 | 77 76 1 656 | 78 76 1 657 | 80 76 1 658 | 84 76 1 659 | 92 76 1 660 | 108 76 1 661 | 140 76 1 662 | 77 77 389 663 | 78 77 1 664 | 79 77 1 665 | 81 77 1 666 | 85 77 1 667 | 93 77 1 668 | 109 77 1 669 | 141 77 1 670 | 78 78 397 671 | 79 78 1 672 | 80 78 1 673 | 82 78 1 674 | 86 78 1 675 | 94 78 1 676 | 110 78 1 677 | 142 78 1 678 | 79 79 401 679 | 80 79 1 680 | 81 79 1 681 | 83 79 1 682 | 87 79 1 683 | 95 79 1 684 | 111 79 1 685 | 143 79 1 686 | 80 80 409 687 | 81 80 1 688 | 82 80 1 689 | 84 80 1 690 | 88 80 1 691 | 96 80 1 692 | 112 80 1 693 | 144 80 1 694 | 81 81 419 695 | 82 81 1 696 | 83 81 1 697 | 85 81 1 698 | 89 81 1 699 | 97 81 1 700 | 113 81 1 701 | 145 81 1 702 | 82 82 421 703 | 83 82 1 704 | 84 82 1 705 | 86 82 1 706 | 90 82 1 707 | 98 82 1 708 | 114 82 1 709 | 146 82 1 710 | 83 83 431 711 | 84 83 1 712 | 85 83 1 713 | 87 83 1 714 | 91 83 1 715 | 99 83 1 716 | 115 83 1 717 | 147 83 1 718 | 84 84 433 719 | 85 84 1 720 | 86 84 1 721 | 88 84 1 722 | 92 84 1 723 | 100 84 1 724 | 116 84 1 725 | 148 84 1 726 | 85 85 439 727 | 86 85 1 728 | 87 85 1 729 | 89 85 1 730 | 93 85 1 731 | 101 85 1 732 | 117 85 1 733 | 149 85 1 734 | 86 86 443 735 | 87 86 1 736 | 88 86 1 737 | 90 86 1 738 | 94 86 1 739 | 102 86 1 740 | 118 86 1 741 | 150 86 1 742 | 87 87 449 743 | 88 87 1 744 | 89 87 1 745 | 91 87 1 746 | 95 87 1 747 | 103 87 1 748 | 119 87 1 749 | 88 88 457 750 | 89 88 1 751 | 90 88 1 752 | 92 88 1 753 | 96 88 1 754 | 104 88 1 755 | 120 88 1 756 | 89 89 461 757 | 90 89 1 758 | 91 89 1 759 | 93 89 1 760 | 97 89 1 761 | 105 89 1 762 | 121 89 1 763 | 90 90 463 764 | 91 90 1 765 | 92 90 1 766 | 94 90 1 767 | 98 90 1 768 | 106 90 1 769 | 122 90 1 770 | 91 91 467 771 | 92 91 1 772 | 93 91 1 773 | 95 91 1 774 | 99 91 1 775 | 107 91 1 776 | 123 91 1 777 | 92 92 479 778 | 93 92 1 779 | 94 92 1 780 | 96 92 1 781 | 100 92 1 782 | 108 92 1 783 | 124 92 1 784 | 93 93 487 785 | 94 93 1 786 | 95 93 1 787 | 97 93 1 788 | 101 93 1 789 | 109 93 1 790 | 125 93 1 791 | 94 94 491 792 | 95 94 1 793 | 96 94 1 794 | 98 94 1 795 | 102 94 1 796 | 110 94 1 797 | 126 94 1 798 | 95 95 499 799 | 96 95 1 800 | 97 95 1 801 | 99 95 1 802 | 103 95 1 803 | 111 95 1 804 | 127 95 1 805 | 96 96 503 806 | 97 96 1 807 | 98 96 1 808 | 100 96 1 809 | 104 96 1 810 | 112 96 1 811 | 128 96 1 812 | 97 97 509 813 | 98 97 1 814 | 99 97 1 815 | 101 97 1 816 | 105 97 1 817 | 113 97 1 818 | 129 97 1 819 | 98 98 521 820 | 99 98 1 821 | 100 98 1 822 | 102 98 1 823 | 106 98 1 824 | 114 98 1 825 | 130 98 1 826 | 99 99 523 827 | 100 99 1 828 | 101 99 1 829 | 103 99 1 830 | 107 99 1 831 | 115 99 1 832 | 131 99 1 833 | 100 100 541 834 | 101 100 1 835 | 102 100 1 836 | 104 100 1 837 | 108 100 1 838 | 116 100 1 839 | 132 100 1 840 | 101 101 547 841 | 102 101 1 842 | 103 101 1 843 | 105 101 1 844 | 109 101 1 845 | 117 101 1 846 | 133 101 1 847 | 102 102 557 848 | 103 102 1 849 | 104 102 1 850 | 106 102 1 851 | 110 102 1 852 | 118 102 1 853 | 134 102 1 854 | 103 103 563 855 | 104 103 1 856 | 105 103 1 857 | 107 103 1 858 | 111 103 1 859 | 119 103 1 860 | 135 103 1 861 | 104 104 569 862 | 105 104 1 863 | 106 104 1 864 | 108 104 1 865 | 112 104 1 866 | 120 104 1 867 | 136 104 1 868 | 105 105 571 869 | 106 105 1 870 | 107 105 1 871 | 109 105 1 872 | 113 105 1 873 | 121 105 1 874 | 137 105 1 875 | 106 106 577 876 | 107 106 1 877 | 108 106 1 878 | 110 106 1 879 | 114 106 1 880 | 122 106 1 881 | 138 106 1 882 | 107 107 587 883 | 108 107 1 884 | 109 107 1 885 | 111 107 1 886 | 115 107 1 887 | 123 107 1 888 | 139 107 1 889 | 108 108 593 890 | 109 108 1 891 | 110 108 1 892 | 112 108 1 893 | 116 108 1 894 | 124 108 1 895 | 140 108 1 896 | 109 109 599 897 | 110 109 1 898 | 111 109 1 899 | 113 109 1 900 | 117 109 1 901 | 125 109 1 902 | 141 109 1 903 | 110 110 601 904 | 111 110 1 905 | 112 110 1 906 | 114 110 1 907 | 118 110 1 908 | 126 110 1 909 | 142 110 1 910 | 111 111 607 911 | 112 111 1 912 | 113 111 1 913 | 115 111 1 914 | 119 111 1 915 | 127 111 1 916 | 143 111 1 917 | 112 112 613 918 | 113 112 1 919 | 114 112 1 920 | 116 112 1 921 | 120 112 1 922 | 128 112 1 923 | 144 112 1 924 | 113 113 617 925 | 114 113 1 926 | 115 113 1 927 | 117 113 1 928 | 121 113 1 929 | 129 113 1 930 | 145 113 1 931 | 114 114 619 932 | 115 114 1 933 | 116 114 1 934 | 118 114 1 935 | 122 114 1 936 | 130 114 1 937 | 146 114 1 938 | 115 115 631 939 | 116 115 1 940 | 117 115 1 941 | 119 115 1 942 | 123 115 1 943 | 131 115 1 944 | 147 115 1 945 | 116 116 641 946 | 117 116 1 947 | 118 116 1 948 | 120 116 1 949 | 124 116 1 950 | 132 116 1 951 | 148 116 1 952 | 117 117 643 953 | 118 117 1 954 | 119 117 1 955 | 121 117 1 956 | 125 117 1 957 | 133 117 1 958 | 149 117 1 959 | 118 118 647 960 | 119 118 1 961 | 120 118 1 962 | 122 118 1 963 | 126 118 1 964 | 134 118 1 965 | 150 118 1 966 | 119 119 653 967 | 120 119 1 968 | 121 119 1 969 | 123 119 1 970 | 127 119 1 971 | 135 119 1 972 | 120 120 659 973 | 121 120 1 974 | 122 120 1 975 | 124 120 1 976 | 128 120 1 977 | 136 120 1 978 | 121 121 661 979 | 122 121 1 980 | 123 121 1 981 | 125 121 1 982 | 129 121 1 983 | 137 121 1 984 | 122 122 673 985 | 123 122 1 986 | 124 122 1 987 | 126 122 1 988 | 130 122 1 989 | 138 122 1 990 | 123 123 677 991 | 124 123 1 992 | 125 123 1 993 | 127 123 1 994 | 131 123 1 995 | 139 123 1 996 | 124 124 683 997 | 125 124 1 998 | 126 124 1 999 | 128 124 1 1000 | 132 124 1 1001 | 140 124 1 1002 | 125 125 691 1003 | 126 125 1 1004 | 127 125 1 1005 | 129 125 1 1006 | 133 125 1 1007 | 141 125 1 1008 | 126 126 701 1009 | 127 126 1 1010 | 128 126 1 1011 | 130 126 1 1012 | 134 126 1 1013 | 142 126 1 1014 | 127 127 709 1015 | 128 127 1 1016 | 129 127 1 1017 | 131 127 1 1018 | 135 127 1 1019 | 143 127 1 1020 | 128 128 719 1021 | 129 128 1 1022 | 130 128 1 1023 | 132 128 1 1024 | 136 128 1 1025 | 144 128 1 1026 | 129 129 727 1027 | 130 129 1 1028 | 131 129 1 1029 | 133 129 1 1030 | 137 129 1 1031 | 145 129 1 1032 | 130 130 733 1033 | 131 130 1 1034 | 132 130 1 1035 | 134 130 1 1036 | 138 130 1 1037 | 146 130 1 1038 | 131 131 739 1039 | 132 131 1 1040 | 133 131 1 1041 | 135 131 1 1042 | 139 131 1 1043 | 147 131 1 1044 | 132 132 743 1045 | 133 132 1 1046 | 134 132 1 1047 | 136 132 1 1048 | 140 132 1 1049 | 148 132 1 1050 | 133 133 751 1051 | 134 133 1 1052 | 135 133 1 1053 | 137 133 1 1054 | 141 133 1 1055 | 149 133 1 1056 | 134 134 757 1057 | 135 134 1 1058 | 136 134 1 1059 | 138 134 1 1060 | 142 134 1 1061 | 150 134 1 1062 | 135 135 761 1063 | 136 135 1 1064 | 137 135 1 1065 | 139 135 1 1066 | 143 135 1 1067 | 136 136 769 1068 | 137 136 1 1069 | 138 136 1 1070 | 140 136 1 1071 | 144 136 1 1072 | 137 137 773 1073 | 138 137 1 1074 | 139 137 1 1075 | 141 137 1 1076 | 145 137 1 1077 | 138 138 787 1078 | 139 138 1 1079 | 140 138 1 1080 | 142 138 1 1081 | 146 138 1 1082 | 139 139 797 1083 | 140 139 1 1084 | 141 139 1 1085 | 143 139 1 1086 | 147 139 1 1087 | 140 140 809 1088 | 141 140 1 1089 | 142 140 1 1090 | 144 140 1 1091 | 148 140 1 1092 | 141 141 811 1093 | 142 141 1 1094 | 143 141 1 1095 | 145 141 1 1096 | 149 141 1 1097 | 142 142 821 1098 | 143 142 1 1099 | 144 142 1 1100 | 146 142 1 1101 | 150 142 1 1102 | 143 143 823 1103 | 144 143 1 1104 | 145 143 1 1105 | 147 143 1 1106 | 144 144 827 1107 | 145 144 1 1108 | 146 144 1 1109 | 148 144 1 1110 | 145 145 829 1111 | 146 145 1 1112 | 147 145 1 1113 | 149 145 1 1114 | 146 146 839 1115 | 147 146 1 1116 | 148 146 1 1117 | 150 146 1 1118 | 147 147 853 1119 | 148 147 1 1120 | 149 147 1 1121 | 148 148 857 1122 | 149 148 1 1123 | 150 148 1 1124 | 149 149 859 1125 | 150 149 1 1126 | 150 150 863 1127 | -------------------------------------------------------------------------------- /Chap9/example_A.mtx: -------------------------------------------------------------------------------- 1 | %%MatrixMarket matrix coordinate pattern general 2 | %Example of computation of the reach of a node 3 | 11 11 27 4 | 1 1 5 | 6 1 6 | 7 1 7 | 2 2 8 | 3 2 9 | 8 2 10 | 3 3 11 | 10 3 12 | 11 3 13 | 4 4 14 | 6 4 15 | 10 4 16 | 5 5 17 | 8 5 18 | 11 5 19 | 6 6 20 | 9 6 21 | 10 6 22 | 7 7 23 | 11 7 24 | 8 8 25 | 10 8 26 | 11 8 27 | 9 9 28 | 10 10 29 | 11 10 30 | 11 11 31 | -------------------------------------------------------------------------------- /Chap9/reach_example.mtx: -------------------------------------------------------------------------------- 1 | %%MatrixMarket matrix coordinate real general 2 | %Example of computation of the reach of a node 3 | 14 14 36 4 | 1 1 1.0 5 | 3 1 1.0 6 | 2 2 1.0 7 | 4 2 1.0 8 | 7 2 1.0 9 | 9 2 1.0 10 | 3 3 1.0 11 | 5 3 1.0 12 | 8 3 1.0 13 | 4 4 1.0 14 | 9 4 1.0 15 | 5 5 1.0 16 | 8 5 1.0 17 | 6 6 1.0 18 | 9 6 1.0 19 | 10 6 1.0 20 | 7 7 1.0 21 | 10 7 1.0 22 | 11 7 1.0 23 | 8 8 1.0 24 | 10 8 1.0 25 | 9 9 1.0 26 | 12 9 1.0 27 | 13 9 1.0 28 | 10 10 1.0 29 | 11 10 1.0 30 | 13 10 1.0 31 | 14 10 1.0 32 | 11 11 1.0 33 | 12 11 1.0 34 | 13 11 1.0 35 | 12 12 1.0 36 | 13 12 1.0 37 | 13 13 1.0 38 | 14 13 1.0 39 | 14 14 1.0 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Julia code for the book Numerical Linear Algebra 2 | 3 | [![Build Status](https://travis-ci.org/EricDarve/numerical_linear_algebra.svg?branch=master)](https://travis-ci.org/EricDarve/numerical_linear_algebra) 4 | 5 | To use this code, please download and install Julia from [julialang.org/downloads](https://julialang.org/downloads/). 6 | 7 | ### Julia installation 8 | 9 | Step 1: if you have installed Julia on your computer, you can download this repository using the green `Clone or download` button above. Once you have Julia installed, you can run all the Julia codes in this repository (files with extension `.jl`). 10 | 11 | To run the Julia notebooks (files with extension `.ipynb`), you need to install [IJulia](https://github.com/JuliaLang/IJulia.jl) and [Jupyter](https://jupyter.readthedocs.io/en/latest/). 12 | 13 | Step 2: IJulia is a Julia package. To install it, start the Julia application. At the `julia>` prompt, type: 14 | 15 | using Pkg 16 | Pkg.add("IJulia") 17 | 18 | See [IJulia](https://github.com/JuliaLang/IJulia.jl) for more detailed instructions. 19 | 20 | Step 3: Install Jupyter following these [instructions](https://jupyter.readthedocs.io/en/latest/install.html). 21 | 22 | Step 4: type `jupyter notebook` in a [terminal window](https://jupyter.readthedocs.io/en/latest/running.html). Make sure you are in the directory containing your notebook. You should be able to open the notebook from the jupyter window inside your web browser. 23 | 24 | You can run the example notebook `Demo.ipynb` contained in this repository. After opening `Demo.ipynb`, wait for the kernel to be ready (check the top right corner of the window), then click on `Cell -> Run All` to update the plot. You may have to change the Julia kernel to match the one that is installed. Click on `Kernel -> change kernel` for this. 25 | 26 | Read the notebook. You should see a plot at the end. 27 | 28 | You are now ready to go! 29 | -------------------------------------------------------------------------------- /load_plot_pkg.jl: -------------------------------------------------------------------------------- 1 | using PlotlyJS 2 | 3 | # Set default values for all plots 4 | nlaStyle = let 5 | axis = attr(showgrid=true, gridcolor="#E5E5E5", 6 | linewidth=1.0, 7 | titlefont_color="#555555", titlefont_size=18, 8 | linecolor="black", mirror=true, zeroline=false, 9 | ticks="inside") 10 | layout = Layout(font_size=16, xaxis=axis, yaxis=axis, 11 | titlefont_size=18, width=500, height=300) 12 | 13 | colors = Cycler([ 14 | "#E24A33", "#348ABD", "#988ED5", "#777777", 15 | "#FBC15E", "#8EBA42", "#FFB5B8" 16 | ]) 17 | gta = attr( 18 | marker_line_width=0.5, marker_line_color="#348ABD", 19 | marker_color=colors, marker_size=10 20 | ) 21 | Style(layout=layout, global_trace=gta) 22 | end 23 | 24 | use_style!(nlaStyle) 25 | 26 | function plotToPDF(p,fileName) 27 | savefig(p,"$fileName.html") 28 | cmd = `/usr/libexec/cups/filter/xhtmltopdf 0 0 0 0 0 $fileName.html` 29 | run(pipeline(cmd, stdout="$fileName.pdf")) 30 | cmd = `pdfcrop $fileName.pdf` 31 | run(cmd) 32 | end 33 | -------------------------------------------------------------------------------- /src/gees.jl: -------------------------------------------------------------------------------- 1 | function pretty_print(A) 2 | m = size(A,1) 3 | n = size(A,2) 4 | for i=1:m 5 | for j=1:n 6 | @printf "%9.1e" A[i,j] 7 | end 8 | @printf "\n" 9 | end 10 | end 11 | 12 | function lt(z1,z2) 13 | if abs( abs(z1)-abs(z2) ) > eps(Float32) * (abs(z1) + abs(z2)) 14 | return abs(z1) < abs(z2) 15 | elseif abs( real(z1-z2) ) > eps(Float32) * (abs(z1) + abs(z2)) 16 | return real(z1) < real(z2) 17 | else 18 | return imag(z1) < imag(z2) 19 | end 20 | end 21 | 22 | """ 23 | eigenvalue_sorted(A) 24 | 25 | Sort eigenvalues of A first by the real part then by the imaginary part. 26 | Assumes that A is real and we have pairs of complex conjugate eigenvalues. 27 | """ 28 | function eigenvalue_sorted(A) 29 | F = eigen(A) 30 | D = F.values 31 | sort!(D, lt=lt) 32 | return D 33 | end 34 | 35 | """ 36 | house(x) 37 | 38 | Computes the Householder transformation for input vector x 39 | """ 40 | function house(x) 41 | sigma = dot(x[2:end],x[2:end]) 42 | v = copy(x) 43 | 44 | if sigma == 0 45 | beta = 0 46 | return beta, v 47 | end 48 | 49 | sq = sqrt(x[1]^2 + sigma) 50 | if x[1] > 0 51 | v[1] += sq 52 | else 53 | v[1] -= sq 54 | end 55 | 56 | beta = 2.0 / (v[1]^2 + sigma) 57 | 58 | return beta, v 59 | end 60 | 61 | """ 62 | givens(a, b) 63 | 64 | Computes the Givens transform; a and b should be scalars 65 | """ 66 | function givens(a, b) 67 | if b == 0 68 | c = 1 69 | s = 0 70 | else 71 | if abs(b) > abs(a) 72 | tau = -a/b 73 | s = 1.0/sqrt(1.0+tau*tau) 74 | c = s*tau 75 | else 76 | tau = -b/a 77 | c = 1.0/sqrt(1.0+tau*tau) 78 | s = c*tau 79 | end 80 | end 81 | return (c, s) 82 | end 83 | 84 | """ 85 | apply_left_householder!(A, row, col, beta, v) 86 | 87 | Apply a Householder reflection to the left of matrix `A`. 88 | 89 | `row` is the starting row index to apply the transform. 90 | `col` is the starting column index. `beta` and `v` are the 91 | parameters for the Householder reflection. 92 | 93 | """ 94 | function apply_left_householder!(A, row, col, beta, v) 95 | n = size(A,1) 96 | vA = zeros(n) 97 | lv = length(v) 98 | # Apply transform to the left 99 | # vA = beta * v^T * A 100 | for j=col:n 101 | for i=row:row+lv-1 102 | vA[j] += v[i-row+1] * A[i,j] 103 | end 104 | vA[j] *= beta 105 | end 106 | # A - beta v (v^T A) 107 | for j=col:n, i=row:row+lv-1 108 | A[i,j] -= v[i-row+1] * vA[j] 109 | end 110 | end 111 | 112 | """ 113 | apply_right_householder!(A, row, col, beta, v) 114 | 115 | Apply a Householder reflection to the right of matrix `A`. 116 | 117 | `row` is the ending row index to apply the transform. 118 | `col` is the starting column index. `beta` and `v` are the 119 | parameters for the Householder reflection. 120 | """ 121 | function apply_right_householder!(A, row, col, beta, v) 122 | n = size(A,1) 123 | Av = zeros(n) 124 | lv = length(v) 125 | # Apply transform to the right 126 | # Av = beta * A * v 127 | for j=col:col+lv-1 128 | for i=1:row 129 | Av[i] += v[j-col+1] * A[i,j] 130 | end 131 | end 132 | for i=1:row 133 | Av[i] *= beta 134 | end 135 | # A - beta (Av) v^T 136 | for j=col:col+lv-1, i=1:row 137 | A[i,j] -= Av[i] * v[j-col+1] 138 | end 139 | end 140 | 141 | function gehrd!(A) 142 | """Reduced square matrix A to upper Hessenberg form""" 143 | n = size(A,1) 144 | for k=1:n-2 145 | # Compute Householder reflection for column k 146 | beta, v = house(A[k+1:n,k]) 147 | # Apply the reflection on the left 148 | apply_left_householder!(A, k+1, k, beta, v) 149 | # Apply the reflection on the right 150 | apply_right_householder!(A, n, k+1, beta, v) 151 | end 152 | end 153 | 154 | function apply_left_givens!(A, row, col, c, s) 155 | n = size(A,1) 156 | for j=col:n 157 | A[row,j], A[row+1,j] = 158 | ( c * A[row,j] - s * A[row+1,j], 159 | s * A[row,j] + c * A[row+1,j] ) 160 | end 161 | end 162 | 163 | function apply_right_givens!(A, row, col, c, s) 164 | n = size(A,1) 165 | for i=1:row 166 | A[i,col], A[i,col+1] = 167 | ( c * A[i,col] - s * A[i,col+1], 168 | s * A[i,col] + c * A[i,col+1] ) 169 | end 170 | end 171 | 172 | """ 173 | givens_QR_iteration_s!(A) 174 | 175 | QR iteration using Givens rotations. 176 | """ 177 | function givens_QR_iteration_s!(A) 178 | """First version of the algorithm to apply Givens for the QR iteration""" 179 | n = size(A,1) 180 | G = zeros(2,n-1) 181 | for k=1:n-1 182 | c, s = givens(A[k,k], A[k+1,k]) 183 | G[:,k] = [c; s] 184 | # Multiply by Givens rotation to the left 185 | apply_left_givens!(A, k, k, c, s) 186 | end 187 | for k=1:n-1 188 | # Multiply by Givens rotation to the right 189 | apply_right_givens!(A, k+1, k, G[1,k], G[2,k]) 190 | end 191 | end 192 | 193 | """ 194 | givens_QR_iteration!(A) 195 | 196 | QR iteration with bulge chasing 197 | """ 198 | function givens_QR_iteration!(A) 199 | n = size(A,1) 200 | for k=1:n-1 201 | c, s = givens(A[k,k], A[k+1,k]) 202 | apply_left_givens!(A, k, max(1,k-1), c, s) 203 | apply_right_givens!(A, min(n,k+2), k, c, s) 204 | end 205 | end 206 | 207 | """ 208 | double_shift_st(A) 209 | 210 | For a real 2x2 matrix, calculate the sum and product of its eigenvalues. 211 | """ 212 | function double_shift_st(A) 213 | a = A[1,1] 214 | b = A[1,2] 215 | c = A[2,1] 216 | d = A[2,2] 217 | s = a+d # sum 218 | t = a*d - b*c # product 219 | return s,t 220 | end 221 | 222 | """ 223 | gees_single_step!(A) 224 | 225 | Single step in QR iteration with double real shift 226 | """ 227 | function gees_single_step!(A, exceptional_shift) 228 | n = size(A,1) 229 | 230 | @assert n>=3 231 | 232 | tol = 0.01 233 | # This tolerance is used to test for early convergence of the last 234 | # 2x2 or 1x1 block. 235 | 236 | # Which shift should we apply? 237 | if abs(A[n-1,n-2]) < tol * (abs(A[n-2,n-2]) + abs(A[n-1,n-1])) || 238 | ! ( abs(A[n,n-1]) < tol * (abs(A[n-1,n-1]) + abs(A[n,n])) ) 239 | # Either: 240 | # (double shift test) == true 241 | # or 242 | # ! (single shift test) == true 243 | # double shift is the fall back position if the single shift test fails. 244 | s, t = double_shift_st(A[n-1:n,n-1:n]) 245 | 246 | else # Single shift should be used 247 | s = 2*A[n,n] 248 | t = A[n,n]^2 249 | end 250 | 251 | if exceptional_shift 252 | println("Exceptional shift") 253 | # This case is difficult to handle. 254 | # A special shift is required to break the convergence 255 | # stall. We use the reference eig function for this. 256 | # Of course, this is not a "practical" solution. 257 | F = eigen(A); D = F.values 258 | D = sort(D, lt=lt) 259 | root = D[1] 260 | s = 2.0*real(root) 261 | t = abs(root)^2 262 | end 263 | 264 | # Assembling the first column 265 | v = [ A[1,1]*A[1,1] + A[1,2]*A[2,1] - s*A[1,1] + t; 266 | A[2,1]*(A[1,1]+A[2,2]-s); 267 | A[2,1]*A[3,2] ] 268 | 269 | beta, v = house(v) 270 | 271 | apply_left_householder!( A, 1, 1, beta, v) 272 | apply_right_householder!(A, min(4,n), 1, beta, v) 273 | 274 | for k=2:n-1 275 | beta, v = house(A[k:min(k+2,n),k-1]) 276 | apply_left_householder!( A, k, k-1, beta, v) 277 | apply_right_householder!(A, min(k+3,n), k, beta, v) 278 | end 279 | end 280 | 281 | function reduce_eps!(A, tol) 282 | # Zero out all small entries on the sub-diagonal 283 | n = size(A,1) 284 | for i=1:n-1 285 | if abs(A[i+1,i]) < tol * (abs(A[i,i])+abs(A[i+1,i+1])) 286 | A[i+1,i] = 0 287 | end 288 | end 289 | end 290 | 291 | function gees!(A) 292 | n = size(A,1) 293 | if n==1 294 | return fill(A[1,1],1) 295 | end 296 | D = zeros(Complex{Float64},n) 297 | 298 | # Tolerance for deflation 299 | tol = eps(Float64) 300 | 301 | q = n # Size of the matrix we are currently working with 302 | iter = 1 # Counter to detect convergence failure 303 | iter_per_evalue = 0 # Used to trigger an exceptional shift 304 | 305 | # Zero out small entries 306 | reduce_eps!(A, tol) 307 | 308 | while q > 0 309 | 310 | if iter > 10*n 311 | println("Failure to converge") 312 | println("Size of matrix = ",n) 313 | println("Eigenvalues found:") 314 | println(D) 315 | D1 = eigenvalue_sorted(A) 316 | println("Remaining eigenvalues at point of failure:") 317 | println(D1) 318 | return D # The eigenvalues we were able to calculate up to the failure 319 | end 320 | 321 | deflation = true # Were we able to deflate the matrix? 322 | 323 | while deflation 324 | deflation = false 325 | # Test for convergence 326 | # Test deflation for the last 2x2 block 327 | if q <= 2 || A[q-1,q-2] == 0 328 | if q >= 2 329 | # The last 2x2 block has converged 330 | deflation = true # Deflating now 331 | # Compute the eigenvalues 332 | a = A[q-1,q-1]; b = A[q-1,q]; c = A[q,q-1]; d = A[q,q] 333 | # Last 2x2 block 334 | htr = (a+d)/2 # Half-trace 335 | dis = (a-d)^2/4 + b*c # Discriminant 336 | if dis > 0 # Pair of real eigenvalues 337 | D[q-1] = htr - sqrt(dis) 338 | D[q] = htr + sqrt(dis) 339 | else # Complex conjugate eigenvalues 340 | D[q-1] = htr - sqrt(-dis)*im 341 | D[q] = htr + sqrt(-dis)*im 342 | end 343 | # Reduce the size of the matrix 344 | q -= 2 345 | if q>=1 346 | A = A[1:q,1:q] 347 | end 348 | end 349 | end 350 | 351 | if q==0 352 | return D 353 | end 354 | 355 | # Testing deflation for the last 1x1 block 356 | if q <= 1 || A[q,q-1] == 0 357 | deflation = true 358 | D[q] = A[q,q] 359 | q -= 1 360 | if q>=1 361 | A = A[1:q,1:q] 362 | end 363 | end 364 | 365 | if q==0 366 | return D 367 | end 368 | 369 | if deflation 370 | iter_per_evalue = 0 # Reset the counter 371 | end 372 | end 373 | 374 | # If q <= 2 we will compute the eigenvalues at the next iteration 375 | if q >= 3 376 | # Searching for the smallest unreduced sub-block 377 | p = q 378 | while p > 1 && A[p,p-1] != 0 379 | p -= 1 380 | end 381 | 382 | # If the unreduced sub-block has size 2 or less, we move on 383 | # to the next iteration. 384 | if q-p+1 >= 3 385 | B = A[p:q,p:q] # Extract sub-block 386 | exceptional_shift = ((iter_per_evalue%5) == 0 && 387 | iter_per_evalue>0) 388 | # Francis QR step 389 | gees_single_step!(B, exceptional_shift) 390 | # Reduce matrix 391 | reduce_eps!(B, tol) 392 | A[p:q,p:q] = B # Copy the resulting matrix back 393 | iter += 1 # Increment iteration counter 394 | iter_per_evalue += 1 395 | # Increment counter for exceptional_shift 396 | end 397 | end 398 | end 399 | end 400 | 401 | using Test 402 | function gees_testsuite() 403 | n_case = 5 # Number of test cases 404 | s_test = 10 # Length of each test case 405 | 406 | err = zeros(n_case*s_test) 407 | h = 1e3*eps(Float64) 408 | 409 | itest = 1 # Test counter 410 | 411 | for i_case = 1:n_case 412 | for t = 1:s_test 413 | println("\n *** Test no ",itest," ***") 414 | 415 | rng = MersenneTwister(2016+itest) 416 | 417 | if i_case == 1 && t <= 4 418 | n = t 419 | A = rand(rng, n, n) # Small random 420 | elseif i_case == 1 && t == 5 421 | # Demmel case 1, p. 173 422 | A = Float64[0 0 1.0; 1.0 0 0; 0 1.0 0] 423 | elseif i_case == 1 && t == 6 424 | # Demmel case 2, p. 173 425 | A = Float64[0 1 0 0; 1 0 h 0; 0 -h 0 1; 0 0 1 0] 426 | elseif i_case == 1 427 | # Random matrix 428 | n = t 429 | A = zeros(n,n) 430 | n0 = div(n,2) 431 | n1 = n - n0 432 | As = rand(rng, n0, n0) 433 | A[1:n0,1:n0] = As + As' 434 | Ass = rand(rng, n1, n1) 435 | A[n-n1+1:n,n-n1+1:n] = Ass - Ass' + rand(rng) * UniformScaling(1.0) 436 | X = rand(rng, n, n); 437 | A = X * A / X 438 | elseif i_case == 2 439 | # Simple permutation 440 | n = t 441 | A = zeros(n,n) 442 | for j=1:n, i=1:n 443 | if i == j+1 444 | A[i,j] = 1 445 | elseif i==1 && j==n 446 | A[i,j] = 1 447 | end 448 | end 449 | elseif i_case == 3 450 | # Random permutation 451 | # Eigenvalues are on the unit circle 452 | n = t 453 | r_perm = randperm(rng, n) 454 | A = zeros(n,n) 455 | for j=1:n, i=1:n 456 | if r_perm[i] == j 457 | A[i,j] = 1 458 | end 459 | end 460 | elseif i_case == 4 461 | # Random permutation with small perturbation 462 | n = t 463 | r_perm = randperm(rng, n) 464 | A = zeros(n,n) 465 | for j=1:n, i=1:n 466 | if r_perm[i] == j 467 | A[i,j] = 1 468 | end 469 | end 470 | if n >= 2 471 | i = 1 472 | if A[i,1] != 0 473 | i = 2 474 | end 475 | A[i,1] = h 476 | end 477 | else 478 | # Random orthogonal matrix 479 | # Eigenvalues are on the unit circle 480 | n = t 481 | A = rand(rng, n, n) 482 | F = qr(A); A = Matrix(F.Q) 483 | end 484 | 485 | n = size(A,1) 486 | println("Size of matrix ",n) 487 | 488 | D0 = eigenvalue_sorted(A) 489 | 490 | # Reduction to upper Hessenberg form 491 | gehrd!(A) 492 | 493 | if n >= 3 494 | @test norm(tril(A,-2)) < 1e-8 495 | gees_single_step!(A,false) 496 | D1 = eigenvalue_sorted(A) 497 | @test norm(D0 - D1) < 1e-7 498 | end 499 | 500 | # Eigensolver 501 | D2 = gees!(A) 502 | D2 = eigenvalue_sorted(diagm(0 => D2)) 503 | 504 | D1 = eigenvalue_sorted(A) 505 | 506 | @show norm(D0 - D1) 507 | @show norm(D1 - D2) 508 | 509 | @assert norm(D0 - D2) < 1e-7 510 | @assert norm(D1 - D2) < 1e-7 511 | 512 | # Save error for plotting 513 | err[itest] = norm(D0 - D2) 514 | 515 | itest += 1 516 | end 517 | end 518 | 519 | return err # For plotting 520 | end 521 | -------------------------------------------------------------------------------- /src/gees_test.jl: -------------------------------------------------------------------------------- 1 | using Printf 2 | using LinearAlgebra 3 | using Random 4 | 5 | include("gees.jl") 6 | 7 | function test() 8 | # Householder transforms 9 | 10 | for icase=1:20 11 | if icase <= 2 12 | if icase == 1 13 | n = 2 14 | else 15 | n = 128 16 | end 17 | x = zeros(n) 18 | x[1] = 1 19 | elseif icase <= 4 20 | if icase == 3 21 | n = 2 22 | else 23 | n = 128 24 | end 25 | x = zeros(n) 26 | x[1] = -1 27 | elseif icase <= 6 28 | if icase == 5 29 | n = 2 30 | else 31 | n = 128 32 | end 33 | x = zeros(n) 34 | x[1] = 1 35 | x[2] = eps(Float64) 36 | elseif icase <= 8 37 | if icase == 7 38 | n = 2 39 | else 40 | n = 128 41 | end 42 | x = zeros(n) 43 | x[1] = -1 44 | x[2] = eps(Float64) 45 | elseif icase == 9 46 | n = 3 47 | x = [244.60002521653865,4.109790267811492e-79,2.786261257333573e-81] 48 | else 49 | rng = MersenneTwister(2018) 50 | n = (icase-7) 51 | x = rand(rng, n) 52 | end 53 | 54 | beta, v = house(x) 55 | 56 | # if icase == 1 || icase == 2 57 | # @test beta == 0 58 | # elseif icase == 3 || icase == 4 59 | # @test beta == 2 60 | # end 61 | 62 | # Orthogonal transform tests 63 | I_n = diagm(0 => fill(1.0,n)) 64 | B = copy(I_n) 65 | apply_left_householder!(B, 1, 1, beta, v) 66 | if norm(B'*B - UniformScaling(1.0)) >= (1<<3) * eps(Float64) 67 | @show v 68 | @show beta 69 | @show B 70 | end 71 | @test norm(B'*B - UniformScaling(1.0)) < (1<<3) * eps(Float64) 72 | 73 | B = copy(I_n) 74 | apply_right_householder!(B, n, 1, beta, v) 75 | @test norm(B'*B - UniformScaling(1.0)) < (1<<3) * eps(Float64) 76 | 77 | c, s = givens(x[1], x[2]) 78 | 79 | B = copy(I_n) 80 | apply_left_givens!(B, 1, 1, c, s) 81 | @test norm(B'*B - UniformScaling(1.0)) < (1<<3) * eps(Float64) 82 | 83 | B = copy(I_n) 84 | apply_right_givens!(B, n, 1, c, s) 85 | @test norm(B'*B - UniformScaling(1.0)) < (1<<3) * eps(Float64) 86 | 87 | # Testing left Householder transform 88 | rng = MersenneTwister(2018) 89 | A = rand(rng, n, n) 90 | A[:,1] = x 91 | A0 = copy(A) 92 | beta, v = house(A[:,1]) 93 | apply_left_householder!(A, 1, 1, beta, v) 94 | @test norm(A[2:n,1]) < (1<<4) * eps(Float64) 95 | 96 | # Testing right Householder transform 97 | A = copy(A0)' 98 | beta, v = house(A[1,:]') 99 | apply_right_householder!(A, n, 1, beta, v) 100 | @test norm(A[1,2:n]) < (1<<4) * eps(Float64) 101 | 102 | # Givens rotations 103 | A0 = copy(A) 104 | c, s = givens(A[1,1], A[2,1]) 105 | apply_left_givens!(A, 1, 1, c, s) 106 | @test abs(A[2,1]) < 2*eps(Float64) 107 | 108 | # Testing right Givens 109 | A = copy(A0)' 110 | c, s = givens(A[1,1], A[1,2]) 111 | apply_right_givens!(A, n, 1, c, s) 112 | @test abs(A[1,2]) < 2*eps(Float64) 113 | end 114 | 115 | # Test gehrd!(A) 116 | rng = MersenneTwister(2018) 117 | X = rand(rng, n, n) 118 | D0 = rand(rng,n); D0 = sort(D0,rev=true); 119 | A = X * diagm(0 => D0) / X 120 | F = eigen(A); D1 = F.values; V = F.vectors; D1 = sort(D1,rev=true); 121 | @test norm(D0 - D1) < 1e-11 122 | gehrd!(A) 123 | @test norm(tril(A,-2)) < 1e-14 124 | F = eigen(A); D2 = F.values; V = F.vectors; D2 = sort(D2,rev=true); 125 | @test norm(D1 - D2) < 1e-11 126 | 127 | # QR with Givens, sequential version 128 | rng = MersenneTwister(2018) 129 | n = 8 130 | X = rand(rng, n, n) 131 | D0 = rand(rng,n); D0 = sort(D0,rev=true); 132 | A = X * diagm(0 => D0) / X 133 | # Upper Hessenberg 134 | gehrd!(A) 135 | F = eigen(A); D1 = F.values; V = F.vectors; D1 = sort(D1,rev=true); 136 | @test norm(D0 - D1) < (1<<5) * eps(Float64) 137 | @test norm(tril(A,-2)) < (1<<3) * eps(Float64) 138 | givens_QR_iteration_s!(A) 139 | F = eigen(A); D1 = F.values; V = F.vectors; D1 = sort(D1,rev=true); 140 | @test norm(D0 - D1) < (1<<5) * eps(Float64) 141 | @test norm(tril(A,-2)) < (1<<3) * eps(Float64) 142 | 143 | # QR with bulge chasing 144 | rng = MersenneTwister(2018) 145 | n = 8 146 | X = rand(rng, n, n) 147 | D0 = rand(rng,n); D0 = sort(D0,rev=true); 148 | A = X * diagm(0 => D0) / X 149 | gehrd!(A) 150 | givens_QR_iteration!(A) 151 | F = eigen(A); D1 = F.values; V = F.vectors; D1 = sort(D1,rev=true); 152 | @test norm(D0 - D1) < (1<<5) * eps(Float64) 153 | @test norm(tril(A,-2)) < (1<<3) * eps(Float64) 154 | 155 | # QR with double shift, single step 156 | rng = MersenneTwister(2018) 157 | n = 8 158 | X = rand(rng, n, n) 159 | D0 = rand(rng,n); D0 = sort(D0,rev=true); 160 | A = X * diagm(0 => D0) / X 161 | gehrd!(A) 162 | @test norm(tril(A,-2)) < (1<<3) * eps(Float64) 163 | gees_single_step!(A,false) 164 | F = eigen(A); D1 = F.values; V = F.vectors; D1 = sort(D1,rev=true); 165 | @test norm(D0 - D1) < (1<<5) * eps(Float64) 166 | end 167 | 168 | test() 169 | gees_testsuite() 170 | -------------------------------------------------------------------------------- /src/geqrf.jl: -------------------------------------------------------------------------------- 1 | """ 2 | house(x) 3 | 4 | Computes the Householder transformation for input vector x. 5 | """ 6 | function house(x) 7 | """Computes the Householder transformation for input vector x""" 8 | sigma = dot(x[2:end],x[2:end]) 9 | v = copy(x) 10 | 11 | if sigma == 0 12 | beta = 0 13 | return beta, v 14 | end 15 | 16 | sq = sqrt(x[1]^2 + sigma) 17 | if x[1] > 0 18 | v[1] += sq 19 | else 20 | v[1] -= sq 21 | end 22 | 23 | beta = 2.0 / (v[1]^2 + sigma) 24 | 25 | return beta, v 26 | end 27 | 28 | """ 29 | geqrf!(A) 30 | 31 | QR factorization of A using Householder transformation 32 | """ 33 | function geqrf!(A) 34 | m = size(A,1) 35 | n = size(A,2) 36 | vA = zeros(n) 37 | kend = (m > n ? n : m-1) 38 | for k=1:kend 39 | beta, v = house(A[k:end,k]) 40 | for j=k:n 41 | # vA = beta * v^T * A 42 | vA[j] = 0.0 43 | for i=k:m 44 | vA[j] += v[i-k+1] * A[i,j] 45 | end 46 | vA[j] *= beta 47 | end 48 | # A - beta v (v^T A) 49 | for j=k:n, i=k:m 50 | A[i,j] -= v[i-k+1] * vA[j] 51 | end 52 | A[k+1:end,k] = v[2:end] 53 | # Saving v in the lower triangular part of A. 54 | # This was not done here but one can always 55 | # divide v by v[1] such that v[1] = 1 is always true. 56 | # In that case, v[1] does not need to be stored. 57 | end 58 | # Lower triangular part of A: sequence of v vectors 59 | # Upper triangular part: factor R 60 | end 61 | 62 | """ 63 | givens(a, b) 64 | 65 | Computes the Givens transform; a and b should be scalars 66 | """ 67 | function givens(a, b) 68 | if b == 0 69 | c = 1 70 | s = 0 71 | else 72 | if abs(b) > abs(a) 73 | tau = -a/b 74 | s = 1.0/sqrt(1.0+tau*tau) 75 | c = s*tau 76 | else 77 | tau = -b/a 78 | c = 1.0/sqrt(1.0+tau*tau) 79 | s = c*tau 80 | end 81 | end 82 | return (c, s) 83 | end 84 | 85 | """ 86 | geqrfCGS!(A) 87 | 88 | QR factorization of A using Gram-Schmidt 89 | """ 90 | function geqrfCGS!(A) 91 | m = size(A,1) 92 | n = size(A,2) 93 | @assert m >= n 94 | R = zeros(Float64, n,n) 95 | for j=1:n 96 | # Orthogonalize 97 | for i=1:j-1, k=1:m 98 | R[i,j] += A[k,i] * A[k,j] 99 | end 100 | for i=1:j-1, k=1:m 101 | A[k,j] -= A[k,i] * R[i,j] 102 | end 103 | R[j,j] = norm( A[:,j] ) 104 | # Normalize column 105 | A[:,j] /= R[j,j] 106 | end 107 | # A contains the Q factor at the end 108 | return R 109 | end 110 | 111 | """ 112 | geqrfMGS!(A) 113 | 114 | QR factorization of A using modified Gram-Schmidt 115 | """ 116 | function geqrfMGS!(A) 117 | m = size(A,1) 118 | n = size(A,2) 119 | @assert m >= n 120 | R = zeros(Float64, n,n) 121 | for j=1:n 122 | # Orthogonalize 123 | for i=1:j-1 124 | for k=1:m 125 | R[i,j] += A[k,i] * A[k,j] 126 | end 127 | for k=1:m 128 | A[k,j] -= A[k,i] * R[i,j] 129 | end 130 | end 131 | # Normalize column 132 | R[j,j] = norm( A[:,j] ) 133 | A[:,j] /= R[j,j] 134 | end 135 | # A contains the Q factor at the end 136 | return R 137 | end 138 | -------------------------------------------------------------------------------- /src/getrf.jl: -------------------------------------------------------------------------------- 1 | function getrfOuter!(A) 2 | n = size(A,1) 3 | for k=1:n 4 | @assert A[k,k] != 0 5 | for i=k+1:n 6 | A[i,k] /= A[k,k] 7 | end 8 | 9 | # Outer-product of column k and row k 10 | for i=k+1:n 11 | for j=k+1:n 12 | A[i,j] -= A[i,k] * A[k,j] 13 | end 14 | end 15 | end 16 | end 17 | 18 | function getrfAxpy!(A) 19 | n = size(A,1) 20 | for j=1:n 21 | for k=1:j-1 22 | # Linear combination of column j and k 23 | for i=k+1:n 24 | A[i,j] -= A[i,k] * A[k,j] 25 | end 26 | end 27 | 28 | @assert A[j,j] != 0 29 | for i=j+1:n 30 | A[i,j] /= A[j,j] 31 | end 32 | end 33 | end 34 | 35 | function getrfDot!(A) 36 | n = size(A,1) 37 | for j=1:n 38 | # Update above the diagonal 39 | for i=2:j 40 | # Dot product 41 | for k=1:i-1 42 | A[i,j] -= A[i,k] * A[k,j] 43 | end 44 | end 45 | 46 | # Update below the diagonal 47 | @assert A[j,j] != 0 48 | for i=j+1:n 49 | # Dot product 50 | for k=1:j-1 51 | A[i,j] -= A[i,k] * A[k,j] 52 | end 53 | A[i,j] /= A[j,j] 54 | end 55 | end 56 | end 57 | 58 | function getrf!(A) 59 | # Uses pivoting 60 | n = size(A,1) 61 | P = collect(1:n) 62 | for k=1:n 63 | # Find pivot 64 | imx = k - 1 + argmax( abs.(A[k:end,k]) ) # row with largest entry 65 | # Swap rows 66 | for j=1:n 67 | A[k,j],A[imx,j] = A[imx,j],A[k,j] 68 | end 69 | P[[k,imx]] = P[[imx,k]] 70 | 71 | # Proceed with factorization 72 | for i=k+1:n 73 | A[i,k] /= A[k,k] 74 | end 75 | 76 | for j=k+1:n, i=k+1:n 77 | A[i,j] -= A[i,k] * A[k,j] 78 | end 79 | end 80 | return P 81 | end 82 | 83 | function getrfRook!(A) 84 | # Rook pivoting for rank-revealing LU 85 | n = size(A,1) 86 | P_row = collect(1:n); P_col = collect(1:n); 87 | for k=1:n 88 | # Rook pivoting 89 | row = 1; row0 = 0; col = 1; col0 = 0 90 | while row != row0 || col != col0 91 | row0, col0 = row, col # Save old values 92 | row_A = abs.(A[row+k-1, k:end]) # Search in pivots' row 93 | col = argmax(row_A) 94 | col_A = abs.(A[k:end, col+k-1]) # Search in pivot's column 95 | row = argmax(col_A) 96 | end 97 | # If we reach this line, this means that the pivot is the largest 98 | # in its row and column. 99 | row += k-1; col += k-1 100 | # Swap rows and columns 101 | P_row[k], P_row[row] = P_row[row], P_row[k] 102 | P_col[k], P_col[col] = P_col[col], P_col[k] 103 | for j=1:n 104 | A[k,j],A[row,j] = A[row,j],A[k,j] 105 | end 106 | for i=1:n 107 | A[i,k],A[i,col] = A[i,col],A[i,k] 108 | end 109 | 110 | # Perform usual LU step 111 | if A[k,k] != 0 112 | for i=k+1:n 113 | A[i,k] /= A[k,k] 114 | end 115 | for j=k+1:n, i=k+1:n 116 | A[i,j] -= A[i,k] * A[k,j] 117 | end 118 | end 119 | end 120 | return P_row, P_col 121 | end 122 | 123 | function getrs!(A, x) 124 | n = length(b) 125 | # Solve using matrix L 126 | for j = 1:n 127 | for i = j+1:n 128 | x[i] -= A[i,j] * x[j] 129 | end 130 | end 131 | # Solve using matrix U 132 | for j = n:-1:1 133 | x[j] /= A[j,j] 134 | for i = 1:j-1 135 | x[i] -= A[i,j] * x[j] 136 | end 137 | end 138 | end 139 | 140 | function getrs(A, b) 141 | n = length(b) 142 | x = copy(b) 143 | getrs!(A, x) 144 | return x 145 | end 146 | 147 | function getrs(A, P, b) 148 | n = length(b) 149 | @assert length(P) == n 150 | x = Vector{Float64}(undef,n) 151 | for i = 1:n 152 | x[i] = b[P[i]] 153 | end 154 | getrs!(A, x) 155 | return x 156 | end 157 | 158 | function getrs(A, P_row, P_col, b) 159 | n = length(b) 160 | @assert length(P_row) == n && length(P_col) == n 161 | y = Vector{Float64}(undef,n) 162 | for i = 1:n 163 | y[i] = b[P_row[i]] 164 | end 165 | getrs!(A, y) 166 | x = Vector{Float64}(undef,n) 167 | for i = 1:n 168 | x[P_col[i]] = y[i] 169 | end 170 | return x 171 | end 172 | -------------------------------------------------------------------------------- /src/potrf.jl: -------------------------------------------------------------------------------- 1 | function potrf!(A) 2 | n = size(A,1) 3 | for j=1:n 4 | for k=1:j-1, i=j:n 5 | A[i,j] -= A[i,k] * A[j,k] 6 | end 7 | ajj = sqrt(A[j,j]) 8 | for i=j:n 9 | A[i,j] /= ajj 10 | end 11 | end 12 | end 13 | 14 | function potrs(A,x) 15 | n = length(b) 16 | x = copy(b) 17 | # Solve using matrix G 18 | for j = 1:n 19 | x[j] /= A[j,j] 20 | for i = j+1:n 21 | x[i] -= A[i,j] * x[j] 22 | end 23 | end 24 | # Solve using matrix G^T 25 | for i = n:-1:1 26 | for j = i+1:n 27 | x[i] -= A[j,i] * x[j] 28 | end 29 | x[i] /= A[i,i] 30 | end 31 | return x 32 | end 33 | -------------------------------------------------------------------------------- /src/trtrs.jl: -------------------------------------------------------------------------------- 1 | function trtrs(L, b) 2 | n = length(b) 3 | x = copy(b) 4 | for j = 1:n 5 | x[j] = x[j] / L[j,j] 6 | for i = j+1:n 7 | x[i] -= L[i,j] * x[j] 8 | # This is fast because the row index is the inner loop 9 | end 10 | end 11 | return x 12 | end 13 | 14 | function trtrsRow(L, b) # This is the slow implementation 15 | n = length(b) 16 | x = Vector{Float64}(undef,n) 17 | for i=1:n 18 | z = 0.0 19 | for j = 1:i-1 20 | z += L[i,j] * x[j] 21 | end 22 | x[i] = (b[i] - z) / L[i,i] 23 | end 24 | return x 25 | end 26 | -------------------------------------------------------------------------------- /test/runtests.jl: -------------------------------------------------------------------------------- 1 | using Random 2 | using LinearAlgebra 3 | 4 | # Initialize the random number generator 5 | rng = MersenneTwister(2017) 6 | 7 | # Triangular solvers 8 | 9 | include("../src/trtrs.jl") 10 | 11 | # Size of the matrix 12 | n = 32 13 | 14 | # Lower triangular matrix 15 | L = zeros(Float64,n,n) 16 | # Filling the matrix with random integer entries 17 | for j=1:n # Column j 18 | L[j,j] = 1 # Should be non-zero 19 | L[j+1:n,j] = rand(rng, -2:2, n-j) 20 | end 21 | 22 | # Initializing the right-hand side 23 | xe = rand(rng, 0:9, n) # This will be our solution 24 | b = L * xe 25 | 26 | x = trtrsRow(L, b) 27 | # Let's check the result 28 | @assert x == xe 29 | 30 | x = trtrs(L, b) 31 | @assert x == xe 32 | 33 | 34 | # LU solvers 35 | include("../src/getrf.jl") 36 | 37 | # Random initialization of matrix A 38 | L = zeros(Float64,n,n) 39 | U = zeros(Float64,n,n) 40 | for i=1:n 41 | L[i,i] = 1 42 | L[i+1:n,i] = rand(rng, -2:2, n-i) 43 | U[i,i] = rand(rng, 1:2) 44 | U[i,i+1:n] = rand(rng, -2:2, n-i) 45 | end 46 | A = L * U 47 | A0 = copy(A) 48 | 49 | # Initializing the right-hand side 50 | xe = rand(rng, 0:9, n) # This will be our solution 51 | b = A * xe 52 | 53 | # Test our solvers 54 | map([getrfOuter!, getrfAxpy!, getrfDot!]) do solver 55 | A = copy(A0) 56 | solver(A) 57 | # Solve 58 | x = getrs(A, b) 59 | @assert x == xe 60 | end 61 | 62 | 63 | # LU with pivoting 64 | # Random initialization of matrix A 65 | L = zeros(Float64,n,n) 66 | U = zeros(Float64,n,n) 67 | P = randperm(rng,n) # Randow row permutation 68 | for i=1:n 69 | L[P[i],i] = 3 # Largest entry in the column 70 | L[P[i+1:n],i] = rand(rng, -2:2, n-i) 71 | U[i,i] = rand(rng, 1:2) 72 | U[i,i+1:n] = rand(rng, -2:2, n-i) 73 | end 74 | A = L * U 75 | A0 = copy(A) 76 | 77 | # Initializing the right-hand side 78 | xe = rand(rng, 0:9, n) # This will be our solution 79 | b = A * xe 80 | 81 | A = copy(A0) 82 | P = getrf!(A) 83 | # Solve 84 | x = getrs(A, P, b) 85 | @assert x == xe 86 | 87 | 88 | # Rank revealing 89 | # Initialize matrix 90 | d = (1.0/2.0).^(n-1:-1:0) 91 | Q, = qr(rand(rng, n,n)) 92 | A = Q * diagm(0 => d); 93 | 94 | # Testing rook pivoting kernel 95 | b = rand(rng, n) 96 | x1 = (A1 = copy(A); P = getrf!(A1); getrs(A1, P, b)) 97 | x2 = (A1 = copy(A); (P_row, P_col) = getrfRook!(A1); getrs(A1, P_row, P_col, b)) 98 | @assert norm(x1-x2)/norm(x2) < 10*eps(Float64) 99 | 100 | 101 | # Cholesky factorization 102 | include("../src/potrf.jl") 103 | 104 | # Random initialization of matrix A 105 | G = zeros(Float64,n,n) 106 | for i=1:n 107 | G[i,i] = rand(rng, 1:2) 108 | G[i+1:n,i] = rand(rng, -2:2, n-i) 109 | end 110 | A = G * transpose(G) 111 | A0 = copy(A) 112 | 113 | # Initializing the right-hand side 114 | xe = rand(rng, 0:9, n) # This will be our solution 115 | b = A * xe 116 | 117 | A = copy(A0) 118 | potrf!(A) 119 | # Solve 120 | x = potrs(A, b) 121 | @assert norm(x - xe) == 0 122 | 123 | # Cholesky factorization 124 | include("../src/geqrf.jl") 125 | 126 | n = 32 127 | x = rand(rng, n) 128 | beta, v = house(x) 129 | y = zeros(n); y[1] = norm(x) 130 | Px = x - beta * dot(v,x) * v 131 | if Px[1] * y[1] < 0 132 | y = -y 133 | end 134 | @assert norm(Px - y) < 10 * eps(Float64) 135 | 136 | e1 = zeros(n); e1[1] = 1.0 137 | x = zeros(n); x[1] = 2.0 138 | beta, v = house(x) 139 | @assert beta == 0.0 140 | 141 | x[1] = -2.0 142 | beta, v = house(x) 143 | @assert beta == 0.0 144 | 145 | # x[2:end] very small and x1 > 0 146 | x = eps(Float64) * rand(rng, n) 147 | x[1] = 1.0 148 | beta, v = house(x) 149 | y = zeros(n); y[1] = norm(x) 150 | Px = x - beta * dot(v,x) * v 151 | if Px[1] * y[1] < 0 152 | y = -y 153 | end 154 | @assert norm(Px - y) < 8.0*eps(Float64)*eps(Float64) 155 | 156 | # x[2:end] very small and x1 < 0 157 | x = eps(Float64) * rand(rng, n) 158 | x[1] = -1.0 159 | beta, v = house(x) 160 | y = zeros(n); y[1] = norm(x) 161 | Px = x - beta * dot(v,x) * v 162 | if Px[1] * y[1] < 0 163 | y = -y 164 | end 165 | @assert norm(Px - y) == 0 166 | 167 | # QR factorization 168 | 169 | function test_QR(A) 170 | m = size(A,1) 171 | n = size(A,2) 172 | Q,R = qr(copy(A)) 173 | geqrf!(A) 174 | for i=1:min(m,n) 175 | if i <= min(m,n) 176 | if R[i,i] * A[i,i] < 0 177 | R[i,:] = -R[i,:] 178 | end 179 | end 180 | @assert norm(R[i,i:end] - A[i,i:end]) < 1e3*eps(Float64) 181 | end 182 | end 183 | 184 | # Square matrix 185 | n = 64 186 | test_QR(rand(rng, n, n)) 187 | 188 | # Fat matrix 189 | m = 32; n = 64 190 | test_QR(rand(rng, m, n)) 191 | 192 | m = 2; n = 1024 193 | test_QR(rand(rng, m, n)) 194 | 195 | # Thin matrix 196 | m = 64; n = 32 197 | test_QR(rand(rng, m, n)) 198 | 199 | m = 1024; n = 2 200 | test_QR(rand(rng, m, n)) 201 | 202 | # Test Givens' rotations 203 | n = 64 204 | A = triu(rand(rng, n,n),-1) 205 | Q,R = qr(copy(A)) 206 | for k=1:n-1 207 | c, s = givens(A[k,k], A[k+1,k]) 208 | # Apply the Givens rotation to row k and k+1 209 | for j=k:n 210 | A[k,j], A[k+1,j] = 211 | ( c * A[k,j] - s * A[k+1,j], 212 | s * A[k,j] + c * A[k+1,j] ) 213 | end 214 | end 215 | for i=1:n 216 | if R[i,i] * A[i,i] < 0 217 | R[i,:] = -R[i,:] 218 | end 219 | @assert norm(R[i,i:end] - A[i,i:end]) < 1e2*eps(Float64) 220 | end 221 | 222 | 223 | # CGS 224 | function orthogonal_matrix(m,n) 225 | # Building an orthogonal matrix Q 226 | Q = zeros(m,n) 227 | for j=0:n-1, i=0:m-1 228 | Q[i+1,j+1] = cos(π*(2i+1)*j/2m) 229 | end 230 | for j=1:n 231 | Q[:,j] /= norm(Q[:,j]) 232 | end 233 | return Q 234 | end 235 | 236 | # Testing QR factorization using CGS 237 | n = 16 238 | m = 32 239 | 240 | # Building an orthogonal matrix Q 241 | Q = orthogonal_matrix(m,n) 242 | 243 | # Initializing an upper triangular matrix R 244 | R = triu(Float64[ i/j for i=1:n, j=1:n ]) 245 | 246 | # Matrix A 247 | A = Q*R 248 | # QR factorization 249 | RGS = geqrfCGS!(A) 250 | # The factor Q is stored in A 251 | 252 | # These matrices should now be equal 253 | @assert norm(Q-A) < 1e2 * eps(Float64) 254 | @assert norm(R-RGS) < 1e2 * eps(Float64) 255 | 256 | # MGS 257 | 258 | # Matrix A 259 | A = Q*R 260 | # QR factorization 261 | RGS = geqrfMGS!(A) 262 | # The factor Q is stored in A 263 | 264 | # These matrices should now be equal 265 | @assert norm(Q-A) < 1e2 * eps(Float64) 266 | @assert norm(R-RGS) < 1e2 * eps(Float64) 267 | 268 | 269 | #= 270 | 271 | HDF5 does not install correctly on Travis; skipping this for now 272 | 273 | INFO: Building HDF5 274 | Installing dependency hdf5-tools via `apt-get install hdf5-tools`: 275 | E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied) 276 | E: Unable to lock the administration directory (/var/lib/dpkg/), are you root? 277 | ================================[ ERROR: HDF5 ]================================= 278 | 279 | # Test HDF5 280 | n = 512 281 | A = rand(rng, n, n) 282 | Pkg.add("HDF5") 283 | using HDF5 284 | h5open("data.h5", "w") do file 285 | @write file A # alternatively, say "@write file A" 286 | end 287 | A0 = h5read("data.h5", "A") 288 | @assert norm(A - A0) == 0 289 | 290 | =# 291 | --------------------------------------------------------------------------------