Added Project and Report

This commit is contained in:
elvis
2024-07-30 14:43:25 +02:00
parent c828453e94
commit 3ad6f7f86f
311 changed files with 13490 additions and 3280 deletions

348
project/QR/housQR.jl Normal file
View File

@ -0,0 +1,348 @@
module housQR
import Base: size, show, getproperty, getfield, propertynames, \, *
using LinearAlgebra: norm, I, triu, diagm, dot, mul!
export QRhous, qrfact
@doc raw"""
```julia
QRhous{T <: Real}
```
Struct that holds a QR factorization. The R factor is stored in
the upper triangular part of the matrix A. The diagonal of R is stored in the
vector d. The Q factor is computed lazily.
"""
mutable struct QRhous{T <: Real}
raw"""
`A` holds the R factor in the upper triangular part minus the diagonal
and the housholder vectors in the lower triangular.
"""
QR::AbstractVecOrMat{T} # R after the QR factorization
raw"""
`d` holds the diagonal of the R factor.
"""
d::AbstractArray{T} # diagonal of R
raw"""
`AQ` holds the cached value for Q, is `nothing` if not yet computed
"""
AQ::Union{Nothing, AbstractVecOrMat{T}} # Q
raw"""
`AR` holds the cached value for R, is `nothing` if not yet computed
"""
AR::Union{Nothing, AbstractVecOrMat{T}} # R0
QRhous(QR, d, AQ=nothing, AR=nothing) = new{eltype(QR)}(QR, d, AQ, AR)
end
@doc raw"""
```julia
householder_vector(x::AbstractVecOrMat{T})::Tuple{AbstractVecOrMat{T}, T}
```
Computes a normalized vector u such that ``Hx = se_1, H = I - 2uu^T``.
### Input
- `x` -- the input vector
### Output
A tuple [u, s], where u is the householder vector of x and ``s = \big | x \big |``
"""
function householder_vector(x::AbstractVecOrMat{T})::Tuple{AbstractVecOrMat{T}, T} where T
s = norm(x)
if x[1] 0
s = -s
end
u = copy(x)
u[1] -= s
u ./= norm(u)
return u, s
end
@doc raw"""
```julia
qrfact(A::Matrix{T})::QRhous{T}
```
Computes the QR factorization of A: A = QR.
### Input
- 'A' -- the input matrix; ``A \in \mathbb{R}^{m \times n}``.
### Output
A `QRhous` object containing the QR factorization of A.
See also [`QRhous`](@ref).
"""
function qrfact(A::Matrix{T})::QRhous{T} where T
(m, n) = size(A)
R = deepcopy(A)
d = zeros(min(n, m))
tmp = similar(R)
for k 1:min(n, m)
@views (u, s) = householder_vector(R[k:m, k])
# construct R
d[k] = s
@views mul!(tmp[k:m, k+1:n], 2*u, u' * R[k:m, k+1:n])
@views R[k:m, k+1:n] .-= tmp[k:m, k+1:n]
R[k:m, k] .= u
end
return QRhous(R, d)
end
@doc raw"""
```julia
qyhoust(A::QRhous{T}, y::AbstractArray{T})
```
Computes the product ``Q_0^Ty,`` where ``Q_0`` is the ``n \times n`` (upper) part of the matrix Q of the QR factorization of A.
### Input
- `A` -- the QR factorization of A.
- `y` -- the vector to be multiplied by ``Q_0^T``.
### Output
The product ``Q_0^Ty``.
See also [`qyhous`](@ref).
"""
function qyhoust(A::QRhous{T}, y::AbstractArray{T})::AbstractArray{T} where T
m, n = size(A.QR)
z = deepcopy(y)
tmp = similar(z)
for j 1:n
@views tmp[j:m] .= 2 * dot(A.QR[j:m, j], z[j:m]) * A.QR[j:m, j]
@views z[j:m] .-= tmp[j:m]
end
return z
end
@doc raw"""
```julia
qyhous(A::QRhous{T}, y::AbstractArray{T})
```
Computes the product ``Q_0y,`` where ``Q_0`` is the ``n \times n`` (upper) part of the matrix Q of the QR factorization of A.
### Input
- `A` -- the QR factorization of A.
- `y` -- the vector to be multiplied by ``Q_0``.
### Output
The product ``Q_0y``.
See also [`qyhoust`](@ref).
"""
function qyhous(A::QRhous{T}, y::AbstractArray{T}) where T
m, n = size(A.QR)
z = deepcopy(y)
tmp = similar(z)
for j n:-1:1
@views tmp[j:m] .= 2 * dot(A.QR[j:m, j], z[j:m]) * A.QR[j:m, j]
@views z[j:m] .-= tmp[j:m]
end
return z
end
@doc raw"""
```julia
multiplybyr(A::QRhous{T}, y::AbstractArray{T})
```
Computes the product ``Ry,`` where ``R`` is the upper part of the matrix A, already transformed by the QR factorization.
"""
function multiplybyr(A::QRhous{T}, y::AbstractArray{T}) where T
m, n = size(A.QR)
min_size = min(m, n)
vcat(A.R * y[1:min_size], zeros(max(0, m - n)))
end
@doc raw"""
```julia
calculateQ(A::QRhous{T})
```
Computes the Q factor of the QR factorization of A. The result is cached.
### Input
- `A` -- the QR factorization of `A`.
### Output
The Q factor of the QR factorization of `A`.
"""
function calculateQ(A::QRhous{T}) where T
if !isnothing(A.AQ)
return A.AQ
end
m, n = size(A.QR)
A.AQ = zeros(m, 0)
id = Matrix{eltype(A.QR)}(I, m, n)
for i eachcol(id)
A.AQ = [A.AQ qyhous(A, i)]
end
return A.AQ
end
@doc raw"""
```julia
calculateR(A::QRhous{T})
```
Computes the R factor of the QR factorization of `A`.
The R factor is the upper part of the matrix A, already transformed by the QR factorization.
The result is cached.
### Input
- `A` -- the QR factorization of `A`.
### Output
The R factor of the QR factorization of `A`.
"""
function calculateR(A::QRhous{T}) where T
if !isnothing(A.AR)
return A.AR
end
m, n = size(A.QR)
min_size = min(m, n)
# @show triu(A.QR[1:n, :], 1)
A.AR = triu(A.QR[1:min_size, 1:min_size], 1) + diagm(A.d)
return A.AR
end
@doc """
```julia
(\\)(A::QRhous{T}, b::AbstractVector{T})
```
Solves the linear system ``Ax = b`` using the QR factorization of A.
First, it computes the product ```Q^t b``` and then solves the triangular system ```R x = Q^t b``` via backsubstitution.
### Input
- `A` -- the QR factorization of A.
- `b` -- the right-hand side vector.
### Output
The solution vector x.
"""
function (\)(A::QRhous{T}, b::AbstractVector{T}) where T
m, n = size(A)
v = qyhoust(A, b)
x = zeros(n)
tmp = x[1]
for j min(m, n):-1:1
@views tmp = dot(x[j+1:n], A.QR[j, j+1:n])
x[j] = (v[j] - tmp) * inv(A.d[j])
end
return x
end
@doc raw"""
```julia
(*)(A::QRhous{T}, x::AbstractVecOrMat{T})
```
Computes the product ``Ax,`` where ``A`` is the QR factorization of A.
### Input
- `A` -- the QR factorization of A.
- `x` -- the vector to be multiplied by ``A``.
### Output
The product ``Ax``.
"""
function (*)(A::QRhous{T}, x::AbstractVecOrMat{T}) where T
return qyhous(A, multiplybyr(A, x))
end
@doc raw"""
```julia
show(io::IO, mime, A::QRhous{T})
```
Pretty printing for the factoried matrix A. Computes explicitly Q and R.
"""
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)
println(io)
print(io, "R factor: ")
show(io, mime, A.R)
end
@doc raw"""
```julia
getproperty(A::QRhous{T}, name::Symbol)
```
Calculates explicitely Q and R if required.
"""
function Base.getproperty(A::QRhous{T}, name::Symbol) where T
if name === :R
return calculateR(A)
elseif name === :Q
return calculateQ(A)
else
getfield(A, name)
end
end
@doc raw"""
```julia
propertynames(A::QRhous, [private::Bool = false])
```
Returns a tuple of all the properties of a QRhous matrix.
```jldoctest
julia> :R ∈ propertynames(qrfact([1 0; 0 1]))
true
```
"""
Base.propertynames(A::QRhous, private::Bool=false) = (:R, :Q, (private ? fieldnames(typeof(A)) : ())...)
@doc raw"""
```julia
size(A::QRhous)
```
Returns the size of the original matrix A. It is also the size of the support matrix.
"""
Base.size(A::QRhous) = size(getfield(A, :QR))
end # module housQR