Files
cmdla/project/housQR.jl
2023-11-25 20:17:20 +01:00

135 lines
3.0 KiB
Julia

module housQR
import Base: size, show, getproperty, getfield, propertynames, \, *
using LinearAlgebra: norm, I, triu, diagm, dot
export QRhous, qrfact
mutable struct QRhous{T <: Real}
A::AbstractVecOrMat{T}
d::AbstractArray{T}
AQ::Union{Nothing, AbstractVecOrMat{T}}
AR::Union{Nothing, AbstractVecOrMat{T}}
QRhous(A, d, AQ=nothing, AR=nothing) = new{eltype(A)}(A, d, AQ, AR)
end
function householder_vector(x::AbstractVecOrMat{T})::Tuple{Vector{T}, T} where T
# returns the normalized vector u such that H*x is a multiple of e_1
s = norm(x)
if x[1] 0
s = -s
end
u = copy(x)
u[1] -= s
u ./= norm(u)
return u, s
end
function qrfact(A::Matrix{T})::QRhous where T
(m, n) = size(A)
R = deepcopy(A)
d = zeros(n)
for k 1:min(m, n)
@views (u, s) = householder_vector(R[k:m, k])
# construct R
d[k] = s
@views R[k:m, k+1:n] -= 2 * u * (u' * R[k:m, k+1:n])
R[k:m, k] .= u
end
return QRhous(R, d)
end
function qyhous(A::QRhous{T}, y::AbstractArray{T}) where T
m, n = size(A)
z = deepcopy(y)
for k n:-1:1
# z[j:m] = z[j:m] - 2 * A.A[j:m, j] * (A.A[j:m, j]' * z[j:m])
@views z[k:m] -= 2 * A.A[k:m, k] .* dot(A.A[k:m, k], z[k:m])
end
return z
end
function qyhoust(A::QRhous{T}, y::AbstractArray{T}) where T
m, n = size(A)
z = deepcopy(y)
for k 1:n
# z[j:m] = z[j:m] - 2 * A.A[j:m, j] * (A.A[j:m, j]' * z[j:m])
@views z[k:m] -= 2 * A.A[k:m, k] .* dot(A.A[k:m, k], z[k:m])
end
return z
end
function calculateQ(A::QRhous{T}) where T
if A.AQ != nothing
return A.AQ
end
m, n = size(A.A)
A.AQ = zeros(m, 0)
id = Matrix{eltype(A.A)}(I, m, n)
for i eachcol(id)
A.AQ = [A.AQ qyhous(A, i)]
end
return A.AQ
end
function calculateR(A::QRhous{T}) where T
if A.AR != nothing
return A.AR
end
m, n = size(A.A)
A.AR = triu(A.A[1:n, :], 1) + diagm(A.d)
return A.AR
end
function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, A::QRhous{T}) where T
summary(io, A); println(io)
print(io, "Q factor: ")
show(io, mime, A.Q)
print(io, "\nR factor: ")
show(io, mime, A.R)
end
function Base.getproperty(A::QRhous{T}, d::Symbol) where T
if d === :R
return calculateR(A)
elseif d === :Q
return calculateQ(A)
else
getfield(A, d)
end
end
Base.propertynames(A::QRhous, private::Bool=false) = (:R, :Q, (private ? fieldnames(typeof(A)) : ())...)
Base.size(A::QRhous) = size(getfield(A, :A))
function (\)(A::QRhous{T}, b::AbstractVector{T}) where T
n, m = size(A)
v = qyhoust(A, b)
x = zeros(m)
@show size(v)
@show size(x)
@show size(A.A)
@show size(A.d)
@show m
#@inbounds begin
for j m:-1:1
@views x[j] = (v[j] - dot(x[j+1:m], A.A[j, j+1:m])) * A.d[j]^-1
end
#end
return x
end
function (*)(A::QRhous{T}, x::AbstractVecOrMat{T}) where T
return qyhous(A, (A.R * x))
end
end