|
| 1 | +struct SymmetricToeplitzPlusHankel{T} <: AbstractMatrix{T} |
| 2 | + v::Vector{T} |
| 3 | + n::Int |
| 4 | +end |
| 5 | + |
| 6 | +function SymmetricToeplitzPlusHankel(v::Vector{T}) where T |
| 7 | + n = (length(v)+1)÷2 |
| 8 | + SymmetricToeplitzPlusHankel{T}(v, n) |
| 9 | +end |
| 10 | + |
| 11 | +size(A::SymmetricToeplitzPlusHankel{T}) where T = (A.n, A.n) |
| 12 | +getindex(A::SymmetricToeplitzPlusHankel{T}, i::Integer, j::Integer) where T = A.v[abs(i-j)+1] + A.v[i+j-1] |
| 13 | + |
| 14 | +struct SymmetricBandedToeplitzPlusHankel{T} <: BandedMatrices.AbstractBandedMatrix{T} |
| 15 | + v::Vector{T} |
| 16 | + n::Int |
| 17 | + b::Int |
| 18 | +end |
| 19 | + |
| 20 | +function SymmetricBandedToeplitzPlusHankel(v::Vector{T}, n::Integer) where T |
| 21 | + SymmetricBandedToeplitzPlusHankel{T}(v, n, length(v)-1) |
| 22 | +end |
| 23 | + |
| 24 | +size(A::SymmetricBandedToeplitzPlusHankel{T}) where T = (A.n, A.n) |
| 25 | +function getindex(A::SymmetricBandedToeplitzPlusHankel{T}, i::Integer, j::Integer) where T |
| 26 | + v = A.v |
| 27 | + if abs(i-j) < length(v) |
| 28 | + if i+j-1 ≤ length(v) |
| 29 | + v[abs(i-j)+1] + v[i+j-1] |
| 30 | + else |
| 31 | + v[abs(i-j)+1] |
| 32 | + end |
| 33 | + else |
| 34 | + zero(T) |
| 35 | + end |
| 36 | +end |
| 37 | +bandwidths(A::SymmetricBandedToeplitzPlusHankel{T}) where T = (A.b, A.b) |
| 38 | + |
| 39 | +# |
| 40 | +# Jac*W-W*Jac' = G*J*G' |
| 41 | +# This returns G and J, where J = [0 I; -I 0], respecting the skew-symmetry of the right-hand side. |
| 42 | +# |
| 43 | +function compute_skew_generators(A::SymmetricToeplitzPlusHankel{T}) where T |
| 44 | + v = A.v |
| 45 | + n = size(A, 1) |
| 46 | + J = [zero(T) one(T); -one(T) zero(T)] |
| 47 | + G = zeros(T, n, 2) |
| 48 | + G[n, 1] = one(T) |
| 49 | + u2 = reverse(v[2:n+1]) |
| 50 | + u2[1:n-1] .+= v[n+1:2n-1] |
| 51 | + G[:, 2] .= -u2 |
| 52 | + G, J |
| 53 | +end |
| 54 | + |
| 55 | +function cholesky(A::SymmetricToeplitzPlusHankel{T}) where T |
| 56 | + n = size(A, 1) |
| 57 | + G, J = compute_skew_generators(A) |
| 58 | + L = zeros(T, n, n) |
| 59 | + r = A[:, 1] |
| 60 | + r2 = zeros(T, n) |
| 61 | + l = zeros(T, n) |
| 62 | + v = zeros(T, n) |
| 63 | + col1 = zeros(T, n) |
| 64 | + STPHcholesky!(L, G, r, r2, l, v, col1, n) |
| 65 | + return Cholesky(L, 'L', 0) |
| 66 | +end |
| 67 | + |
| 68 | +function STPHcholesky!(L::Matrix{T}, G, r, r2, l, v, col1, n) where T |
| 69 | + @inbounds @simd for k in 1:n-1 |
| 70 | + x = sqrt(r[1]) |
| 71 | + for j in 1:n-k+1 |
| 72 | + L[j+k-1, k] = l[j] = r[j]/x |
| 73 | + end |
| 74 | + for j in 1:n-k+1 |
| 75 | + v[j] = G[j, 1]*G[1,2]-G[j,2]*G[1,1] |
| 76 | + end |
| 77 | + F12 = k == 1 ? T(2) : T(1) |
| 78 | + r2[1] = (r[2] - v[1])/F12 |
| 79 | + for j in 2:n-k |
| 80 | + r2[j] = (r[j+1]+r[j-1] + r[1]*col1[j] - col1[1]*r[j] - v[j])/F12 |
| 81 | + end |
| 82 | + r2[n-k+1] = (r[n-k] + r[1]*col1[n-k+1] - col1[1]*r[n-k+1] - v[n-k+1])/F12 |
| 83 | + cst = r[2]/x |
| 84 | + for j in 1:n-k |
| 85 | + r[j] = r2[j+1] - cst*l[j+1] |
| 86 | + end |
| 87 | + for j in 1:n-k |
| 88 | + col1[j] = -F12/x*l[j+1] |
| 89 | + end |
| 90 | + c1 = G[1, 1] |
| 91 | + c2 = G[1, 2] |
| 92 | + for j in 1:n-k |
| 93 | + G[j, 1] = G[j+1, 1] - l[j+1]*c1/x |
| 94 | + G[j, 2] = G[j+1, 2] - l[j+1]*c2/x |
| 95 | + end |
| 96 | + end |
| 97 | + L[n, n] = sqrt(r[1]) |
| 98 | +end |
| 99 | + |
| 100 | +function cholesky(A::SymmetricBandedToeplitzPlusHankel{T}) where T |
| 101 | + n = size(A, 1) |
| 102 | + b = A.b |
| 103 | + R = BandedMatrix{T}(undef, (n, n), (0, bandwidth(A, 2))) |
| 104 | + r = A[1:b+2, 1] |
| 105 | + r2 = zeros(T, b+3) |
| 106 | + l = zeros(T, b+3) |
| 107 | + col1 = zeros(T, b+2) |
| 108 | + SBTPHcholesky!(R, r, r2, l, col1, n, b) |
| 109 | + return Cholesky(R, 'U', 0) |
| 110 | +end |
| 111 | + |
| 112 | +function SBTPHcholesky!(R::BandedMatrix{T}, r, r2, l, col1, n, b) where T |
| 113 | + @inbounds @simd for k in 1:n |
| 114 | + x = sqrt(r[1]) |
| 115 | + for j in 1:b+1 |
| 116 | + l[j] = r[j]/x |
| 117 | + end |
| 118 | + for j in 1:min(n-k+1, b+1) |
| 119 | + R[k, j+k-1] = l[j] |
| 120 | + end |
| 121 | + F12 = k == 1 ? T(2) : T(1) |
| 122 | + r2[1] = r[2]/F12 |
| 123 | + for j in 2:b+1 |
| 124 | + r2[j] = (r[j+1]+r[j-1] + r[1]*col1[j] - col1[1]*r[j])/F12 |
| 125 | + end |
| 126 | + r2[b+2] = (r[b+1] + r[1]*col1[b+2] - col1[1]*r[b+2])/F12 |
| 127 | + cst = r[2]/x |
| 128 | + for j in 1:b+2 |
| 129 | + r[j] = r2[j+1] - cst*l[j+1] |
| 130 | + end |
| 131 | + for j in 1:b+2 |
| 132 | + col1[j] = -F12/x*l[j+1] |
| 133 | + end |
| 134 | + end |
| 135 | +end |
0 commit comments