Notebook 19 – Math 2121, Fall 2020
Below are functions and examples covering the most important algorithms from the whole course.
xxxxxxxxxxusing LinearAlgebra1.0e-9xxxxxxxxxxDEFAULT_TOLERANCE = 1e-9rowop_swap (generic function with 1 method)xxxxxxxxxxbegin # the functions here are all helper methods used internally # for the implementation of RREF, pivot_positions, etc. # it's not recommended to use these functions directly function find_leading(A, row=1, tol=DEFAULT_TOLERANCE) (m, n) = size(A) for col=1:n if abs(A[row, col]) > tol return col end end return 0 end function find_nonzeros_in_column(A, row_start, col, tol=DEFAULT_TOLERANCE) (m, n) = size(A) return [i for i=row_start:m if abs(A[i, col]) > tol] end function rowop_replace(A, source_row, target_row, scalar_factor) source_row != target_row for j=1:size(A)[2] A[target_row,j] += A[source_row,j] * scalar_factor end return A end function rowop_scale(A, target_row, scalar_factor) scalar_factor != 0 for j=1:size(A)[2] A[target_row,j] *= scalar_factor end A end function rowop_swap(A, s, t) for j=1:size(A)[2] A[t,j], A[s,j] = A[s,j], A[t,j] end A endendRREF (generic function with 2 methods)xxxxxxxxxxfunction RREF(A, tol=DEFAULT_TOLERANCE) # returns reduced echelon form of input matrix A A = float(copy(A)) (m, n) = size(A) row = 1 for col=1:n nonzeros = find_nonzeros_in_column(A, row, col, tol) if length(nonzeros) == 0 continue end i = nonzeros[1] for j=nonzeros[2:end] if abs(A[i, col]) < abs(A[j, col]) i = j end end if abs(A[i, col] - 1) < tol A[i, col] = 1 else A = rowop_scale(A, i, 1 / A[i, col]) end for j=nonzeros if i != j A = rowop_replace(A, i, j, -A[j, col]) end end if i != row A = rowop_swap(A, row, i) end row += 1 end for row=m:-1:1 l = find_leading(A, row, tol) if l > 0 for k=1:row - 1 if abs(A[k,l]) > tol rowop_replace(A, row, k, -A[k,l]) end end end end # round entries to give nicer output; could omit this step for row=1:m for col=1:n if abs(A[row,col] - round(A[row,col])) < tol A[row,col] = round(A[row,col]) end end end return Aendpivot_positions (generic function with 2 methods)xxxxxxxxxxfunction pivot_positions(A, tol=DEFAULT_TOLERANCE) # returns list of pivot positions in input matrix A rref = RREF(A, tol) return [ (i, find_leading(rref, i)) for i=1:size(A)[1] if find_leading(rref, i) > 0 ]endsolve_linear_system (generic function with 2 methods)xxxxxxxxxxfunction solve_linear_system(A, b, tol=DEFAULT_TOLERANCE) # returns a solution to Ax = b if one exists, otherwise throws as error M = hcat([A b]) rref = RREF(M) pivots = pivot_positions(M, tol) n = size(A)[2] solution_exists = ! ((n + 1) in [j for (i, j) = pivots]) solution_exists sol = zeros(n, 1) for (i, j) = pivots sol[j] = rref[i, end] end return solendcolumn_space_basis (generic function with 2 methods)xxxxxxxxxxfunction column_space_basis(A, tol=DEFAULT_TOLERANCE) # returns a matrix whose columns are a basis for the column space A # the columns in the returned matrix are a subset of the columns of A pivots = pivot_positions(A, tol) ans = zeros(size(A)[1], 0) for (i, j) = pivots ans = hcat(ans, A[1:end, j]) end return ansendnull_space_basis (generic function with 2 methods)xxxxxxxxxxfunction null_space_basis(A, tol=DEFAULT_TOLERANCE) # returns a matrix whose columns are a basis for the nullspace of A n = size(A)[2] pivots = pivot_positions(A, tol) rref = RREF(A, tol) free = [j for j=1:n if ! any(j == pivot[2] for pivot=pivots)] ans = zeros(n, length(free)) for k = 1:length(free) ans[free[k], k] = 1 for (i, j) = pivots ans[j, k] = -rref[i, free[k]] end end return ansendis_diagonalizable (generic function with 1 method)xxxxxxxxxxfunction is_diagonalizable(A) # returns true if A is diagonalizable m, n = size(A) return m == n && rank(eigen(A).vectors) == mendgram_schmidt_process (generic function with 1 method)xxxxxxxxxxfunction gram_schmidt_process(A; orthonormal=false) # returns matrix whose columns are the output of the Gram-Schmidt process # applied to the columns of the input matrix `A`. If the parameter `orthonormal` # is set to true, then these columns are normalized to have unit length m, n = size(A) Q = zeros(m, n) for j=1:n a, u = A[1:m, j], A[1:m, j] for i = 1:(j - 1) v = Q[1:m, i] u -= v .* dot(a, v) / dot(v, v) end Q[1:m, j] = orthonormal ? u / norm(u) : u end return Qendorthogonal_projection (generic function with 1 method)xxxxxxxxxxfunction orthogonal_projection(v, A) # returns orthogonal projection of v onto Col A basis = column_space_basis(A) Q = gram_schmidt_process(basis; orthonormal=true) return Q * transpose(Q) * vendleast_squares_solution (generic function with 2 methods)xxxxxxxxxxfunction least_squares_solution(A, b, tol=DEFAULT_TOLERANCE) # returns a single least-squares solution to Ax = b return solve_linear_system(transpose(A) * A, transpose(A) * b, tol)endpseudoinverse (generic function with 2 methods)xxxxxxxxxxfunction pseudoinverse(A, tol=DEFAULT_TOLERANCE) U, singular_values, V = svd(A, full=true) S = transpose(zeros(size(A))) for i=1:length(singular_values) if abs(singular_values[i]) > tol S[i, i] = 1 / singular_values[i] end end return V * S * transpose(U)end random_matrix (generic function with 2 methods)xxxxxxxxxxfunction random_matrix(m, n, rank=-1) # returns a random m-by-n matrix with the given `rank`. # if the input `rank` is not set, then returned matrix will # have full rank which is min(m, n) # the function is mostly for examples # there is a tiny probability that the returned # matrix will not have the expected rank rank = rank == -1 ? minimum([m n]) : rank 0 <= rank <= minimum([m n]) ans = zeros(m, n) for i=1:rank ans += rand(-1:0.0001:1, m, 1) * rand(-1:0.0001:1, 1, n) end return 10 * ansendVariable names in Pluto
Pluto notebooks do not allow you to redefine variables names, so a variable can only be assigned once. You won't have this problem if you just import this notebook into Julia without using Pluto, which you can do by opening Julia in your terminal from the directory that contains this file and then running
include("19_Math2121_Fall2020.jl")
To make it easier to extend the examples in this notebook, the variable names used below all begin with underscores, like _A, _b, etc., so as not to crowd the usual namespace of variables. There is no need to continue this convention if you add to this notebook.
Numerical tolerance
Warning: it is a tricky problem to determine when floating point operations should give the value tol that we use to determine when a floating point x number is zero, by checking if abs(x) < tol. Whether or not you get sensible output from these functions may depend on the value of tol. You can set this manually by passing in a value for tol. For example:
RREF(A) # uses default tolerance
RREF(A, 1e-10) # uses tol = 1e-10
That said, most of the time we don't have to worry about this parameter.
By default tol is set to 1.0e-9.
Matrix operations
4×4 Array{Float64,2}:
0.377141 -6.76723 5.62943 7.26387
2.51621 1.98108 0.956934 -0.534678
2.2948 -3.02732 4.62686 4.53796
-0.785845 -4.35937 2.60611 4.05582xxxxxxxxxx# creates a 4-by-4 matrix of rank 2_A = random_matrix(4, 4, 2)4×4 Transpose{Float64,Array{Float64,2}}:
0.377141 2.51621 2.2948 -0.785845
-6.76723 1.98108 -3.02732 -4.35937
5.62943 0.956934 4.62686 2.60611
7.26387 -0.534678 4.53796 4.05582xxxxxxxxxxtranspose(_A)4
4
xxxxxxxxxxsize(_A)4xxxxxxxxxxsize(_A)[1]4xxxxxxxxxxsize(_A)[2]4×1 Array{Int64,2}:
0
2
2
-2xxxxxxxxxx_b = rand(-2:2, 4, 1)4×1 Array{Int64,2}:
-2
2
1
2xxxxxxxxxx_c = rand(-2:2, 4, 1)4×1 Array{Float64,2}:
-16.803342999999998
6.945391
-5.8768449999999985
-11.618156999999998xxxxxxxxxx# matrix multiplication_A * _b4×1 Array{Int64,2}:
-2
4
3
0xxxxxxxxxx# vector addition_b + _c4×1 Array{Int64,2}:
0
4
2
-4xxxxxxxxxx# multiply corresponding entries of two matrices/vectors of same size together# note this is NOT matrix multiplication_b .* _c4×4 Diagonal{Int64,Array{Int64,1}}:
0 ⋅ ⋅ ⋅
⋅ 2 ⋅ ⋅
⋅ ⋅ 2 ⋅
⋅ ⋅ ⋅ -2xxxxxxxxxx# create diagonal matrix from vectorDiagonal(_b[:])4×4 Array{Float64,2}:
0.377141 -6.76723 5.62943 7.26387
2.51621 1.98108 0.956934 -0.534678
2.2948 -3.02732 4.62686 4.53796
-0.785845 -4.35937 2.60611 4.05582xxxxxxxxxx_A2×2 Array{Float64,2}:
2.51621 1.98108
2.2948 -3.02732xxxxxxxxxx# submatrices _A[2:3, 1:2] # 2-by-2 submatrix-6.76723
1.98108
-3.02732
-4.35937
xxxxxxxxxx_A[:, 2] # column 22.51621
1.98108
0.956934
-0.534678
xxxxxxxxxx_A[2, :] # row 2-3.0273244999999993xxxxxxxxxx_A[3, 2] # entry in row 3, column 23×3 Array{Int64,2}:
1 2 3
3 4 2
0 1 0xxxxxxxxxx_square_matrix = [1 2 3; 3 4 2; 0 1 0]7.0xxxxxxxxxxdet(_square_matrix)5xxxxxxxxxxtr(_square_matrix)3×6 Array{Int64,2}:
1 2 3 1 0 0
3 4 2 0 1 0
0 1 0 0 0 1xxxxxxxxxxhcat(_square_matrix, I)3×6 Array{Float64,2}:
1.0 0.0 0.0 -0.285714 0.428571 -1.14286
0.0 1.0 0.0 0.0 0.0 1.0
0.0 0.0 1.0 0.428571 -0.142857 -0.285714xxxxxxxxxxRREF(hcat(_square_matrix, I))3×3 Array{Float64,2}:
-0.285714 0.428571 -1.14286
-0.0 0.0 1.0
0.428571 -0.142857 -0.285714xxxxxxxxxx_square_matrix^-13×3 Array{Int64,2}:
7 13 7
15 24 17
3 4 2xxxxxxxxxx_square_matrix^2Row reduction
4×4 Array{Float64,2}:
0.377141 -6.76723 5.62943 7.26387
2.51621 1.98108 0.956934 -0.534678
2.2948 -3.02732 4.62686 4.53796
-0.785845 -4.35937 2.60611 4.05582xxxxxxxxxx_A4×4 Array{Float64,2}:
1.0 0.0 0.991744 0.606026
-0.0 1.0 -0.776596 -1.03962
0.0 0.0 0.0 0.0
0.0 0.0 0.0 -0.0xxxxxxxxxxRREF(_A)1
1
2
2
xxxxxxxxxxpivot_positions(_A)4×2 Array{Float64,2}:
0.377141 -6.76723
2.51621 1.98108
2.2948 -3.02732
-0.785845 -4.35937xxxxxxxxxxcolumn_space_basis(_A)4×2 Array{Float64,2}:
-0.991744 -0.606026
0.776596 1.03962
1.0 0.0
0.0 1.0xxxxxxxxxxnull_space_basis(_A)4×2 Array{Float64,2}:
0.0 0.0
0.0 1.11022e-16
8.88178e-16 0.0
4.44089e-16 -8.88178e-16xxxxxxxxxx_A * null_space_basis(_A) # should be close to zero2xxxxxxxxxxrank(_A)falsexxxxxxxxxx# to detect if some vectors are linearly independent, assemble the vectors# as the columns of a matrix A and check whether rank(A) == size(A)[2]rank(_A) == size(_A)[2] # columns of matrix not linearly dependentSolving linear systems
4×4 Array{Float64,2}:
-3.57174 -7.35301 -3.42201 3.81875
5.69388 6.33517 -1.96969 1.70079
7.69715 3.05182 -10.2608 10.2693
-11.0038 -13.5657 1.98354 -1.37461xxxxxxxxxx_M = random_matrix(4, 4, 2)4×1 Array{Float64,2}:
-5.958647520884568
5.114630507983956
2.4275068057374454
-10.96086766946625xxxxxxxxxx_test_vec = _M * rand(size(_M)[2], 1)4×1 Array{Float64,2}:
-0.007336740627503224
0.8139325807742661
0.0
0.0xxxxxxxxxx# solving _M * v == _test_vec_test_sol = solve_linear_system(_M, _test_vec)4×1 Array{Float64,2}:
-5.95865
5.11463
2.42751
-10.96094×1 Array{Float64,2}:
-5.95865
5.11463
2.42751
-10.9609xxxxxxxxxx# these vectors should be the same, meaning our solution is a valid solution _M * _test_sol, _test_vec2xxxxxxxxxx_dim_nul_M = size(null_space_basis(_M))[2]4×1 Array{Float64,2}:
0.04221002984635365
0.7791793775967624
0.06048291925849458
0.03362373291973686xxxxxxxxxx# to generate arbitrary solutions to Mx = b, just add to any given solution# linear combinations of the basis element for Nul(M)_other_sol = _test_sol + null_space_basis(_M) * rand(_dim_nul_M, 1)4×1 Array{Float64,2}:
-5.95865
5.11463
2.42751
-10.96094×1 Array{Float64,2}:
-5.95865
5.11463
2.42751
-10.9609xxxxxxxxxx# these should still be equal_M * _other_sol, _test_vec-0.684311
-0.80944
1.0
0.0
x
# beware: if b is not in Col A then A \ b gives nonsensical output or an error# the vector below is the first element of a basis for the null space of A^T# the null space of A^T is the orthogonal complement of the column space of A# hence this vector is *not* contained in the column space of A_vec_not_in_column_space = null_space_basis(transpose(_A))[:, 1]x
# method `solve_linear_system` will raise an error if no solution exists# solve_linear_system(_A, _vec_not_in_column_space)Complex numbers
5 + 6imx
5 + 6 * im5x
real(5 + 6 * im)6x
imag(5 + 6 * im)5 - 6imx
conj(5 + 6 * im)9 + 8imx
(5 + 6 * im) + (4 + 2 * im)8 + 34imxxxxxxxxxx(5 + 6 * im) * (4 + 2 * im)1.6 + 0.7imxxxxxxxxxx(5 + 6 * im) / (4 + 2 * im)7.810249675906654xxxxxxxxxxabs(5 + 6 * im)truex
abs(5 + 6 * im) == sqrt((5 + 6 * im) * conj(5 + 6 * im))2 + 3imxxxxxxxxxx_z = 2 + 3 * im2×2 Array{Int64,2}:
2 -3
3 2xxxxxxxxxx[real(_z) -imag(_z); imag(_z) real(_z)]Eigenvalues and eigenvectors
4×4 Array{Float64,2}:
6.0118 -5.45765 -5.14928 -0.975021
2.02876 0.464118 4.78987 -3.90178
-4.63644 -6.61134 -3.49888 -9.10147
10.7833 4.37568 -1.54777 13.5531xxxxxxxxxx# random 4-by-4 matrix of rank 3_B = random_matrix(4, 4, 3) # diagonalizable4×4 Array{Int64,2}:
1 2 3 4
0 1 2 3
0 0 1 2
0 0 0 1xxxxxxxxxx_C = [1 2 3 4; 0 1 2 3; 0 0 1 2; 0 0 0 1] # not diagonalizabletruexxxxxxxxxxis_diagonalizable(_B)falsexxxxxxxxxxis_diagonalizable(_C)-7.42946e-15+0.0im
0.254658-6.67987im
0.254658+6.67987im
16.0208+0.0im
xxxxxxxxxx# eigenvalus of a matrixeigen(_B).values-4.90617e-15+0.0im
0.254658-6.67987im
0.254658+6.67987im
16.0208+0.0im
eigen(transpose(_B)).values # same eigenvalues as _B, some may be complex numbers4×4 Array{Complex{Float64},2}:
-0.172547+0.0im -0.0297456+0.418441im -0.0297456-0.418441im 0.260016+0.0im
-0.734333+0.0im -0.671807-0.0im -0.671807+0.0im -0.289454+0.0im
0.495264+0.0im 0.118236+0.491568im 0.118236-0.491568im -0.359243+0.0im
0.430925+0.0im 0.0936165-0.329111im 0.0936165+0.329111im 0.848264+0.0imxxxxxxxxxx# eigenvectors of a matrixeigen(_B).vectors4×4 Array{Complex{Float64},2}:
-0.435685+0.0im -0.160302+0.442395im -0.160302-0.442395im 0.761407+0.0im
0.215249+0.0im 0.591921-0.0im 0.591921+0.0im 0.00637559+0.0im
0.711081+0.0im 0.440853+0.198845im 0.440853-0.198845im -0.246823+0.0im
0.508144+0.0im 0.437822-0.0513943im 0.437822+0.0513943im 0.599414+0.0imxxxxxxxxxxeigen(transpose(_B)).vectors # different eigenvectors from B1.0
1.0
1.0
1.0
xxxxxxxxxxeigen(_C).values4×4 Array{Float64,2}:
1.0 -1.0 1.0 -1.0
0.0 1.11022e-16 -1.11022e-16 1.11022e-16
0.0 0.0 1.2326e-32 -1.2326e-32
0.0 0.0 0.0 1.36846e-48xxxxxxxxxxeigen(_C).vectors4×4 Array{Complex{Float64},2}:
-0.172547+0.0im -0.0297456+0.418441im -0.0297456-0.418441im 0.260016+0.0im
-0.734333+0.0im -0.671807-0.0im -0.671807+0.0im -0.289454+0.0im
0.495264+0.0im 0.118236+0.491568im 0.118236-0.491568im -0.359243+0.0im
0.430925+0.0im 0.0936165-0.329111im 0.0936165+0.329111im 0.848264+0.0im4×4 Diagonal{Complex{Float64},Array{Complex{Float64},1}}:
-7.42946e-15+0.0im ⋅ ⋅ ⋅
⋅ 0.254658-6.67987im ⋅ ⋅
⋅ ⋅ 0.254658+6.67987im ⋅
⋅ ⋅ ⋅ 16.0208+0.0imxxxxxxxxxx# if matrix is diagonalizable_P, _D = eigen(_B).vectors, Diagonal(eigen(_B).values)2.830578330796744e-14xxxxxxxxxxnorm(_P * _D * _P^-1 - _B) # if this is very small, then B equals P * D * P^-14×4 Array{Float64,2}:
12.0236 -3.42889 -9.78571 9.80823
-3.42889 0.928236 -1.82147 0.473901
-9.78571 -1.82147 -6.99775 -10.6492
9.80823 0.473901 -10.6492 27.1062xxxxxxxxxx# if matrix is symmetric, the eigenvectors will be orthonormal already _symmetric = _B + transpose(_B)4×4 Array{Float64,2}:
0.323252 0.234151 0.793089 0.4601
0.196796 0.918942 -0.341333 -0.0175587
0.911403 -0.24589 -0.12072 -0.307098
0.161629 -0.200641 -0.489826 0.832881xxxxxxxxxx_eigenvectors = eigen(_symmetric).vectors4×4 Array{Float64,2}:
1.0 -7.95206e-18 1.78588e-16 5.29273e-17
-7.95206e-18 1.0 9.42052e-17 -2.45753e-17
1.78588e-16 9.42052e-17 1.0 -2.18036e-16
5.29273e-17 -2.45753e-17 -2.18036e-16 1.0xxxxxxxxxx# shows that eigenvectors are already orthonormaltranspose(_eigenvectors) * _eigenvectorsInner products and orthogonal projections
3.4641016151377544xxxxxxxxxx# length of a vectornorm(_b) # returns the same thing as sqrt(sum(_b .* _b))2xxxxxxxxxx# dot productdot(_b, _c) # returns the same thing as sum(_b .* _c)5×3 Array{Float64,2}:
-2.43045 2.55144 -6.17487
-3.3509 9.80676 4.91765
0.676911 -5.97453 -7.44102
-6.03631 5.55339 -7.68659
-0.555015 -2.87016 -7.55904xxxxxxxxxx# creates 5-by-3 matrix with rank 3, meaning columns are linearly independent_basis = random_matrix(5, 3, 3)3xxxxxxxxxxrank(_basis) # should be 35×3 Array{Float64,2}:
-2.43045 -0.80474 -2.92988
-3.3509 5.17955 -0.557834
0.676911 -5.03979 -0.0171806
-6.03631 -2.78207 1.61207
-0.555015 -3.63658 -1.35563xxxxxxxxxx_orthogonal_basis = gram_schmidt_process(_basis)3×3 Array{Float64,2}:
54.3388 1.29626e-14 -2.6544e-14
1.29626e-14 73.8394 -7.95571e-15
-2.6544e-14 -7.95571e-15 13.3321xxxxxxxxxx# diagonal entries should be positive and off-diagonal entries close to zerotranspose(_orthogonal_basis) * _orthogonal_basis5×3 Array{Float64,2}:
-0.32971 -0.0936508 -0.802416
-0.454575 0.602765 -0.152776
0.0918283 -0.5865 -0.00470532
-0.818872 -0.32376 0.441503
-0.0752921 -0.423203 -0.37127xxxxxxxxxx# setting orthonormal=true will return matrix with unit length orthogonal columns_orthonormal_basis = gram_schmidt_process(_basis, orthonormal=true)3×3 Array{Float64,2}:
1.0 -6.35764e-17 3.31234e-16
-6.35764e-17 1.0 2.36696e-16
3.31234e-16 2.36696e-16 1.0xxxxxxxxxx# diagonal entries should be 1.0 and off-diagonal entries close to zerotranspose(_orthonormal_basis) * _orthonormal_basis5×1 Array{Int64,2}:
2
-2
-1
-4
-1xxxxxxxxxx_v = rand(-5:5, 5, 1)5×1 Array{Float64,2}:
0.9157012881291711
-0.6344293450681221
-0.19998600158597624
-4.355743010034982
0.3483621248361716xxxxxxxxxx_v_hat = orthogonal_projection(_v, _basis)5×4 Array{Float64,2}:
1.0 0.0 0.0 2.82911
0.0 1.0 0.0 1.27133
-0.0 -0.0 1.0 -0.736532
0.0 0.0 0.0 -0.0
0.0 0.0 0.0 0.0xxxxxxxxxx# if _v_hat is in the span of _basis, then there should be no pivots in last columnRREF(hcat([_basis _v_hat])) 3×1 Array{Float64,2}:
1.3131522849785959e-15
3.2528969620086696e-15
5.634650153790826e-15xxxxxxxxxx# entries should be close to zero as _v - _v_hat is orthogonal to span of _basistranspose(_basis) * (_v - _v_hat)4×5 Array{Float64,2}:
1.0 0.0 0.991744 0.606026 0.914466
-0.0 1.0 -0.776596 -1.03962 0.0978552
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 -0.0 -0.0xxxxxxxxxxRREF(hcat([_A orthogonal_projection(_b, _A)]))Least-squares solutions
4×1 Array{Float64,2}:
0.9144659461447051
0.09785518382324851
0.0
0.0xxxxxxxxxx_least_squares_solution = least_squares_solution(_A, _b)4×1 Array{Float64,2}:
0.9144659461447051
0.09785518382324851
0.0
0.0xxxxxxxxxx# returns same thing as least_squares_solution(_A, _b)solve_linear_system(transpose(_A) * _A, transpose(_A) * _b)4×1 Array{Float64,2}:
11.1937
6.62625
5.95538
-0.1050764×1 Array{Float64,2}:
11.1937
6.62625
5.95538
-0.105076xxxxxxxxxxtranspose(_A) * _A * _least_squares_solution, transpose(_A) * _b2xxxxxxxxxx_dim_nul = size(null_space_basis(transpose(_A) * _A))[2]4×1 Array{Float64,2}:
-0.31484149960282926
1.493477642011315
0.7712839971084404
0.7662893290500663xxxxxxxxxx# to form an arbitrary least-squares solution to Ax = b, just add# to a single least-squares solution any linear combination of a # basis for the null space of transpose(A) * A_another_least_squares_solution = _least_squares_solution + null_space_basis(transpose(_A) * _A) * rand(_dim_nul, 1)4×1 Array{Float64,2}:
-0.317326
2.49485
1.80228
-1.145224×1 Array{Float64,2}:
-0.317326
2.49485
1.80228
-1.14522xxxxxxxxxx_A * _another_least_squares_solution, _A * _least_squares_solutionSingular value decompositions
4
5
xxxxxxxxxx_m, _n = 4, 54×5 Array{Float64,2}:
-3.4233 7.59986 0.0224568 -8.46628 5.98055
-4.28842 -0.502641 5.19409 1.47641 7.49157
1.62312 -1.38475 -1.15415 1.33975 -2.83553
-3.4536 0.860067 3.53104 -0.335714 6.03324xxxxxxxxxx_X = random_matrix(_m, _n, 2)SVD{Float64,Float64,Array{Float64,2}}
U factor:
4×4 Array{Float64,2}:
0.718735 0.661076 -0.209989 0.0479817
0.479036 -0.664983 -0.512437 -0.256378
-0.247517 0.0170652 -0.62418 0.74084
0.438953 -0.347108 0.551101 0.61897
singular values:
4-element Array{Float64,1}:
16.002967090628864
10.105428798819345
1.1687268383051277e-15
4.133566008353511e-16
Vt factor:
5×5 Array{Float64,2}:
-0.401955 0.371292 0.271195 -0.365978 0.702202
0.179619 0.498363 -0.463561 -0.637207 -0.313766
0.537101 -0.502761 0.344718 -0.564462 0.145963
-0.65493 -0.578057 -0.327772 -0.339399 -0.119548
0.297923 -0.163886 -0.696634 0.161919 0.610628xxxxxxxxxx_U, _singular_values, _V = svd(_X, full=true)4×5 Array{Float64,2}:
16.003 0.0 0.0 0.0 0.0
0.0 10.1054 0.0 0.0 0.0
0.0 0.0 1.16873e-15 0.0 0.0
0.0 0.0 0.0 4.13357e-16 0.0xxxxxxxxxxbegin _Sigma = zeros(size(_X)) for i=1:length(_singular_values) _Sigma[i, i] = _singular_values[i] end _Sigmaend5.393785051703609e-15xxxxxxxxxx# should be very small valuenorm(_U * _Sigma * transpose(_V) - _X)5×4 Array{Float64,2}:
-0.00630251 -0.023852 0.00652033 -0.0171951
0.0492776 -0.0216802 -0.00490116 -0.00693373
-0.0181451 0.0386225 -0.00497738 0.0233614
-0.0581218 0.0309759 0.00458449 0.0118486
0.0110118 0.0416671 -0.0113908 0.0300385xxxxxxxxxx_X_plus = pseudoinverse(_X)8.40622e-15
5.89168e-17
xxxxxxxxxx# should be very small values norm(_X * _X_plus * _X - _X), norm(_X_plus * _X * _X_plus - _X_plus)