From a99bbfff8b52805342a1b54bc4f7564f6af7d5dc Mon Sep 17 00:00:00 2001 From: Mikael Slevinsky Date: Wed, 27 Mar 2019 17:42:04 -0500 Subject: [PATCH 1/5] initial dump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit adds functions and data structures required to implement Algorithms 6.1 & 6.2 in http://arxiv.org/abs/1903.08538 - deflation criteria (§ 6.3) - two types of symmetric matrices used for intermediate computations and processing: `SymBandedPlusBulge` and `SymBlockArrowHead` - *the* algorithms (symmetric_eigen, § 6.1 & 6.4) - a data structure to store the factored form of the eigenvectors, EmbeddedBlockOperator (§ 6.5) still needs tests and improvements --- README.md | 40 +- src/ApproxFun.jl | 4 +- src/LinearAlgebra/LinearAlgebra.jl | 4 + src/LinearAlgebra/SymBandedPlusBulge.jl | 176 +++++++++ src/LinearAlgebra/SymBlockArrowHead.jl | 252 +++++++++++++ src/LinearAlgebra/deflationcheck.jl | 45 +++ src/Operators/Operator.jl | 1 + src/Operators/banded/DiagonalOperator.jl | 0 src/Operators/eigen.jl | 347 ++++++++++++++++++ .../general/EmbeddedBlockOperator.jl | 134 +++++++ src/Operators/general/general.jl | 1 + 11 files changed, 982 insertions(+), 22 deletions(-) create mode 100644 src/LinearAlgebra/SymBandedPlusBulge.jl create mode 100644 src/LinearAlgebra/SymBlockArrowHead.jl create mode 100644 src/LinearAlgebra/deflationcheck.jl delete mode 100644 src/Operators/banded/DiagonalOperator.jl create mode 100644 src/Operators/eigen.jl create mode 100644 src/Operators/general/EmbeddedBlockOperator.jl diff --git a/README.md b/README.md index ec28fbbf7..89bbe4064 100644 --- a/README.md +++ b/README.md @@ -241,26 +241,26 @@ end This solves the confined anharmonic oscillator, `[-𝒟² + V(x)] u = λu`, where `u(±10) = 0`, `V(x) = ω*x² + x⁴`, and `ω = 25`. ```julia - n = 3000 - ω = 25.0 - d = Segment(-10..10) - S = Ultraspherical(0.5, d) - NS = NormalizedPolynomialSpace(S) - V = Fun(x->ω*x^2+x^4, S) - L = -Derivative(S, 2) + V - C = Conversion(domainspace(L), rangespace(L)) - B = Dirichlet(S) - QS = QuotientSpace(B) - Q = Conversion(QS, S) - D1 = Conversion(S, NS) - D2 = Conversion(NS, S) - R = D1*Q - P = cache(PartialInverseOperator(C, (0, ApproxFun.bandwidth(L, 1) + ApproxFun.bandwidth(R, 1) + ApproxFun.bandwidth(C, 2)))) - A = R'D1*P*L*D2*R - B = R'R - SA = Symmetric(A[1:n,1:n], :L) - SB = Symmetric(B[1:n,1:n], :L) - λ = eigvals(SA, SB)[1:round(Int, 3n/5)] +n = 3000 +ω = 25.0 +d = Segment(-10..10) +S = Ultraspherical(0.5, d) +NS = NormalizedPolynomialSpace(S) +V = Fun(x->ω*x^2+x^4, S) +L = -Derivative(S, 2) + V +C = Conversion(domainspace(L), rangespace(L)) +B = Dirichlet(S) +QS = QuotientSpace(B) +Q = Conversion(QS, S) +D1 = Conversion(S, NS) +D2 = Conversion(NS, S) +R = D1*Q +P = cache(PartialInverseOperator(C, (0, ApproxFun.bandwidth(L, 1) + ApproxFun.bandwidth(R, 1) + ApproxFun.bandwidth(C, 2)))) +A = R'D1*P*L*D2*R +B = R'R +SA = Symmetric(A[1:n,1:n], :L) +SB = Symmetric(B[1:n,1:n], :L) +λ = eigvals(SA, SB)[1:round(Int, 3n/5)] ``` diff --git a/src/ApproxFun.jl b/src/ApproxFun.jl index 4f393329c..28cfe8b3d 100644 --- a/src/ApproxFun.jl +++ b/src/ApproxFun.jl @@ -27,14 +27,14 @@ import Base: values, convert, getindex, setindex!, *, +, -, ==, <, <=, >, |, !, getproperty, findfirst, unsafe_getindex, fld, cld, div, real, imag, @_inline_meta, eachindex, firstindex, lastindex, keys, isreal, OneTo, Array, Vector, Matrix, view, ones, @propagate_inbounds, print_array, - split + split, checkbounds import Base.Broadcast: BroadcastStyle, Broadcasted, AbstractArrayStyle, broadcastable, DefaultArrayStyle, broadcasted import Statistics: mean -import LinearAlgebra: BlasInt, BlasFloat, norm, ldiv!, mul!, det, eigvals, dot, cross, +import LinearAlgebra: BlasInt, BlasFloat, norm, ldiv!, mul!, lmul!, det, eigvals, dot, cross, qr, qr!, rank, isdiag, istril, istriu, issymmetric, ishermitian, Tridiagonal, diagm, diagm_container, factorize, nullspace, Hermitian, Symmetric, adjoint, transpose, char_uplo diff --git a/src/LinearAlgebra/LinearAlgebra.jl b/src/LinearAlgebra/LinearAlgebra.jl index ef6992036..539a5b28d 100644 --- a/src/LinearAlgebra/LinearAlgebra.jl +++ b/src/LinearAlgebra/LinearAlgebra.jl @@ -19,3 +19,7 @@ include("RaggedMatrix.jl") include("rowvector.jl") + +include("deflationcheck.jl") +include("SymBandedPlusBulge.jl") +include("SymBlockArrowHead.jl") diff --git a/src/LinearAlgebra/SymBandedPlusBulge.jl b/src/LinearAlgebra/SymBandedPlusBulge.jl new file mode 100644 index 000000000..37fb74a1e --- /dev/null +++ b/src/LinearAlgebra/SymBandedPlusBulge.jl @@ -0,0 +1,176 @@ +""" + Represent a symmetric banded matrix plus a bulge: + [ □ ◺ + ◹ □ ◺ + ◹ □ □ ◺ + □ □ □ + ◹ □ □ ◺ + ◹ □ ◺ + ◹ □ ] +""" +mutable struct SymBandedPlusBulge{T} <: AbstractMatrix{T} + A::Matrix{T} + b::Int + bulge::Int +end + +size(A::SymBandedPlusBulge) = size(A.A) + +function getindex(A::SymBandedPlusBulge{T}, i::Integer, j::Integer) where T + b = A.b + bulge = A.bulge + col1 = bulge - 2b + col2 = bulge - b + row1 = col1 - b + row2 = col2 - 2b + AA = A.A + if -b ≤ i-j ≤ b + if j ≥ i + return AA[i,j] + else + return AA[j,i] + end + elseif 1 ≤ j-col1 ≤ b && 1 ≤ i-row1 ≤ b && j-col1 > i-row1 + return AA[i,j] + elseif 1 ≤ j-col2 ≤ b && 1 ≤ i-row2-(j-col2-1) ≤ b + return AA[i,j] + elseif 1 ≤ i-col1 ≤ b && 1 ≤ j-row1 ≤ b && i-col1 > j-row1 + return AA[j,i] + elseif 1 ≤ i-col2 ≤ b && 1 ≤ j-row2-(i-col2-1) ≤ b + return AA[j,i] + else + return zero(T) + end +end + +setindex!(A::SymBandedPlusBulge{T}, v, i::Integer, j::Integer) where T = setindex!(A.A, v, i, j) + +function computeHouseholder!(A::SymBandedPlusBulge{T}, w::Vector{T}, col::Int) where T + b = A.b + corr = zero(T) + fill!(w, corr) + row = col - b + @inbounds for i = max(row-b, 1):row + corr += abs2(A[i, col]) + w[i] = A[i, col] + end + normw = sqrt(corr) + corr = copysign(normw, A[row, col]) + w[row] += corr + normw = sqrt(normw^2+corr*muladd(T(2),w[row],-corr)) + if normw == zero(normw) + return w + else + return LinearAlgebra.__normalize!(w, normw) + end +end + +function applyHouseholder!(w::Vector{T}, wQ::Vector{T}, Q::Matrix{T}, bulge::Int, b::Int) where T + sw = max(bulge - 2b, 1) + fw = min(bulge - b, size(Q, 1)) + s = 1 + f = size(Q, 1) + + # wQ = (w^⊤ Q)^⊤ + fill!(wQ, zero(T)) + @inbounds for j = s:f + wQj = zero(T) + @simd for i = sw:fw + wQj += w[i]*Q[i,j] + end + wQ[j] = wQj + end + + # H Q = Q - 2/dot(w, w) (w (w^⊤ Q)) + # twodivnrmw = 2/dot(w, w) + twodivnrmw = T(2) + @inbounds for j = s:f + wQj = wQ[j] + @simd for i = sw:fw + Q[i,j] -= twodivnrmw*w[i]*wQj + end + end + #Q .= Q - 2*w*(w'Q) + + Q +end + +function similarity!(w::Vector{T}, v::Vector{T}, Aw::Vector{T}, A::SymBandedPlusBulge{T}) where T + bulge = A.bulge + b = A.b + sw = max(bulge - 2b, 1) + fw = min(bulge - b, size(A, 1)) + sv = max(bulge - 3b, 1) + fv = min(bulge, size(A, 1)) + s = min(sv, sw) + f = max(fv, fw) + + # Aw = A*w + fill!(Aw, zero(T)) + @inbounds for j = sw:fw + wj = w[j] + @simd for i = sv:fv + Aw[i] += A[i,j]*wj + end + end + + # v = Aw - dot(w, Aw)/dot(w, w)*w + fill!(v, zero(T)) + # cst = -dot(w, Aw)/dot(w, w) + cst = -dot(w, Aw) + @inbounds for i = sv:fv + v[i] = muladd(cst, w[i], Aw[i]) + end + + # H A H^⊤ = A - 2/dot(w, w) ( vw^⊤ + wv^⊤ ) + # twodivnrmw = 2/dot(w, w) + twodivnrmw = T(2) + @inbounds for j = s:f + vj = v[j] + wj = w[j] + @simd for i = s:f + A[i,j] -= twodivnrmw*(v[i]*wj+w[i]*vj) + end + end + + A.bulge -= 1 + A +end + +function chasebulge!(w::Vector{T}, v::Vector{T}, Aw::Vector{T}, A::SymBandedPlusBulge{T}) where T + bulge = A.bulge + b = A.b + for k = bulge:-1:b+1 + computeHouseholder!(A, w, k) + similarity!(w, v, Aw, A) + end + + A +end + +function chasebulge!(A::SymBandedPlusBulge{T}) where T + w = zeros(T, size(A, 2)) + v = zero(w) + Aw = zero(w) + chasebulge!(w, v, Aw, A) +end + +function chasebulge!(w::Vector{T}, v::Vector{T}, Aw::Vector{T}, A::SymBandedPlusBulge{T}, wQ::Vector{T}, Q::Matrix{T}) where T + bulge = A.bulge + b = A.b + for k = bulge:-1:b+1 + computeHouseholder!(A, w, k) + applyHouseholder!(w, wQ, Q, k, b) + similarity!(w, v, Aw, A) + end + + A, Q +end + +function chasebulge!(A::SymBandedPlusBulge{T}, Q::Matrix{T}) where T + w = zeros(T, size(A, 2)) + v = zero(w) + Aw = zero(w) + wQ = zero(w) + chasebulge!(w, v, Aw, A, wQ, Q) +end diff --git a/src/LinearAlgebra/SymBlockArrowHead.jl b/src/LinearAlgebra/SymBlockArrowHead.jl new file mode 100644 index 000000000..1f54d2c98 --- /dev/null +++ b/src/LinearAlgebra/SymBlockArrowHead.jl @@ -0,0 +1,252 @@ +""" + Represent a symmetric block arrowhead matrix: + [A B + B^⊤ C] +""" +struct SymBlockArrowHead{T,M<:AbstractMatrix{T}} <: AbstractMatrix{T} + A::M + B::Matrix{T} + C::Matrix{T} + function SymBlockArrowHead(A::M, B::Matrix{T}, C::Matrix{T}) where {T, M<:AbstractMatrix{T}} + @assert size(A, 1) == size(A, 2) == size(B, 1) + @assert size(B, 2) == size(C, 1) == size(C, 2) + new{T, M}(A, B, C) + end +end + +size(A::SymBlockArrowHead) = (s = sum(size(A.B)); (s, s)) + +function getindex(A::SymBlockArrowHead{T}, i::Integer, j::Integer) where T + @boundscheck checkbounds(A, i, j) + if i ≤ size(A.A, 1) && j ≤ size(A.A, 2) + A.A[i,j] + elseif i ≤ size(A.A, 1) && j > size(A.A, 2) + return A.B[i, j - size(A.A, 2)] + elseif j ≤ size(A.A, 2) && i > size(A.A, 1) + return A.B[j, i - size(A.A, 1)] + elseif size(A.A, 1) < i ≤ size(A, 1) && size(A.A, 2) < j ≤ size(A, 2) + return A.C[i - size(A.A, 1), j - size(A.A, 2)] + else + return zero(T) + end +end + +function setindex!(A::SymBlockArrowHead{T}, v, i::Integer, j::Integer) where T + if i ≤ size(A.A, 1) && j ≤ size(A.A, 2) + A.A[i,j] = v + elseif i ≤ size(A.A, 1) && j > size(A.A, 2) + return A.B[i, j - size(A.A, 2)] = v + elseif j ≤ size(A.A, 2) && i > size(A.A, 1) + return A.B[j, i - size(A.A, 1)] = v + elseif size(A.A, 1) < i ≤ size(A, 1) && size(A.A, 2) < j ≤ size(A, 2) + return A.C[i - size(A.A, 1), j - size(A.A, 2)] = v + else + throw(error("Index out of reach.")) + end +end + +function computeHouseholder!(A::SymBlockArrowHead{T,SymBandedPlusBulge{T}}, w::Vector{T}, row::Int, col::Int) where T + b = A.A.b + corr = zero(T) + fill!(w, corr) + @inbounds for i = max(row-b, 1):row + corr += abs2(A[i, col]) + w[i] = A[i, col] + end + normw = sqrt(corr) + corr = copysign(normw, A[row, col]) + w[row] += corr + normw = sqrt(normw^2+corr*muladd(T(2),w[row],-corr)) + if normw == zero(normw) + return w + else + return LinearAlgebra.__normalize!(w, normw) + end +end + +function applyHouseholder!(w::Vector{T}, wQ::Vector{T}, Q::Matrix{T}, bulge::Int, b::Int, row::Int) where T + sw = max(bulge - b, 1) + fw = min(bulge, size(Q, 1)) + s = 1 + f = size(Q, 1) + + # wQ = (w^⊤ Q)^⊤ + fill!(wQ, zero(T)) + @inbounds for j = s:f + wQj = zero(T) + @simd for i = sw:fw + wQj += w[i]*Q[i,j] + end + wQ[j] = wQj + end + + # H Q = Q - 2/dot(w, w) (w (w^⊤ Q)) + # twodivnrmw = 2/dot(w, w) + twodivnrmw = T(2) + @inbounds for j = s:f + wQj = wQ[j] + @simd for i = sw:fw + Q[i,j] -= twodivnrmw*w[i]*wQj + end + end + #Q .= Q - 2*w*(w'Q) + + Q +end + +function similarity!(w::Vector{T}, v::Vector{T}, Aw::Vector{T}, A::SymBlockArrowHead{T,SymBandedPlusBulge{T}}, row::Int) where T + bulge = A.A.bulge + b = A.A.b + sw = max(row-b, 1) + fw = min(row, size(A, 2)) + sv = max(bulge - 3b, 1) + fv = min(bulge, size(A, 1)) + sv1 = size(A, 2) - b + 1 + fv1 = size(A, 2) + s = min(sv, sw) + f = max(fv, fw) + + # Aw = A*w + fill!(Aw, zero(T)) + @inbounds for j = sw:fw + wj = w[j] + @simd for i = sv:fv + Aw[i] += A[i,j]*wj + end + @simd for i = sv1:fv1 + Aw[i] += A[i,j]*wj + end + end + + # v = Aw - dot(w, Aw)/dot(w, w)*w + fill!(v, zero(T)) + # cst = -dot(w, Aw)/dot(w, w) + cst = -dot(w, Aw) + @inbounds @simd for i = sv:fv + v[i] = muladd(cst, w[i], Aw[i]) + end + @inbounds @simd for i = sv1:fv1 + v[i] = muladd(cst, w[i], Aw[i]) + end + + # H A H^⊤ = A - 2/dot(w, w) ( vw^⊤ + wv^⊤ ) + # twodivnrmw = 2/dot(w, w) + twodivnrmw = T(2) + @inbounds for j = s:f + vj = v[j] + wj = w[j] + @simd for i = s:f + A[i,j] -= twodivnrmw*(v[i]*wj+w[i]*vj) + end + end + @inbounds for j = sv1:fv1 + vj = v[j] + wj = w[j] + @simd for i = s:f + A[i,j] -= twodivnrmw*(v[i]*wj+w[i]*vj) + end + end + + A +end + +function symblockarrowhead2symbanded!(w::Vector{T}, v::Vector{T}, Aw::Vector{T}, A::SymBlockArrowHead{T,SymBandedPlusBulge{T}}) where T + n = size(A, 2) + b = A.A.b + + for j = 1:b-1 + computeHouseholder!(A, w, b+1-j, n+1-j) + similarity!(w, v, Aw, A, b+1-j) + end + + for m = 2:floor(Int, n÷b)-1 + A.A.bulge = m*A.A.b + for j = 1:b + computeHouseholder!(A, w, m*b+1-j, n+1-j) + similarity!(w, v, Aw, A, m*b+1-j) + end + chasebulge!(w, v, Aw, A.A) + end + + A +end + +function symblockarrowhead2symbanded!(A::SymBlockArrowHead{T,SymBandedPlusBulge{T}}) where T + w = zeros(T, size(A, 2)) + v = zero(w) + Aw = zero(w) + symblockarrowhead2symbanded!(w, v, Aw, A) +end + +function symblockarrowhead2symbanded!(w::Vector{T}, v::Vector{T}, Aw::Vector{T}, A::SymBlockArrowHead{T,SymBandedPlusBulge{T}}, wQ::Vector{T}, Q::Matrix{T}) where T + n = size(A, 2) + b = A.A.b + + for j = 1:b-1 + computeHouseholder!(A, w, b+1-j, n+1-j) + applyHouseholder!(w, wQ, Q, b+1-j, b, n+1-j) + similarity!(w, v, Aw, A, b+1-j) + end + + for m = 2:floor(Int, n÷b)-1 + A.A.bulge = m*A.A.b + for j = 1:b + computeHouseholder!(A, w, m*b+1-j, n+1-j) + applyHouseholder!(w, wQ, Q, m*b+1-j, b, n+1-j) + similarity!(w, v, Aw, A, m*b+1-j) + end + chasebulge!(w, v, Aw, A.A, wQ, Q) + end + + A +end + +function symblockarrowhead2symbanded!(A::SymBlockArrowHead{T,SymBandedPlusBulge{T}}, Q::Matrix{T}) where T + w = zeros(T, size(A, 2)) + v = zero(w) + Aw = zero(w) + wQ = zero(w) + symblockarrowhead2symbanded!(w, v, Aw, A, wQ, Q) +end + +function structured_cholesky!(A::SymBlockArrowHead{T,Diagonal{T,V}}) where {T,V} + D = A.A + d = D.diag + d .= sqrt.(d) + B = A.B + ldiv!(D, B) + A.C .= cholesky(A.C-B'B).factors + UpperTriangular(A) +end + +function structured_invcholesky!(A::SymBlockArrowHead{T, Diagonal{T,V}}) where {T,V} + D = A.A + d = D.diag + d .= sqrt.(d) + B = A.B + ldiv!(D, B) + A.C .= cholesky(A.C-B'B).factors + # A, B, C are the old D^{1/2}, E, F. + d .= inv.(d) + A.C .= inv(UpperTriangular(A.C)).data + B .= -lmul!(D, B*A.C) + UpperTriangular(A) +end + +function congruence!(L::SymBlockArrowHead{T,M}, C::SymBlockArrowHead{T, Diagonal{T,V}}) where {T, M, V} + R = structured_invcholesky!(C) + A = L.A + B = L.B + CC = L.C + D = R.data.A + E = R.data.B + F = UpperTriangular(R.data.C) + DAD = D*A*D + DAEpDBF = D*(A*E + B*F) + EtBF = E'B*F + EtAEpEtBFpFtBtEpFtCF = E'A*E + F'CC*F + (EtBF+EtBF') + A .= DAD + B .= DAEpDBF + CC .= EtAEpEtBFpFtBtEpFtCF + L, C +end diff --git a/src/LinearAlgebra/deflationcheck.jl b/src/LinearAlgebra/deflationcheck.jl new file mode 100644 index 000000000..2b988706a --- /dev/null +++ b/src/LinearAlgebra/deflationcheck.jl @@ -0,0 +1,45 @@ +function deflationcheck(M::Matrix, Λ::Vector, tol::Real, verbose::Bool) + b, k = size(M) + @assert k == length(Λ) + maxΛ = maximum(abs, Λ) + minΛ = minimum(abs, Λ) + j = 1 + maxΛ2j = (abs(Λ[j]) + minΛ)*(abs(Λ[j]) + maxΛ) + FroM2 = colnorm2(M, j) + while FroM2 ≤ tol*maxΛ2j && j < k + j += 1 + maxΛ2j = max(maxΛ2j, (abs(Λ[j]) + minΛ)*(abs(Λ[j]) + maxΛ)) + FroM2 += colnorm2(M, j) + verbose && println(" j = ", j, ", ||M_{1:b,1:j}||_F^2 = ", FroM2, ", ϵ (|λ_j| + |λ_min|)(|λ_j| + |λ_max|) = ", tol*maxΛ2j, ".") + end + j-1 +end + +function deflationcheck(M::Matrix, N::Matrix, Λ::Vector, tol::Real, verbose::Bool) + b, k = size(M) + β, κ = size(N) + @assert b == β && k == κ + @assert k == length(Λ) + maxΛ = maximum(abs, Λ) + minΛ = minimum(abs, Λ) + j = 1 + maxΛj = abs2(Λ[j]) + maxΛ2j = (abs(Λ[j]) + minΛ)*(abs(Λ[j]) + maxΛ) + FroMN2 = colnorm2(M, j) + maxΛj*colnorm2(N, j) + while FroMN2 ≤ tol*maxΛ2j && j < k + j += 1 + maxΛj = max(maxΛj, abs2(Λ[j])) + maxΛ2j = max(maxΛ2j, (abs(Λ[j]) + minΛ)*(abs(Λ[j]) + maxΛ)) + FroMN2 += colnorm2(M, j) + maxΛj*colnorm2(N, j) + verbose && println(" j = ", j, ", ||M_{1:b,1:j}||_F^2 + |λ_j|^2||N_{1:b,1:j}||_F^2 = ", FroMN2, ", ϵ (|λ_j| + |λ_min|)(|λ_j| + |λ_max|) = ", tol*maxΛ2j, ".") + end + j-1 +end + +function colnorm2(M::Matrix, J::Int) + ret = zero(real(eltype(M))) + @inbounds for i = 1:size(M, 1) + ret += abs2(M[i, J]) + end + ret +end diff --git a/src/Operators/Operator.jl b/src/Operators/Operator.jl index 6abd4a0a4..0872a7078 100644 --- a/src/Operators/Operator.jl +++ b/src/Operators/Operator.jl @@ -608,6 +608,7 @@ include("systems.jl") include("qr.jl") include("nullspace.jl") +include("eigen.jl") diff --git a/src/Operators/banded/DiagonalOperator.jl b/src/Operators/banded/DiagonalOperator.jl deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/Operators/eigen.jl b/src/Operators/eigen.jl new file mode 100644 index 000000000..3f6d07c7c --- /dev/null +++ b/src/Operators/eigen.jl @@ -0,0 +1,347 @@ +const sqrt2m1 = sqrt(2)-1 + +function symmetric_eigen(L::Operator{T}, n::Int; verbose::Bool = false, tol::Real = eps(T), CONST::Real = sqrt2m1) where T + # ndef is the number of deflated eigenvalues + # ALLEIGS is a container for the converged eigenvalues + # b is the bandwidth of the symmetric banded operator + # (k, k) are the dimensions of the deflation window + ds = domainspace(L) + rs = rangespace(L) + ndef = 0 + ALLEIGS = T[] + ALLQ = EmbeddedBlockOperator{T,Matrix{T},typeof(ds),typeof(rs)}[] + b = maximum(bandwidths(L)) + k = 2b + + # We start by determining a good deflation window. + + Lk = Symmetric(L[1:k,1:k])#SymBandedMatrix(L, b, 1:k) + Lb = L[k+1:k+b,1:k] + Λ, Q = eigen(Lk) + M = Lb*Q + + j = 0 + while j < 1 + k *= 2 + Lk = Symmetric(L[1:k,1:k])#SymBandedMatrix(L, b, 1:k) + Lb = L[k+1:k+b,1:k] + Λ, Q = eigen(Lk) + M = Lb*Q + j = deflationcheck(M, Λ, tol^2, verbose)÷b*b + verbose && println("This is the size of the deflation window: ",k," and this is the number of deflated eigenvalues: ",j) + end + + SBA = SymBlockArrowHead(SymBandedPlusBulge(Matrix(Diagonal(Λ[j+1:k])), b, b), Matrix(M[:,j+1:k]'), Matrix(L[k+1:k+b,k+1:k+b])) + + push!(ALLEIGS, Λ[1:j]...) + push!(ALLQ, EmbeddedBlockOperator(Q, ndef, ds, rs)) + ndef += j + + w = zeros(T, k+b) + v = zero(w) + Lw = zero(w) + wQ = zero(w) + F = Eigen(zeros(T, k), zeros(T, k, k)) + + while ndef < n + # With the dimensions of the deflation window, (k, k), found & fixed, + # we now create a SymBlockArrowHead matrix upon which we are able to + # perform similarity transformations to return to banded form. + + Q = Matrix{T}(I, k, k) + symblockarrowhead2symbanded!(w, v, Lw, SBA, wQ, Q) + push!(ALLQ, EmbeddedBlockOperator(Matrix(Q'), ndef, ds, rs)) + + replenishLk!(Lk, SBA, L, ndef) + replenishLb!(Lb, L, ndef, k, b) + + if j < CONST*k + verbose && println("Failed to deflate! Doubling the dimensions of the deflation window.") + Lk = [Lk L[ndef+1:ndef+k,ndef+k+1:ndef+2k]; L[ndef+k+1:ndef+2k,ndef+1:ndef+2k]] + k *= 2 + Lk = SymBandedMatrix(Lk, b, 1:k) + Lb = L[ndef+k+1:ndef+k+b, ndef+1:ndef+k] + M = zeros(T, b, k) + w = zeros(T, k+b) + v = zero(w) + Lw = zero(w) + wQ = zero(w) + end + + Λ, Q = eigen(Lk) + + mul!(fill!(M, zero(T)), Lb, Q) + j = deflationcheck(M, Λ, tol^2, verbose)÷b*b + verbose && println("This is the size of the deflation window: ",k," and this is the number of deflated eigenvalues: ",j) + + SBA = SymBlockArrowHead(SymBandedPlusBulge(Matrix(Diagonal(Λ[j+1:k])), b, b), Matrix(M[:,j+1:k]'), Matrix(L[ndef+k+1:ndef+k+b,ndef+k+1:ndef+k+b])) + + push!(ALLEIGS, Λ[1:j]...) + push!(ALLQ, EmbeddedBlockOperator(Q, ndef, ds, rs)) + ndef += j + end + + ALLEIGS, ALLQ +end + +function symmetric_eigen(L::Operator{T}, C::Operator{T}, n::Int; verbose::Bool = false, tol::Real = eps(T), CONST::Real = sqrt2m1) where T + # ndef is the number of deflated eigenvalues + # ALLEIGS is a container for the converged eigenvalues + # b is the bandwidth of the symmetric banded operator + # (k, k) are the dimensions of the deflation window + ds = domainspace(L) + rs = rangespace(L) + ndef = 0 + ALLEIGS = T[] + ALLV = EmbeddedBlockOperator{T,Matrix{T},typeof(ds),typeof(rs)}[] + b = max(maximum(bandwidths(L)), maximum(bandwidths(C))) + k = 2b + + # We start by determining a good deflation window. + + Lk = SymBandedMatrix(L, b, 1:k) + Lb = L[k+1:k+b,1:k] + Ck = SymBandedMatrix(C, b, 1:k) + Cb = C[k+1:k+b,1:k] + Λ, V = eigen(Lk, Ck) + M = Lb*V + N = Cb*V + + j = 0 + while j < 1 + k *= 2 + Lk = SymBandedMatrix(L, b, 1:k) + Lb = L[k+1:k+b,1:k] + Ck = SymBandedMatrix(C, b, 1:k) + Cb = C[k+1:k+b,1:k] + Λ, V = eigen(Lk, Ck) + M = Lb*V + N = Cb*V + j = deflationcheck(M, N, Λ, tol^2, verbose)÷b*b + verbose && println("This is the size of the deflation window: ",k," and this is the number of deflated eigenvalues: ",j) + end + + SBAL = SymBlockArrowHead(SymBandedPlusBulge(Matrix(Diagonal(Λ[j+1:k])), b, b), Matrix(M[:,j+1:k]'), Matrix(L[k+1:k+b,k+1:k+b])) + SBAC = SymBlockArrowHead(Diagonal(ones(T, k-j)), Matrix(N[:,j+1:k]'), Matrix(C[k+1:k+b,k+1:k+b])) + + push!(ALLEIGS, Λ[1:j]...) + push!(ALLV, EmbeddedBlockOperator(V, ndef, ds, rs)) + ndef += j + + w = zeros(T, k+b) + v = zero(w) + Lw = zero(w) + wQ = zero(w) + #F = Eigen(zeros(T, k), zeros(T, k, k)) + + while ndef < n + # With the dimensions of the deflation window, (k, k), found & fixed, + # we now create a SymBlockArrowHead matrix upon which we are able to + # perform similarity transformations to return to banded form. + + congruence!(SBAL, SBAC) + push!(ALLV, EmbeddedBlockOperator(Matrix(UpperTriangular(SBAC)), ndef, ds, rs)) + + Q = Matrix{T}(I, k, k) + symblockarrowhead2symbanded!(w, v, Lw, SBAL, wQ, Q) + push!(ALLV, EmbeddedBlockOperator(Q', ndef, ds, rs)) + + replenishLk!(Lk, SBAL, SBAC, L, ndef) + replenishLb!(Lb, L, ndef, k, b) + replenishCk!(Ck, SBAC, C, b, ndef) + replenishLb!(Cb, C, ndef, k, b) + + if j < CONST*k + verbose && println("Failed to deflate! Doubling the dimensions of the deflation window.") + + Lk = [Lk L[ndef+1:ndef+k,ndef+k+1:ndef+2k]; L[ndef+k+1:ndef+2k,ndef+1:ndef+2k]] + Ck = [Ck C[ndef+1:ndef+k,ndef+k+1:ndef+2k]; C[ndef+k+1:ndef+2k,ndef+1:ndef+2k]] + k *= 2 + Lk = SymBandedMatrix(Lk, b, 1:k) + Ck = SymBandedMatrix(Ck, b, 1:k) + Lb = L[ndef+k+1:ndef+k+b, ndef+1:ndef+k] + Cb = C[ndef+k+1:ndef+k+b, ndef+1:ndef+k] + M = zeros(T, b, k) + N = zeros(T, b, k) + w = zeros(T, k+b) + v = zero(w) + Lw = zero(w) + wQ = zero(w) + #F = Eigen(zeros(T, k), zeros(T, k, k)) + end + + Λ, V = eigen(Lk, Ck) + mul!(fill!(M, zero(T)), Lb, V) + mul!(fill!(N, zero(T)), Cb, V) + j = deflationcheck(M, N, Λ, tol^2, verbose)÷b*b + verbose && println("This is the size of the deflation window: ",k," and this is the number of deflated eigenvalues: ",j) + + SBAL = SymBlockArrowHead(SymBandedPlusBulge(Matrix(Diagonal(Λ[j+1:k])), b, b), Matrix(M[:,j+1:k]'), Matrix(L[ndef+k+1:ndef+k+b,ndef+k+1:ndef+k+b])) + SBAC = SymBlockArrowHead(Diagonal(ones(T, k-j)), Matrix(N[:,j+1:k]'), Matrix(C[ndef+k+1:ndef+k+b,ndef+k+1:ndef+k+b])) + + push!(ALLEIGS, Λ[1:j]...) + push!(ALLV, EmbeddedBlockOperator(V, ndef, ds, rs)) + ndef += j + end + + ALLEIGS, ALLV +end + + + +symmetric_eigvals(L::Operator{T}, n::Int; kwargs...) where T = symmetric_eigen(L, n; kwargs...)[1][1:n] +symmetric_eigvals(L::Operator{T}, C::Operator{T}, n::Int; kwargs...) where T = symmetric_eigen(L, C, n; kwargs...)[1][1:n] + + + + + +# Miscellaneous + +function SymBandedMatrix(M::Operator{T}, b::Int, ir::UnitRange) where T + B = BandedMatrix{T}(undef, length(ir), length(ir), b, b) + A = M[ir, ir] + shft = first(ir)-1 + @inbounds for i in 1:length(ir) + for j in colrange(B, i) + B[i,j] = A[i+shft, j+shft] + end + end + Symmetric(B) +end + +function SymBandedMatrix(M::AbstractMatrix{T}, b::Int, ir::UnitRange) where T + B = BandedMatrix{T}(undef, length(ir), length(ir), b, b) + shft = first(ir)-1 + @inbounds for i in 1:length(ir) + for j in colrange(B, i) + B[i,j] = M[i+shft, j+shft] + end + end + Symmetric(B) +end + + +function replenishLk!(A::AbstractMatrix, SBA::SymBlockArrowHead, M::Operator, ndef::Int) + b = maximum(bandwidths(M)) # SBA.A.b + m, n = size(SBA.A) + @inbounds for j = 1:size(SBA.A, 2) + @simd for i = 1:size(SBA.A, 1) + A[i,j] = SBA[i,j] + end + end + @inbounds for j = size(SBA.A, 2)+1:size(SBA, 2) + @simd for i = 1:size(SBA, 1)-b#size(SBA, 1)-2b+1:size(SBA, 1)-b + A[i,j] = SBA[i,j] + end + end + @inbounds for j = size(SBA.A, 2)+1:size(A, 2) + @simd for i = size(SBA.A, 1)+1:size(A, 1) + A[i,j] = M[i+ndef,j+ndef] + end + end + A +end + +function replenishLk!(A::Symmetric{T,MB}, SBA::SymBlockArrowHead, M::Operator, ndef::Int) where {T,MB<:BandedMatrix{T}} + b = SBA.A.b + m, n = size(SBA.A) + @inbounds for i = size(SBA.A, 1)+1:size(A, 1) + @simd for j in colrange(A, i) + A.data[i,j] = M[i+ndef,j+ndef] + end + end + @inbounds for i = size(SBA, 1)-2b+1:size(SBA, 1)-b + for j in colrange(A, i) + A.data[i,j] = SBA[i,j] + end + end + @inbounds for i = 1:size(SBA.A, 1) + for j in colrange(A, i) + A.data[i,j] = SBA[i,j] + end + end + A +end + +function replenishLk!(A::Symmetric{T,MB}, SBAL::SymBlockArrowHead, SBAC::SymBlockArrowHead, M::Operator, ndef::Int) where {T,MB<:BandedMatrix{T}} + b = SBAL.A.b + m, n = size(SBAL.A) + for i = size(SBAL.A, 1)+1:size(A, 1) + @simd for j in colrange(A, i) + A.data[i,j] = M[i+ndef,j+ndef] + end + end + @inbounds for i = size(SBAL, 1)-2b+1:size(SBAL, 1)-b + for j in colrange(A, i) + A.data[i,j] = SBAL[i,j] + end + end + @inbounds for i = 1:size(SBAL.A, 1) + for j in colrange(A, i) + A.data[i,j] = SBAL[i,j] + end + end + @inbounds for i = size(SBAL.A, 1)+1:size(SBAL, 1) + for j = i:size(SBAL, 2) + A.data[i,j] = SBAL[i,j] + end + end + k = size(SBAC.A, 1) + temp1 = UpperTriangular(SBAC.C) + temp2 = UpperTriangular(Matrix(M[ndef+k+b+1:ndef+k+2b,ndef+k+1:ndef+k+b])) + temp3 = temp2*temp1 + @inbounds for i = k+b+1:k+2b + for j = k+1:k+b + A.data[i,j] = temp3[i-k-b,j-k] + end + end + A +end + +function replenishCk!(A::Symmetric{T,MB}, SBA::SymBlockArrowHead, M::Operator, b::Int, ndef::Int) where {T,MB<:BandedMatrix{T}} + m, n = size(SBA.A) + k = size(SBA.A, 1) + temp1 = UpperTriangular(SBA.C) + temp2 = UpperTriangular(Matrix(M[ndef+k+b+1:ndef+k+2b,ndef+k+1:ndef+k+b])) + temp3 = temp2*temp1 + @inbounds for i = size(SBA.A, 1)+1:size(A, 1) + @simd for j in colrange(A, i) + A.data[i,j] = M[i+ndef,j+ndef] + end + end + @inbounds for i = 1:size(SBA, 1) + for j in colrange(A, i) + A.data[i,j] = 0 + end + A.data[i,i] = 1 + end + @inbounds for i = k+b+1:k+2b + for j = k+1:k+b + A.data[i,j] = temp3[i-k-b,j-k] + end + end + A +end + +function replenishLb!(L::Matrix{T}, M::Operator{T}, ndef::Int, k::Int, b::Int) where T + ndefpk = ndef+k + @inbounds for j = 1:k + jpndef = j+ndef + @simd for i = 1:b + L[i,j] = M[i+ndefpk, jpndef] + end + end + L +end + +function replenishLb!(L::BandedMatrix{T}, M::Operator{T}, ndef::Int, k::Int, b::Int) where T + ndefpk = ndef+k + @inbounds for j = 1:k + jpndef = j+ndef + @simd for i in 1:b #rowrange(L, j)#i = 1:k + L[i,j] = M[i+ndefpk, jpndef] + end + end + L +end diff --git a/src/Operators/general/EmbeddedBlockOperator.jl b/src/Operators/general/EmbeddedBlockOperator.jl new file mode 100644 index 000000000..12197d28c --- /dev/null +++ b/src/Operators/general/EmbeddedBlockOperator.jl @@ -0,0 +1,134 @@ +export EmbeddedBlockOperator + +""" + Represent a square block operator embedded in the identity: + [ I + X + I ] + where the first identity is k x k and the second is infinite-dimensional. +""" +struct EmbeddedBlockOperator{T,M<:AbstractMatrix{T},DS,RS} <: Operator{T} + X::M + temp::Vector{T} + k::Int + domainspace::DS + rangespace::RS + function EmbeddedBlockOperator{T,M,DS,RS}(X::M, k::Int, ds::DS, rs::RS) where {T,M,DS,RS} + m, n = size(X) + @assert m == n + new{T,M,DS,RS}(X, zeros(T, m), k, ds, rs) + end +end + +EmbeddedBlockOperator(X::M, k::Int, ds, rs) where M = EmbeddedBlockOperator{eltype(X), M, typeof(ds), typeof(rs)}(X, k, ds, rs) +EmbeddedBlockOperator(X::M, k::Int) where M = EmbeddedBlockOperator(X, k, SequenceSpace(), SequenceSpace()) + +bandwidths(A::EmbeddedBlockOperator) = (size(A.X, 1)-1, size(A.X, 2)-1) +domainspace(A::EmbeddedBlockOperator) = A.domainspace +rangespace(A::EmbeddedBlockOperator) = A.rangespace + +function getindex(A::EmbeddedBlockOperator{T}, i::Integer, j::Integer) where T + k = A.k + n = size(A.X, 1) + if i ≤ k + if j ≤ k + if i == j + return one(T) + else + return zero(T) + end + else + return zero(T) + end + elseif k < i ≤ k+n + if k < j ≤ k+n + return A.X[i-k,j-k] + else + return zero(T) + end + else + if i == j + return one(T) + else + return zero(T) + end + end +end + +function lmul!(A::EmbeddedBlockOperator{T}, x::AbstractVector{T}) where T + X = A.X + y = A.temp + k = A.k + n = size(X, 1) + @assert length(x) ≥ k + n + fill!(y, zero(T)) + @inbounds for j = 1:n + xj = x[k+j] + for i = 1:n + y[i] += X[i,j]*xj + end + end + @inbounds for i = k+1:k+n x[i] = y[i-k] end + + x +end + +function lmul!(A::AdjointOperator{T,M}, x::AbstractVector{T}) where {T,M<:EmbeddedBlockOperator{T}} + X = A.op.X + y = A.op.temp + k = A.op.k + n = size(X, 1) + @assert length(x) ≥ k + n + fill!(y, zero(T)) + @inbounds for i = 1:n + yi = zero(eltype(y)) + for j = 1:n + yi += conj(X[j,i])*x[k+j] + end + y[i] += yi + end + @inbounds for i = k+1:k+n x[i] = y[i-k] end + + x +end + +function lmul!(A::TransposeOperator{T,M}, x::AbstractVector{T}) where {T,M<:EmbeddedBlockOperator{T}} + X = A.op.X + y = A.op.temp + k = A.op.k + n = size(X, 1) + @assert length(x) ≥ k + n + fill!(y, zero(T)) + @inbounds for i = 1:n + yi = zero(eltype(y)) + for j = 1:n + yi += X[j,i]*x[k+j] + end + y[i] += yi + end + @inbounds for i = k+1:k+n x[i] = y[i-k] end + + x +end + + +function lmul!(A::Vector{M}, x::Vector{T}) where {T,M<:EmbeddedBlockOperator{T}} + for N = length(A):-1:1 + lmul!(A[N], x) + end + x +end + +function lmul!(A::Adjoint{AdjointOperator{T,M},Vector{M}}, x::Vector{T}) where {T,M<:EmbeddedBlockOperator{T}} + for N = 1:length(A) + lmul!(A[N], x) + end + x +end + +function lmul!(A::Transpose{TransposeOperator{T,M},Vector{M}}, x::Vector{T}) where {T,M<:EmbeddedBlockOperator{T}} + for N = 1:length(A) + lmul!(A[N], x) + end + x +end diff --git a/src/Operators/general/general.jl b/src/Operators/general/general.jl index f4924e025..78f7e66f2 100644 --- a/src/Operators/general/general.jl +++ b/src/Operators/general/general.jl @@ -2,6 +2,7 @@ include("algebra.jl") include("CachedOperator.jl") include("FiniteOperator.jl") include("OperatorLayout.jl") +include("EmbeddedBlockOperator.jl") include("PartialInverseOperator.jl") include("InterlaceOperator.jl") include("OperatorFunction.jl") From 9ce822d139cd3cb416af86dc28def54a22fbd1be Mon Sep 17 00:00:00 2001 From: Mikael Slevinsky Date: Wed, 27 Mar 2019 17:48:03 -0500 Subject: [PATCH 2/5] export bandwidth --- README.md | 2 +- src/Operators/Operator.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 89bbe4064..ee999d622 100644 --- a/README.md +++ b/README.md @@ -255,7 +255,7 @@ Q = Conversion(QS, S) D1 = Conversion(S, NS) D2 = Conversion(NS, S) R = D1*Q -P = cache(PartialInverseOperator(C, (0, ApproxFun.bandwidth(L, 1) + ApproxFun.bandwidth(R, 1) + ApproxFun.bandwidth(C, 2)))) +P = cache(PartialInverseOperator(C, (0, bandwidth(L, 1) + bandwidth(R, 1) + bandwidth(C, 2)))) A = R'D1*P*L*D2*R B = R'R SA = Symmetric(A[1:n,1:n], :L) diff --git a/src/Operators/Operator.jl b/src/Operators/Operator.jl index 0872a7078..960eb2054 100644 --- a/src/Operators/Operator.jl +++ b/src/Operators/Operator.jl @@ -1,5 +1,5 @@ export Operator -export bandwidths, bandrange, \, periodic +export bandwidth, bandwidths, bandrange, \, periodic export neumann export ldirichlet,rdirichlet,lneumann,rneumann export ldiffbc,rdiffbc,diffbcs From fdb041638373ffa9168bdb39a90887dfb6308434 Mon Sep 17 00:00:00 2001 From: Mikael Slevinsky Date: Wed, 27 Mar 2019 17:49:57 -0500 Subject: [PATCH 3/5] remove bandwidth import in test --- test/EigTest.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/test/EigTest.jl b/test/EigTest.jl index e44263ea2..f828022b8 100644 --- a/test/EigTest.jl +++ b/test/EigTest.jl @@ -1,5 +1,4 @@ using ApproxFun, BandedMatrices, SpecialFunctions, Test - import ApproxFun: bandwidth # # Fix for BigFloat stackoverflow From 61fb113f7d4d626f8dba09689db5c28abd766823 Mon Sep 17 00:00:00 2001 From: Mikael Slevinsky Date: Fri, 29 Mar 2019 13:12:55 -0500 Subject: [PATCH 4/5] generalized symmetric_eigen is debugged --- src/Operators/eigen.jl | 117 +++++++++++------------------------------ 1 file changed, 32 insertions(+), 85 deletions(-) diff --git a/src/Operators/eigen.jl b/src/Operators/eigen.jl index 3f6d07c7c..bd3d605f2 100644 --- a/src/Operators/eigen.jl +++ b/src/Operators/eigen.jl @@ -15,7 +15,7 @@ function symmetric_eigen(L::Operator{T}, n::Int; verbose::Bool = false, tol::Rea # We start by determining a good deflation window. - Lk = Symmetric(L[1:k,1:k])#SymBandedMatrix(L, b, 1:k) + Lk = Symmetric(L[1:k,1:k]) Lb = L[k+1:k+b,1:k] Λ, Q = eigen(Lk) M = Lb*Q @@ -23,7 +23,7 @@ function symmetric_eigen(L::Operator{T}, n::Int; verbose::Bool = false, tol::Rea j = 0 while j < 1 k *= 2 - Lk = Symmetric(L[1:k,1:k])#SymBandedMatrix(L, b, 1:k) + Lk = Symmetric(L[1:k,1:k]) Lb = L[k+1:k+b,1:k] Λ, Q = eigen(Lk) M = Lb*Q @@ -41,7 +41,6 @@ function symmetric_eigen(L::Operator{T}, n::Int; verbose::Bool = false, tol::Rea v = zero(w) Lw = zero(w) wQ = zero(w) - F = Eigen(zeros(T, k), zeros(T, k, k)) while ndef < n # With the dimensions of the deflation window, (k, k), found & fixed, @@ -99,20 +98,20 @@ function symmetric_eigen(L::Operator{T}, C::Operator{T}, n::Int; verbose::Bool = # We start by determining a good deflation window. - Lk = SymBandedMatrix(L, b, 1:k) + Lk = Symmetric(L[1:k,1:k]) Lb = L[k+1:k+b,1:k] - Ck = SymBandedMatrix(C, b, 1:k) + Ck = Symmetric(C[1:k,1:k]) Cb = C[k+1:k+b,1:k] Λ, V = eigen(Lk, Ck) M = Lb*V N = Cb*V j = 0 - while j < 1 + while j < 2b k *= 2 - Lk = SymBandedMatrix(L, b, 1:k) + Lk = Symmetric(L[1:k,1:k]) Lb = L[k+1:k+b,1:k] - Ck = SymBandedMatrix(C, b, 1:k) + Ck = Symmetric(C[1:k,1:k]) Cb = C[k+1:k+b,1:k] Λ, V = eigen(Lk, Ck) M = Lb*V @@ -132,7 +131,6 @@ function symmetric_eigen(L::Operator{T}, C::Operator{T}, n::Int; verbose::Bool = v = zero(w) Lw = zero(w) wQ = zero(w) - #F = Eigen(zeros(T, k), zeros(T, k, k)) while ndef < n # With the dimensions of the deflation window, (k, k), found & fixed, @@ -144,7 +142,7 @@ function symmetric_eigen(L::Operator{T}, C::Operator{T}, n::Int; verbose::Bool = Q = Matrix{T}(I, k, k) symblockarrowhead2symbanded!(w, v, Lw, SBAL, wQ, Q) - push!(ALLV, EmbeddedBlockOperator(Q', ndef, ds, rs)) + push!(ALLV, EmbeddedBlockOperator(Matrix(Q'), ndef, ds, rs)) replenishLk!(Lk, SBAL, SBAC, L, ndef) replenishLb!(Lb, L, ndef, k, b) @@ -167,7 +165,6 @@ function symmetric_eigen(L::Operator{T}, C::Operator{T}, n::Int; verbose::Bool = v = zero(w) Lw = zero(w) wQ = zero(w) - #F = Eigen(zeros(T, k), zeros(T, k, k)) end Λ, V = eigen(Lk, Ck) @@ -198,18 +195,6 @@ symmetric_eigvals(L::Operator{T}, C::Operator{T}, n::Int; kwargs...) where T = s # Miscellaneous -function SymBandedMatrix(M::Operator{T}, b::Int, ir::UnitRange) where T - B = BandedMatrix{T}(undef, length(ir), length(ir), b, b) - A = M[ir, ir] - shft = first(ir)-1 - @inbounds for i in 1:length(ir) - for j in colrange(B, i) - B[i,j] = A[i+shft, j+shft] - end - end - Symmetric(B) -end - function SymBandedMatrix(M::AbstractMatrix{T}, b::Int, ir::UnitRange) where T B = BandedMatrix{T}(undef, length(ir), length(ir), b, b) shft = first(ir)-1 @@ -221,54 +206,27 @@ function SymBandedMatrix(M::AbstractMatrix{T}, b::Int, ir::UnitRange) where T Symmetric(B) end - -function replenishLk!(A::AbstractMatrix, SBA::SymBlockArrowHead, M::Operator, ndef::Int) - b = maximum(bandwidths(M)) # SBA.A.b - m, n = size(SBA.A) - @inbounds for j = 1:size(SBA.A, 2) - @simd for i = 1:size(SBA.A, 1) - A[i,j] = SBA[i,j] +function replenishLk!(Lk::Symmetric{T,MB}, SBA::SymBlockArrowHead, L::Operator, ndef::Int) where {T,MB<:BandedMatrix{T}} + k = size(Lk, 1) + l = size(SBA.A, 1) + @inbounds for i = 1:l + for j in colrange(Lk, i) + Lk.data[i,j] = SBA[i,j] end end - @inbounds for j = size(SBA.A, 2)+1:size(SBA, 2) - @simd for i = 1:size(SBA, 1)-b#size(SBA, 1)-2b+1:size(SBA, 1)-b - A[i,j] = SBA[i,j] + @inbounds for i = l+1:k + for j in colrange(Lk, i) + Lk.data[i,j] = L[i+ndef,j+ndef] end end - @inbounds for j = size(SBA.A, 2)+1:size(A, 2) - @simd for i = size(SBA.A, 1)+1:size(A, 1) - A[i,j] = M[i+ndef,j+ndef] - end - end - A -end - -function replenishLk!(A::Symmetric{T,MB}, SBA::SymBlockArrowHead, M::Operator, ndef::Int) where {T,MB<:BandedMatrix{T}} - b = SBA.A.b - m, n = size(SBA.A) - @inbounds for i = size(SBA.A, 1)+1:size(A, 1) - @simd for j in colrange(A, i) - A.data[i,j] = M[i+ndef,j+ndef] - end - end - @inbounds for i = size(SBA, 1)-2b+1:size(SBA, 1)-b - for j in colrange(A, i) - A.data[i,j] = SBA[i,j] - end - end - @inbounds for i = 1:size(SBA.A, 1) - for j in colrange(A, i) - A.data[i,j] = SBA[i,j] - end - end - A + Lk end function replenishLk!(A::Symmetric{T,MB}, SBAL::SymBlockArrowHead, SBAC::SymBlockArrowHead, M::Operator, ndef::Int) where {T,MB<:BandedMatrix{T}} b = SBAL.A.b m, n = size(SBAL.A) for i = size(SBAL.A, 1)+1:size(A, 1) - @simd for j in colrange(A, i) + for j in colrange(A, i) A.data[i,j] = M[i+ndef,j+ndef] end end @@ -293,7 +251,7 @@ function replenishLk!(A::Symmetric{T,MB}, SBAL::SymBlockArrowHead, SBAC::SymBloc temp3 = temp2*temp1 @inbounds for i = k+b+1:k+2b for j = k+1:k+b - A.data[i,j] = temp3[i-k-b,j-k] + A.data[i,j] = A.data[j,i] = temp3[i-k-b,j-k] end end A @@ -301,47 +259,36 @@ end function replenishCk!(A::Symmetric{T,MB}, SBA::SymBlockArrowHead, M::Operator, b::Int, ndef::Int) where {T,MB<:BandedMatrix{T}} m, n = size(SBA.A) - k = size(SBA.A, 1) - temp1 = UpperTriangular(SBA.C) - temp2 = UpperTriangular(Matrix(M[ndef+k+b+1:ndef+k+2b,ndef+k+1:ndef+k+b])) - temp3 = temp2*temp1 @inbounds for i = size(SBA.A, 1)+1:size(A, 1) - @simd for j in colrange(A, i) + for j in colrange(A, i) A.data[i,j] = M[i+ndef,j+ndef] end end - @inbounds for i = 1:size(SBA, 1) + @inbounds for i = 1:size(SBA.A, 1)+b for j in colrange(A, i) A.data[i,j] = 0 end A.data[i,i] = 1 end + k = size(SBA.A, 1) + temp1 = UpperTriangular(SBA.C) + temp2 = UpperTriangular(Matrix(M[ndef+k+b+1:ndef+k+2b,ndef+k+1:ndef+k+b])) + temp3 = temp2*temp1 @inbounds for i = k+b+1:k+2b for j = k+1:k+b - A.data[i,j] = temp3[i-k-b,j-k] + A.data[i,j] = A.data[j,i] = temp3[i-k-b,j-k] end end A end -function replenishLb!(L::Matrix{T}, M::Operator{T}, ndef::Int, k::Int, b::Int) where T - ndefpk = ndef+k - @inbounds for j = 1:k - jpndef = j+ndef - @simd for i = 1:b - L[i,j] = M[i+ndefpk, jpndef] - end - end - L -end - -function replenishLb!(L::BandedMatrix{T}, M::Operator{T}, ndef::Int, k::Int, b::Int) where T +function replenishLb!(Lb::BandedMatrix{T}, L::Operator{T}, ndef::Int, k::Int, b::Int) where T ndefpk = ndef+k - @inbounds for j = 1:k + @inbounds for j = k-b+1:k jpndef = j+ndef - @simd for i in 1:b #rowrange(L, j)#i = 1:k - L[i,j] = M[i+ndefpk, jpndef] + for i in 1:(b+j-k) + Lb[i,j] = L[i+ndefpk, jpndef] end end - L + Lb end From c13f5d621226be4c44ecb4ca175e8c0a7cc02ae0 Mon Sep 17 00:00:00 2001 From: Mikael Slevinsky Date: Mon, 1 Apr 2019 14:41:15 -0500 Subject: [PATCH 5/5] SymBandedPlusBulge's backend: Matrix => BandedMatrix --- src/LinearAlgebra/SymBandedPlusBulge.jl | 8 +++++--- src/LinearAlgebra/SymBlockArrowHead.jl | 12 ++++++------ src/Operators/eigen.jl | 8 ++++---- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/LinearAlgebra/SymBandedPlusBulge.jl b/src/LinearAlgebra/SymBandedPlusBulge.jl index 37fb74a1e..b6cf65749 100644 --- a/src/LinearAlgebra/SymBandedPlusBulge.jl +++ b/src/LinearAlgebra/SymBandedPlusBulge.jl @@ -8,12 +8,14 @@ ◹ □ ◺ ◹ □ ] """ -mutable struct SymBandedPlusBulge{T} <: AbstractMatrix{T} - A::Matrix{T} +mutable struct SymBandedPlusBulge{T,M<:BandedMatrix{T}} <: AbstractMatrix{T} + A::M b::Int bulge::Int end +SymBandedPlusBulge(A::AbstractMatrix, b::Int, bulge::Int) = SymBandedPlusBulge(BandedMatrix(A, (2b, 2b)), b, bulge) + size(A::SymBandedPlusBulge) = size(A.A) function getindex(A::SymBandedPlusBulge{T}, i::Integer, j::Integer) where T @@ -43,7 +45,7 @@ function getindex(A::SymBandedPlusBulge{T}, i::Integer, j::Integer) where T end end -setindex!(A::SymBandedPlusBulge{T}, v, i::Integer, j::Integer) where T = setindex!(A.A, v, i, j) +setindex!(A::SymBandedPlusBulge{T}, v, i::Integer, j::Integer) where T = (b = A.b; -2b ≤ i-j ≤ 2b && setindex!(A.A, v, i, j)) function computeHouseholder!(A::SymBandedPlusBulge{T}, w::Vector{T}, col::Int) where T b = A.b diff --git a/src/LinearAlgebra/SymBlockArrowHead.jl b/src/LinearAlgebra/SymBlockArrowHead.jl index 1f54d2c98..b1555c7d2 100644 --- a/src/LinearAlgebra/SymBlockArrowHead.jl +++ b/src/LinearAlgebra/SymBlockArrowHead.jl @@ -45,7 +45,7 @@ function setindex!(A::SymBlockArrowHead{T}, v, i::Integer, j::Integer) where T end end -function computeHouseholder!(A::SymBlockArrowHead{T,SymBandedPlusBulge{T}}, w::Vector{T}, row::Int, col::Int) where T +function computeHouseholder!(A::SymBlockArrowHead{T,SymBandedPlusBulge{T,V}}, w::Vector{T}, row::Int, col::Int) where {T,V} b = A.A.b corr = zero(T) fill!(w, corr) @@ -94,7 +94,7 @@ function applyHouseholder!(w::Vector{T}, wQ::Vector{T}, Q::Matrix{T}, bulge::Int Q end -function similarity!(w::Vector{T}, v::Vector{T}, Aw::Vector{T}, A::SymBlockArrowHead{T,SymBandedPlusBulge{T}}, row::Int) where T +function similarity!(w::Vector{T}, v::Vector{T}, Aw::Vector{T}, A::SymBlockArrowHead{T,SymBandedPlusBulge{T,V}}, row::Int) where {T,V} bulge = A.A.bulge b = A.A.b sw = max(row-b, 1) @@ -150,7 +150,7 @@ function similarity!(w::Vector{T}, v::Vector{T}, Aw::Vector{T}, A::SymBlockArrow A end -function symblockarrowhead2symbanded!(w::Vector{T}, v::Vector{T}, Aw::Vector{T}, A::SymBlockArrowHead{T,SymBandedPlusBulge{T}}) where T +function symblockarrowhead2symbanded!(w::Vector{T}, v::Vector{T}, Aw::Vector{T}, A::SymBlockArrowHead{T,SymBandedPlusBulge{T,V}}) where {T,V} n = size(A, 2) b = A.A.b @@ -171,14 +171,14 @@ function symblockarrowhead2symbanded!(w::Vector{T}, v::Vector{T}, Aw::Vector{T}, A end -function symblockarrowhead2symbanded!(A::SymBlockArrowHead{T,SymBandedPlusBulge{T}}) where T +function symblockarrowhead2symbanded!(A::SymBlockArrowHead{T,SymBandedPlusBulge{T,V}}) where {T,V} w = zeros(T, size(A, 2)) v = zero(w) Aw = zero(w) symblockarrowhead2symbanded!(w, v, Aw, A) end -function symblockarrowhead2symbanded!(w::Vector{T}, v::Vector{T}, Aw::Vector{T}, A::SymBlockArrowHead{T,SymBandedPlusBulge{T}}, wQ::Vector{T}, Q::Matrix{T}) where T +function symblockarrowhead2symbanded!(w::Vector{T}, v::Vector{T}, Aw::Vector{T}, A::SymBlockArrowHead{T,SymBandedPlusBulge{T,V}}, wQ::Vector{T}, Q::Matrix{T}) where {T,V} n = size(A, 2) b = A.A.b @@ -201,7 +201,7 @@ function symblockarrowhead2symbanded!(w::Vector{T}, v::Vector{T}, Aw::Vector{T}, A end -function symblockarrowhead2symbanded!(A::SymBlockArrowHead{T,SymBandedPlusBulge{T}}, Q::Matrix{T}) where T +function symblockarrowhead2symbanded!(A::SymBlockArrowHead{T,SymBandedPlusBulge{T,V}}, Q::Matrix{T}) where {T,V} w = zeros(T, size(A, 2)) v = zero(w) Aw = zero(w) diff --git a/src/Operators/eigen.jl b/src/Operators/eigen.jl index bd3d605f2..5ac96c2e8 100644 --- a/src/Operators/eigen.jl +++ b/src/Operators/eigen.jl @@ -31,7 +31,7 @@ function symmetric_eigen(L::Operator{T}, n::Int; verbose::Bool = false, tol::Rea verbose && println("This is the size of the deflation window: ",k," and this is the number of deflated eigenvalues: ",j) end - SBA = SymBlockArrowHead(SymBandedPlusBulge(Matrix(Diagonal(Λ[j+1:k])), b, b), Matrix(M[:,j+1:k]'), Matrix(L[k+1:k+b,k+1:k+b])) + SBA = SymBlockArrowHead(SymBandedPlusBulge(Diagonal(Λ[j+1:k]), b, b), Matrix(M[:,j+1:k]'), Matrix(L[k+1:k+b,k+1:k+b])) push!(ALLEIGS, Λ[1:j]...) push!(ALLQ, EmbeddedBlockOperator(Q, ndef, ds, rs)) @@ -73,7 +73,7 @@ function symmetric_eigen(L::Operator{T}, n::Int; verbose::Bool = false, tol::Rea j = deflationcheck(M, Λ, tol^2, verbose)÷b*b verbose && println("This is the size of the deflation window: ",k," and this is the number of deflated eigenvalues: ",j) - SBA = SymBlockArrowHead(SymBandedPlusBulge(Matrix(Diagonal(Λ[j+1:k])), b, b), Matrix(M[:,j+1:k]'), Matrix(L[ndef+k+1:ndef+k+b,ndef+k+1:ndef+k+b])) + SBA = SymBlockArrowHead(SymBandedPlusBulge(Diagonal(Λ[j+1:k]), b, b), Matrix(M[:,j+1:k]'), Matrix(L[ndef+k+1:ndef+k+b,ndef+k+1:ndef+k+b])) push!(ALLEIGS, Λ[1:j]...) push!(ALLQ, EmbeddedBlockOperator(Q, ndef, ds, rs)) @@ -120,7 +120,7 @@ function symmetric_eigen(L::Operator{T}, C::Operator{T}, n::Int; verbose::Bool = verbose && println("This is the size of the deflation window: ",k," and this is the number of deflated eigenvalues: ",j) end - SBAL = SymBlockArrowHead(SymBandedPlusBulge(Matrix(Diagonal(Λ[j+1:k])), b, b), Matrix(M[:,j+1:k]'), Matrix(L[k+1:k+b,k+1:k+b])) + SBAL = SymBlockArrowHead(SymBandedPlusBulge(Diagonal(Λ[j+1:k]), b, b), Matrix(M[:,j+1:k]'), Matrix(L[k+1:k+b,k+1:k+b])) SBAC = SymBlockArrowHead(Diagonal(ones(T, k-j)), Matrix(N[:,j+1:k]'), Matrix(C[k+1:k+b,k+1:k+b])) push!(ALLEIGS, Λ[1:j]...) @@ -173,7 +173,7 @@ function symmetric_eigen(L::Operator{T}, C::Operator{T}, n::Int; verbose::Bool = j = deflationcheck(M, N, Λ, tol^2, verbose)÷b*b verbose && println("This is the size of the deflation window: ",k," and this is the number of deflated eigenvalues: ",j) - SBAL = SymBlockArrowHead(SymBandedPlusBulge(Matrix(Diagonal(Λ[j+1:k])), b, b), Matrix(M[:,j+1:k]'), Matrix(L[ndef+k+1:ndef+k+b,ndef+k+1:ndef+k+b])) + SBAL = SymBlockArrowHead(SymBandedPlusBulge(Diagonal(Λ[j+1:k]), b, b), Matrix(M[:,j+1:k]'), Matrix(L[ndef+k+1:ndef+k+b,ndef+k+1:ndef+k+b])) SBAC = SymBlockArrowHead(Diagonal(ones(T, k-j)), Matrix(N[:,j+1:k]'), Matrix(C[ndef+k+1:ndef+k+b,ndef+k+1:ndef+k+b])) push!(ALLEIGS, Λ[1:j]...)