From badc334500fbe0d84d769b298709b98788d77836 Mon Sep 17 00:00:00 2001 From: Andreas Noack Date: Tue, 19 Dec 2017 12:58:29 +0100 Subject: [PATCH] Deprecate getindex(::Factorization, ::Symbol) in favor of dot overloading --- base/deprecated.jl | 6 + base/linalg/bunchkaufman.jl | 38 ++-- base/linalg/cholesky.jl | 77 +++++---- base/linalg/dense.jl | 8 +- base/linalg/eigen.jl | 27 ++- base/linalg/hessenberg.jl | 16 +- base/linalg/linalg.jl | 7 +- base/linalg/lq.jl | 30 ++-- base/linalg/lu.jl | 54 +++--- base/linalg/qr.jl | 82 +++++---- base/linalg/schur.jl | 82 ++++----- base/linalg/svd.jl | 106 ++++++------ .../src/IterativeEigensolvers.jl | 2 +- stdlib/SuiteSparse/src/cholmod.jl | 92 +++++----- stdlib/SuiteSparse/src/spqr.jl | 40 ++--- stdlib/SuiteSparse/src/umfpack.jl | 49 +++--- stdlib/SuiteSparse/test/cholmod.jl | 162 +++++++++--------- stdlib/SuiteSparse/test/spqr.jl | 16 +- stdlib/SuiteSparse/test/umfpack.jl | 18 +- test/linalg/bunchkaufman.jl | 16 +- test/linalg/cholesky.jl | 42 ++--- test/linalg/dense.jl | 10 +- test/linalg/eigen.jl | 38 ++-- test/linalg/hessenberg.jl | 14 +- test/linalg/lq.jl | 23 ++- test/linalg/lu.jl | 24 +-- test/linalg/qr.jl | 32 ++-- test/linalg/schur.jl | 64 +++---- test/linalg/svd.jl | 44 ++--- 29 files changed, 609 insertions(+), 610 deletions(-) diff --git a/base/deprecated.jl b/base/deprecated.jl index 83ee0c8f63fbfe..123fd1e7bd896c 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -3423,6 +3423,12 @@ workspace() = error("workspace() is discontinued, check out Revise.jl for an alt # PR #25113 @deprecate_binding CartesianRange CartesianIndices +# Use getproperty instead of getindex for Factorizations +function getindex(F::Factorization, s::Symbol) + depwarn("F[:$s] is deprecated, use F.$s instead.", :getindex) + return getproperty(F, s) +end + # END 0.7 deprecations # BEGIN 1.0 deprecations diff --git a/base/linalg/bunchkaufman.jl b/base/linalg/bunchkaufman.jl index d7d956af2201a4..03945b61a0ba3a 100644 --- a/base/linalg/bunchkaufman.jl +++ b/base/linalg/bunchkaufman.jl @@ -86,8 +86,8 @@ convert(::Type{BunchKaufman{T}}, B::BunchKaufman) where {T} = convert(::Type{Factorization{T}}, B::BunchKaufman{T}) where {T} = B convert(::Type{Factorization{T}}, B::BunchKaufman) where {T} = convert(BunchKaufman{T}, B) -size(B::BunchKaufman) = size(B.LD) -size(B::BunchKaufman, d::Integer) = size(B.LD, d) +size(B::BunchKaufman) = size(getfield(B, :LD)) +size(B::BunchKaufman, d::Integer) = size(getfield(B, :LD), d) issymmetric(B::BunchKaufman) = B.symmetric ishermitian(B::BunchKaufman) = !B.symmetric @@ -115,7 +115,7 @@ function _ipiv2perm_bk(v::AbstractVector{T}, maxi::Integer, uplo::Char) where T end """ - getindex(B::BunchKaufman, d::Symbol) + getproperty(B::BunchKaufman, d::Symbol) Extract the factors of the Bunch-Kaufman factorization `B`. The factorization can take the two forms `L*D*L'` or `U*D*U'` (or `L*D*Transpose(L)` in the complex symmetric case) where `L` is a @@ -153,7 +153,7 @@ permutation: 3 2 -julia> F[:L]*F[:D]*F[:L]' - A[F[:p], F[:p]] +julia> F.L*F.D*F.L' - A[F.p, F.p] 3×3 Array{Float64,2}: 0.0 0.0 0.0 0.0 0.0 0.0 @@ -161,35 +161,35 @@ julia> F[:L]*F[:D]*F[:L]' - A[F[:p], F[:p]] julia> F = bkfact(Symmetric(A)); -julia> F[:U]*F[:D]*F[:U]' - F[:P]*A*F[:P]' +julia> F.U*F.D*F.U' - F.P*A*F.P' 3×3 Array{Float64,2}: 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ``` """ -function getindex(B::BunchKaufman{T}, d::Symbol) where {T<:BlasFloat} +@inline function getproperty(B::BunchKaufman{T}, d::Symbol) where {T<:BlasFloat} n = size(B, 1) if d == :p - return _ipiv2perm_bk(B.ipiv, n, B.uplo) + return _ipiv2perm_bk(getfield(B, :ipiv), n, getfield(B, :uplo)) elseif d == :P - return Matrix{T}(I, n, n)[:,invperm(B[:p])] + return Matrix{T}(I, n, n)[:,invperm(B.p)] elseif d == :L || d == :U || d == :D - if B.rook - LUD, od = LAPACK.syconvf_rook!(B.uplo, 'C', copy(B.LD), B.ipiv) + if getfield(B, :rook) + LUD, od = LAPACK.syconvf_rook!(getfield(B, :uplo), 'C', copy(getfield(B, :LD)), getfield(B, :ipiv)) else - LUD, od = LAPACK.syconv!(B.uplo, copy(B.LD), B.ipiv) + LUD, od = LAPACK.syconv!(getfield(B, :uplo), copy(getfield(B, :LD)), getfield(B, :ipiv)) end if d == :D - if B.uplo == 'L' + if getfield(B, :uplo) == 'L' odl = od[1:n - 1] - return Tridiagonal(odl, diag(LUD), B.symmetric ? odl : conj.(odl)) + return Tridiagonal(odl, diag(LUD), getfield(B, :symmetric) ? odl : conj.(odl)) else # 'U' odu = od[2:n] - return Tridiagonal(B.symmetric ? odu : conj.(odu), diag(LUD), odu) + return Tridiagonal(getfield(B, :symmetric) ? odu : conj.(odu), diag(LUD), odu) end elseif d == :L - if B.uplo == 'L' + if getfield(B, :uplo) == 'L' return UnitLowerTriangular(LUD) else throw(ArgumentError("factorization is U*D*Transpose(U) but you requested L")) @@ -202,7 +202,7 @@ function getindex(B::BunchKaufman{T}, d::Symbol) where {T<:BlasFloat} end end else - throw(KeyError(d)) + getfield(B, d) end end @@ -212,11 +212,11 @@ function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, B::BunchKaufman) if issuccess(B) println(io, summary(B)) println(io, "D factor:") - show(io, mime, B[:D]) + show(io, mime, B.D) println(io, "\n$(B.uplo) factor:") - show(io, mime, B[Symbol(B.uplo)]) + show(io, mime, B.uplo == 'L' ? B.L : B.U) println(io, "\npermutation:") - show(io, mime, B[:p]) + show(io, mime, B.p) else print(io, "Failed factorization of type $(typeof(B))") end diff --git a/base/linalg/cholesky.jl b/base/linalg/cholesky.jl index 0e36604a6f67ed..832b6653553eb4 100644 --- a/base/linalg/cholesky.jl +++ b/base/linalg/cholesky.jl @@ -285,7 +285,7 @@ end Compute the Cholesky factorization of a dense symmetric positive definite matrix `A` and return a `Cholesky` factorization. The matrix `A` can either be a [`Symmetric`](@ref) or [`Hermitian`](@ref) `StridedMatrix` or a *perfectly* symmetric or Hermitian `StridedMatrix`. -The triangular Cholesky factor can be obtained from the factorization `F` with: `F[:L]` and `F[:U]`. +The triangular Cholesky factor can be obtained from the factorization `F` with: `F.L` and `F.U`. The following functions are available for `Cholesky` objects: [`size`](@ref), [`\\`](@ref), [`inv`](@ref), [`det`](@ref), [`logdet`](@ref) and [`isposdef`](@ref). @@ -305,19 +305,19 @@ U factor: ⋅ 1.0 5.0 ⋅ ⋅ 3.0 -julia> C[:U] +julia> C.U 3×3 UpperTriangular{Float64,Array{Float64,2}}: 2.0 6.0 -8.0 ⋅ 1.0 5.0 ⋅ ⋅ 3.0 -julia> C[:L] +julia> C.L 3×3 LowerTriangular{Float64,Array{Float64,2}}: 2.0 ⋅ ⋅ 6.0 1.0 ⋅ -8.0 5.0 3.0 -julia> C[:L] * C[:U] == A +julia> C.L * C.U == A true ``` """ @@ -332,7 +332,7 @@ cholfact(A::Union{StridedMatrix,RealHermSymComplexHerm{<:Real,<:StridedMatrix}}, Compute the pivoted Cholesky factorization of a dense symmetric positive semi-definite matrix `A` and return a `CholeskyPivoted` factorization. The matrix `A` can either be a [`Symmetric`](@ref) or [`Hermitian`](@ref) `StridedMatrix` or a *perfectly* symmetric or Hermitian `StridedMatrix`. -The triangular Cholesky factor can be obtained from the factorization `F` with: `F[:L]` and `F[:U]`. +The triangular Cholesky factor can be obtained from the factorization `F` with: `F.L` and `F.U`. The following functions are available for `PivotedCholesky` objects: [`size`](@ref), [`\\`](@ref), [`inv`](@ref), [`det`](@ref), and [`rank`](@ref). The argument `tol` determines the tolerance for determining the rank. @@ -361,14 +361,14 @@ convert(::Type{CholeskyPivoted{T}},C::CholeskyPivoted) where {T} = convert(::Type{Factorization{T}}, C::CholeskyPivoted{T}) where {T} = C convert(::Type{Factorization{T}}, C::CholeskyPivoted) where {T} = convert(CholeskyPivoted{T}, C) -convert(::Type{AbstractMatrix}, C::Cholesky) = C.uplo == 'U' ? C[:U]'C[:U] : C[:L]*C[:L]' +convert(::Type{AbstractMatrix}, C::Cholesky) = C.uplo == 'U' ? C.U'C.U : C.L*C.L' convert(::Type{AbstractArray}, C::Cholesky) = convert(AbstractMatrix, C) convert(::Type{Matrix}, C::Cholesky) = convert(Array, convert(AbstractArray, C)) convert(::Type{Array}, C::Cholesky) = convert(Matrix, C) function convert(::Type{AbstractMatrix}, F::CholeskyPivoted) - ip = invperm(F[:p]) - (F[:L] * F[:U])[ip,ip] + ip = invperm(F.p) + (F.L * F.U)[ip,ip] end convert(::Type{AbstractArray}, F::CholeskyPivoted) = convert(AbstractMatrix, F) convert(::Type{Matrix}, F::CholeskyPivoted) = convert(Array, convert(AbstractArray, F)) @@ -380,25 +380,38 @@ copy(C::CholeskyPivoted) = CholeskyPivoted(copy(C.factors), C.uplo, C.piv, C.ran size(C::Union{Cholesky, CholeskyPivoted}) = size(C.factors) size(C::Union{Cholesky, CholeskyPivoted}, d::Integer) = size(C.factors, d) -function getindex(C::Cholesky, d::Symbol) - d == :U && return UpperTriangular(Symbol(C.uplo) == d ? C.factors : C.factors') - d == :L && return LowerTriangular(Symbol(C.uplo) == d ? C.factors : C.factors') - d == :UL && return Symbol(C.uplo) == :U ? UpperTriangular(C.factors) : LowerTriangular(C.factors) - throw(KeyError(d)) -end -function getindex(C::CholeskyPivoted{T}, d::Symbol) where T<:BlasFloat - d == :U && return UpperTriangular(Symbol(C.uplo) == d ? C.factors : C.factors') - d == :L && return LowerTriangular(Symbol(C.uplo) == d ? C.factors : C.factors') - d == :p && return C.piv - if d == :P +@inline function getproperty(C::Cholesky, d::Symbol) + Cfactors = getfield(C, :factors) + Cuplo = getfield(C, :uplo) + if d == :U + return UpperTriangular(Symbol(Cuplo) == d ? Cfactors : Cfactors') + elseif d == :L + return LowerTriangular(Symbol(Cuplo) == d ? Cfactors : Cfactors') + elseif d == :UL + return Symbol(Cuplo) == :U ? UpperTriangular(Cfactors) : LowerTriangular(Cfactors) + else + return getfield(C, d) + end +end +@inline function getproperty(C::CholeskyPivoted{T}, d::Symbol) where T<:BlasFloat + Cfactors = getfield(C, :factors) + Cuplo = getfield(C, :uplo) + if d == :U + return UpperTriangular(Symbol(Cuplo) == d ? Cfactors : Cfactors') + elseif d == :L + return LowerTriangular(Symbol(Cuplo) == d ? Cfactors : Cfactors') + elseif d == :p + return getfield(C, :piv) + elseif d == :P n = size(C, 1) P = zeros(T, n, n) for i = 1:n - P[C.piv[i],i] = one(T) + P[getfield(C, :piv)[i], i] = one(T) end return P + else + return getfield(C, d) end - throw(KeyError(d)) end issuccess(C::Cholesky) = C.info == 0 @@ -406,7 +419,7 @@ issuccess(C::Cholesky) = C.info == 0 function show(io::IO, mime::MIME{Symbol("text/plain")}, C::Cholesky{<:Any,<:AbstractMatrix}) if issuccess(C) println(io, summary(C), "\n$(C.uplo) factor:") - show(io, mime, C[:UL]) + show(io, mime, C.UL) else print(io, "Failed factorization of type $(typeof(C))") end @@ -414,9 +427,9 @@ end function show(io::IO, mime::MIME{Symbol("text/plain")}, C::CholeskyPivoted{<:Any,<:AbstractMatrix}) println(io, summary(C), "\n$(C.uplo) factor with rank $(rank(C)):") - show(io, mime, C.uplo == 'U' ? C[:U] : C[:L]) + show(io, mime, C.uplo == 'U' ? C.U : C.L) println(io, "\npermutation:") - show(io, mime, C[:p]) + show(io, mime, C.p) end ldiv!(C::Cholesky{T,<:AbstractMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = @@ -534,8 +547,8 @@ rank(C::CholeskyPivoted) = C.rank """ lowrankupdate!(C::Cholesky, v::StridedVector) -> CC::Cholesky -Update a Cholesky factorization `C` with the vector `v`. If `A = C[:U]'C[:U]` then -`CC = cholfact(C[:U]'C[:U] + v*v')` but the computation of `CC` only uses `O(n^2)` +Update a Cholesky factorization `C` with the vector `v`. If `A = C.U'C.U` then +`CC = cholfact(C.U'C.U + v*v')` but the computation of `CC` only uses `O(n^2)` operations. The input factorization `C` is updated in place such that on exit `C == CC`. The vector `v` is destroyed during the computation. """ @@ -580,8 +593,8 @@ end """ lowrankdowndate!(C::Cholesky, v::StridedVector) -> CC::Cholesky -Downdate a Cholesky factorization `C` with the vector `v`. If `A = C[:U]'C[:U]` then -`CC = cholfact(C[:U]'C[:U] - v*v')` but the computation of `CC` only uses `O(n^2)` +Downdate a Cholesky factorization `C` with the vector `v`. If `A = C.U'C.U` then +`CC = cholfact(C.U'C.U - v*v')` but the computation of `CC` only uses `O(n^2)` operations. The input factorization `C` is updated in place such that on exit `C == CC`. The vector `v` is destroyed during the computation. """ @@ -633,8 +646,8 @@ end """ lowrankupdate(C::Cholesky, v::StridedVector) -> CC::Cholesky -Update a Cholesky factorization `C` with the vector `v`. If `A = C[:U]'C[:U]` -then `CC = cholfact(C[:U]'C[:U] + v*v')` but the computation of `CC` only uses +Update a Cholesky factorization `C` with the vector `v`. If `A = C.U'C.U` +then `CC = cholfact(C.U'C.U + v*v')` but the computation of `CC` only uses `O(n^2)` operations. """ lowrankupdate(C::Cholesky, v::StridedVector) = lowrankupdate!(copy(C), copy(v)) @@ -642,8 +655,8 @@ lowrankupdate(C::Cholesky, v::StridedVector) = lowrankupdate!(copy(C), copy(v)) """ lowrankdowndate(C::Cholesky, v::StridedVector) -> CC::Cholesky -Downdate a Cholesky factorization `C` with the vector `v`. If `A = C[:U]'C[:U]` -then `CC = cholfact(C[:U]'C[:U] - v*v')` but the computation of `CC` only uses +Downdate a Cholesky factorization `C` with the vector `v`. If `A = C.U'C.U` +then `CC = cholfact(C.U'C.U - v*v')` but the computation of `CC` only uses `O(n^2)` operations. """ lowrankdowndate(C::Cholesky, v::StridedVector) = lowrankdowndate!(copy(C), copy(v)) diff --git a/base/linalg/dense.jl b/base/linalg/dense.jl index 89615a7771babb..4a81482633fa45 100644 --- a/base/linalg/dense.jl +++ b/base/linalg/dense.jl @@ -709,8 +709,8 @@ function sqrt(A::StridedMatrix{<:Real}) return triu!(parent(sqrt(UpperTriangular(A)))) else SchurF = schurfact(complex(A)) - R = triu!(parent(sqrt(UpperTriangular(SchurF[:T])))) # unwrapping unnecessary? - return SchurF[:vectors] * R * SchurF[:vectors]' + R = triu!(parent(sqrt(UpperTriangular(SchurF.T)))) # unwrapping unnecessary? + return SchurF.vectors * R * SchurF.vectors' end end function sqrt(A::StridedMatrix{<:Complex}) @@ -723,8 +723,8 @@ function sqrt(A::StridedMatrix{<:Complex}) return triu!(parent(sqrt(UpperTriangular(A)))) else SchurF = schurfact(A) - R = triu!(parent(sqrt(UpperTriangular(SchurF[:T])))) # unwrapping unnecessary? - return SchurF[:vectors] * R * SchurF[:vectors]' + R = triu!(parent(sqrt(UpperTriangular(SchurF.T)))) # unwrapping unnecessary? + return SchurF.vectors * R * SchurF.vectors' end end diff --git a/base/linalg/eigen.jl b/base/linalg/eigen.jl index 2c92c9fa4ba556..121f62b85237b3 100644 --- a/base/linalg/eigen.jl +++ b/base/linalg/eigen.jl @@ -20,13 +20,6 @@ end GeneralizedEigen(values::AbstractVector{V}, vectors::AbstractMatrix{T}) where {T,V} = GeneralizedEigen{T,V,typeof(vectors),typeof(values)}(values, vectors) - -function getindex(A::Union{Eigen,GeneralizedEigen}, d::Symbol) - d == :values && return A.values - d == :vectors && return A.vectors - throw(KeyError(d)) -end - isposdef(A::Union{Eigen,GeneralizedEigen}) = isreal(A.values) && all(x -> x > 0, A.values) """ @@ -69,8 +62,8 @@ end eigfact(A; permute::Bool=true, scale::Bool=true) -> Eigen Computes the eigenvalue decomposition of `A`, returning an `Eigen` factorization object `F` -which contains the eigenvalues in `F[:values]` and the eigenvectors in the columns of the -matrix `F[:vectors]`. (The `k`th eigenvector can be obtained from the slice `F[:vectors][:, k]`.) +which contains the eigenvalues in `F.values` and the eigenvectors in the columns of the +matrix `F.vectors`. (The `k`th eigenvector can be obtained from the slice `F.vectors[:, k]`.) The following functions are available for `Eigen` objects: [`inv`](@ref), [`det`](@ref), and [`isposdef`](@ref). @@ -84,13 +77,13 @@ make rows and columns more equal in norm. The default is `true` for both options julia> F = eigfact([1.0 0.0 0.0; 0.0 3.0 0.0; 0.0 0.0 18.0]) Base.LinAlg.Eigen{Float64,Float64,Array{Float64,2},Array{Float64,1}}([1.0, 3.0, 18.0], [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]) -julia> F[:values] +julia> F.values 3-element Array{Float64,1}: 1.0 3.0 18.0 -julia> F[:vectors] +julia> F.vectors 3×3 Array{Float64,2}: 1.0 0.0 0.0 0.0 1.0 0.0 @@ -154,9 +147,9 @@ julia> eigvecs([1.0 0.0 0.0; 0.0 3.0 0.0; 0.0 0.0 18.0]) """ eigvecs(A::Union{Number, AbstractMatrix}; permute::Bool=true, scale::Bool=true) = eigvecs(eigfact(A, permute=permute, scale=scale)) -eigvecs(F::Union{Eigen{T,V,S,U}, GeneralizedEigen{T,V,S,U}}) where {T,V,S,U} = F[:vectors]::S +eigvecs(F::Union{Eigen, GeneralizedEigen}) = F.vectors -eigvals(F::Union{Eigen{T,V,S,U}, GeneralizedEigen{T,V,S,U}}) where {T,V,S,U} = F[:values]::U +eigvals(F::Union{Eigen, GeneralizedEigen}) = F.values """ eigvals!(A; permute::Bool=true, scale::Bool=true) -> values @@ -352,8 +345,8 @@ end Computes the generalized eigenvalue decomposition of `A` and `B`, returning a `GeneralizedEigen` factorization object `F` which contains the generalized eigenvalues in -`F[:values]` and the generalized eigenvectors in the columns of the matrix `F[:vectors]`. -(The `k`th generalized eigenvector can be obtained from the slice `F[:vectors][:, k]`.) +`F.values` and the generalized eigenvectors in the columns of the matrix `F.vectors`. +(The `k`th generalized eigenvector can be obtained from the slice `F.vectors[:, k]`.) # Examples ```jldoctest @@ -369,12 +362,12 @@ julia> B = [0 1; 1 0] julia> F = eigfact(A, B); -julia> F[:values] +julia> F.values 2-element Array{Complex{Float64},1}: 0.0 + 1.0im 0.0 - 1.0im -julia> F[:vectors] +julia> F.vectors 2×2 Array{Complex{Float64},2}: 0.0-1.0im 0.0+1.0im -1.0-0.0im -1.0+0.0im diff --git a/base/linalg/hessenberg.jl b/base/linalg/hessenberg.jl index 1d13fb7eb591f2..f0f817f2efcd1a 100644 --- a/base/linalg/hessenberg.jl +++ b/base/linalg/hessenberg.jl @@ -25,8 +25,8 @@ hessfact(A::StridedMatrix{<:BlasFloat}) = hessfact!(copy(A)) hessfact(A) -> Hessenberg Compute the Hessenberg decomposition of `A` and return a `Hessenberg` object. If `F` is the -factorization object, the unitary matrix can be accessed with `F[:Q]` and the Hessenberg -matrix with `F[:H]`. When `Q` is extracted, the resulting type is the `HessenbergQ` object, +factorization object, the unitary matrix can be accessed with `F.Q` and the Hessenberg +matrix with `F.H`. When `Q` is extracted, the resulting type is the `HessenbergQ` object, and may be converted to a regular matrix with [`convert(Array, _)`](@ref) (or `Array(_)` for short). @@ -40,7 +40,7 @@ julia> A = [4. 9. 7.; 4. 4. 1.; 4. 3. 2.] julia> F = hessfact(A); -julia> F[:Q] * F[:H] * F[:Q]' +julia> F.Q * F.H * F.Q' 3×3 Array{Float64,2}: 4.0 9.0 7.0 4.0 4.0 1.0 @@ -60,10 +60,10 @@ HessenbergQ(A::Hessenberg) = HessenbergQ(A.factors, A.τ) size(A::HessenbergQ, d) = size(A.factors, d) size(A::HessenbergQ) = size(A.factors) -function getindex(A::Hessenberg, d::Symbol) - d == :Q && return HessenbergQ(A) - d == :H && return triu(A.factors, -1) - throw(KeyError(d)) +@inline function getproperty(F::Hessenberg, d::Symbol) + d == :Q && return HessenbergQ(F) + d == :H && return triu(getfield(F, :factors), -1) + return getfield(F, d) end function getindex(A::HessenbergQ, i::Integer, j::Integer) @@ -77,7 +77,7 @@ end ## reconstruct the original matrix convert(::Type{Matrix}, A::HessenbergQ{<:BlasFloat}) = LAPACK.orghr!(1, size(A.factors, 1), copy(A.factors), A.τ) convert(::Type{Array}, A::HessenbergQ) = convert(Matrix, A) -convert(::Type{AbstractMatrix}, F::Hessenberg) = (fq = Array(F[:Q]); (fq * F[:H]) * fq') +convert(::Type{AbstractMatrix}, F::Hessenberg) = (fq = Array(F.Q); (fq * F.H) * fq') convert(::Type{AbstractArray}, F::Hessenberg) = convert(AbstractMatrix, F) convert(::Type{Matrix}, F::Hessenberg) = convert(Array, convert(AbstractArray, F)) convert(::Type{Array}, F::Hessenberg) = convert(Matrix, F) diff --git a/base/linalg/linalg.jl b/base/linalg/linalg.jl index 9dd0c65d719df2..4c0df31076d5ad 100644 --- a/base/linalg/linalg.jl +++ b/base/linalg/linalg.jl @@ -34,9 +34,10 @@ import Base: A_mul_Bt, At_ldiv_Bt, A_rdiv_Bc, At_ldiv_B, Ac_mul_Bc, A_mul_Bc, Ac import Base: USE_BLAS64, abs, acos, acosh, acot, acoth, acsc, acsch, adjoint, asec, asech, asin, asinh, atan, atanh, axes, big, broadcast, ceil, conj, convert, copy, copyto!, cos, cosh, cot, coth, csc, csch, eltype, exp, findmax, findmin, fill!, floor, getindex, hcat, - imag, inv, isapprox, isone, IndexStyle, kron, length, log, map, ndims, oneunit, parent, - power_by_squaring, print_matrix, promote_rule, real, round, sec, sech, setindex!, show, - similar, sin, sincos, sinh, size, sqrt, tan, tanh, transpose, trunc, typed_hcat, vec + getproperty, imag, inv, isapprox, isone, IndexStyle, kron, length, log, map, ndims, + oneunit, parent, power_by_squaring, print_matrix, promote_rule, real, round, sec, sech, + setindex!, show, similar, sin, sincos, sinh, size, sqrt, tan, tanh, transpose, trunc, + typed_hcat, vec using Base: hvcat_fill, iszero, IndexLinear, _length, promote_op, promote_typeof, @propagate_inbounds, @pure, reduce, typed_vcat # We use `_length` because of non-1 indices; releases after julia 0.5 diff --git a/base/linalg/lq.jl b/base/linalg/lq.jl index 1738e1c3a13eee..baa5ee8c8a5491 100644 --- a/base/linalg/lq.jl +++ b/base/linalg/lq.jl @@ -56,7 +56,7 @@ function lq(A::Union{Number,AbstractMatrix}; full::Bool = false, thin::Union{Boo full::Bool = !thin end F = lqfact(A) - L, Q = F[:L], F[:Q] + L, Q = F.L, F.Q return L, !full ? Array(Q) : mul!(Q, Matrix{eltype(Q)}(I, size(Q.factors, 2), size(Q.factors, 2))) end @@ -65,34 +65,32 @@ copy(A::LQ) = LQ(copy(A.factors), copy(A.τ)) convert(::Type{LQ{T}},A::LQ) where {T} = LQ(convert(AbstractMatrix{T}, A.factors), convert(Vector{T}, A.τ)) convert(::Type{Factorization{T}}, A::LQ{T}) where {T} = A convert(::Type{Factorization{T}}, A::LQ) where {T} = convert(LQ{T}, A) -convert(::Type{AbstractMatrix}, A::LQ) = A[:L]*A[:Q] +convert(::Type{AbstractMatrix}, A::LQ) = A.L*A.Q convert(::Type{AbstractArray}, A::LQ) = convert(AbstractMatrix, A) convert(::Type{Matrix}, A::LQ) = convert(Array, convert(AbstractArray, A)) convert(::Type{Array}, A::LQ) = convert(Matrix, A) adjoint(A::LQ{T}) where {T} = QR{T,typeof(A.factors)}(A.factors', A.τ) -function getindex(A::LQ, d::Symbol) - m, n = size(A) +@inline function getproperty(F::LQ, d::Symbol) + m, n = size(F) if d == :L - return tril!(A.factors[1:m, 1:min(m,n)]) + return tril!(getfield(F, :factors)[1:m, 1:min(m,n)]) elseif d == :Q - return LQPackedQ(A.factors,A.τ) + return LQPackedQ(getfield(F, :factors), getfield(F, :τ)) else - throw(KeyError(d)) + return getfield(F, d) end end getindex(A::LQPackedQ, i::Integer, j::Integer) = mul!(A, setindex!(zeros(eltype(A), size(A, 2)), 1, j))[i] -getq(A::LQ) = LQPackedQ(A.factors, A.τ) - function show(io::IO, C::LQ) println(io, "$(typeof(C)) with factors L and Q:") - show(io, C[:L]) + show(io, C.L) println(io) - show(io, C[:Q]) + show(io, C.Q) end convert(::Type{LQPackedQ{T}}, Q::LQPackedQ) where {T} = LQPackedQ(convert(AbstractMatrix{T}, Q.factors), convert(Vector{T}, Q.τ)) @@ -100,8 +98,8 @@ convert(::Type{AbstractMatrix{T}}, Q::LQPackedQ) where {T} = convert(LQPackedQ{T convert(::Type{Matrix}, A::LQPackedQ) = LAPACK.orglq!(copy(A.factors),A.τ) convert(::Type{Array}, A::LQPackedQ) = convert(Matrix, A) -size(A::LQ, dim::Integer) = size(A.factors, dim) -size(A::LQ) = size(A.factors) +size(F::LQ, dim::Integer) = size(getfield(F, :factors), dim) +size(F::LQ) = size(getfield(F, :factors)) # size(Q::LQPackedQ) yields the shape of Q's square form function size(Q::LQPackedQ) @@ -121,9 +119,9 @@ end ## Multiplication by LQ mul!(A::LQ{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = - A[:L] * LAPACK.ormlq!('L', 'N', A.factors, A.τ, B) + A.L * LAPACK.ormlq!('L', 'N', A.factors, A.τ, B) mul!(A::LQ{T}, B::QR{T}) where {T<:BlasFloat} = - A[:L] * LAPACK.ormlq!('L', 'N', A.factors, A.τ, Matrix(B)) + A.L * LAPACK.ormlq!('L', 'N', A.factors, A.τ, Matrix(B)) mul!(A::QR{T}, B::LQ{T}) where {T<:BlasFloat} = mul!(zeros(eltype(A), size(A)), Matrix(A), Matrix(B)) function *(A::LQ{TA}, B::StridedVecOrMat{TB}) where {TA,TB} @@ -289,6 +287,6 @@ end function ldiv!(A::LQ{T}, B::StridedVecOrMat{T}) where T - mul!(Adjoint(A[:Q]), ldiv!(LowerTriangular(A[:L]),B)) + mul!(Adjoint(A.Q), ldiv!(LowerTriangular(A.L),B)) return B end diff --git a/base/linalg/lu.jl b/base/linalg/lu.jl index d8ca0dae384942..1477d46e266b7f 100644 --- a/base/linalg/lu.jl +++ b/base/linalg/lu.jl @@ -130,14 +130,14 @@ The individual components of the factorization `F` can be accessed by indexing: | Component | Description | |:----------|:------------------------------------| -| `F[:L]` | `L` (lower triangular) part of `LU` | -| `F[:U]` | `U` (upper triangular) part of `LU` | -| `F[:p]` | (right) permutation `Vector` | -| `F[:P]` | (right) permutation `Matrix` | +| `F.L` | `L` (lower triangular) part of `LU` | +| `F.U` | `U` (upper triangular) part of `LU` | +| `F.p` | (right) permutation `Vector` | +| `F.P` | (right) permutation `Matrix` | The relationship between `F` and `A` is -`F[:L]*F[:U] == A[F[:p], :]` +`F.L*F.U == A[F.p, :]` `F` further supports the following functions: @@ -169,7 +169,7 @@ U factor: 4.0 3.0 0.0 -1.5 -julia> F[:L] * F[:U] == A[F[:p], :] +julia> F.L * F.U == A[F.p, :] true ``` """ @@ -224,7 +224,7 @@ true """ function lu(A::AbstractMatrix, pivot::Union{Val{false}, Val{true}} = Val(true)) F = lufact(A, pivot) - F[:L], F[:U], F[:p] + F.L, F.U, F.p end function convert(::Type{LU{T}}, F::LU) where T @@ -237,8 +237,8 @@ convert(::Type{Factorization{T}}, F::LU) where {T} = convert(LU{T}, F) copy(A::LU{T,S}) where {T,S} = LU{T,S}(copy(A.factors), copy(A.ipiv), A.info) -size(A::LU) = size(A.factors) -size(A::LU,n) = size(A.factors,n) +size(A::LU) = size(getfield(A, :factors)) +size(A::LU, i) = size(getfield(A, :factors), i) function ipiv2perm(v::AbstractVector{T}, maxi::Integer) where T p = T[1:maxi;] @@ -248,20 +248,20 @@ function ipiv2perm(v::AbstractVector{T}, maxi::Integer) where T return p end -function getindex(F::LU{T,<:StridedMatrix}, d::Symbol) where T +function getproperty(F::LU{T,<:StridedMatrix}, d::Symbol) where T m, n = size(F) if d == :L - L = tril!(F.factors[1:m, 1:min(m,n)]) + L = tril!(getfield(F, :factors)[1:m, 1:min(m,n)]) for i = 1:min(m,n); L[i,i] = one(T); end return L elseif d == :U - return triu!(F.factors[1:min(m,n), 1:n]) + return triu!(getfield(F, :factors)[1:min(m,n), 1:n]) elseif d == :p - return ipiv2perm(F.ipiv, m) + return ipiv2perm(getfield(F, :ipiv), m) elseif d == :P - return Matrix{T}(I, m, m)[:,invperm(F[:p])] + return Matrix{T}(I, m, m)[:,invperm(F.p)] else - throw(KeyError(d)) + getfield(F, d) end end @@ -270,9 +270,9 @@ issuccess(F::LU) = F.info == 0 function show(io::IO, mime::MIME{Symbol("text/plain")}, F::LU) if issuccess(F) println(io, summary(F), "\nL factor:") - show(io, mime, F[:L]) + show(io, mime, F.L) println(io, "\nU factor:") - show(io, mime, F[:U]) + show(io, mime, F.U) else print(io, "Failed factorization of type $(typeof(F))") end @@ -463,28 +463,28 @@ end factorize(A::Tridiagonal) = lufact(A) -function getindex(F::LU{T,Tridiagonal{T,V}}, d::Symbol) where {T,V} +function getproperty(F::LU{T,Tridiagonal{T,V}}, d::Symbol) where {T,V} m, n = size(F) if d == :L - L = Array(Bidiagonal(ones(T, n), F.factors.dl, d)) + L = Array(Bidiagonal(ones(T, n), getfield(getfield(F, :factors), :dl), d)) for i = 2:n - tmp = L[F.ipiv[i], 1:i - 1] - L[F.ipiv[i], 1:i - 1] = L[i, 1:i - 1] + tmp = L[getfield(F, :ipiv)[i], 1:i - 1] + L[getfield(F, :ipiv)[i], 1:i - 1] = L[i, 1:i - 1] L[i, 1:i - 1] = tmp end return L elseif d == :U - U = Array(Bidiagonal(F.factors.d, F.factors.du, d)) + U = Array(Bidiagonal(getfield(getfield(F, :factors), :d), getfield(getfield(F, :factors), :du), d)) for i = 1:n - 2 - U[i,i + 2] = F.factors.du2[i] + U[i,i + 2] = getfield(getfield(F, :factors), :du2)[i] end return U elseif d == :p - return ipiv2perm(F.ipiv, m) + return ipiv2perm(getfield(F, :ipiv), m) elseif d == :P - return Matrix{T}(I, m, m)[:,invperm(F[:p])] + return Matrix{T}(I, m, m)[:,invperm(F.p)] end - throw(KeyError(d)) + return getfield(F, d) end # See dgtts2.f @@ -593,7 +593,7 @@ end /(B::AbstractMatrix,A::LU) = transpose(Transpose(A) \ Transpose(B)) # Conversions -convert(::Type{AbstractMatrix}, F::LU) = (F[:L] * F[:U])[invperm(F[:p]),:] +convert(::Type{AbstractMatrix}, F::LU) = (F.L * F.U)[invperm(F.p),:] convert(::Type{AbstractArray}, F::LU) = convert(AbstractMatrix, F) convert(::Type{Matrix}, F::LU) = convert(Array, convert(AbstractArray, F)) convert(::Type{Array}, F::LU) = convert(Matrix, F) diff --git a/base/linalg/qr.jl b/base/linalg/qr.jl index b7292a4c80816f..3dd7a6a0feb2b5 100644 --- a/base/linalg/qr.jl +++ b/base/linalg/qr.jl @@ -258,17 +258,17 @@ The returned object `F` stores the factorization in a packed format: The individual components of the factorization `F` can be accessed by indexing with a symbol: - - `F[:Q]`: the orthogonal/unitary matrix `Q` - - `F[:R]`: the upper triangular matrix `R` - - `F[:p]`: the permutation vector of the pivot ([`QRPivoted`](@ref) only) - - `F[:P]`: the permutation matrix of the pivot ([`QRPivoted`](@ref) only) + - `F.Q`: the orthogonal/unitary matrix `Q` + - `F.R`: the upper triangular matrix `R` + - `F.p`: the permutation vector of the pivot ([`QRPivoted`](@ref) only) + - `F.P`: the permutation matrix of the pivot ([`QRPivoted`](@ref) only) The following functions are available for the `QR` objects: [`inv`](@ref), [`size`](@ref), and [`\\`](@ref). When `A` is rectangular, `\\` will return a least squares solution and if the solution is not unique, the one with smallest norm is returned. -Multiplication with respect to either full/square or non-full/square `Q` is allowed, i.e. both `F[:Q]*F[:R]` -and `F[:Q]*A` are supported. A `Q` matrix can be converted into a regular matrix with +Multiplication with respect to either full/square or non-full/square `Q` is allowed, i.e. both `F.Q*F.R` +and `F.Q*A` are supported. A `Q` matrix can be converted into a regular matrix with [`Matrix`](@ref). # Examples @@ -284,7 +284,7 @@ Base.LinAlg.QRCompactWY{Float64,Array{Float64,2}} with factors Q and R: [-0.6 0.0 0.8; -0.8 0.0 -0.6; 0.0 -1.0 0.0] [-5.0 10.0; 0.0 -1.0] -julia> F[:Q] * F[:R] == A +julia> F.Q * F.R == A true ``` @@ -327,13 +327,13 @@ function qr(A::Union{Number,AbstractMatrix}, pivot::Union{Val{false},Val{true}} end function _qr(A::Union{Number,AbstractMatrix}, ::Val{false}; full::Bool = false) F = qrfact(A, Val(false)) - Q, R = getq(F), F[:R]::Matrix{eltype(F)} + Q, R = F.Q, F.R sQf1 = size(Q.factors, 1) return (!full ? Array(Q) : mul!(Q, Matrix{eltype(Q)}(I, sQf1, sQf1))), R end function _qr(A::Union{Number, AbstractMatrix}, ::Val{true}; full::Bool = false) F = qrfact(A, Val(true)) - Q, R, p = getq(F), F[:R]::Matrix{eltype(F)}, F[:p]::Vector{BlasInt} + Q, R, p = F.Q, F.R, F.p sQf1 = size(Q.factors, 1) return (!full ? Array(Q) : mul!(Q, Matrix{eltype(Q)}(I, sQf1, sQf1))), R, p end @@ -410,55 +410,55 @@ convert(::Type{Factorization{T}}, A::QR) where {T} = convert(QR{T}, A) convert(::Type{QRCompactWY{T}}, A::QRCompactWY) where {T} = QRCompactWY(convert(AbstractMatrix{T}, A.factors), convert(AbstractMatrix{T}, A.T)) convert(::Type{Factorization{T}}, A::QRCompactWY{T}) where {T} = A convert(::Type{Factorization{T}}, A::QRCompactWY) where {T} = convert(QRCompactWY{T}, A) -convert(::Type{AbstractMatrix}, F::Union{QR,QRCompactWY}) = F[:Q] * F[:R] +convert(::Type{AbstractMatrix}, F::Union{QR,QRCompactWY}) = F.Q * F.R convert(::Type{AbstractArray}, F::Union{QR,QRCompactWY}) = convert(AbstractMatrix, F) convert(::Type{Matrix}, F::Union{QR,QRCompactWY}) = convert(Array, convert(AbstractArray, F)) convert(::Type{Array}, F::Union{QR,QRCompactWY}) = convert(Matrix, F) convert(::Type{QRPivoted{T}}, A::QRPivoted) where {T} = QRPivoted(convert(AbstractMatrix{T}, A.factors), convert(Vector{T}, A.τ), A.jpvt) convert(::Type{Factorization{T}}, A::QRPivoted{T}) where {T} = A convert(::Type{Factorization{T}}, A::QRPivoted) where {T} = convert(QRPivoted{T}, A) -convert(::Type{AbstractMatrix}, F::QRPivoted) = (F[:Q] * F[:R])[:,invperm(F[:p])] +convert(::Type{AbstractMatrix}, F::QRPivoted) = (F.Q * F.R)[:,invperm(F.p)] convert(::Type{AbstractArray}, F::QRPivoted) = convert(AbstractMatrix, F) convert(::Type{Matrix}, F::QRPivoted) = convert(Array, convert(AbstractArray, F)) convert(::Type{Array}, F::QRPivoted) = convert(Matrix, F) function show(io::IO, F::Union{QR, QRCompactWY, QRPivoted}) println(io, "$(typeof(F)) with factors Q and R:") - show(io, F[:Q]) + show(io, F.Q) println(io) - show(io, F[:R]) + show(io, F.R) end -function getindex(A::QR, d::Symbol) - m, n = size(A) +@inline function getproperty(F::QR, d::Symbol) + m, n = size(F) if d == :R - return triu!(A.factors[1:min(m,n), 1:n]) + return triu!(getfield(F, :factors)[1:min(m,n), 1:n]) elseif d == :Q - return getq(A) + return QRPackedQ(getfield(F, :factors), F.τ) else - throw(KeyError(d)) + getfield(F, d) end end -function getindex(A::QRCompactWY, d::Symbol) - m, n = size(A) +@inline function getproperty(F::QRCompactWY, d::Symbol) + m, n = size(F) if d == :R - return triu!(A.factors[1:min(m,n), 1:n]) + return triu!(getfield(F, :factors)[1:min(m,n), 1:n]) elseif d == :Q - return getq(A) + return QRCompactWYQ(getfield(F, :factors), F.T) else - throw(KeyError(d)) + getfield(F, d) end end -function getindex(A::QRPivoted{T}, d::Symbol) where T - m, n = size(A) +@inline function getproperty(F::QRPivoted{T}, d::Symbol) where T + m, n = size(F) if d == :R - return triu!(A.factors[1:min(m,n), 1:n]) + return triu!(getfield(F, :factors)[1:min(m,n), 1:n]) elseif d == :Q - return getq(A) + return QRPackedQ(getfield(F, :factors), F.τ) elseif d == :p - return A.jpvt + return getfield(F, :jpvt) elseif d == :P - p = A[:p] + p = F.p n = length(p) P = zeros(T, n, n) for i in 1:n @@ -466,16 +466,12 @@ function getindex(A::QRPivoted{T}, d::Symbol) where T end return P else - throw(KeyError(d)) + getfield(F, d) end end abstract type AbstractQ{T} <: AbstractMatrix{T} end -# Type-stable interface to get Q -getq(A::QRCompactWY) = QRCompactWYQ(A.factors,A.T) -getq(A::Union{QR, QRPivoted}) = QRPackedQ(A.factors,A.τ) - """ QRPackedQ <: AbstractMatrix @@ -511,9 +507,9 @@ convert(::Type{AbstractMatrix{S}}, Q::QRCompactWYQ) where {S} = convert(QRCompac convert(::Type{Matrix}, A::AbstractQ{T}) where {T} = mul!(A, Matrix{T}(I, size(A.factors, 1), min(size(A.factors)...))) convert(::Type{Array}, A::AbstractQ) = convert(Matrix, A) -size(A::Union{QR,QRCompactWY,QRPivoted}, dim::Integer) = size(A.factors, dim) -size(A::Union{QR,QRCompactWY,QRPivoted}) = size(A.factors) -size(A::AbstractQ, dim::Integer) = 0 < dim ? (dim <= 2 ? size(A.factors, 1) : 1) : throw(BoundsError()) +size(A::Union{QR,QRCompactWY,QRPivoted}, dim::Integer) = size(getfield(A, :factors), dim) +size(A::Union{QR,QRCompactWY,QRPivoted}) = size(getfield(A, :factors)) +size(A::AbstractQ, dim::Integer) = 0 < dim ? (dim <= 2 ? size(getfield(A, :factors), 1) : 1) : throw(BoundsError()) size(A::AbstractQ) = size(A, 1), size(A, 2) @@ -740,9 +736,9 @@ function *(adjA::Adjoint{<:Any,<:StridedVecOrMat}, adjQ::Adjoint{<:Any,<:Abstrac end ldiv!(A::QRCompactWY{T}, b::StridedVector{T}) where {T<:BlasFloat} = - (ldiv!(UpperTriangular(A[:R]), view(mul!(Adjoint(A[:Q]), b), 1:size(A, 2))); b) + (ldiv!(UpperTriangular(A.R), view(mul!(Adjoint(A.Q), b), 1:size(A, 2))); b) ldiv!(A::QRCompactWY{T}, B::StridedMatrix{T}) where {T<:BlasFloat} = - (ldiv!(UpperTriangular(A[:R]), view(mul!(Adjoint(A[:Q]), B), 1:size(A, 2), 1:size(B, 2))); B) + (ldiv!(UpperTriangular(A.R), view(mul!(Adjoint(A.Q), B), 1:size(A, 2), 1:size(B, 2))); B) # Julia implementation similar to xgelsy function ldiv!(A::QRPivoted{T}, B::StridedMatrix{T}, rcond::Real) where T<:BlasFloat @@ -774,10 +770,10 @@ function ldiv!(A::QRPivoted{T}, B::StridedMatrix{T}, rcond::Real) where T<:BlasF rnk += 1 end C, τ = LAPACK.tzrzf!(A.factors[1:rnk,:]) - ldiv!(UpperTriangular(C[1:rnk,1:rnk]),view(mul!(Adjoint(getq(A)), view(B, 1:mA, 1:nrhs)), 1:rnk, 1:nrhs)) + ldiv!(UpperTriangular(C[1:rnk,1:rnk]),view(mul!(Adjoint(A.Q), view(B, 1:mA, 1:nrhs)), 1:rnk, 1:nrhs)) B[rnk+1:end,:] = zero(T) LAPACK.ormrz!('L', eltype(B)<:Complex ? 'C' : 'T', C, τ, view(B,1:nA,1:nrhs)) - B[1:nA,:] = view(B, 1:nA, :)[invperm(A[:p]::Vector{BlasInt}),:] + B[1:nA,:] = view(B, 1:nA, :)[invperm(A.p),:] return B, rnk end ldiv!(A::QRPivoted{T}, B::StridedVector{T}) where {T<:BlasFloat} = @@ -788,8 +784,8 @@ function ldiv!(A::QR{T}, B::StridedMatrix{T}) where T m, n = size(A) minmn = min(m,n) mB, nB = size(B) - mul!(Adjoint(A[:Q]), view(B, 1:m, :)) - R = A[:R] + mul!(Adjoint(A.Q), view(B, 1:m, :)) + R = A.R @inbounds begin if n > m # minimum norm solution τ = zeros(T,m) diff --git a/base/linalg/schur.jl b/base/linalg/schur.jl index 73fa0c5f6cf89f..c27b4ced494f69 100644 --- a/base/linalg/schur.jl +++ b/base/linalg/schur.jl @@ -40,9 +40,9 @@ schurfact!(A::StridedMatrix{<:BlasFloat}) = Schur(LinAlg.LAPACK.gees!('V', A)... schurfact(A::StridedMatrix) -> F::Schur Computes the Schur factorization of the matrix `A`. The (quasi) triangular Schur factor can -be obtained from the `Schur` object `F` with either `F[:Schur]` or `F[:T]` and the -orthogonal/unitary Schur vectors can be obtained with `F[:vectors]` or `F[:Z]` such that -`A = F[:vectors] * F[:Schur] * F[:vectors]'`. The eigenvalues of `A` can be obtained with `F[:values]`. +be obtained from the `Schur` object `F` with either `F.Schur` or `F.T` and the +orthogonal/unitary Schur vectors can be obtained with `F.vectors` or `F.Z` such that +`A = F.vectors * F.Schur * F.vectors'`. The eigenvalues of `A` can be obtained with `F.values`. # Examples ```jldoctest @@ -58,7 +58,7 @@ Base.LinAlg.Schur{Float64,Array{Float64,2}} with factors T and Z: and values: [3.0, -2.0] -julia> F[:vectors] * F[:Schur] * F[:vectors]' +julia> F.vectors * F.Schur * F.vectors' 2×2 Array{Float64,2}: 5.0 7.0 -2.0 -4.0 @@ -67,26 +67,24 @@ julia> F[:vectors] * F[:Schur] * F[:vectors]' schurfact(A::StridedMatrix{<:BlasFloat}) = schurfact!(copy(A)) schurfact(A::StridedMatrix{T}) where T = schurfact!(copy_oftype(A, eigtype(T))) -function getindex(F::Schur, d::Symbol) - if d == :T || d == :Schur - return F.T - elseif d == :Z || d == :vectors - return F.Z - elseif d == :values - return F.values +@inline function getproperty(F::Schur, d::Symbol) + if d == :Schur + return getfield(F, :T) + elseif d == :vectors + return getfield(F, :Z) else - throw(KeyError(d)) + getfield(F, d) end end function show(io::IO, F::Schur) println(io, "$(typeof(F)) with factors T and Z:") - show(io, F[:T]) + show(io, F.T) println(io) - show(io, F[:Z]) + show(io, F.Z) println(io) println(io, "and values:") - show(io, F[:values]) + show(io, F.values) end """ @@ -121,7 +119,7 @@ julia> Z * T * Z' """ function schur(A::StridedMatrix) SchurF = schurfact(A) - SchurF[:T], SchurF[:Z], SchurF[:values] + SchurF.T, SchurF.Z, SchurF.values end schur(A::Symmetric) = schur(copyto!(similar(parent(A)), A)) schur(A::Hermitian) = schur(copyto!(similar(parent(A)), A)) @@ -137,7 +135,7 @@ Same as [`ordschur`](@ref) but overwrites the factorization `F`. """ function ordschur!(schur::Schur, select::Union{Vector{Bool},BitVector}) _, _, vals = ordschur!(schur.T, schur.Z, select) - schur[:values][:] = vals + schur.values[:] = vals return schur end @@ -146,8 +144,8 @@ end Reorders the Schur factorization `F` of a matrix `A = Z*T*Z'` according to the logical array `select` returning the reordered factorization `F` object. The selected eigenvalues appear -in the leading diagonal of `F[:Schur]` and the corresponding leading columns of -`F[:vectors]` form an orthogonal/unitary basis of the corresponding right invariant +in the leading diagonal of `F.Schur` and the corresponding leading columns of +`F.vectors` form an orthogonal/unitary basis of the corresponding right invariant subspace. In the real case, a complex conjugate pair of eigenvalues must be either both included or both excluded via `select`. """ @@ -204,11 +202,11 @@ schurfact!(A::StridedMatrix{T}, B::StridedMatrix{T}) where {T<:BlasFloat} = schurfact(A::StridedMatrix, B::StridedMatrix) -> F::GeneralizedSchur Computes the Generalized Schur (or QZ) factorization of the matrices `A` and `B`. The -(quasi) triangular Schur factors can be obtained from the `Schur` object `F` with `F[:S]` -and `F[:T]`, the left unitary/orthogonal Schur vectors can be obtained with `F[:left]` or -`F[:Q]` and the right unitary/orthogonal Schur vectors can be obtained with `F[:right]` or -`F[:Z]` such that `A=F[:left]*F[:S]*F[:right]'` and `B=F[:left]*F[:T]*F[:right]'`. The -generalized eigenvalues of `A` and `B` can be obtained with `F[:alpha]./F[:beta]`. +(quasi) triangular Schur factors can be obtained from the `Schur` object `F` with `F.S` +and `F.T`, the left unitary/orthogonal Schur vectors can be obtained with `F.left` or +`F.Q` and the right unitary/orthogonal Schur vectors can be obtained with `F.right` or +`F.Z` such that `A=F.left*F.S*F.right'` and `B=F.left*F.T*F.right'`. The +generalized eigenvalues of `A` and `B` can be obtained with `F.alpha./F.beta`. """ schurfact(A::StridedMatrix{T},B::StridedMatrix{T}) where {T<:BlasFloat} = schurfact!(copy(A),copy(B)) function schurfact(A::StridedMatrix{TA}, B::StridedMatrix{TB}) where {TA,TB} @@ -223,8 +221,8 @@ Same as `ordschur` but overwrites the factorization `F`. """ function ordschur!(gschur::GeneralizedSchur, select::Union{Vector{Bool},BitVector}) _, _, α, β, _, _ = ordschur!(gschur.S, gschur.T, gschur.Q, gschur.Z, select) - gschur[:alpha][:] = α - gschur[:beta][:] = β + gschur.alpha[:] = α + gschur.beta[:] = β return gschur end @@ -233,10 +231,10 @@ end Reorders the Generalized Schur factorization `F` of a matrix pair `(A, B) = (Q*S*Z', Q*T*Z')` according to the logical array `select` and returns a GeneralizedSchur object `F`. The -selected eigenvalues appear in the leading diagonal of both `F[:S]` and `F[:T]`, and the +selected eigenvalues appear in the leading diagonal of both `F.S` and `F.T`, and the left and right orthogonal/unitary Schur vectors are also reordered such that -`(A, B) = F[:Q]*(F[:S], F[:T])*F[:Z]'` still holds and the generalized eigenvalues of `A` -and `B` can still be obtained with `F[:alpha]./F[:beta]`. +`(A, B) = F.Q*(F.S, F.T)*F.Z'` still holds and the generalized eigenvalues of `A` +and `B` can still be obtained with `F.alpha./F.beta`. """ ordschur(gschur::GeneralizedSchur, select::Union{Vector{Bool},BitVector}) = GeneralizedSchur(ordschur(gschur.S, gschur.T, gschur.Q, gschur.Z, select)...) @@ -264,23 +262,15 @@ ordschur(S::StridedMatrix{Ty}, T::StridedMatrix{Ty}, Q::StridedMatrix{Ty}, Z::StridedMatrix{Ty}, select::Union{Vector{Bool},BitVector}) where {Ty<:BlasFloat} = ordschur!(copy(S), copy(T), copy(Q), copy(Z), select) -function getindex(F::GeneralizedSchur, d::Symbol) - if d == :S - return F.S - elseif d == :T - return F.T - elseif d == :alpha - return F.alpha - elseif d == :beta - return F.beta - elseif d == :values - return F.alpha./F.beta - elseif d == :Q || d == :left - return F.Q - elseif d == :Z || d == :right - return F.Z +@inline function getproperty(F::GeneralizedSchur, d::Symbol) + if d == :values + return getfield(F, :alpha) ./ getfield(F, :beta) + elseif d == :left + return getfield(F, :Q) + elseif d == :right + return getfield(F, :Z) else - throw(KeyError(d)) + getfield(F, d) end end @@ -291,7 +281,7 @@ See [`schurfact`](@ref). """ function schur(A::StridedMatrix, B::StridedMatrix) SchurF = schurfact(A, B) - SchurF[:S], SchurF[:T], SchurF[:Q], SchurF[:Z], SchurF[:alpha], SchurF[:beta] + SchurF.S, SchurF.T, SchurF.Q, SchurF.Z, SchurF.alpha, SchurF.beta end # Conversion diff --git a/base/linalg/svd.jl b/base/linalg/svd.jl index e33dfb91670428..ca38d9cebc397b 100644 --- a/base/linalg/svd.jl +++ b/base/linalg/svd.jl @@ -27,7 +27,7 @@ julia> A = [1. 0. 0. 0. 2.; 0. 0. 3. 0. 0.; 0. 0. 0. 0. 0.; 0. 2. 0. 0. 0.] julia> F = svdfact!(A); -julia> F[:U] * Diagonal(F[:S]) * F[:Vt] +julia> F.U * Diagonal(F.S) * F.Vt 4×5 Array{Float64,2}: 1.0 0.0 0.0 0.0 2.0 0.0 0.0 3.0 0.0 0.0 @@ -64,8 +64,8 @@ end Compute the singular value decomposition (SVD) of `A` and return an `SVD` object. -`U`, `S`, `V` and `Vt` can be obtained from the factorization `F` with `F[:U]`, -`F[:S]`, `F[:V]` and `F[:Vt]`, such that `A = U * Diagonal(S) * Vt`. +`U`, `S`, `V` and `Vt` can be obtained from the factorization `F` with `F.U`, +`F.S`, `F.V` and `F.Vt`, such that `A = U * Diagonal(S) * Vt`. The algorithm produces `Vt` and hence `Vt` is more efficient to extract than `V`. The singular values in `S` are sorted in descending order. @@ -84,7 +84,7 @@ julia> A = [1. 0. 0. 0. 2.; 0. 0. 3. 0. 0.; 0. 0. 0. 0. 0.; 0. 2. 0. 0. 0.] julia> F = svdfact(A); -julia> F[:U] * Diagonal(F[:S]) * F[:Vt] +julia> F.U * Diagonal(F.S) * F.Vt 4×5 Array{Float64,2}: 1.0 0.0 0.0 0.0 2.0 0.0 0.0 3.0 0.0 0.0 @@ -178,17 +178,11 @@ function svd(x::Number; full::Bool = false, thin::Union{Bool,Void} = nothing) return first.(svd(fill(x, 1, 1))) end -function getindex(F::SVD, d::Symbol) - if d == :U - return F.U - elseif d == :S - return F.S - elseif d == :Vt - return F.Vt - elseif d == :V - return F.Vt' +@inline function getproperty(F::SVD, d::Symbol) + if d == :V + return getfield(F, :Vt)' else - throw(KeyError(d)) + return getfield(F, d) end end @@ -249,7 +243,7 @@ julia> svdvals(A) """ svdvals(A::AbstractMatrix{T}) where T = svdvals!(copy_oftype(A, eigtype(T))) svdvals(x::Number) = abs(x) -svdvals(S::SVD{<:Any,T}) where {T} = (S[:S])::Vector{T} +svdvals(S::SVD{<:Any,T}) where {T} = (S.S)::Vector{T} # SVD least squares function ldiv!(A::SVD{T}, B::StridedVecOrMat) where T @@ -297,12 +291,12 @@ julia> B = [0. 1.; 1. 0.] julia> F = svdfact!(A, B); -julia> F[:U]*F[:D1]*F[:R0]*F[:Q]' +julia> F.U*F.D1*F.R0*F.Q' 2×2 Array{Float64,2}: 1.0 0.0 0.0 -1.0 -julia> F[:V]*F[:D2]*F[:R0]*F[:Q]' +julia> F.V*F.D2*F.R0*F.Q' 2×2 Array{Float64,2}: 0.0 1.0 1.0 0.0 @@ -333,21 +327,21 @@ svdfact(A::StridedMatrix{T}, B::StridedMatrix{T}) where {T<:BlasFloat} = svdfact svdfact(A, B) -> GeneralizedSVD Compute the generalized SVD of `A` and `B`, returning a `GeneralizedSVD` factorization -object `F`, such that `A = F[:U]*F[:D1]*F[:R0]*F[:Q]'` and `B = F[:V]*F[:D2]*F[:R0]*F[:Q]'`. +object `F`, such that `A = F.U*F.D1*F.R0*F.Q'` and `B = F.V*F.D2*F.R0*F.Q'`. For an M-by-N matrix `A` and P-by-N matrix `B`, -- `F[:U]` is a M-by-M orthogonal matrix, -- `F[:V]` is a P-by-P orthogonal matrix, -- `F[:Q]` is a N-by-N orthogonal matrix, -- `F[:R0]` is a (K+L)-by-N matrix whose rightmost (K+L)-by-(K+L) block is +- `U` is a M-by-M orthogonal matrix, +- `V` is a P-by-P orthogonal matrix, +- `Q` is a N-by-N orthogonal matrix, +- `R0` is a (K+L)-by-N matrix whose rightmost (K+L)-by-(K+L) block is nonsingular upper block triangular, -- `F[:D1]` is a M-by-(K+L) diagonal matrix with 1s in the first K entries, -- `F[:D2]` is a P-by-(K+L) matrix whose top right L-by-L block is diagonal, +- `D1` is a M-by-(K+L) diagonal matrix with 1s in the first K entries, +- `D2` is a P-by-(K+L) matrix whose top right L-by-L block is diagonal, `K+L` is the effective numerical rank of the matrix `[A; B]`. -The entries of `F[:D1]` and `F[:D2]` are related, as explained in the LAPACK +The entries of `F.D1` and `F.D2` are related, as explained in the LAPACK documentation for the [generalized SVD](http://www.netlib.org/lapack/lug/node36.html) and the [xGGSVD3](http://www.netlib.org/lapack/explore-html/d6/db3/dggsvd3_8f.html) @@ -367,12 +361,12 @@ julia> B = [0. 1.; 1. 0.] julia> F = svdfact(A, B); -julia> F[:U]*F[:D1]*F[:R0]*F[:Q]' +julia> F.U*F.D1*F.R0*F.Q' 2×2 Array{Float64,2}: 1.0 0.0 0.0 -1.0 -julia> F[:V]*F[:D2]*F[:R0]*F[:Q]' +julia> F.V*F.D2*F.R0*F.Q' 2×2 Array{Float64,2}: 0.0 1.0 1.0 0.0 @@ -423,47 +417,47 @@ julia> V*D2*R0*Q' """ function svd(A::AbstractMatrix, B::AbstractMatrix) F = svdfact(A, B) - F[:U], F[:V], F[:Q], F[:D1], F[:D2], F[:R0] + F.U, F.V, F.Q, F.D1, F.D2, F.R0 end svd(x::Number, y::Number) = first.(svd(fill(x, 1, 1), fill(y, 1, 1))) -function getindex(obj::GeneralizedSVD{T}, d::Symbol) where T - if d == :U - return obj.U - elseif d == :V - return obj.V - elseif d == :Q - return obj.Q - elseif d == :alpha || d == :a - return obj.a - elseif d == :beta || d == :b - return obj.b +@inline function getproperty(F::GeneralizedSVD{T}, d::Symbol) where T + Fa = getfield(F, :a) + Fb = getfield(F, :b) + Fk = getfield(F, :k) + Fl = getfield(F, :l) + FU = getfield(F, :U) + FV = getfield(F, :V) + FQ = getfield(F, :Q) + FR = getfield(F, :R) + if d == :alpha + return Fa + elseif d == :beta + return Fb elseif d == :vals || d == :S - return obj.a[1:obj.k + obj.l] ./ obj.b[1:obj.k + obj.l] + return Fa[1:Fk + Fl] ./ Fb[1:Fk + Fl] elseif d == :D1 - m = size(obj.U, 1) - if m - obj.k - obj.l >= 0 - return [Matrix{T}(I, obj.k, obj.k) zeros(T, obj.k, obj.l) ; - zeros(T, obj.l, obj.k) Diagonal(obj.a[obj.k + 1:obj.k + obj.l]) ; - zeros(T, m - obj.k - obj.l, obj.k + obj.l) ] + m = size(FU, 1) + if m - Fk - Fl >= 0 + return [Matrix{T}(I, Fk, Fk) zeros(T, Fk, Fl) ; + zeros(T, Fl, Fk) Diagonal(Fa[Fk + 1:Fk + Fl]); + zeros(T, m - Fk - Fl, Fk + Fl) ] else - return [Matrix{T}(I, m, obj.k) [zeros(T, obj.k, m - obj.k); Diagonal(obj.a[obj.k + 1:m])] zeros(T, m, obj.k + obj.l - m)] + return [Matrix{T}(I, m, Fk) [zeros(T, Fk, m - Fk); Diagonal(Fa[Fk + 1:m])] zeros(T, m, Fk + Fl - m)] end elseif d == :D2 - m = size(obj.U, 1) - p = size(obj.V, 1) - if m - obj.k - obj.l >= 0 - return [zeros(T, obj.l, obj.k) Diagonal(obj.b[obj.k + 1:obj.k + obj.l]); zeros(T, p - obj.l, obj.k + obj.l)] + m = size(FU, 1) + p = size(FV, 1) + if m - Fk - Fl >= 0 + return [zeros(T, Fl, Fk) Diagonal(Fb[Fk + 1:Fk + Fl]); zeros(T, p - Fl, Fk + Fl)] else - return [zeros(T, p, obj.k) [Diagonal(obj.b[obj.k + 1:m]); zeros(T, obj.k + p - m, m - obj.k)] [zeros(T, m - obj.k, obj.k + obj.l - m); Matrix{T}(I, obj.k + p - m, obj.k + obj.l - m)]] + return [zeros(T, p, Fk) [Diagonal(Fb[Fk + 1:m]); zeros(T, Fk + p - m, m - Fk)] [zeros(T, m - Fk, Fk + Fl - m); Matrix{T}(I, Fk + p - m, Fk + Fl - m)]] end - elseif d == :R - return obj.R elseif d == :R0 - n = size(obj.Q, 1) - return [zeros(T, obj.k + obj.l, n - obj.k - obj.l) obj.R] + n = size(FQ, 1) + return [zeros(T, Fk + Fl, n - Fk - Fl) FR] else - throw(KeyError(d)) + getfield(F, d) end end diff --git a/stdlib/IterativeEigensolvers/src/IterativeEigensolvers.jl b/stdlib/IterativeEigensolvers/src/IterativeEigensolvers.jl index 50910bb3b50ff8..a163d67a3a7d2a 100644 --- a/stdlib/IterativeEigensolvers/src/IterativeEigensolvers.jl +++ b/stdlib/IterativeEigensolvers/src/IterativeEigensolvers.jl @@ -280,7 +280,7 @@ julia> A = Diagonal(1:4); julia> s = svds(A, nsv = 2)[1]; -julia> s[:S] +julia> s.S 2-element Array{Float64,1}: 4.0 2.9999999999999996 diff --git a/stdlib/SuiteSparse/src/cholmod.jl b/stdlib/SuiteSparse/src/cholmod.jl index cef9a4dc21a5d0..977a0e1e5d6496 100644 --- a/stdlib/SuiteSparse/src/cholmod.jl +++ b/stdlib/SuiteSparse/src/cholmod.jl @@ -2,7 +2,7 @@ module CHOLMOD -import Base: (*), convert, copy, eltype, getindex, show, size, +import Base: (*), convert, copy, eltype, getindex, getproperty, show, size, IndexStyle, IndexLinear, IndexCartesian, adjoint import Base.LinAlg: (\), @@ -196,13 +196,13 @@ struct C_Dense{T<:VTypes} <: SuiteSparseStruct end mutable struct Dense{T<:VTypes} <: DenseMatrix{T} - p::Ptr{C_Dense{T}} - function Dense{Tv}(p::Ptr{C_Dense{Tv}}) where Tv<:VTypes - if p == C_NULL + ptr::Ptr{C_Dense{T}} + function Dense{Tv}(ptr::Ptr{C_Dense{Tv}}) where Tv<:VTypes + if ptr == C_NULL throw(ArgumentError("dense matrix construction failed for " * "unknown reasons. Please submit a bug report.")) end - A = new(p) + A = new(ptr) finalizer(free!, A) return A end @@ -248,20 +248,20 @@ struct C_SparseVoid <: SuiteSparseStruct end mutable struct Sparse{Tv<:VTypes} <: AbstractSparseMatrix{Tv,SuiteSparse_long} - p::Ptr{C_Sparse{Tv}} - function Sparse{Tv}(p::Ptr{C_Sparse{Tv}}) where Tv<:VTypes - if p == C_NULL + ptr::Ptr{C_Sparse{Tv}} + function Sparse{Tv}(ptr::Ptr{C_Sparse{Tv}}) where Tv<:VTypes + if ptr == C_NULL throw(ArgumentError("sparse matrix construction failed for " * "unknown reasons. Please submit a bug report.")) end - A = new(p) + A = new(ptr) finalizer(free!, A) return A end end Sparse(p::Ptr{C_Sparse{Tv}}) where {Tv<:VTypes} = Sparse{Tv}(p) -Base.unsafe_convert(::Type{Ptr{Tv}}, A::Sparse{Tv}) where {Tv} = A.p +Base.unsafe_convert(::Type{Ptr{Tv}}, A::Sparse{Tv}) where {Tv} = getfield(A, :ptr) # Factor @@ -331,30 +331,31 @@ else end mutable struct Factor{Tv} <: Factorization{Tv} - p::Ptr{C_Factor{Tv}} - function Factor{Tv}(p::Ptr{C_Factor{Tv}}, register_finalizer = true) where Tv - if p == C_NULL + ptr::Ptr{C_Factor{Tv}} + function Factor{Tv}(ptr::Ptr{C_Factor{Tv}}, register_finalizer = true) where Tv + if ptr == C_NULL throw(ArgumentError("factorization construction failed for " * "unknown reasons. Please submit a bug report.")) end - F = new(p) + F = new(ptr) if register_finalizer finalizer(free!, F) end return F end end -Factor(p::Ptr{C_Factor{Tv}}) where {Tv<:VTypes} = Factor{Tv}(p) +Factor(ptr::Ptr{C_Factor{Tv}}) where {Tv<:VTypes} = Factor{Tv}(ptr) # All pointer loads should be checked to make sure that SuiteSparse is not called with # a C_NULL pointer which could cause a segfault. Pointers are set to null # when serialized so this can happen when mutiple processes are in use. function Base.unsafe_convert(::Type{Ptr{T}}, x::Union{Dense,Sparse,Factor}) where T<:SuiteSparseStruct - if x.p == C_NULL + xp = getfield(x, :ptr) + if xp == C_NULL throw(ArgumentError("pointer to the $T object is null. This can " * "happen if the object has been serialized.")) else - return x.p + return xp end end Base.pointer(x::Dense{Tv}) where {Tv} = Base.unsafe_convert(Ptr{C_Dense{Tv}}, x) @@ -463,7 +464,7 @@ end function check_dense(A::Dense{T}) where T<:VTypes ccall((:cholmod_l_check_dense, :libcholmod), Cint, (Ptr{C_Dense{T}}, Ptr{UInt8}), - A.p, common_struct) != 0 + pointer(A), common_struct) != 0 end # Non-Dense wrappers @@ -821,7 +822,7 @@ get_perm(FC::FactorComponent) = get_perm(Factor(FC)) # Convertion/construction function convert(::Type{Dense{T}}, A::StridedVecOrMat) where T<:VTypes d = allocate_dense(size(A, 1), size(A, 2), stride(A, 2), T) - s = unsafe_load(d.p) + s = unsafe_load(pointer(d)) for i in eachindex(A) unsafe_store!(s.x, A[i], i) end @@ -858,7 +859,7 @@ function Sparse(m::Integer, n::Integer, end o = allocate_sparse(m, n, colptr0[n + 1], iss, true, stype, Tv) - s = unsafe_load(o.p) + s = unsafe_load(pointer(o)) unsafe_copyto!(s.p, pointer(colptr0), n + 1) unsafe_copyto!(s.i, pointer(rowval0), colptr0[n + 1]) @@ -898,7 +899,7 @@ function Sparse(A::SparseMatrixCSC{Tv,SuiteSparse_long}, stype::Integer) where T end o = allocate_sparse(A.m, A.n, nnz(A), true, true, stype, Tv) - s = unsafe_load(o.p) + s = unsafe_load(pointer(o)) for i = 1:(A.n + 1) unsafe_store!(s.p, A.colptr[i] - 1, i) end @@ -937,7 +938,7 @@ function convert(::Type{Sparse}, AH::Hermitian{Tv,SparseMatrixCSC{Tv,SuiteSparse # Here we allocate a Symmetric/Hermitian CHOLMOD.Sparse matrix so we only need to copy # a single triangle of AH o = allocate_sparse(A.m, A.n, length(A.nzval), true, true, AH.uplo == 'L' ? -1 : 1, Tv) - s = unsafe_load(o.p) + s = unsafe_load(pointer(o)) for i = 1:length(A.colptr) unsafe_store!(s.p, A.colptr[i] - 1, i) end @@ -1026,7 +1027,7 @@ end ## convertion back to base Julia types function convert(::Type{Matrix{T}}, D::Dense{T}) where T - s = unsafe_load(D.p) + s = unsafe_load(pointer(D)) a = Matrix{T}(uninitialized, s.nrow, s.ncol) copyto!(a, D) end @@ -1038,7 +1039,7 @@ Base.copyto!(dest::AbstractArray{T,2}, D::Dense{T}) where {T<:VTypes} = _copy!(d Base.copyto!(dest::AbstractArray, D::Dense) = _copy!(dest, D) function _copy!(dest::AbstractArray, D::Dense) - s = unsafe_load(D.p) + s = unsafe_load(pointer(D)) n = s.nrow*s.ncol n <= length(dest) || throw(BoundsError(dest, n)) if s.d == s.nrow && isa(dest, Array) @@ -1063,7 +1064,7 @@ end convert(::Type{Vector}, D::Dense{T}) where {T} = convert(Vector{T}, D) function convert(::Type{SparseMatrixCSC{Tv,SuiteSparse_long}}, A::Sparse{Tv}) where Tv - s = unsafe_load(A.p) + s = unsafe_load(pointer(A)) if s.stype != 0 throw(ArgumentError("matrix has stype != 0. Convert to matrix " * "with stype == 0 before converting to SparseMatrixCSC")) @@ -1081,7 +1082,7 @@ function convert(::Type{SparseMatrixCSC{Tv,SuiteSparse_long}}, A::Sparse{Tv}) wh end end function convert(::Type{Symmetric{Float64,SparseMatrixCSC{Float64,SuiteSparse_long}}}, A::Sparse{Float64}) - s = unsafe_load(A.p) + s = unsafe_load(pointer(A)) if !issymmetric(A) throw(ArgumentError("matrix is not symmetric")) end @@ -1098,7 +1099,7 @@ function convert(::Type{Symmetric{Float64,SparseMatrixCSC{Float64,SuiteSparse_lo end end function convert(::Type{Hermitian{Tv,SparseMatrixCSC{Tv,SuiteSparse_long}}}, A::Sparse{Tv}) where Tv<:VTypes - s = unsafe_load(A.p) + s = unsafe_load(pointer(A)) if !ishermitian(A) throw(ArgumentError("matrix is not Hermitian")) end @@ -1115,14 +1116,14 @@ function convert(::Type{Hermitian{Tv,SparseMatrixCSC{Tv,SuiteSparse_long}}}, A:: end end function sparse(A::Sparse{Float64}) # Notice! Cannot be type stable because of stype - s = unsafe_load(A.p) + s = unsafe_load(pointer(A)) if s.stype == 0 return convert(SparseMatrixCSC{Float64,SuiteSparse_long}, A) end return convert(Symmetric{Float64,SparseMatrixCSC{Float64,SuiteSparse_long}}, A) end function sparse(A::Sparse{Complex{Float64}}) # Notice! Cannot be type stable because of stype - s = unsafe_load(A.p) + s = unsafe_load(pointer(A)) if s.stype == 0 return convert(SparseMatrixCSC{Complex{Float64},SuiteSparse_long}, A) end @@ -1134,7 +1135,7 @@ function sparse(F::Factor) L = Sparse(F) A = sparse(L*L') else - LD = sparse(F[:LD]) + LD = sparse(F.LD) L, d = getLd!(LD) A = (L * Diagonal(d)) * L' end @@ -1167,7 +1168,7 @@ sparse(FC::FactorComponent{Tv,:LD}) where {Tv} = sparse(Sparse(Factor(FC))) let offset = fieldoffset(C_Sparse{Float64}, findfirst(name -> name === :stype, fieldnames(C_Sparse{Float64}))) global change_stype! function change_stype!(A::Sparse, i::Integer) - unsafe_store!(convert(Ptr{Cint}, A.p), i, div(offset, 4) + 1) + unsafe_store!(convert(Ptr{Cint}, pointer(A)), i, div(offset, 4) + 1) return A end end @@ -1265,9 +1266,14 @@ function getindex(A::Sparse{T}, i0::Integer, i1::Integer) where T ((r1 > r2) || (unsafe_load(s.i, r1) + 1 != i0)) ? zero(T) : unsafe_load(s.x, r1) end -function getindex(F::Factor, sym::Symbol) - sym == :p && return get_perm(F) - FactorComponent(F, sym) +@inline function getproperty(F::Factor, sym::Symbol) + if sym == :p + return get_perm(F) + elseif sym == :ptr + return getfield(F, :ptr) + else + return FactorComponent(F, sym) + end end function getLd!(S::SparseMatrixCSC) @@ -1302,7 +1308,7 @@ function *(A::Sparse{Tv}, adjB::Adjoint{Tv,Sparse{Tv}}) where Tv<:VRealTypes ## The A*A' case is handled by cholmod_aat. This routine requires ## A->stype == 0 (storage of upper and lower parts). If neccesary ## the matrix A is first converted to stype == 0 - s = unsafe_load(A.p) + s = unsafe_load(pointer(A)) if s.stype != 0 aa1 = copy(A, 0, 1) return aat(aa1, SuiteSparse_long[0:s.ncol-1;], 1) @@ -1413,13 +1419,13 @@ A fill-reducing permutation is used. `F = cholfact(A)` is most frequently used to solve systems of equations with `F\\b`, but also the methods [`diag`](@ref), [`det`](@ref), and [`logdet`](@ref) are defined for `F`. -You can also extract individual factors from `F`, using `F[:L]`. +You can also extract individual factors from `F`, using `F.L`. However, since pivoting is on by default, the factorization is internally represented as `A == P'*L*L'*P` with a permutation matrix `P`; using just `L` without accounting for `P` will give incorrect answers. To include the effects of permutation, -it's typically preferable to extract "combined" factors like `PtL = F[:PtL]` -(the equivalent of `P'*L`) and `LtP = F[:UP]` (the equivalent of `L'*P`). +it's typically preferable to extract "combined" factors like `PtL = F.PtL` +(the equivalent of `P'*L`) and `LtP = F.UP` (the equivalent of `L'*P`). Setting the optional `shift` keyword argument computes the factorization of `A+shift*I` instead of `A`. If the `perm` argument is nonempty, @@ -1510,13 +1516,13 @@ A fill-reducing permutation is used. `F = ldltfact(A)` is most frequently used to solve systems of equations `A*x = b` with `F\\b`. The returned factorization object `F` also supports the methods [`diag`](@ref), [`det`](@ref), [`logdet`](@ref), and [`inv`](@ref). -You can extract individual factors from `F` using `F[:L]`. +You can extract individual factors from `F` using `F.L`. However, since pivoting is on by default, the factorization is internally represented as `A == P'*L*D*L'*P` with a permutation matrix `P`; using just `L` without accounting for `P` will give incorrect answers. To include the effects of permutation, it is typically preferable to extract -"combined" factors like `PtL = F[:PtL]` (the equivalent of -`P'*L`) and `LtP = F[:UP]` (the equivalent of `L'*P`). +"combined" factors like `PtL = F.PtL` (the equivalent of +`P'*L`) and `LtP = F.UP` (the equivalent of `L'*P`). The complete list of supported factors is `:L, :PtL, :D, :UP, :U, :LD, :DU, :PtLD, :DUP`. Setting the optional `shift` keyword argument computes the factorization of @@ -1791,7 +1797,7 @@ function isposdef(F::Factor) end function ishermitian(A::Sparse{Float64}) - s = unsafe_load(A.p) + s = unsafe_load(pointer(A)) if s.stype != 0 return true else @@ -1804,7 +1810,7 @@ function ishermitian(A::Sparse{Float64}) end end function ishermitian(A::Sparse{Complex{Float64}}) - s = unsafe_load(A.p) + s = unsafe_load(pointer(A)) if s.stype != 0 return true else diff --git a/stdlib/SuiteSparse/src/spqr.jl b/stdlib/SuiteSparse/src/spqr.jl index c675839baef6d3..d50f06f28ba799 100644 --- a/stdlib/SuiteSparse/src/spqr.jl +++ b/stdlib/SuiteSparse/src/spqr.jl @@ -158,7 +158,7 @@ end qrfact(A) -> QRSparse Compute the `QR` factorization of a sparse matrix `A`. Fill-reducing row and column permutations -are used such that `F[:R] = F[:Q]'*A[F[:prow],F[:pcol]]`. The main application of this type is to +are used such that `F.R = F.Q'*A[F.prow,F.pcol]`. The main application of this type is to solve least squares or underdetermined problems with [`\\`](@ref). The function calls the C library SPQR. # Examples @@ -258,29 +258,27 @@ function Base.LinAlg.mul!(A::StridedMatrix, adjQ::Adjoint{<:Any,<:QRSparseQ}) return A end -Base.LinAlg.getq(F::QRSparse) = QRSparseQ(F.factors, F.τ) - """ - getindex(F::QRSparse, d::Symbol) + getproperty(F::QRSparse, d::Symbol) Extract factors of a QRSparse factorization. Possible values of `d` are -- `:Q` : `QRSparseQ` matrix of the ``Q`` factor in Householder form -- `:R` : `UpperTriangular` ``R`` factor -- `:prow` : Vector of the row permutations applied to the factorized matrix -- `:pcol` : Vector of the column permutations applied to the factorized matrix +- `Q` : `QRSparseQ` matrix of the ``Q`` factor in Householder form +- `R` : `UpperTriangular` ``R`` factor +- `prow` : Vector of the row permutations applied to the factorized matrix +- `pcol` : Vector of the column permutations applied to the factorized matrix # Examples ```jldoctest julia> F = qrfact(sparse([1,3,2,3,4], [1,1,2,3,4], [1.0,2.0,3.0,4.0,5.0])); -julia> F[:Q] +julia> F.Q 4×4 Base.SparseArrays.SPQR.QRSparseQ{Float64,Int64}: 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 -julia> F[:R] +julia> F.R 4×4 SparseMatrixCSC{Float64,Int64} with 5 stored entries: [1, 1] = 3.0 [2, 2] = 4.0 @@ -288,14 +286,14 @@ julia> F[:R] [2, 4] = 2.0 [4, 4] = 1.0 -julia> F[:prow] +julia> F.prow 4-element Array{Int64,1}: 2 3 4 1 -julia> F[:pcol] +julia> F.pcol 4-element Array{Int64,1}: 2 3 @@ -303,30 +301,28 @@ julia> F[:pcol] 1 ``` """ -function Base.getindex(F::QRSparse, d::Symbol) +@inline function Base.getproperty(F::QRSparse, d::Symbol) if d == :Q - return LinAlg.getq(F) - elseif d == :R - return F.R + return QRSparseQ(F.factors, F.τ) elseif d == :prow return invperm(F.rpivinv) elseif d == :pcol return F.cpiv else - throw(KeyError(d)) + getfield(F, d) end end function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, F::QRSparse) println(io, summary(F)) println(io, "Q factor:") - show(io, mime, F[:Q]) + show(io, mime, F.Q) println(io, "\nR factor:") - show(io, mime, F[:R]) + show(io, mime, F.R) println(io, "\nRow permutation:") - show(io, mime, F[:prow]) + show(io, mime, F.prow) println(io, "\nColumn permutation:") - show(io, mime, F[:pcol]) + show(io, mime, F.pcol) end # With a real lhs and complex rhs with the same precision, we can reinterpret @@ -379,7 +375,7 @@ function _ldiv_basic(F::QRSparse, B::StridedVecOrMat) X0 = view(X, 1:size(B, 1), :) # Apply Q' to B - Base.LinAlg.mul!(Adjoint(LinAlg.getq(F)), X0) + Base.LinAlg.mul!(Adjoint(F.Q), X0) # Zero out to get basic solution X[rnk + 1:end, :] = 0 diff --git a/stdlib/SuiteSparse/src/umfpack.jl b/stdlib/SuiteSparse/src/umfpack.jl index cd54d8ff6be753..47635a2aec567b 100644 --- a/stdlib/SuiteSparse/src/umfpack.jl +++ b/stdlib/SuiteSparse/src/umfpack.jl @@ -4,7 +4,7 @@ module UMFPACK export UmfpackLU -import Base: (\), findnz, getindex, show, size +import Base: (\), findnz, getproperty, show, size import Base.LinAlg: Factorization, det, lufact, ldiv! using Base.LinAlg: Adjoint, Transpose @@ -117,16 +117,16 @@ The individual components of the factorization `F` can be accessed by indexing: | Component | Description | |:----------|:------------------------------------| -| `F[:L]` | `L` (lower triangular) part of `LU` | -| `F[:U]` | `U` (upper triangular) part of `LU` | -| `F[:p]` | right permutation `Vector` | -| `F[:q]` | left permutation `Vector` | -| `F[:Rs]` | `Vector` of scaling factors | -| `F[:(:)]` | `(L,U,p,q,Rs)` components | +| `L` | `L` (lower triangular) part of `LU` | +| `U` | `U` (upper triangular) part of `LU` | +| `p` | right permutation `Vector` | +| `q` | left permutation `Vector` | +| `Rs` | `Vector` of scaling factors | +| `:` | `(L,U,p,q,Rs)` components | The relation between `F` and `A` is -`F[:L]*F[:U] == (F[:Rs] .* A)[F[:p], F[:q]]` +`F.L*F.U == (F.Rs .* A)[F.p, F.q]` `F` further supports the following functions: @@ -447,22 +447,25 @@ function _AqldivB_kernel!(X::StridedMatrix{Tb}, lu::UmfpackLU{Float64}, end -function getindex(lu::UmfpackLU, d::Symbol) - L,U,p,q,Rs = umf_extract(lu) - if d == :L - return L - elseif d == :U - return U - elseif d == :p - return p - elseif d == :q - return q - elseif d == :Rs - return Rs - elseif d == :(:) - return (L,U,p,q,Rs) +@inline function getproperty(lu::UmfpackLU, d::Symbol) + if d == :L || d == :U || d == :p || d == :q || d == :Rs || d == :(:) + # Guard the call to umf_extract behaind a branch to avoid infinite recursion + L, U, p, q, Rs = umf_extract(lu) + if d == :L + return L + elseif d == :U + return U + elseif d == :p + return p + elseif d == :q + return q + elseif d == :Rs + return Rs + elseif d == :(:) + return (L, U, p, q, Rs) + end else - throw(KeyError(d)) + getfield(lu, d) end end diff --git a/stdlib/SuiteSparse/test/cholmod.jl b/stdlib/SuiteSparse/test/cholmod.jl index 7da1870f46fc04..cc6ad4e60da2a5 100644 --- a/stdlib/SuiteSparse/test/cholmod.jl +++ b/stdlib/SuiteSparse/test/cholmod.jl @@ -499,114 +499,114 @@ end @testset "cholfact, no permutation" begin Fs = cholfact(As, perm=[1:3;]) - @test Fs[:p] == [1:3;] - @test sparse(Fs[:L]) ≈ Lf + @test Fs.p == [1:3;] + @test sparse(Fs.L) ≈ Lf @test sparse(Fs) ≈ As b = rand(3) @test Fs\b ≈ Af\b - @test Fs[:UP]\(Fs[:PtL]\b) ≈ Af\b - @test Fs[:L]\b ≈ Lf\b - @test Fs[:U]\b ≈ Lf'\b - @test Fs[:L]'\b ≈ Lf'\b - @test Fs[:U]'\b ≈ Lf\b - @test Fs[:PtL]\b ≈ Lf\b - @test Fs[:UP]\b ≈ Lf'\b - @test Fs[:PtL]'\b ≈ Lf'\b - @test Fs[:UP]'\b ≈ Lf\b - @test_throws CHOLMOD.CHOLMODException Fs[:D] - @test_throws CHOLMOD.CHOLMODException Fs[:LD] - @test_throws CHOLMOD.CHOLMODException Fs[:DU] - @test_throws CHOLMOD.CHOLMODException Fs[:PLD] - @test_throws CHOLMOD.CHOLMODException Fs[:DUPt] + @test Fs.UP\(Fs.PtL\b) ≈ Af\b + @test Fs.L\b ≈ Lf\b + @test Fs.U\b ≈ Lf'\b + @test Fs.L'\b ≈ Lf'\b + @test Fs.U'\b ≈ Lf\b + @test Fs.PtL\b ≈ Lf\b + @test Fs.UP\b ≈ Lf'\b + @test Fs.PtL'\b ≈ Lf'\b + @test Fs.UP'\b ≈ Lf\b + @test_throws CHOLMOD.CHOLMODException Fs.D + @test_throws CHOLMOD.CHOLMODException Fs.LD + @test_throws CHOLMOD.CHOLMODException Fs.DU + @test_throws CHOLMOD.CHOLMODException Fs.PLD + @test_throws CHOLMOD.CHOLMODException Fs.DUPt end @testset "cholfact, with permutation" begin Fs = cholfact(As, perm=p) - @test Fs[:p] == p + @test Fs.p == p Afp = Af[p,p] - Lfp = cholfact(Afp)[:L] - @test sparse(Fs[:L]) ≈ Lfp + Lfp = cholfact(Afp).L + @test sparse(Fs.L) ≈ Lfp @test sparse(Fs) ≈ As b = rand(3) @test Fs\b ≈ Af\b - @test Fs[:UP]\(Fs[:PtL]\b) ≈ Af\b - @test Fs[:L]\b ≈ Lfp\b - @test Fs[:U]'\b ≈ Lfp\b - @test Fs[:U]\b ≈ Lfp'\b - @test Fs[:L]'\b ≈ Lfp'\b - @test Fs[:PtL]\b ≈ Lfp\b[p] - @test Fs[:UP]\b ≈ (Lfp'\b)[p_inv] - @test Fs[:PtL]'\b ≈ (Lfp'\b)[p_inv] - @test Fs[:UP]'\b ≈ Lfp\b[p] - @test_throws CHOLMOD.CHOLMODException Fs[:PL] - @test_throws CHOLMOD.CHOLMODException Fs[:UPt] - @test_throws CHOLMOD.CHOLMODException Fs[:D] - @test_throws CHOLMOD.CHOLMODException Fs[:LD] - @test_throws CHOLMOD.CHOLMODException Fs[:DU] - @test_throws CHOLMOD.CHOLMODException Fs[:PLD] - @test_throws CHOLMOD.CHOLMODException Fs[:DUPt] + @test Fs.UP\(Fs.PtL\b) ≈ Af\b + @test Fs.L\b ≈ Lfp\b + @test Fs.U'\b ≈ Lfp\b + @test Fs.U\b ≈ Lfp'\b + @test Fs.L'\b ≈ Lfp'\b + @test Fs.PtL\b ≈ Lfp\b[p] + @test Fs.UP\b ≈ (Lfp'\b)[p_inv] + @test Fs.PtL'\b ≈ (Lfp'\b)[p_inv] + @test Fs.UP'\b ≈ Lfp\b[p] + @test_throws CHOLMOD.CHOLMODException Fs.PL + @test_throws CHOLMOD.CHOLMODException Fs.UPt + @test_throws CHOLMOD.CHOLMODException Fs.D + @test_throws CHOLMOD.CHOLMODException Fs.LD + @test_throws CHOLMOD.CHOLMODException Fs.DU + @test_throws CHOLMOD.CHOLMODException Fs.PLD + @test_throws CHOLMOD.CHOLMODException Fs.DUPt end @testset "ldltfact, no permutation" begin Fs = ldltfact(As, perm=[1:3;]) - @test Fs[:p] == [1:3;] - @test sparse(Fs[:LD]) ≈ LDf + @test Fs.p == [1:3;] + @test sparse(Fs.LD) ≈ LDf @test sparse(Fs) ≈ As b = rand(3) @test Fs\b ≈ Af\b - @test Fs[:UP]\(Fs[:PtLD]\b) ≈ Af\b - @test Fs[:DUP]\(Fs[:PtL]\b) ≈ Af\b - @test Fs[:L]\b ≈ L_f\b - @test Fs[:U]\b ≈ L_f'\b - @test Fs[:L]'\b ≈ L_f'\b - @test Fs[:U]'\b ≈ L_f\b - @test Fs[:PtL]\b ≈ L_f\b - @test Fs[:UP]\b ≈ L_f'\b - @test Fs[:PtL]'\b ≈ L_f'\b - @test Fs[:UP]'\b ≈ L_f\b - @test Fs[:D]\b ≈ D_f\b - @test Fs[:D]'\b ≈ D_f\b - @test Fs[:LD]\b ≈ D_f\(L_f\b) - @test Fs[:DU]'\b ≈ D_f\(L_f\b) - @test Fs[:LD]'\b ≈ L_f'\(D_f\b) - @test Fs[:DU]\b ≈ L_f'\(D_f\b) - @test Fs[:PtLD]\b ≈ D_f\(L_f\b) - @test Fs[:DUP]'\b ≈ D_f\(L_f\b) - @test Fs[:PtLD]'\b ≈ L_f'\(D_f\b) - @test Fs[:DUP]\b ≈ L_f'\(D_f\b) + @test Fs.UP\(Fs.PtLD\b) ≈ Af\b + @test Fs.DUP\(Fs.PtL\b) ≈ Af\b + @test Fs.L\b ≈ L_f\b + @test Fs.U\b ≈ L_f'\b + @test Fs.L'\b ≈ L_f'\b + @test Fs.U'\b ≈ L_f\b + @test Fs.PtL\b ≈ L_f\b + @test Fs.UP\b ≈ L_f'\b + @test Fs.PtL'\b ≈ L_f'\b + @test Fs.UP'\b ≈ L_f\b + @test Fs.D\b ≈ D_f\b + @test Fs.D'\b ≈ D_f\b + @test Fs.LD\b ≈ D_f\(L_f\b) + @test Fs.DU'\b ≈ D_f\(L_f\b) + @test Fs.LD'\b ≈ L_f'\(D_f\b) + @test Fs.DU\b ≈ L_f'\(D_f\b) + @test Fs.PtLD\b ≈ D_f\(L_f\b) + @test Fs.DUP'\b ≈ D_f\(L_f\b) + @test Fs.PtLD'\b ≈ L_f'\(D_f\b) + @test Fs.DUP\b ≈ L_f'\(D_f\b) end @testset "ldltfact, with permutation" begin Fs = ldltfact(As, perm=p) - @test Fs[:p] == p + @test Fs.p == p @test sparse(Fs) ≈ As b = rand(3) Asp = As[p,p] - LDp = sparse(ldltfact(Asp, perm=[1,2,3])[:LD]) - # LDp = sparse(Fs[:LD]) + LDp = sparse(ldltfact(Asp, perm=[1,2,3]).LD) + # LDp = sparse(Fs.LD) Lp, dp = SuiteSparse.CHOLMOD.getLd!(copy(LDp)) Dp = sparse(Diagonal(dp)) @test Fs\b ≈ Af\b - @test Fs[:UP]\(Fs[:PtLD]\b) ≈ Af\b - @test Fs[:DUP]\(Fs[:PtL]\b) ≈ Af\b - @test Fs[:L]\b ≈ Lp\b - @test Fs[:U]\b ≈ Lp'\b - @test Fs[:L]'\b ≈ Lp'\b - @test Fs[:U]'\b ≈ Lp\b - @test Fs[:PtL]\b ≈ Lp\b[p] - @test Fs[:UP]\b ≈ (Lp'\b)[p_inv] - @test Fs[:PtL]'\b ≈ (Lp'\b)[p_inv] - @test Fs[:UP]'\b ≈ Lp\b[p] - @test Fs[:LD]\b ≈ Dp\(Lp\b) - @test Fs[:DU]'\b ≈ Dp\(Lp\b) - @test Fs[:LD]'\b ≈ Lp'\(Dp\b) - @test Fs[:DU]\b ≈ Lp'\(Dp\b) - @test Fs[:PtLD]\b ≈ Dp\(Lp\b[p]) - @test Fs[:DUP]'\b ≈ Dp\(Lp\b[p]) - @test Fs[:PtLD]'\b ≈ (Lp'\(Dp\b))[p_inv] - @test Fs[:DUP]\b ≈ (Lp'\(Dp\b))[p_inv] - @test_throws CHOLMOD.CHOLMODException Fs[:DUPt] - @test_throws CHOLMOD.CHOLMODException Fs[:PLD] + @test Fs.UP\(Fs.PtLD\b) ≈ Af\b + @test Fs.DUP\(Fs.PtL\b) ≈ Af\b + @test Fs.L\b ≈ Lp\b + @test Fs.U\b ≈ Lp'\b + @test Fs.L'\b ≈ Lp'\b + @test Fs.U'\b ≈ Lp\b + @test Fs.PtL\b ≈ Lp\b[p] + @test Fs.UP\b ≈ (Lp'\b)[p_inv] + @test Fs.PtL'\b ≈ (Lp'\b)[p_inv] + @test Fs.UP'\b ≈ Lp\b[p] + @test Fs.LD\b ≈ Dp\(Lp\b) + @test Fs.DU'\b ≈ Dp\(Lp\b) + @test Fs.LD'\b ≈ Lp'\(Dp\b) + @test Fs.DU\b ≈ Lp'\(Dp\b) + @test Fs.PtLD\b ≈ Dp\(Lp\b[p]) + @test Fs.DUP'\b ≈ Dp\(Lp\b[p]) + @test Fs.PtLD'\b ≈ (Lp'\(Dp\b))[p_inv] + @test Fs.DUP\b ≈ (Lp'\(Dp\b))[p_inv] + @test_throws CHOLMOD.CHOLMODException Fs.DUPt + @test_throws CHOLMOD.CHOLMODException Fs.PLD end @testset "Element promotion and type inference" begin @@ -622,7 +622,7 @@ end gc() @testset "Issue 11747 - Wrong show method defined for FactorComponent" begin - v = cholfact(sparse(Float64[ 10 1 1 1; 1 10 0 0; 1 0 10 0; 1 0 0 10]))[:L] + v = cholfact(sparse(Float64[ 10 1 1 1; 1 10 0 0; 1 0 10 0; 1 0 0 10])).L for s in (sprint(show, MIME("text/plain"), v), sprint(show, v)) @test contains(s, "method: simplicial") @test !contains(s, "#undef") diff --git a/stdlib/SuiteSparse/test/spqr.jl b/stdlib/SuiteSparse/test/spqr.jl index 970c91fabef5e4..a918610787b346 100644 --- a/stdlib/SuiteSparse/test/spqr.jl +++ b/stdlib/SuiteSparse/test/spqr.jl @@ -8,7 +8,7 @@ using Base.LinAlg: mul!, Adjoint, Transpose m, n = 100, 10 nn = 100 -@test size(qrfact(sprandn(m, n, 0.1))[:Q]) == (m, m) +@test size(qrfact(sprandn(m, n, 0.1)).Q) == (m, m) @testset "element type of A: $eltyA" for eltyA in (Float64, Complex{Float64}) if eltyA <: Real @@ -25,21 +25,21 @@ nn = 100 @test_throws ArgumentError size(F, 0) @testset "getindex" begin - @test istriu(F[:R]) - @test isperm(F[:pcol]) - @test isperm(F[:prow]) - @test_throws KeyError F[:T] + @test istriu(F.R) + @test isperm(F.pcol) + @test isperm(F.prow) + @test_throws ErrorException F.T end @testset "apply Q" begin - Q = F[:Q] + Q = F.Q Imm = Matrix{Float64}(I, m, m) @test Q' * (Q*Imm) ≈ Imm @test (Imm*Q) * Q' ≈ Imm # test that Q'Pl*A*Pr = R - R0 = Q'*Array(A[F[:prow], F[:pcol]]) - @test R0[1:n, :] ≈ F[:R] + R0 = Q'*Array(A[F.prow, F.pcol]) + @test R0[1:n, :] ≈ F.R @test norm(R0[n + 1:end, :], 1) < 1e-12 offsizeA = Matrix{Float64}(I, m+1, m+1) diff --git a/stdlib/SuiteSparse/test/umfpack.jl b/stdlib/SuiteSparse/test/umfpack.jl index b551228d66745e..764326a115c006 100644 --- a/stdlib/SuiteSparse/test/umfpack.jl +++ b/stdlib/SuiteSparse/test/umfpack.jl @@ -20,8 +20,8 @@ A = convert(SparseMatrixCSC{Tv,Ti}, A0) lua = lufact(A) @test nnz(lua) == 18 - @test_throws KeyError lua[:Z] - L,U,p,q,Rs = lua[:(:)] + @test_throws ErrorException lua.Z + L,U,p,q,Rs = lua.:(:) @test (Diagonal(Rs) * A)[p,q] ≈ L * U det(lua) ≈ det(Array(A)) @@ -78,7 +78,7 @@ Ac = convert(SparseMatrixCSC{ComplexF64,Ti}, Ac0) x = complex.(ones(size(Ac, 1)), ones(size(Ac,1))) lua = lufact(Ac) - L,U,p,q,Rs = lua[:(:)] + L,U,p,q,Rs = lua.:(:) @test (Diagonal(Rs) * Ac)[p,q] ≈ L * U b = Ac*x @test Ac\b ≈ x @@ -93,7 +93,7 @@ for (m, n) in ((10,5), (5, 10)) A = sparse([1:min(m,n); rand(1:m, 10)], [1:min(m,n); rand(1:n, 10)], elty == Float64 ? randn(min(m, n) + 10) : complex.(randn(min(m, n) + 10), randn(min(m, n) + 10))) F = lufact(A) - L, U, p, q, Rs = F[:(:)] + L, U, p, q, Rs = F.:(:) @test (Diagonal(Rs) * A)[p,q] ≈ L * U end end @@ -121,10 +121,10 @@ F = lufact(sparse(ones(Tin, 1, 1))) L = sparse(ones(Tout, 1, 1)) - @test F[:p] == F[:q] == [1] - @test F[:Rs] == [1.0] - @test F[:L] == F[:U] == L - @test F[:(:)] == (L, L, [1], [1], [1.0]) + @test F.p == F.q == [1] + @test F.Rs == [1.0] + @test F.L == F.U == L + @test F.:(:) == (L, L, [1], [1], [1.0]) end @testset "BigFloat not supported" for T in (BigFloat, Complex{BigFloat}) @@ -152,7 +152,7 @@ A = sparse(1.0I, 4, 4) A[1:2,1:2] = [-.01 -200; 200 .001] F = lufact(A) - @test F[:p] == [3 ; 4 ; 2 ; 1] + @test F.p == [3 ; 4 ; 2 ; 1] end @testset "Test that A[c|t]_ldiv_B!{T<:Complex}(X::StridedMatrix{T}, lu::UmfpackLU{Float64}, B::StridedMatrix{T}) works as expected." begin diff --git a/test/linalg/bunchkaufman.jl b/test/linalg/bunchkaufman.jl index c935f45ae4cbc3..e844df6a5a8ec6 100644 --- a/test/linalg/bunchkaufman.jl +++ b/test/linalg/bunchkaufman.jl @@ -2,6 +2,7 @@ using Test +using Base: getproperty using Base.LinAlg: BlasComplex, BlasFloat, BlasReal, QRPivoted n = 10 @@ -60,14 +61,15 @@ bimg = randn(n,2)/2 end # Test extraction of factors if eltya <: Real - @test bc1[uplo]*bc1[:D]*bc1[uplo]' ≈ aher[bc1[:p], bc1[:p]] - @test bc1[uplo]*bc1[:D]*bc1[uplo]' ≈ bc1[:P]*aher*bc1[:P]' - end + @test getproperty(bc1, uplo)*bc1.D*getproperty(bc1, uplo)' ≈ aher[bc1.p, bc1.p] + @test getproperty(bc1, uplo)*bc1.D*getproperty(bc1, uplo)' ≈ bc1.P*aher*bc1.P' + end + bc1 = bkfact(Symmetric(asym, uplo)) - @test bc1[uplo]*bc1[:D]*Transpose(bc1[uplo]) ≈ asym[bc1[:p], bc1[:p]] - @test bc1[uplo]*bc1[:D]*Transpose(bc1[uplo]) ≈ bc1[:P]*asym*Transpose(bc1[:P]) - @test_throws KeyError bc1[:Z] - @test_throws ArgumentError uplo == :L ? bc1[:U] : bc1[:L] + @test getproperty(bc1, uplo)*bc1.D*Transpose(getproperty(bc1, uplo)) ≈ asym[bc1.p, bc1.p] + @test getproperty(bc1, uplo)*bc1.D*Transpose(getproperty(bc1, uplo)) ≈ bc1.P*asym*Transpose(bc1.P) + @test_throws ErrorException bc1.Z + @test_throws ArgumentError uplo == :L ? bc1.U : bc1.L end end diff --git a/test/linalg/cholesky.jl b/test/linalg/cholesky.jl index 09d56e19f8037f..7dda6e29a646cc 100644 --- a/test/linalg/cholesky.jl +++ b/test/linalg/cholesky.jl @@ -11,7 +11,7 @@ function unary_ops_tests(a, ca, tol; n=size(a, 1)) @test logdet(ca) ≈ logdet(a) @test logdet(ca) ≈ log(det(ca)) # logdet is less likely to overflow @test isposdef(ca) - @test_throws KeyError ca[:Z] + @test_throws ErrorException ca.Z @test size(ca) == size(a) @test Array(copy(ca)) ≈ a end @@ -20,11 +20,11 @@ function factor_recreation_tests(a_U, a_L) c_U = cholfact(a_U) c_L = cholfact(a_L) cl = chol(a_L) - ls = c_L[:L] + ls = c_L.L @test Array(c_U) ≈ Array(c_L) ≈ a_U @test ls*ls' ≈ a_U - @test triu(c_U.factors) ≈ c_U[:U] - @test tril(c_L.factors) ≈ c_L[:L] + @test triu(c_U.factors) ≈ c_U.U + @test tril(c_L.factors) ≈ c_L.L @test istriu(cl) @test cl'cl ≈ a_U @test cl'cl ≈ a_L @@ -57,7 +57,7 @@ end @inferred cholfact(apd) @inferred chol(apd) capd = factorize(apd) - r = capd[:U] + r = capd.U κ = cond(apd, 1) #condition number unary_ops_tests(apd, capd, ε*κ*n) @@ -102,7 +102,7 @@ end capds = cholfact!(copy(apds)) unary_ops_tests(apds, capds, ε*κ*n) end - ulstring = sprint((t, s) -> show(t, "text/plain", s), capds[:UL]) + ulstring = sprint((t, s) -> show(t, "text/plain", s), capds.UL) @test sprint((t, s) -> show(t, "text/plain", s), capds) == "$(typeof(capds))\nU factor:\n$ulstring" else capdh = cholfact(apdh) @@ -111,7 +111,7 @@ end unary_ops_tests(apdh, capdh, ε*κ*n) capdh = cholfact!(copy(apd)) unary_ops_tests(apd, capdh, ε*κ*n) - ulstring = sprint((t, s) -> show(t, "text/plain", s), capdh[:UL]) + ulstring = sprint((t, s) -> show(t, "text/plain", s), capdh.UL) @test sprint((t, s) -> show(t, "text/plain", s), capdh) == "$(typeof(capdh))\nU factor:\n$ulstring" end @@ -135,7 +135,7 @@ end @test rank(cpapd) == n @test all(diff(diag(real(cpapd.factors))).<=0.) # diagonal should be non-increasing - @test cpapd[:P]*cpapd[:L]*cpapd[:U]*cpapd[:P]' ≈ apd + @test cpapd.P*cpapd.L*cpapd.U*cpapd.P' ≈ apd end for eltyb in (Float32, Float64, ComplexF32, ComplexF64, Int) @@ -195,8 +195,8 @@ end A = randn(5,5) end A = convert(Matrix{eltya}, A'A) - @test Matrix(cholfact(A)[:L]) ≈ Matrix(invoke(Base.LinAlg._chol!, Tuple{AbstractMatrix, Type{LowerTriangular}}, copy(A), LowerTriangular)[1]) - @test Matrix(cholfact(A)[:U]) ≈ Matrix(invoke(Base.LinAlg._chol!, Tuple{AbstractMatrix, Type{UpperTriangular}}, copy(A), UpperTriangular)[1]) + @test Matrix(cholfact(A).L) ≈ Matrix(invoke(Base.LinAlg._chol!, Tuple{AbstractMatrix, Type{LowerTriangular}}, copy(A), LowerTriangular)[1]) + @test Matrix(cholfact(A).U) ≈ Matrix(invoke(Base.LinAlg._chol!, Tuple{AbstractMatrix, Type{UpperTriangular}}, copy(A), UpperTriangular)[1]) end end end @@ -217,15 +217,17 @@ end A = complex.(randn(10,5), randn(10, 5)) v = complex.(randn(5), randn(5)) for uplo in (:U, :L) - AcA = A'A - BcB = AcA + v*v' - BcB = (BcB + BcB')/2 - F = cholfact(Hermitian(AcA, uplo)) - G = cholfact(Hermitian(BcB, uplo)) - @test LinAlg.lowrankupdate(F, v)[uplo] ≈ G[uplo] - @test_throws DimensionMismatch LinAlg.lowrankupdate(F, ones(eltype(v), length(v)+1)) - @test LinAlg.lowrankdowndate(G, v)[uplo] ≈ F[uplo] - @test_throws DimensionMismatch LinAlg.lowrankdowndate(G, ones(eltype(v), length(v)+1)) + @eval begin + AcA = $(A)'*$(A) + BcB = AcA + $v*$v' + BcB = (BcB + BcB')/2 + F = cholfact(Hermitian(AcA, $(QuoteNode(uplo)))) + G = cholfact(Hermitian(BcB, $(QuoteNode(uplo)))) + @test LinAlg.lowrankupdate(F, $v).$uplo ≈ G.$uplo + @test_throws DimensionMismatch LinAlg.lowrankupdate(F, ones(eltype($v), length($v)+1)) + @test LinAlg.lowrankdowndate(G, $v).$uplo ≈ F.$uplo + @test_throws DimensionMismatch LinAlg.lowrankdowndate(G, ones(eltype($v), length($v)+1)) + end end end @@ -251,7 +253,7 @@ end 0.11192755545114 - 0.1603741874112385im 0.8439562576196216 + 1.0850814110398734im -1.0568488936791578 - 0.06025820467086475im 0.12696236014017806 - 0.09853584666755086im] cholfact(Hermitian(apd, :L), Val(true)) \ b - r = factorize(apd)[:U] + r = factorize(apd).U E = abs.(apd - r'*r) ε = eps(abs(float(one(ComplexF32)))) n = 10 diff --git a/test/linalg/dense.jl b/test/linalg/dense.jl index e7c7d6d31e01de..1c4b64c2148988 100644 --- a/test/linalg/dense.jl +++ b/test/linalg/dense.jl @@ -379,7 +379,7 @@ end @test exp(A5) ≈ eA5 # Hessenberg - @test hessfact(A1)[:H] ≈ convert(Matrix{elty}, + @test hessfact(A1).H ≈ convert(Matrix{elty}, [4.000000000000000 -1.414213562373094 -1.414213562373095 -1.414213562373095 4.999999999999996 -0.000000000000000 0 -0.000000000000002 3.000000000000000]) @@ -578,19 +578,19 @@ end @test all(z -> (0 < real(z) < π || abs(real(z)) < abstol && imag(z) >= 0 || abs(real(z) - π) < abstol && imag(z) <= 0), - eigfact(acos(A))[:values]) + eigfact(acos(A)).values) @test all(z -> (-π/2 < real(z) < π/2 || abs(real(z) + π/2) < abstol && imag(z) >= 0 || abs(real(z) - π/2) < abstol && imag(z) <= 0), - eigfact(asin(A))[:values]) + eigfact(asin(A)).values) @test all(z -> (-π < imag(z) < π && real(z) > 0 || 0 <= imag(z) < π && abs(real(z)) < abstol || abs(imag(z) - π) < abstol && real(z) >= 0), - eigfact(acosh(A))[:values]) + eigfact(acosh(A)).values) @test all(z -> (-π/2 < imag(z) < π/2 || abs(imag(z) + π/2) < abstol && real(z) <= 0 || abs(imag(z) - π/2) < abstol && real(z) <= 0), - eigfact(asinh(A))[:values]) + eigfact(asinh(A)).values) end end end diff --git a/test/linalg/eigen.jl b/test/linalg/eigen.jl index a5c224f9f14890..bf9f05f2982f06 100644 --- a/test/linalg/eigen.jl +++ b/test/linalg/eigen.jl @@ -40,8 +40,8 @@ aimg = randn(n,n)/2 @test det(a) ≈ det(f) @test inv(a) ≈ inv(f) @test isposdef(a) == isposdef(f) - @test eigvals(f) === f[:values] - @test eigvecs(f) === f[:vectors] + @test eigvals(f) === f.values + @test eigvecs(f) === f.vectors @test Array(f) ≈ a num_fact = eigfact(one(eltya)) @@ -61,17 +61,17 @@ aimg = randn(n,n)/2 a_sg = view(a, 1:n, n1+1:n2) end f = eigfact(asym_sg, a_sg'a_sg) - @test asym_sg*f[:vectors] ≈ (a_sg'a_sg*f[:vectors]) * Diagonal(f[:values]) - @test f[:values] ≈ eigvals(asym_sg, a_sg'a_sg) - @test prod(f[:values]) ≈ prod(eigvals(asym_sg/(a_sg'a_sg))) atol=200ε - @test eigvecs(asym_sg, a_sg'a_sg) == f[:vectors] - @test eigvals(f) === f[:values] - @test eigvecs(f) === f[:vectors] - @test_throws KeyError f[:Z] + @test asym_sg*f.vectors ≈ (a_sg'a_sg*f.vectors) * Diagonal(f.values) + @test f.values ≈ eigvals(asym_sg, a_sg'a_sg) + @test prod(f.values) ≈ prod(eigvals(asym_sg/(a_sg'a_sg))) atol=200ε + @test eigvecs(asym_sg, a_sg'a_sg) == f.vectors + @test eigvals(f) === f.values + @test eigvecs(f) === f.vectors + @test_throws ErrorException f.Z d,v = eig(asym_sg, a_sg'a_sg) - @test d == f[:values] - @test v == f[:vectors] + @test d == f.values + @test v == f.vectors end @testset "Non-symmetric generalized eigenproblem" begin if isa(a, Array) @@ -82,15 +82,15 @@ aimg = randn(n,n)/2 a2_nsg = view(a, n1+1:n2, n1+1:n2) end f = eigfact(a1_nsg, a2_nsg) - @test a1_nsg*f[:vectors] ≈ (a2_nsg*f[:vectors]) * Diagonal(f[:values]) - @test f[:values] ≈ eigvals(a1_nsg, a2_nsg) - @test prod(f[:values]) ≈ prod(eigvals(a1_nsg/a2_nsg)) atol=50000ε - @test eigvecs(a1_nsg, a2_nsg) == f[:vectors] - @test_throws KeyError f[:Z] + @test a1_nsg*f.vectors ≈ (a2_nsg*f.vectors) * Diagonal(f.values) + @test f.values ≈ eigvals(a1_nsg, a2_nsg) + @test prod(f.values) ≈ prod(eigvals(a1_nsg/a2_nsg)) atol=50000ε + @test eigvecs(a1_nsg, a2_nsg) == f.vectors + @test_throws ErrorException f.Z d,v = eig(a1_nsg, a2_nsg) - @test d == f[:values] - @test v == f[:vectors] + @test d == f.values + @test v == f.vectors end end end @@ -109,7 +109,7 @@ end let aa = rand(200, 200) for a in (aa, view(aa, 1:n, 1:n)) f = eigfact(a) - @test a ≈ f[:vectors] * Diagonal(f[:values]) / f[:vectors] + @test a ≈ f.vectors * Diagonal(f.values) / f.vectors end end diff --git a/test/linalg/hessenberg.jl b/test/linalg/hessenberg.jl index 6f0ff890f4ff23..48cfb3de877aaa 100644 --- a/test/linalg/hessenberg.jl +++ b/test/linalg/hessenberg.jl @@ -19,15 +19,15 @@ let n = 10 if eltya != BigFloat H = hessfact(A) - @test size(H[:Q], 1) == size(A, 1) - @test size(H[:Q], 2) == size(A, 2) - @test size(H[:Q]) == size(A) - @test_throws KeyError H[:Z] + @test size(H.Q, 1) == size(A, 1) + @test size(H.Q, 2) == size(A, 2) + @test size(H.Q) == size(A) + @test_throws ErrorException H.Z @test convert(Array, H) ≈ A - @test (H[:Q] * H[:H]) * H[:Q]' ≈ A - @test (H[:Q]' *A) * H[:Q] ≈ H[:H] + @test (H.Q * H.H) * H.Q' ≈ A + @test (H.Q' *A) * H.Q ≈ H.H #getindex for HessenbergQ - @test H[:Q][1,1] ≈ Array(H[:Q])[1,1] + @test H.Q[1,1] ≈ Array(H.Q)[1,1] end end end diff --git a/test/linalg/lq.jl b/test/linalg/lq.jl index adf7bb36323a32..239f94ecbe87f1 100644 --- a/test/linalg/lq.jl +++ b/test/linalg/lq.jl @@ -38,22 +38,21 @@ rectangularQ(Q::LinAlg.LQPackedQ) = convert(Array, Q) α = rand(eltya) aα = fill(α,1,1) - @test lqfact(α)[:L]*lqfact(α)[:Q] ≈ lqfact(aα)[:L]*lqfact(aα)[:Q] - @test lq(α)[1]*lq(α)[2] ≈ lqfact(aα)[:L]*lqfact(aα)[:Q] - @test abs(lqfact(α)[:Q][1,1]) ≈ one(eltya) + @test lqfact(α).L*lqfact(α).Q ≈ lqfact(aα).L*lqfact(aα).Q + @test lq(α)[1]*lq(α)[2] ≈ lqfact(aα).L*lqfact(aα).Q + @test abs(lqfact(α).Q[1,1]) ≈ one(eltya) tab = promote_type(eltya,eltyb) for i = 1:2 let a = i == 1 ? a : view(a, 1:n - 1, 1:n - 1), b = i == 1 ? b : view(b, 1:n - 1), n = i == 1 ? n : n - 1 lqa = lqfact(a) - l,q = lqa[:L], lqa[:Q] + l,q = lqa.L, lqa.Q qra = qrfact(a) @testset "Basic ops" begin @test size(lqa,1) == size(a,1) @test size(lqa,3) == 1 - @test size(lqa[:Q],3) == 1 - @test Base.LinAlg.getq(lqa) == lqa[:Q] - @test_throws KeyError lqa[:Z] + @test size(lqa.Q,3) == 1 + @test_throws ErrorException lqa.Z @test Array(lqa') ≈ a' @test lqa * lqa' ≈ a * a' @test lqa' * lqa ≈ a' * a @@ -67,7 +66,7 @@ rectangularQ(Q::LinAlg.LQPackedQ) = convert(Array, Q) end @testset "Binary ops" begin @test a*(lqa\b) ≈ b atol=3000ε - @test lqa*b ≈ qra[:Q]*qra[:R]*b atol=3000ε + @test lqa*b ≈ qra.Q*qra.R*b atol=3000ε @test (sq = size(q.factors, 2); *(Matrix{eltyb}(I, sq, sq), Adjoint(q))*squareQ(q)) ≈ Matrix(I, n, n) atol=5000ε if eltya != Int @test Matrix{eltyb}(I, n, n)*q ≈ convert(AbstractMatrix{tab},q) @@ -97,7 +96,7 @@ rectangularQ(Q::LinAlg.LQPackedQ) = convert(Array, Q) @testset "Matmul with LQ factorizations" begin lqa = lqfact(a[:,1:n1]) - l,q = lqa[:L], lqa[:Q] + l,q = lqa.L, lqa.Q @test rectangularQ(q)*rectangularQ(q)' ≈ Matrix(I, n1, n1) @test squareQ(q)'*squareQ(q) ≈ Matrix(I, n1, n1) @test_throws DimensionMismatch mul!(Matrix{eltya}(I, n+1, n+1),q) @@ -148,7 +147,7 @@ end @testset "getindex on LQPackedQ (#23733)" begin local m, n function getqs(F::Base.LinAlg.LQ) - implicitQ = F[:Q] + implicitQ = F.Q sq = size(implicitQ.factors, 2) explicitQ = mul!(implicitQ, Matrix{eltype(implicitQ)}(I, sq, sq)) return implicitQ, explicitQ @@ -184,13 +183,13 @@ end ((3, 3), 3), # A 3-by-3 => full/square Q 3-by-3 ((3, 4), 4), # A 3-by-4 => full/square Q 4-by-4 ((4, 3), 3) )# A 4-by-3 => full/square Q 3-by-3 - @test size(lqfact(randn(mA, nA))[:Q]) == (nQ, nQ) + @test size(lqfact(randn(mA, nA)).Q) == (nQ, nQ) end end @testset "postmultiplication with / right-application of LQPackedQ (#23779)" begin function getqs(F::Base.LinAlg.LQ) - implicitQ = F[:Q] + implicitQ = F.Q explicitQ = mul!(implicitQ, Matrix{eltype(implicitQ)}(I, size(implicitQ)...)) return implicitQ, explicitQ end diff --git a/test/linalg/lu.jl b/test/linalg/lu.jl index 83368fc8c1dea1..01eb2a57198e09 100644 --- a/test/linalg/lu.jl +++ b/test/linalg/lu.jl @@ -51,9 +51,9 @@ dimg = randn(n)/2 -0.5 -0.5 0.1 1.0]) F = eigfact(A, permute=false, scale=false) eig(A, permute=false, scale=false) - @test F[:vectors]*Diagonal(F[:values])/F[:vectors] ≈ A + @test F.vectors*Diagonal(F.values)/F.vectors ≈ A F = eigfact(A) - # @test norm(F[:vectors]*Diagonal(F[:values])/F[:vectors] - A) > 0.01 + # @test norm(F.vectors*Diagonal(F.values)/F.vectors - A) > 0.01 end end @testset "Singular LU" begin @@ -64,8 +64,8 @@ dimg = randn(n)/2 κ = cond(a,1) @testset "(Automatic) Square LU decomposition" begin lua = factorize(a) - @test_throws KeyError lua[:Z] - l,u,p = lua[:L], lua[:U], lua[:p] + @test_throws ErrorException lua.Z + l,u,p = lua.L, lua.U, lua.p ll,ul,pl = lu(a) @test ll * ul ≈ a[pl,:] @test l*u ≈ a[p,:] @@ -76,7 +76,7 @@ dimg = randn(n)/2 # test conversion of LU factorization's numerical type bft = eltya <: Real ? Base.LinAlg.LU{BigFloat} : Base.LinAlg.LU{Complex{BigFloat}} bflua = convert(bft, lua) - @test bflua[:L]*bflua[:U] ≈ big.(a)[p,:] rtol=ε + @test bflua.L*bflua.U ≈ big.(a)[p,:] rtol=ε end # compact printing lstring = sprint(show,l) @@ -88,9 +88,9 @@ dimg = randn(n)/2 lud = lufact(d) @test LinAlg.issuccess(lud) @test lufact(lud) == lud - @test_throws KeyError lud[:Z] - @test lud[:L]*lud[:U] ≈ lud[:P]*Array(d) - @test lud[:L]*lud[:U] ≈ Array(d)[lud[:p],:] + @test_throws ErrorException lud.Z + @test lud.L*lud.U ≈ lud.P*Array(d) + @test lud.L*lud.U ≈ Array(d)[lud.p,:] @test AbstractArray(lud) ≈ d end @testset for eltyb in (Float32, Float64, ComplexF32, ComplexF64, Int) @@ -178,18 +178,18 @@ dimg = randn(n)/2 end @testset "Thin LU" begin lua = @inferred lufact(a[:,1:n1]) - @test lua[:L]*lua[:U] ≈ lua[:P]*a[:,1:n1] + @test lua.L*lua.U ≈ lua.P*a[:,1:n1] end @testset "Fat LU" begin lua = lufact(a[1:n1,:]) - @test lua[:L]*lua[:U] ≈ lua[:P]*a[1:n1,:] + @test lua.L*lua.U ≈ lua.P*a[1:n1,:] end end @testset "LU of Symmetric/Hermitian" begin for HS in (Hermitian(a'a), Symmetric(a'a)) luhs = lufact(HS) - @test luhs[:L]*luhs[:U] ≈ luhs[:P]*Matrix(HS) + @test luhs.L*luhs.U ≈ luhs.P*Matrix(HS) end end end @@ -210,7 +210,7 @@ end b = rand(1:10,n,2) @inferred lufact(a) lua = factorize(a) - l,u,p = lua[:L], lua[:U], lua[:p] + l,u,p = lua.L, lua.U, lua.p @test l*u ≈ a[p,:] @test l[invperm(p),:]*u ≈ a @test a*inv(lua) ≈ Matrix(I, n, n) diff --git a/test/linalg/qr.jl b/test/linalg/qr.jl index 65fba4cf3dcad1..7dde1590af57fe 100644 --- a/test/linalg/qr.jl +++ b/test/linalg/qr.jl @@ -39,8 +39,8 @@ rectangularQ(Q::LinAlg.AbstractQ) = convert(Array, Q) @testset "QR decomposition of a Number" begin α = rand(eltyb) aα = fill(α, 1, 1) - @test qrfact(α)[:Q] * qrfact(α)[:R] ≈ qrfact(aα)[:Q] * qrfact(aα)[:R] - @test abs(qrfact(α)[:Q][1,1]) ≈ one(eltyb) + @test qrfact(α).Q * qrfact(α).R ≈ qrfact(aα).Q * qrfact(aα).R + @test abs(qrfact(α).Q[1,1]) ≈ one(eltyb) end for (a, b) in ((raw_a, raw_b), @@ -49,8 +49,8 @@ rectangularQ(Q::LinAlg.AbstractQ) = convert(Array, Q) @testset "QR decomposition (without pivoting)" begin qra = @inferred qrfact(a) @inferred qr(a) - q, r = qra[:Q], qra[:R] - @test_throws KeyError qra[:Z] + q, r = qra.Q, qra.R + @test_throws ErrorException qra.Z @test q'*squareQ(q) ≈ Matrix(I, a_1, a_1) @test q*squareQ(q)' ≈ Matrix(I, a_1, a_1) @test q'*Matrix(1.0I, a_1, a_1)' ≈ squareQ(q)' @@ -73,8 +73,8 @@ rectangularQ(Q::LinAlg.AbstractQ) = convert(Array, Q) @testset "Thin QR decomposition (without pivoting)" begin qra = @inferred qrfact(a[:, 1:n1], Val(false)) @inferred qr(a[:, 1:n1], Val(false)) - q,r = qra[:Q], qra[:R] - @test_throws KeyError qra[:Z] + q,r = qra.Q, qra.R + @test_throws ErrorException qra.Z @test q'*squareQ(q) ≈ Matrix(I, a_1, a_1) @test q'*rectangularQ(q) ≈ Matrix(I, a_1, n1) @test q*r ≈ a[:, 1:n1] @@ -93,16 +93,16 @@ rectangularQ(Q::LinAlg.AbstractQ) = convert(Array, Q) @inferred qr(a, Val(true)) qrpa = factorize(a[1:n1,:]) - q,r = qrpa[:Q], qrpa[:R] - @test_throws KeyError qrpa[:Z] - p = qrpa[:p] + q,r = qrpa.Q, qrpa.R + @test_throws ErrorException qrpa.Z + p = qrpa.p @test q'*squareQ(q) ≈ Matrix(I, n1, n1) @test q*squareQ(q)' ≈ Matrix(I, n1, n1) sq = size(q, 2); @test (UpperTriangular(Matrix{eltya}(I, sq, sq))*q')*squareQ(q) ≈ Matrix(I, n1, n1) @test q*r ≈ (isa(qrpa,QRPivoted) ? a[1:n1,p] : a[1:n1,:]) @test q*r[:,invperm(p)] ≈ a[1:n1,:] - @test q*r*Transpose(qrpa[:P]) ≈ a[1:n1,:] + @test q*r*Transpose(qrpa.P) ≈ a[1:n1,:] @test a[1:n1,:]*(qrpa\b[1:n1]) ≈ b[1:n1] atol=5000ε @test Array(qrpa) ≈ a[1:5,:] @test_throws DimensionMismatch q*b[1:n1+1] @@ -113,9 +113,9 @@ rectangularQ(Q::LinAlg.AbstractQ) = convert(Array, Q) end @testset "(Automatic) Thin (pivoted) QR decomposition" begin qrpa = factorize(a[:,1:n1]) - q,r = qrpa[:Q], qrpa[:R] - @test_throws KeyError qrpa[:Z] - p = qrpa[:p] + q,r = qrpa.Q, qrpa.R + @test_throws ErrorException qrpa.Z + p = qrpa.p @test q'*squareQ(q) ≈ Matrix(I, a_1, a_1) @test q*squareQ(q)' ≈ Matrix(I, a_1, a_1) @test q*r ≈ a[:,p] @@ -134,7 +134,7 @@ rectangularQ(Q::LinAlg.AbstractQ) = convert(Array, Q) @testset "Matmul with QR factorizations" begin a = raw_a qrpa = factorize(a[:,1:n1]) - q, r = qrpa[:Q], qrpa[:R] + q, r = qrpa.Q, qrpa.R @test mul!(squareQ(q)', q) ≈ Matrix(I, n, n) @test_throws DimensionMismatch mul!(Matrix{eltya}(I, n+1, n+1),q) @test mul!(squareQ(q), Adjoint(q)) ≈ Matrix(I, n, n) @@ -144,7 +144,7 @@ rectangularQ(Q::LinAlg.AbstractQ) = convert(Array, Q) @test_throws DimensionMismatch Base.LinAlg.mul!(Adjoint(q), zeros(eltya,n1+1)) qra = qrfact(a[:,1:n1], Val(false)) - q, r = qra[:Q], qra[:R] + q, r = qra.Q, qra.R @test mul!(squareQ(q)', q) ≈ Matrix(I, n, n) @test_throws DimensionMismatch mul!(Matrix{eltya}(I, n+1, n+1),q) @test mul!(squareQ(q), Adjoint(q)) ≈ Matrix(I, n, n) @@ -167,7 +167,7 @@ end @testset "Issue 7304" begin A = [-√.5 -√.5; -√.5 √.5] - Q = rectangularQ(qrfact(A)[:Q]) + Q = rectangularQ(qrfact(A).Q) @test vecnorm(A-Q) < eps() end diff --git a/test/linalg/schur.jl b/test/linalg/schur.jl index 2115124d4d0871..1c906037b8b5a8 100644 --- a/test/linalg/schur.jl +++ b/test/linalg/schur.jl @@ -27,12 +27,12 @@ aimg = randn(n,n)/2 d,v = eig(a) f = schurfact(a) - @test f[:vectors]*f[:Schur]*f[:vectors]' ≈ a - @test sort(real(f[:values])) ≈ sort(real(d)) - @test sort(imag(f[:values])) ≈ sort(imag(d)) - @test istriu(f[:Schur]) || eltype(a)<:Real + @test f.vectors*f.Schur*f.vectors' ≈ a + @test sort(real(f.values)) ≈ sort(real(d)) + @test sort(imag(f.values)) ≈ sort(imag(d)) + @test istriu(f.Schur) || eltype(a)<:Real @test convert(Array, f) ≈ a - @test_throws KeyError f[:A] + @test_throws ErrorException f.A sch, vecs, vals = schur(UpperTriangular(triu(a))) @test vecs*sch*vecs' ≈ triu(a) @@ -45,9 +45,9 @@ aimg = randn(n,n)/2 sch, vecs, vals = schur(Tridiagonal(a + transpose(a))) @test vecs*sch*vecs' ≈ Tridiagonal(a + transpose(a)) - tstring = sprint(show,f[:T]) - zstring = sprint(show,f[:Z]) - vstring = sprint(show,f[:values]) + tstring = sprint(show,f.T) + zstring = sprint(show,f.Z) + vstring = sprint(show,f.values) @test sprint(show,f) == "$(typeof(f)) with factors T and Z:\n$tstring\n$(zstring)\nand values:\n$vstring" @testset "Reorder Schur" begin # use asym for real schur to enforce tridiag structure @@ -56,13 +56,13 @@ aimg = randn(n,n)/2 S = schurfact(ordschura) select = bitrand(n) O = ordschur(S, select) - sum(select) != 0 && @test S[:values][find(select)] ≈ O[:values][1:sum(select)] - @test O[:vectors]*O[:Schur]*O[:vectors]' ≈ ordschura - @test_throws KeyError f[:A] + sum(select) != 0 && @test S.values[find(select)] ≈ O.values[1:sum(select)] + @test O.vectors*O.Schur*O.vectors' ≈ ordschura + @test_throws ErrorException f.A Snew = Base.LinAlg.Schur(S.T, S.Z, S.values) SchurNew = ordschur!(copy(Snew), select) - @test O[:vectors] ≈ SchurNew[:vectors] - @test O[:Schur] ≈ SchurNew[:Schur] + @test O.vectors ≈ SchurNew.vectors + @test O.Schur ≈ SchurNew.Schur end if isa(a, Array) @@ -74,37 +74,37 @@ aimg = randn(n,n)/2 end @testset "Generalized Schur" begin f = schurfact(a1_sf, a2_sf) - @test f[:Q]*f[:S]*f[:Z]' ≈ a1_sf - @test f[:Q]*f[:T]*f[:Z]' ≈ a2_sf - @test istriu(f[:S]) || eltype(a)<:Real - @test istriu(f[:T]) || eltype(a)<:Real - @test_throws KeyError f[:A] + @test f.Q*f.S*f.Z' ≈ a1_sf + @test f.Q*f.T*f.Z' ≈ a2_sf + @test istriu(f.S) || eltype(a)<:Real + @test istriu(f.T) || eltype(a)<:Real + @test_throws ErrorException f.A end @testset "Reorder Generalized Schur" begin NS = schurfact(a1_sf, a2_sf) # Currently just testing with selecting gen eig values < 1 - select = abs2.(NS[:values]) .< 1 + select = abs2.(NS.values) .< 1 m = sum(select) S = ordschur(NS, select) # Make sure that the new factorization stil factors matrix - @test S[:Q]*S[:S]*S[:Z]' ≈ a1_sf - @test S[:Q]*S[:T]*S[:Z]' ≈ a2_sf + @test S.Q*S.S*S.Z' ≈ a1_sf + @test S.Q*S.T*S.Z' ≈ a2_sf # Make sure that we have sorted it correctly - @test NS[:values][find(select)] ≈ S[:values][1:m] + @test NS.values[find(select)] ≈ S.values[1:m] Snew = Base.LinAlg.GeneralizedSchur(NS.S, NS.T, NS.alpha, NS.beta, NS.Q, NS.Z) SchurNew = ordschur!(copy(Snew), select) - @test S[:Q] ≈ SchurNew[:Q] - @test S[:S] ≈ SchurNew[:S] - @test S[:T] ≈ SchurNew[:T] - @test S[:Z] ≈ SchurNew[:Z] - @test S[:alpha] ≈ SchurNew[:alpha] - @test S[:beta] ≈ SchurNew[:beta] + @test S.Q ≈ SchurNew.Q + @test S.S ≈ SchurNew.S + @test S.T ≈ SchurNew.T + @test S.Z ≈ SchurNew.Z + @test S.alpha ≈ SchurNew.alpha + @test S.beta ≈ SchurNew.beta sS,sT,sQ,sZ = schur(a1_sf,a2_sf) - @test NS[:Q] ≈ sQ - @test NS[:T] ≈ sT - @test NS[:S] ≈ sS - @test NS[:Z] ≈ sZ + @test NS.Q ≈ sQ + @test NS.T ≈ sT + @test NS.S ≈ sS + @test NS.Z ≈ sZ end end @testset "0x0 matrix" for A in (zeros(eltya, 0, 0), view(rand(eltya, 2, 2), 1:0, 1:0)) diff --git a/test/linalg/svd.jl b/test/linalg/svd.jl index 28e1b8d4159a37..9756a751a9a98b 100644 --- a/test/linalg/svd.jl +++ b/test/linalg/svd.jl @@ -53,48 +53,48 @@ a2img = randn(n,n)/2 usv = svdfact(a) @testset "singular value decomposition" begin - @test usv[:S] === svdvals(usv) - @test usv[:U] * (Diagonal(usv[:S]) * usv[:Vt]) ≈ a + @test usv.S === svdvals(usv) + @test usv.U * (Diagonal(usv.S) * usv.Vt) ≈ a @test convert(Array, usv) ≈ a - @test usv[:Vt]' ≈ usv[:V] - @test_throws KeyError usv[:Z] + @test usv.Vt' ≈ usv.V + @test_throws ErrorException usv.Z b = rand(eltya,n) @test usv\b ≈ a\b if eltya <: BlasFloat svdz = svdfact!(ones(eltya,0,0)) - @test svdz[:U] ≈ Matrix{eltya}(I, 0, 0) - @test svdz[:S] ≈ real(zeros(eltya,0)) - @test svdz[:Vt] ≈ Matrix{eltya}(I, 0, 0) + @test svdz.U ≈ Matrix{eltya}(I, 0, 0) + @test svdz.S ≈ real(zeros(eltya,0)) + @test svdz.Vt ≈ Matrix{eltya}(I, 0, 0) end end @testset "Generalized svd" begin a_svd = a[1:n1, :] gsvd = svdfact(a,a_svd) - @test gsvd[:U]*gsvd[:D1]*gsvd[:R]*gsvd[:Q]' ≈ a - @test gsvd[:V]*gsvd[:D2]*gsvd[:R]*gsvd[:Q]' ≈ a_svd - @test usv[:Vt]' ≈ usv[:V] - @test_throws KeyError usv[:Z] - @test_throws KeyError gsvd[:Z] - @test gsvd[:vals] ≈ svdvals(a,a_svd) + @test gsvd.U*gsvd.D1*gsvd.R*gsvd.Q' ≈ a + @test gsvd.V*gsvd.D2*gsvd.R*gsvd.Q' ≈ a_svd + @test usv.Vt' ≈ usv.V + @test_throws ErrorException usv.Z + @test_throws ErrorException gsvd.Z + @test gsvd.vals ≈ svdvals(a,a_svd) α = eltya == Int ? -1 : rand(eltya) β = svdfact(α) - @test β[:S] == [abs(α)] + @test β.S == [abs(α)] @test svdvals(α) == abs(α) u,v,q,d1,d2,r0 = svd(a,a_svd) - @test u ≈ gsvd[:U] - @test v ≈ gsvd[:V] - @test d1 ≈ gsvd[:D1] - @test d2 ≈ gsvd[:D2] - @test q ≈ gsvd[:Q] - @test gsvd[:a].^2 + gsvd[:b].^2 ≈ ones(eltya,length(gsvd[:a])) + @test u ≈ gsvd.U + @test v ≈ gsvd.V + @test d1 ≈ gsvd.D1 + @test d2 ≈ gsvd.D2 + @test q ≈ gsvd.Q + @test gsvd.a.^2 + gsvd.b.^2 ≈ ones(eltya,length(gsvd.a)) #testing the other layout for D1 & D2 b = rand(eltya,n,2*n) c = rand(eltya,n,2*n) gsvd = svdfact(b,c) - @test gsvd[:U]*gsvd[:D1]*gsvd[:R]*gsvd[:Q]' ≈ b - @test gsvd[:V]*gsvd[:D2]*gsvd[:R]*gsvd[:Q]' ≈ c + @test gsvd.U*gsvd.D1*gsvd.R*gsvd.Q' ≈ b + @test gsvd.V*gsvd.D2*gsvd.R*gsvd.Q' ≈ c end end if eltya <: Base.LinAlg.BlasReal