In [1]:
## Reduction to tridiagonal form!
# We can exactly construct a sequence of orthogonal transformations
# to produce a tridiagonal matrix from an arbitrary symmetric matrix.
In [2]:
## How Householder Matrices can be used to zero out
using LinearAlgebra
using SparseArrays
function housevec(x)
  v = copy(x)
  normx = norm(x)
  s = -sign(x[1])*normx
  v[1] = v[1] -s

  y = v*(v'*x)
  beta = -1/(s*v[1])
  return v,beta,s
end

""" Return the householder matrix to zero out below the ith row and jth column """
function housemat(A,i,j)
  v,beta,s = housevec(A[i:end,j])
  H = Matrix(1.0I,size(A)...)
  H[i:end,i:end] = H[i:end,i:end] - beta*v*v'
  return H,v,beta,s
end

A = randn(5,5)
A = A + A'

H = housemat(A,2,1)[1]
display(H*A*H')
5×5 Matrix{Float64}:
 -0.779083      3.77777   -1.58747e-17  -1.21998e-16  -9.8519e-17
  3.77777       0.175024  -0.106515     -0.40171      -0.634336
 -1.58747e-17  -0.106515   0.477158      1.43702       2.49054
 -1.21998e-16  -0.40171    1.43702      -0.93729       0.626665
 -9.8519e-17   -0.634336   2.49054       0.626665      0.838653
In [3]:
##
B = H*A*H'
H2 = housemat(B,3,2)[1]
display(H2*B*H2')
5×5 Matrix{Float64}:
 -0.779083      3.77777      1.49262e-16  -4.52965e-17   2.26e-17
  3.77777       0.175024     0.758352      9.67017e-17   2.18976e-16
  1.49262e-16   0.758352     1.68758       1.90662       1.9899
 -4.52965e-17  -1.43206e-17  1.90662      -0.76218       0.32621
  2.26e-17      2.46872e-17  1.9899        0.32621      -0.546874
In [4]:
##
Q = H2*H
display(Q*A*Q')
5×5 Matrix{Float64}:
 -0.779083     3.77777      -9.04361e-17  -1.58106e-17   8.29753e-17
  3.77777      0.175024      0.758352      1.17925e-16   2.44333e-16
 -9.04361e-17  0.758352      1.68758       1.90662       1.9899
 -1.58106e-17  1.40027e-17   1.90662      -0.76218       0.32621
  8.29753e-17  2.60237e-16   1.9899        0.32621      -0.546874
In [5]:
##
spones(A::SparseMatrixCSC) = begin fill!(A.nzval, one(eltype(A))); A end
using Plots
pyplot()
using Printf
function animate_myhess(A)
  n = size(A,1)
  V = zeros(n,n) # space to store the householder vectors
  for k = 1:n-2
    x = A[k+1:n,k]
    vk = copy(x)
    vk[1] = x[1] + sign(x[1])*norm(x)
    vk = vk/norm(vk)
    V[k+1:n,k] = vk # store V
    A[k+1:n,k:n] -= 2*vk*(vk'*A[k+1:n,k:n])
    A[1:n,k+1:n] -= 2*(A[1:n,k+1:n]*vk)*vk'
    At = A
    At[abs.(At).<1e-12] .= 0
    spy(-spones(dropzeros!(sparse(At))),markersize = 6.0,
      colorbar=false,axis=false,markercolor=:blue)

    title!(@sprintf("Step %i",k))
    gui()
    sleep(1.5)
  end
  return A,V
end
A = randn(37,37)
A = A + A'
animate_myhess(A)
ArgumentError: Package PyPlot not found in current path.
- Run `import Pkg; Pkg.add("PyPlot")` to install the PyPlot package.

Stacktrace:
  [1] macro expansion
    @ ./loading.jl:2296 [inlined]
  [2] macro expansion
    @ ./lock.jl:273 [inlined]
  [3] __require(into::Module, mod::Symbol)
    @ Base ./loading.jl:2271
  [4] #invoke_in_world#3
    @ ./essentials.jl:1089 [inlined]
  [5] invoke_in_world
    @ ./essentials.jl:1086 [inlined]
  [6] require(into::Module, mod::Symbol)
    @ Base ./loading.jl:2260
  [7] top-level scope
    @ ~/.julia/packages/Plots/FFuQi/src/backends.jl:883
  [8] eval
    @ ./boot.jl:430 [inlined]
  [9] _initialize_backend(pkg::Plots.PyPlotBackend)
    @ Plots ~/.julia/packages/Plots/FFuQi/src/backends.jl:882
 [10] backend(pkg::Plots.PyPlotBackend)
    @ Plots ~/.julia/packages/Plots/FFuQi/src/backends.jl:245
 [11] pyplot()
    @ Plots ~/.julia/packages/Plots/FFuQi/src/backends.jl:86
 [12] top-level scope
    @ In[5]:4
In [6]:
##

function myhess(A)
  # myhess Implement algorithm 26.1 from Trefethen and Bau
  n = size(A,1)
  V = zeros(n,n) # space to store the householder vectors
  for k = 1:n-2
    x = A[k+1:n,k]
    vk = copy(x)
    vk[1] = x[1] + sign(x[1])*norm(x)
    vk = vk/norm(vk)
    V[k+1:n,k] = vk # store V
    A[k+1:n,k:n] -= 2*vk*(vk'*A[k+1:n,k:n])
    A[1:n,k+1:n] -= 2*(A[1:n,k+1:n]*vk)*vk'
  end
  return A,V
end
Out[6]:
myhess (generic function with 1 method)
In [7]:
## show that RQ given QR preserves tridiagonal
A = randn(5,5)
A = A + A'
T = myhess(A)[1]
T = map!(x -> abs(x) > 10*eps(1.0) ? x : 0.0, T, T)
Q,R = qr(T)
display(R*Q)
Q
5×5 Matrix{Float64}:
 -0.528236  -2.89719   -4.44089e-16  1.18401e-15  -1.01855e-15
 -2.89719    0.993984   2.48371      4.44089e-16  -7.63916e-16
  0.0        2.48371    0.718501     2.81394       4.44089e-16
  0.0        0.0        2.81394      0.189853      1.46831
  0.0        0.0        0.0          1.46831       0.859402
Out[7]:
5×5 LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}, Matrix{Float64}}