Skip to content

Commit ca9f079

Browse files
committed
Extend convert_eltype to LinearAgebra.Factorization
1 parent 0060dbe commit ca9f079

File tree

5 files changed

+167
-7
lines changed

5 files changed

+167
-7
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ This page describes the most important changes in `TypeUtils`. The format is bas
88

99
### Added
1010

11+
- Extend `convert_eltype(T,A)` for `A <: LinearAgebra.Factorization`.
12+
1113
- Tests with [`Aqua.jl`](https://github.com/JuliaTesting/Aqua.jl).
1214

1315
### Fixed

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ authors = ["Éric Thiébaut <[email protected]> and contributors"]
44
version = "1.7.1"
55

66
[deps]
7+
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
78
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
89

910
[compat]
1011
Aqua = "0.8"
12+
LinearAlgebra = "<0.0.1, 1"
1113
OffsetArrays = "1"
1214
Requires = "1"
1315
Test = "<0.0.1, 1"

src/TypeUtils.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,19 @@ export
3838
to_same_concrete_type,
3939
unitless
4040

41-
using Base: OneTo
42-
43-
if !isdefined(Base, :get_extension)
44-
using Requires
45-
end
46-
4741
include("macros.jl")
4842

4943
@public BareNumber
5044
@public Converter
5145
@public Dim
5246
@public Unsupported
5347

48+
using Base: OneTo
49+
using LinearAlgebra
50+
if !isdefined(Base, :get_extension)
51+
using Requires
52+
end
53+
5454
include("types.jl")
5555
include("methods.jl")
5656
include("numbers.jl")

src/arrays.jl

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,38 @@ convert_eltype(::Type{T}, x::X) where {T,X} = as(convert_eltype(T, X), x)
157157
convert_eltype(::Type{T}, ::Type{X}) where {T,X} =
158158
error("don't know how to convert the element type of type `$X` to `$T`")
159159

160+
# As of Julia 1.11 `AbstractMatrix{T}(A)` or `AbstractArray{T}(A)` can be used to convert
161+
# element type of `A` for Adjoint, Bidiagonal, Diagonal, Hermitian,
162+
# LinearAlgebra.LQPackedQ, LowerTriangular, SymTridiagonal, Symmetric, Transpose,
163+
# Tridiagonal, UnitLowerTriangular, UnitUpperTriangular, UpperHessenberg, UpperTriangular,
164+
# etc.
160165
convert_eltype(::Type{T}, A::AbstractArray{T}) where {T} = A
161-
convert_eltype(::Type{T}, A::AbstractArray) where {T} = as(AbstractArray{T}, A)
166+
convert_eltype(::Type{T}, A::AbstractArray) where {T} = AbstractArray{T}(A)
162167
convert_eltype(::Type{T}, ::Type{<:Array{<:Any,N}}) where {T,N} = Array{T,N}
163168
convert_eltype(::Type{T}, ::Type{<:AbstractArray{<:Any,N}}) where {T,N} = AbstractArray{T,N}
164169

170+
# `LinearAlgebra.Factorization{T}(A)` can be used to convert element type of `A` for QR,
171+
# LinearAlgebra.QRCompactWY, QRPivoted, LQ, Cholesky, CholeskyPivoted, LU, LDLt,
172+
# BunchKaufman, SVD, etc.
173+
convert_eltype(::Type{T}, A::Factorization{T}) where {T} = A
174+
convert_eltype(::Type{T}, A::Factorization) where {T} = Factorization{T}(A)
175+
if VERSION < v"1.7.0-beta1"
176+
# For old Julia versions, the above is not sufficient for SVD.
177+
convert_eltype(::Type{T}, A::SVD{T}) where {T} = A
178+
convert_eltype(::Type{T}, A::SVD) where {T} =
179+
SVD(convert(AbstractMatrix{T}, A.U),
180+
convert(AbstractVector{real(T)}, A.S),
181+
convert(AbstractMatrix{T}, A.Vt))
182+
end
183+
184+
# For `Adjoint` and `Transpose`, we want to preserve this structure.
185+
for S in (:Adjoint, :Transpose)
186+
@eval begin
187+
convert_eltype(::Type{T}, A::$S{T}) where {T} = A
188+
convert_eltype(::Type{T}, A::$S) where {T} = $S(convert_eltype(T, parent(A)))
189+
end
190+
end
191+
165192
# Convert element type for numbers.
166193
convert_eltype(::Type{T}, ::Type{<:Number}) where {T} = T
167194

test/runtests.jl

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
module TestingTypeUtilsWithoutExtensions
2+
23
using TypeUtils
34
using Test
45

@@ -16,6 +17,7 @@ module TestingTypeUtils
1617

1718
using TypeUtils
1819
using TypeUtils: BareNumber, BIT_INTEGERS, Unsupported
20+
using LinearAlgebra
1921
using Unitful
2022
using OffsetArrays
2123
using Test
@@ -732,6 +734,133 @@ same_value_and_type(x::T, y::T) where {T} = (x === y) || (x == y)
732734

733735
end
734736

737+
@testset "LinearAlgebra" begin
738+
A = ComplexF32.([9+1im 2-3im 1; 0 7 1; 0 0 4])
739+
AAt = A*A'
740+
T = ComplexF64 # a wider type than eltype(A) for exact conversion
741+
742+
B = transpose(A)
743+
@test eltype(B) == eltype(A) != T
744+
@test @inferred(convert_eltype(eltype(B), B)) === B
745+
C = @inferred convert_eltype(T, B)
746+
@test typeof(C) <: Transpose{T}
747+
@test C == B
748+
749+
B = adjoint(A)
750+
@test eltype(B) == eltype(A) != T
751+
@test @inferred(convert_eltype(eltype(B), B)) === B
752+
C = @inferred convert_eltype(T, B)
753+
@test typeof(C) <: Adjoint{T}
754+
@test C == B
755+
756+
B = Diagonal(A)
757+
@test eltype(B) == eltype(A) != T
758+
@test @inferred(convert_eltype(eltype(B), B)) === B
759+
C = @inferred convert_eltype(T, B)
760+
@test typeof(C) <: Diagonal{T}
761+
@test C == B
762+
763+
B = Bidiagonal(A, :U)
764+
@test eltype(B) == eltype(A) != T
765+
@test @inferred(convert_eltype(eltype(B), B)) === B
766+
C = @inferred convert_eltype(T, B)
767+
@test typeof(C) <: Bidiagonal{T}
768+
@test C == B
769+
770+
B = Bidiagonal(A, :L)
771+
@test eltype(B) == eltype(A) != T
772+
@test @inferred(convert_eltype(eltype(B), B)) === B
773+
C = @inferred convert_eltype(T, B)
774+
@test typeof(C) <: Bidiagonal{T}
775+
@test C == B
776+
777+
B = Tridiagonal(A)
778+
@test eltype(B) == eltype(A) != T
779+
@test @inferred(convert_eltype(eltype(B), B)) === B
780+
C = @inferred convert_eltype(T, B)
781+
@test typeof(C) <: Tridiagonal{T}
782+
@test C == B
783+
784+
B = Hermitian(A)
785+
@test eltype(B) == eltype(A) != T
786+
@test @inferred(convert_eltype(eltype(B), B)) === B
787+
C = @inferred convert_eltype(T, B)
788+
@test typeof(C) <: Hermitian{T}
789+
@test C == B
790+
791+
B = Symmetric(A)
792+
@test eltype(B) == eltype(A) != T
793+
@test @inferred(convert_eltype(eltype(B), B)) === B
794+
C = @inferred convert_eltype(T, B)
795+
@test typeof(C) <: Symmetric{T}
796+
@test C == B
797+
798+
B = cholesky(AAt)
799+
@test eltype(B) == eltype(A) != T
800+
@test @inferred(convert_eltype(eltype(B), B)) === B
801+
C = @inferred convert_eltype(T, B)
802+
@test typeof(C) <: Cholesky{T}
803+
@test C.factors == B.factors
804+
805+
pivot = VERSION < v"1.8.0-beta1" ? Val(true) : RowMaximum()
806+
B = cholesky(AAt, pivot)
807+
@test eltype(B) == eltype(A) != T
808+
@test @inferred(convert_eltype(eltype(B), B)) === B
809+
C = @inferred convert_eltype(T, B)
810+
@test typeof(C) <: CholeskyPivoted{T}
811+
@test C.factors == B.factors
812+
813+
B = svd(A)
814+
@test eltype(B) == eltype(A) != T
815+
@test @inferred(convert_eltype(eltype(B), B)) === B
816+
C = @inferred convert_eltype(T, B)
817+
@test typeof(C) <: SVD{T}
818+
@test C.U == B.U
819+
@test C.S == B.S
820+
@test C.Vt == B.Vt
821+
822+
B = qr(A)
823+
@test eltype(B) == eltype(A) != T
824+
@test @inferred(convert_eltype(eltype(B), B)) === B
825+
C = @inferred convert_eltype(T, B)
826+
@test typeof(C) <: Factorization{T}
827+
@test C.Q == B.Q
828+
@test C.R == B.R
829+
830+
pivot = isdefined(LinearAlgebra, :PivotingStrategy) ? ColumnNorm() : Val(true)
831+
B = qr(A, pivot)
832+
@test eltype(B) == eltype(A) != T
833+
@test @inferred(convert_eltype(eltype(B), B)) === B
834+
C = @inferred convert_eltype(T, B)
835+
@test typeof(C) <: QRPivoted{T}
836+
@test C.P == B.P
837+
@test C.Q == B.Q
838+
@test C.R == B.R
839+
@test C.p == B.p
840+
841+
pivot = isdefined(LinearAlgebra, :PivotingStrategy) ? NoPivot() : Val(false)
842+
B = lu(A, pivot)
843+
@test eltype(B) == eltype(A) != T
844+
@test @inferred(convert_eltype(eltype(B), B)) === B
845+
C = @inferred convert_eltype(T, B)
846+
@test typeof(C) <: LU{T}
847+
@test C.L == B.L
848+
@test C.U == B.U
849+
@test C.P == B.P
850+
@test C.p == B.p
851+
852+
pivot = isdefined(LinearAlgebra, :PivotingStrategy) ? RowMaximum() : Val(true)
853+
B = lu(A, pivot)
854+
@test eltype(B) == eltype(A) != T
855+
@test @inferred(convert_eltype(eltype(B), B)) === B
856+
C = @inferred convert_eltype(T, B)
857+
@test typeof(C) <: LU{T}
858+
@test C.L == B.L
859+
@test C.U == B.U
860+
@test C.P == B.P
861+
@test C.p == B.p
862+
end
863+
735864
@testset "Unitful quantities" begin
736865
# bare_type for values
737866
@test Float64 === @inferred bare_type(u"2.0m/s")

0 commit comments

Comments
 (0)