From 209ad6cd5b5cfdd6d5ec652e3188c4d139f006f6 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Sat, 28 Mar 2020 20:37:53 +0100 Subject: [PATCH 01/10] collect summary/show methods in show.jl --- src/LinearMaps.jl | 1 + src/functionmap.jl | 8 ---- src/show.jl | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 src/show.jl diff --git a/src/LinearMaps.jl b/src/LinearMaps.jl index 3224a86a..1eaf13eb 100644 --- a/src/LinearMaps.jl +++ b/src/LinearMaps.jl @@ -235,6 +235,7 @@ include("functionmap.jl") # using a function as linear map include("blockmap.jl") # block linear maps include("kronecker.jl") # Kronecker product of linear maps include("conversion.jl") # conversion of linear maps to matrices +include("show.jl") # show methods for LinearMap objects """ LinearMap(A::LinearMap; kwargs...)::WrappedMap diff --git a/src/functionmap.jl b/src/functionmap.jl index 044a4983..52c7a069 100644 --- a/src/functionmap.jl +++ b/src/functionmap.jl @@ -21,14 +21,6 @@ FunctionMap{T}(f, M::Int; kwargs...) where {T} = FunctionMap{T}(f, nothi FunctionMap{T}(f, M::Int, N::Int; kwargs...) where {T} = FunctionMap{T}(f, nothing, M, N; kwargs...) FunctionMap{T}(f, fc, M::Int; kwargs...) where {T} = FunctionMap{T}(f, fc, M, M; kwargs...) -# show -function Base.show(io::IO, A::FunctionMap{T, F, Nothing}) where {T, F} - print(io, "LinearMaps.FunctionMap{$T}($(A.f), $(A.M), $(A.N); ismutating=$(A._ismutating), issymmetric=$(A._issymmetric), ishermitian=$(A._ishermitian), isposdef=$(A._isposdef))") -end -function Base.show(io::IO, A::FunctionMap{T}) where {T} - print(io, "LinearMaps.FunctionMap{$T}($(A.f), $(A.fc), $(A.M), $(A.N); ismutating=$(A._ismutating), issymmetric=$(A._issymmetric), ishermitian=$(A._ishermitian), isposdef=$(A._isposdef))") -end - # properties Base.size(A::FunctionMap) = (A.M, A.N) LinearAlgebra.issymmetric(A::FunctionMap) = A._issymmetric diff --git a/src/show.jl b/src/show.jl new file mode 100644 index 00000000..50ed57ae --- /dev/null +++ b/src/show.jl @@ -0,0 +1,96 @@ +# summary +function Base.summary(io::IO, A::LinearMap) + print(io, Base.dims2string(size(A))) + print(io, ' ') + _show_typeof(io, A) +end + +# show +Base.show(io::IO, A::LinearMap) = (summary(io, A); _show(io, A)) +function _show(io::IO, A::FunctionMap{T,F,Nothing}) where {T,F} + print(io, "($(A.f); ismutating=$(A._ismutating), issymmetric=$(A._issymmetric), ishermitian=$(A._ishermitian), isposdef=$(A._isposdef))") +end +function _show(io::IO, A::FunctionMap) + print(io, "($(A.f), $(A.fc); ismutating=$(A._ismutating), issymmetric=$(A._issymmetric), ishermitian=$(A._ishermitian), isposdef=$(A._isposdef))") +end +function _show(io::IO, A::Union{CompositeMap,LinearCombination,KroneckerMap,KroneckerSumMap}) + n = length(A.maps) + println(io, " with $n map", n>1 ? "s" : "", ":") + print_maps(io, A.maps) +end +function _show(io::IO, A::Union{AdjointMap,TransposeMap,WrappedMap}) + println(io, " of") + L = A.lmap + if A isa MatrixMap + # summary(io, L) + # println(io, ":") + Base.print_matrix(io, L) + else + _show(io, L) + end +end +function _show(io::IO, A::BlockMap) + nrows = length(A.rows) + n = length(A.maps) + println(io, " with $n block map", n>1 ? "s" : "", " in $nrows block row", nrows>1 ? "s" : "") + print_maps(io, A.maps) +end +function _show(io::IO, A::BlockDiagonalMap) + nrows = length(A.rows) + n = length(A.maps) + println(io, " with $n diagonal block map", n>1 ? "s" : "") + print_maps(io, A.maps) +end +function _show(io::IO, J::UniformScalingMap) + s = "$(J.λ)" + if occursin(r"\w+\s*[\+\-]\s*\w+", s) + s = " ($s)" + else + s = " $s" + end + print(io, "\n$s") +end + +# helper functions +function _show_typeof(io::IO, A::LinearMap{T}) where {T} + Base.show_type_name(io, typeof(A).name) + print(io, '{') + show(io, T) + print(io, '}') +end + +function print_maps(io::IO, maps::Tuple{Vararg{LinearMap}}) + n = length(maps) + if get(io, :limit, true) && n > 10 + s = 1:5 + e = n-5:n + if e[1] - s[end] > 1 + for i in s + # print(io, ' ') + show(io, maps[i]) + end + println(io, "⋮") + for i in e + println(io, "") + # print(io, ' ') + show(io, maps[i]) + end + else + for i in 1:n-1 + # print(io, ' ') + show(io, maps[i]) + println(io, "") + end + # print(io, ' ') + show(io, last(maps)) + end + else + for i in 1:n-1 + # print(io, ' ') + show(io, maps[i]) + println(io, "") + end + # print(io, ' ') + show(io, last(maps)) + end +end From aaf9656db5bec0772234af94f003d22688a23f9e Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Fri, 3 Apr 2020 22:39:41 +0200 Subject: [PATCH 02/10] add generic fallback for _show --- src/show.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/show.jl b/src/show.jl index 50ed57ae..c3e7338f 100644 --- a/src/show.jl +++ b/src/show.jl @@ -7,6 +7,7 @@ end # show Base.show(io::IO, A::LinearMap) = (summary(io, A); _show(io, A)) +_show(io::IO, ::LinearMap) = nothing function _show(io::IO, A::FunctionMap{T,F,Nothing}) where {T,F} print(io, "($(A.f); ismutating=$(A._ismutating), issymmetric=$(A._issymmetric), ishermitian=$(A._ishermitian), isposdef=$(A._isposdef))") end From 14ce01ade5641d381da712d262cdc39cccfb1b77 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Thu, 18 Jun 2020 11:14:31 +0200 Subject: [PATCH 03/10] one-line show of UniformScalingMap --- src/show.jl | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/show.jl b/src/show.jl index c3e7338f..ab4a4504 100644 --- a/src/show.jl +++ b/src/show.jl @@ -44,12 +44,7 @@ function _show(io::IO, A::BlockDiagonalMap) end function _show(io::IO, J::UniformScalingMap) s = "$(J.λ)" - if occursin(r"\w+\s*[\+\-]\s*\w+", s) - s = " ($s)" - else - s = " $s" - end - print(io, "\n$s") + print(io, " with scaling factor: $s") end # helper functions From 5b7e539b6a29c96762931efc7ebcc95deb5482ab Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Wed, 2 Sep 2020 15:43:12 +0200 Subject: [PATCH 04/10] update show --- src/scaledmap.jl | 6 ------ src/show.jl | 10 +++++++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/scaledmap.jl b/src/scaledmap.jl index db44fad8..fbf17575 100644 --- a/src/scaledmap.jl +++ b/src/scaledmap.jl @@ -11,12 +11,6 @@ end ScaledMap(λ::S, lmap::A) where {S<:RealOrComplex,A<:LinearMap} = ScaledMap{Base.promote_op(*, S, eltype(lmap))}(λ, lmap) -# show -function Base.show(io::IO, A::ScaledMap{T}) where {T} - println(io, "LinearMaps.ScaledMap{$T}, scale = $(A.λ)") - show(io, A.lmap) -end - # basic methods Base.size(A::ScaledMap) = size(A.lmap) Base.isreal(A::ScaledMap) = isreal(A.λ) && isreal(A.lmap) diff --git a/src/show.jl b/src/show.jl index ab4a4504..e899fc58 100644 --- a/src/show.jl +++ b/src/show.jl @@ -25,9 +25,10 @@ function _show(io::IO, A::Union{AdjointMap,TransposeMap,WrappedMap}) if A isa MatrixMap # summary(io, L) # println(io, ":") - Base.print_matrix(io, L) + # Base.print_matrix(io, L) + print(io, typeof(L)) else - _show(io, L) + show(io, L) end end function _show(io::IO, A::BlockMap) @@ -37,7 +38,6 @@ function _show(io::IO, A::BlockMap) print_maps(io, A.maps) end function _show(io::IO, A::BlockDiagonalMap) - nrows = length(A.rows) n = length(A.maps) println(io, " with $n diagonal block map", n>1 ? "s" : "") print_maps(io, A.maps) @@ -46,6 +46,10 @@ function _show(io::IO, J::UniformScalingMap) s = "$(J.λ)" print(io, " with scaling factor: $s") end +function _show(io::IO, A::ScaledMap{T}) where {T} + println(io, " with scale: $(A.λ) of") + show(io, A.lmap) +end # helper functions function _show_typeof(io::IO, A::LinearMap{T}) where {T} From 9c803001344fca65b3121849b61ff018a1f776fd Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Wed, 2 Sep 2020 15:43:46 +0200 Subject: [PATCH 05/10] update tests --- test/blockmap.jl | 3 +++ test/composition.jl | 1 + test/functionmap.jl | 2 ++ test/kronecker.jl | 2 ++ test/linearcombination.jl | 1 + test/linearmaps.jl | 45 +++++++++---------------------- test/scaledmap.jl | 1 + test/transpose.jl | 55 ++----------------------------------- test/uniformscalingmap.jl | 1 + test/wrappedmap.jl | 57 +++++++++++++++++++++++++++++++++++++++ 10 files changed, 82 insertions(+), 86 deletions(-) diff --git a/test/blockmap.jl b/test/blockmap.jl index 07e22858..d32cf53b 100644 --- a/test/blockmap.jl +++ b/test/blockmap.jl @@ -7,6 +7,7 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays, BenchmarkTools, Interactive A12 = rand(elty, 10, n2) v = rand(elty, 10) L = @inferred hcat(LinearMap(A11), LinearMap(A12)) + @test occursin("10×$(10+n2) LinearMaps.BlockMap{$elty}", sprint((t, s) -> show(t, "text/plain", s), L)) @test @inferred(LinearMaps.MulStyle(L)) === matrixstyle @test L isa LinearMaps.BlockMap{elty} if elty <: Complex @@ -45,6 +46,7 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays, BenchmarkTools, Interactive @test Matrix(L) ≈ A11 A21 = rand(elty, 20, 10) L = @inferred vcat(LinearMap(A11), LinearMap(A21)) + @test occursin("30×10 LinearMaps.BlockMap{$elty}", sprint((t, s) -> show(t, "text/plain", s), L)) @test L isa LinearMaps.BlockMap{elty} @test @inferred(LinearMaps.MulStyle(L)) === matrixstyle @test (@which [A11; A21]).module != LinearMaps @@ -193,6 +195,7 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays, BenchmarkTools, Interactive @test (@which cat(M1, M2, M3, M2, M1; dims=(1,2))).module != LinearMaps x = randn(elty, size(Md, 2)) Bd = @inferred blockdiag(L1, L2, L3, L2, L1) + @test occursin("25×39 LinearMaps.BlockDiagonalMap{$elty}", sprint((t, s) -> show(t, "text/plain", s), Bd)) @test Matrix(Bd) == Md @test convert(AbstractMatrix, Bd) isa SparseMatrixCSC @test sparse(Bd) == Md diff --git a/test/composition.jl b/test/composition.jl index 27921595..f86693e0 100644 --- a/test/composition.jl +++ b/test/composition.jl @@ -22,6 +22,7 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays F2 = F*F FC2 = FC*FC F4 = FC2 * F2 + @test occursin("10×10 LinearMaps.CompositeMap{Complex{Float64}}", sprint((t, s) -> show(t, "text/plain", s), F4)) @test length(F4.maps) == 4 @test @inferred F4 * v == @inferred F * (F * (F * (F * v))) @test @inferred Matrix(M * transpose(M)) ≈ A * transpose(A) diff --git a/test/functionmap.jl b/test/functionmap.jl index 7e7a0146..56b6f86b 100644 --- a/test/functionmap.jl +++ b/test/functionmap.jl @@ -17,6 +17,7 @@ using Test, LinearMaps, LinearAlgebra, BenchmarkTools MyFT = @inferred LinearMap{ComplexF64}(myft, N) / sqrt(N) U = Matrix(MyFT) # will be a unitary matrix @test @inferred U'U ≈ Matrix{eltype(U)}(I, N, N) + @test occursin("$N×$N LinearMaps.FunctionMap{Complex{Float64}}", sprint((t, s) -> show(t, "text/plain", s), MyFT)) CS = @inferred LinearMap(cumsum, 2) @test size(CS) == (2, 2) @@ -33,6 +34,7 @@ using Test, LinearMaps, LinearAlgebra, BenchmarkTools @test *(CS, v) == cv @test_throws ErrorException CS' * v CS = @inferred LinearMap(cumsum, x -> reverse(cumsum(reverse(x))), 10; ismutating=false) + @test occursin("10×10 LinearMaps.FunctionMap{Float64}", sprint((t, s) -> show(t, "text/plain", s), CS)) cv = cumsum(v) @test @inferred CS * v == cv @test @inferred *(CS, v) == cv diff --git a/test/kronecker.jl b/test/kronecker.jl index c55d0b50..6ca5279a 100644 --- a/test/kronecker.jl +++ b/test/kronecker.jl @@ -9,6 +9,7 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays LB = LinearMap(B) LK = @inferred kron(LA, LB) @test_throws AssertionError LinearMaps.KroneckerMap{Float64}((LA, LB)) + @test occursin("6×6 LinearMaps.KroneckerMap{Complex{Float64}}", sprint((t, s) -> show(t, "text/plain", s), LK)) @test @inferred size(LK) == size(K) @test LinearMaps.MulStyle(LK) === LinearMaps.ThreeArg() for i in (1, 2) @@ -68,6 +69,7 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays LA = LinearMap(A) LB = LinearMap(B) KS = @inferred kronsum(LA, B) + @test occursin("6×6 LinearMaps.KroneckerSumMap{$elty}", sprint((t, s) -> show(t, "text/plain", s), KS)) @test_throws ArgumentError kronsum(LA, [B B]) # non-square map KSmat = kron(A, Matrix(I, 2, 2)) + kron(Matrix(I, 3, 3), B) @test Matrix(KS) ≈ Matrix(kron(A, LinearMap(I, 2)) + kron(LinearMap(I, 3), B)) diff --git a/test/linearcombination.jl b/test/linearcombination.jl index 0325c531..94caaa36 100644 --- a/test/linearcombination.jl +++ b/test/linearcombination.jl @@ -11,6 +11,7 @@ using Test, LinearMaps, LinearAlgebra, BenchmarkTools n = 10 L = sum(fill(CS!, n)) @test_throws AssertionError LinearMaps.LinearCombination{Float64}((CS!, CS!)) + @test occursin("10×10 LinearMaps.LinearCombination{Complex{Float64}}", sprint((t, s) -> show(t, "text/plain", s), L)) @test mul!(u, L, v) ≈ n * cumsum(v) b = @benchmarkable mul!($u, $L, $v, 2, 2) @test run(b, samples=5).allocs <= 1 diff --git a/test/linearmaps.jl b/test/linearmaps.jl index 5628aae7..4144e3eb 100644 --- a/test/linearmaps.jl +++ b/test/linearmaps.jl @@ -21,34 +21,6 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays, BenchmarkTools @test length(M) == length(A) end - Av = A * v - AV = A * V - - @testset "mul! and *" begin - for w in (vec(u), u) - @test M * v == Av - @test N * v == Av - @test @inferred mul!(copy(w), M, v) == mul!(copy(w), A, v) - b = @benchmarkable mul!($w, $M, $v) - @test run(b, samples=3).allocs == 0 - @test @inferred mul!(copy(w), N, v) == mul!(copy(w), A, v) - - # mat-vec-mul - @test @inferred mul!(copy(w), M, v, 0, 0) == zero(w) - @test @inferred mul!(copy(w), M, v, 0, 1) == w - @test @inferred mul!(copy(w), M, v, 0, β) == β * w - @test @inferred mul!(copy(w), M, v, 1, 1) ≈ Av + w - @test @inferred mul!(copy(w), M, v, 1, β) ≈ Av + β * w - @test @inferred mul!(copy(w), M, v, α, 1) ≈ α * Av + w - @test @inferred mul!(copy(w), M, v, α, β) ≈ α * Av + β * w - end - - # test mat-mat-mul! - @test @inferred mul!(copy(W), M, V, α, β) ≈ α * AV + β * W - @test @inferred mul!(copy(W), M, V) ≈ AV - @test typeof(M * V) <: LinearMap - end - @testset "dimension checking" begin w = vec(u) @test_throws DimensionMismatch M * similar(v, length(v) + 1) @@ -70,7 +42,7 @@ struct SimpleComplexFunctionMap <: LinearMap{Complex{Float64}} N::Int end Base.size(A::Union{SimpleFunctionMap,SimpleComplexFunctionMap}) = (A.N, A.N) -Base.:(*)(A::Union{SimpleFunctionMap,SimpleComplexFunctionMap}, v::Vector) = A.f(v) +Base.:(*)(A::Union{SimpleFunctionMap,SimpleComplexFunctionMap}, v::AbstractVector) = A.f(v) LinearAlgebra.mul!(y::AbstractVector, A::Union{SimpleFunctionMap,SimpleComplexFunctionMap}, x::AbstractVector) = copyto!(y, *(A, x)) @testset "new LinearMap type" begin @@ -83,10 +55,12 @@ LinearAlgebra.mul!(y::AbstractVector, A::Union{SimpleFunctionMap,SimpleComplexFu @test @inferred !ishermitian(F) @test @inferred !ishermitian(FC) @test @inferred !isposdef(F) - v = rand(ComplexF64, 10) - w = similar(v) - mul!(w, F, v) - @test w == F * v + @test occursin("10×10 SimpleFunctionMap{Float64}", sprint((t, s) -> show(t, "text/plain", s), F)) + @test occursin("10×10 SimpleComplexFunctionMap{Complex{Float64}}", sprint((t, s) -> show(t, "text/plain", s), FC)) + α = rand(ComplexF64); β = rand(ComplexF64) + v = rand(ComplexF64, 10); V = rand(ComplexF64, 10, 3) + w = rand(ComplexF64, 10); W = rand(ComplexF64, 10, 3) + @test mul!(w, F, v) === w == F * v @test_throws ErrorException F' * v @test_throws ErrorException transpose(F) * v @test_throws ErrorException mul!(w, adjoint(FC), v) @@ -95,6 +69,11 @@ LinearAlgebra.mul!(y::AbstractVector, A::Union{SimpleFunctionMap,SimpleComplexFu L = LowerTriangular(ones(10, 10)) @test FM == L @test F * v ≈ L * v + # generic 5-arg mul! and matrix-mul! + @test mul!(copy(w), F, v, α, β) ≈ L*v*α + w*β + @test mul!(copy(W), F, V) ≈ L*V + @test mul!(copy(W), F, V, α, β) ≈ L*V*α + W*β + Fs = sparse(F) @test SparseMatrixCSC(F) == Fs == L @test Fs isa SparseMatrixCSC diff --git a/test/scaledmap.jl b/test/scaledmap.jl index c87aec54..1105093c 100644 --- a/test/scaledmap.jl +++ b/test/scaledmap.jl @@ -8,6 +8,7 @@ using Test, LinearMaps, LinearAlgebra, BenchmarkTools # real case α = float(π) B = @inferred α * A + @test occursin("7×7 LinearMaps.ScaledMap{Float64} with scale: $α", sprint((t, s) -> show(t, "text/plain", s), B)) x = rand(N) @test @inferred size(B) == size(A) diff --git a/test/transpose.jl b/test/transpose.jl index 823428ec..30933bb2 100644 --- a/test/transpose.jl +++ b/test/transpose.jl @@ -1,59 +1,6 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays @testset "transpose/adjoint" begin - A = 2 * rand(ComplexF64, (20, 10)) .- 1 - v = rand(ComplexF64, 10) - w = rand(ComplexF64, 20) - V = rand(ComplexF64, 10, 3) - W = rand(ComplexF64, 20, 3) - Av = A * v - AV = A * V - M = @inferred LinearMap(A) - N = @inferred LinearMap(M) - - @test @inferred M' * w == A' * w - @test @inferred mul!(copy(V), adjoint(M), W) ≈ A' * W - @test @inferred transpose(M) * w == transpose(A) * w - @test @inferred transpose(LinearMap(transpose(M))) * v == A * v - @test @inferred LinearMap(M')' * v == A * v - @test @inferred(transpose(transpose(M))) === M - @test @inferred(adjoint(adjoint(M))) === M - Mherm = @inferred LinearMap(A'A) - @test @inferred ishermitian(Mherm) - @test @inferred !issymmetric(Mherm) - @test @inferred !issymmetric(transpose(Mherm)) - @test @inferred ishermitian(transpose(Mherm)) - @test @inferred ishermitian(Mherm') - @test @inferred isposdef(Mherm) - @test @inferred isposdef(transpose(Mherm)) - @test @inferred isposdef(adjoint(Mherm)) - @test @inferred !(transpose(M) == adjoint(M)) - @test @inferred !(adjoint(M) == transpose(M)) - @test @inferred transpose(M') * v ≈ transpose(A') * v - @test @inferred transpose(LinearMap(M')) * v ≈ transpose(A') * v - @test @inferred LinearMap(transpose(M))' * v ≈ transpose(A)' * v - @test @inferred transpose(LinearMap(transpose(M))) * v ≈ Av - @test @inferred adjoint(LinearMap(adjoint(M))) * v ≈ Av - - @test @inferred mul!(copy(w), transpose(LinearMap(M')), v) ≈ transpose(A') * v - @test @inferred mul!(copy(w), LinearMap(transpose(M))', v) ≈ transpose(A)' * v - @test @inferred mul!(copy(w), transpose(LinearMap(transpose(M))), v) ≈ Av - @test @inferred mul!(copy(w), adjoint(LinearMap(adjoint(M))), v) ≈ Av - @test @inferred mul!(copy(W), transpose(LinearMap(M')), V) ≈ transpose(A') * V - @test @inferred mul!(copy(W), LinearMap(transpose(M))', V) ≈ transpose(A)' * V - @test @inferred mul!(copy(W), transpose(LinearMap(transpose(M))), V) ≈ AV - @test @inferred mul!(copy(W), adjoint(LinearMap(adjoint(M))), V) ≈ AV - @test @inferred mul!(copy(V), transpose(M), W) ≈ transpose(A) * W - @test @inferred mul!(copy(V), adjoint(M), W) ≈ A' * W - - B = @inferred LinearMap(Symmetric(rand(10, 10))) - @test transpose(B) == B - @test B == transpose(B) - - B = @inferred LinearMap(Hermitian(rand(ComplexF64, 10, 10))) - @test adjoint(B) == B - @test B == B' - CS = @inferred LinearMap{ComplexF64}(cumsum, x -> reverse(cumsum(reverse(x))), 10; ismutating=false) for transform in (adjoint, transpose) @test transform(CS) != CS @@ -61,6 +8,8 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays @test transform(transform(CS)) == CS @test LinearMaps.MulStyle(transform(CS)) === LinearMaps.MulStyle(CS) end + @test occursin("10×10 LinearMaps.TransposeMap{Complex{Float64}}", sprint((t, s) -> show(t, "text/plain", s), transpose(CS))) + @test occursin("10×10 LinearMaps.AdjointMap{Complex{Float64}}", sprint((t, s) -> show(t, "text/plain", s), adjoint(CS))) @test !(transpose(CS) == adjoint(CS)) @test !(adjoint(CS) == transpose(CS)) M = Matrix(CS) diff --git a/test/uniformscalingmap.jl b/test/uniformscalingmap.jl index f83715d4..357d694a 100644 --- a/test/uniformscalingmap.jl +++ b/test/uniformscalingmap.jl @@ -10,6 +10,7 @@ using Test, LinearMaps, LinearAlgebra, BenchmarkTools v = rand(ComplexF64, 10) w = similar(v) Id = @inferred LinearMap(I, 10) + @test occursin("10×10 LinearMaps.UniformScalingMap{Bool}", sprint((t, s) -> show(t, "text/plain", s), Id)) @test_throws ErrorException LinearMaps.UniformScalingMap(1, 10, 20) @test_throws ErrorException LinearMaps.UniformScalingMap(1, (10, 20)) @test size(Id) == (10, 10) diff --git a/test/wrappedmap.jl b/test/wrappedmap.jl index ac04dc75..db36fb1b 100644 --- a/test/wrappedmap.jl +++ b/test/wrappedmap.jl @@ -6,6 +6,7 @@ using Test, LinearMaps, LinearAlgebra SA = A'A + I SB = B'B + I L = @inferred LinearMap{Float64}(A) + @test occursin("10×20 LinearMaps.WrappedMap{Float64}", sprint((t, s) -> show(t, "text/plain", s), L)) MA = @inferred LinearMap(SA) MB = @inferred LinearMap(SB) @test eltype(Matrix{Complex{Float32}}(LinearMap(A))) <: Complex @@ -15,4 +16,60 @@ using Test, LinearMaps, LinearAlgebra @test @inferred !issymmetric(MB) @test @inferred isposdef(MA) @test @inferred isposdef(MB) + + A = 2 * rand(ComplexF64, (20, 10)) .- 1 + v = rand(ComplexF64, 10) + w = rand(ComplexF64, 20) + u = rand(ComplexF64, 20, 1) + V = rand(ComplexF64, 10, 3) + W = rand(ComplexF64, 20, 3) + Av = A * v + AV = A * V + M = @inferred LinearMap(A) + N = @inferred LinearMap(M) + + @test @inferred M' * w == A' * w + @test @inferred mul!(copy(V), adjoint(M), W) ≈ A' * W + @test @inferred transpose(M) * w == transpose(A) * w + @test @inferred transpose(LinearMap(transpose(M))) * v == A * v + @test @inferred LinearMap(M')' * v == A * v + @test @inferred(transpose(transpose(M))) === M + @test @inferred(adjoint(adjoint(M))) === M + Mherm = @inferred LinearMap(A'A) + @test @inferred ishermitian(Mherm) + @test @inferred !issymmetric(Mherm) + @test @inferred !issymmetric(transpose(Mherm)) + @test @inferred ishermitian(transpose(Mherm)) + @test @inferred ishermitian(Mherm') + @test @inferred isposdef(Mherm) + @test @inferred isposdef(transpose(Mherm)) + @test @inferred isposdef(adjoint(Mherm)) + @test @inferred !(transpose(M) == adjoint(M)) + @test @inferred !(adjoint(M) == transpose(M)) + @test @inferred transpose(M') * v ≈ transpose(A') * v + @test @inferred transpose(LinearMap(M')) * v ≈ transpose(A') * v + @test @inferred LinearMap(transpose(M))' * v ≈ transpose(A)' * v + @test @inferred transpose(LinearMap(transpose(M))) * v ≈ Av + @test @inferred adjoint(LinearMap(adjoint(M))) * v ≈ Av + + for w in (vec(u), u) + @test @inferred mul!(copy(w), transpose(LinearMap(M')), v) ≈ transpose(A') * v + @test @inferred mul!(copy(w), LinearMap(transpose(M))', v) ≈ transpose(A)' * v + @test @inferred mul!(copy(w), transpose(LinearMap(transpose(M))), v) ≈ Av + @test @inferred mul!(copy(w), adjoint(LinearMap(adjoint(M))), v) ≈ Av + end + @test @inferred mul!(copy(W), transpose(LinearMap(M')), V) ≈ transpose(A') * V + @test @inferred mul!(copy(W), LinearMap(transpose(M))', V) ≈ transpose(A)' * V + @test @inferred mul!(copy(W), transpose(LinearMap(transpose(M))), V) ≈ AV + @test @inferred mul!(copy(W), adjoint(LinearMap(adjoint(M))), V) ≈ AV + @test @inferred mul!(copy(V), transpose(M), W) ≈ transpose(A) * W + @test @inferred mul!(copy(V), adjoint(M), W) ≈ A' * W + + B = @inferred LinearMap(Symmetric(rand(10, 10))) + @test transpose(B) == B + @test B == transpose(B) + + B = @inferred LinearMap(Hermitian(rand(ComplexF64, 10, 10))) + @test adjoint(B) == B + @test B == B' end From e3c8bab511b42a0133efbab4c59f5ca001cc1567 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Wed, 2 Sep 2020 15:59:20 +0200 Subject: [PATCH 06/10] improve tests --- test/linearmaps.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/linearmaps.jl b/test/linearmaps.jl index 4144e3eb..c8ce5a21 100644 --- a/test/linearmaps.jl +++ b/test/linearmaps.jl @@ -55,8 +55,8 @@ LinearAlgebra.mul!(y::AbstractVector, A::Union{SimpleFunctionMap,SimpleComplexFu @test @inferred !ishermitian(F) @test @inferred !ishermitian(FC) @test @inferred !isposdef(F) - @test occursin("10×10 SimpleFunctionMap{Float64}", sprint((t, s) -> show(t, "text/plain", s), F)) - @test occursin("10×10 SimpleComplexFunctionMap{Complex{Float64}}", sprint((t, s) -> show(t, "text/plain", s), FC)) + @test occursin("10×10 SimpleFunctionMap{$(eltype(F))}", sprint((t, s) -> show(t, "text/plain", s), F)) + @test occursin("10×10 SimpleComplexFunctionMap{$(eltype(FC))}", sprint((t, s) -> show(t, "text/plain", s), FC)) α = rand(ComplexF64); β = rand(ComplexF64) v = rand(ComplexF64, 10); V = rand(ComplexF64, 10, 3) w = rand(ComplexF64, 10); W = rand(ComplexF64, 10, 3) @@ -71,8 +71,10 @@ LinearAlgebra.mul!(y::AbstractVector, A::Union{SimpleFunctionMap,SimpleComplexFu @test F * v ≈ L * v # generic 5-arg mul! and matrix-mul! @test mul!(copy(w), F, v, α, β) ≈ L*v*α + w*β + @test mul!(copy(w), F, v, 0, β) ≈ w*β @test mul!(copy(W), F, V) ≈ L*V @test mul!(copy(W), F, V, α, β) ≈ L*V*α + W*β + @test mul!(copy(W), F, V, 0, β) ≈ W*β Fs = sparse(F) @test SparseMatrixCSC(F) == Fs == L From 2c90a12a997f215a56caf236fea90fdca09a4307 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Wed, 2 Sep 2020 16:10:34 +0200 Subject: [PATCH 07/10] fix complex show tests --- test/composition.jl | 2 +- test/functionmap.jl | 2 +- test/kronecker.jl | 2 +- test/linearcombination.jl | 2 +- test/transpose.jl | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/composition.jl b/test/composition.jl index f86693e0..39eb8082 100644 --- a/test/composition.jl +++ b/test/composition.jl @@ -22,7 +22,7 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays F2 = F*F FC2 = FC*FC F4 = FC2 * F2 - @test occursin("10×10 LinearMaps.CompositeMap{Complex{Float64}}", sprint((t, s) -> show(t, "text/plain", s), F4)) + @test occursin("10×10 LinearMaps.CompositeMap{$(eltype(F4))}", sprint((t, s) -> show(t, "text/plain", s), F4)) @test length(F4.maps) == 4 @test @inferred F4 * v == @inferred F * (F * (F * (F * v))) @test @inferred Matrix(M * transpose(M)) ≈ A * transpose(A) diff --git a/test/functionmap.jl b/test/functionmap.jl index 56b6f86b..8c55ea47 100644 --- a/test/functionmap.jl +++ b/test/functionmap.jl @@ -17,7 +17,7 @@ using Test, LinearMaps, LinearAlgebra, BenchmarkTools MyFT = @inferred LinearMap{ComplexF64}(myft, N) / sqrt(N) U = Matrix(MyFT) # will be a unitary matrix @test @inferred U'U ≈ Matrix{eltype(U)}(I, N, N) - @test occursin("$N×$N LinearMaps.FunctionMap{Complex{Float64}}", sprint((t, s) -> show(t, "text/plain", s), MyFT)) + @test occursin("$N×$N LinearMaps.FunctionMap{$(eltype(MyFT))}", sprint((t, s) -> show(t, "text/plain", s), MyFT)) CS = @inferred LinearMap(cumsum, 2) @test size(CS) == (2, 2) diff --git a/test/kronecker.jl b/test/kronecker.jl index 6ca5279a..88b6dc38 100644 --- a/test/kronecker.jl +++ b/test/kronecker.jl @@ -9,7 +9,7 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays LB = LinearMap(B) LK = @inferred kron(LA, LB) @test_throws AssertionError LinearMaps.KroneckerMap{Float64}((LA, LB)) - @test occursin("6×6 LinearMaps.KroneckerMap{Complex{Float64}}", sprint((t, s) -> show(t, "text/plain", s), LK)) + @test occursin("6×6 LinearMaps.KroneckerMap{$(eltype(LK))}", sprint((t, s) -> show(t, "text/plain", s), LK)) @test @inferred size(LK) == size(K) @test LinearMaps.MulStyle(LK) === LinearMaps.ThreeArg() for i in (1, 2) diff --git a/test/linearcombination.jl b/test/linearcombination.jl index 94caaa36..9d128caf 100644 --- a/test/linearcombination.jl +++ b/test/linearcombination.jl @@ -11,7 +11,7 @@ using Test, LinearMaps, LinearAlgebra, BenchmarkTools n = 10 L = sum(fill(CS!, n)) @test_throws AssertionError LinearMaps.LinearCombination{Float64}((CS!, CS!)) - @test occursin("10×10 LinearMaps.LinearCombination{Complex{Float64}}", sprint((t, s) -> show(t, "text/plain", s), L)) + @test occursin("10×10 LinearMaps.LinearCombination{$(eltype(L))}", sprint((t, s) -> show(t, "text/plain", s), L)) @test mul!(u, L, v) ≈ n * cumsum(v) b = @benchmarkable mul!($u, $L, $v, 2, 2) @test run(b, samples=5).allocs <= 1 diff --git a/test/transpose.jl b/test/transpose.jl index 30933bb2..b86c9873 100644 --- a/test/transpose.jl +++ b/test/transpose.jl @@ -8,8 +8,8 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays @test transform(transform(CS)) == CS @test LinearMaps.MulStyle(transform(CS)) === LinearMaps.MulStyle(CS) end - @test occursin("10×10 LinearMaps.TransposeMap{Complex{Float64}}", sprint((t, s) -> show(t, "text/plain", s), transpose(CS))) - @test occursin("10×10 LinearMaps.AdjointMap{Complex{Float64}}", sprint((t, s) -> show(t, "text/plain", s), adjoint(CS))) + @test occursin("10×10 LinearMaps.TransposeMap{$(eltype(CS))}", sprint((t, s) -> show(t, "text/plain", s), transpose(CS))) + @test occursin("10×10 LinearMaps.AdjointMap{$(eltype(CS))}", sprint((t, s) -> show(t, "text/plain", s), adjoint(CS))) @test !(transpose(CS) == adjoint(CS)) @test !(adjoint(CS) == transpose(CS)) M = Matrix(CS) From 5063182cbc441bc1eaa91c3000ce941e2e52e177 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Wed, 7 Oct 2020 15:41:06 +0200 Subject: [PATCH 08/10] overload Base.parent, add tests --- src/LinearMaps.jl | 9 +++++++++ src/blockmap.jl | 6 ++++++ src/composition.jl | 1 + src/functionmap.jl | 1 + src/kronecker.jl | 5 ++++- src/linearcombination.jl | 1 + src/scaledmap.jl | 1 + src/transpose.jl | 2 ++ src/uniformscalingmap.jl | 1 + src/wrappedmap.jl | 1 + test/blockmap.jl | 6 ++++++ test/composition.jl | 1 + test/functionmap.jl | 1 + test/kronecker.jl | 2 ++ test/linearcombination.jl | 1 + test/linearmaps.jl | 1 + test/scaledmap.jl | 1 + test/transpose.jl | 2 ++ test/uniformscalingmap.jl | 1 + test/wrappedmap.jl | 1 + 20 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/LinearMaps.jl b/src/LinearMaps.jl index 1eaf13eb..f8cc42e6 100644 --- a/src/LinearMaps.jl +++ b/src/LinearMaps.jl @@ -48,6 +48,15 @@ Base.ndims(::LinearMap) = 2 Base.size(A::LinearMap, n) = (n==1 || n==2 ? size(A)[n] : error("LinearMap objects have only 2 dimensions")) Base.length(A::LinearMap) = size(A)[1] * size(A)[2] +""" + parent(A::LinearMap) + +Return the underlying "parent map". This parent map is what was passed as an argument to +the specific `LinearMap` constructor, including implicit constructors and up to implicit +promotion to a `LinearMap` subtype. The fallback is to return the input itself. +""" +Base.parent(A::LinearMap) = A + # check dimension consistency for multiplication A*B _iscompatible((A, B)) = size(A, 2) == size(B, 1) function check_dim_mul(A, B) diff --git a/src/blockmap.jl b/src/blockmap.jl index 92516b27..d31281b9 100644 --- a/src/blockmap.jl +++ b/src/blockmap.jl @@ -17,6 +17,8 @@ BlockMap{T}(maps::As, rows::S) where {T,As<:Tuple{Vararg{LinearMap}},S} = BlockM MulStyle(A::BlockMap) = MulStyle(A.maps...) +Base.parent(A::BlockMap) = A.maps + """ rowcolranges(maps, rows) @@ -458,6 +460,10 @@ Base.cat Base.size(A::BlockDiagonalMap) = (last(A.rowranges[end]), last(A.colranges[end])) +MulStyle(A::BlockDiagonalMap) = MulStyle(A.maps...) + +Base.parent(A::BlockDiagonalMap) = A.maps + LinearAlgebra.issymmetric(A::BlockDiagonalMap) = all(issymmetric, A.maps) LinearAlgebra.ishermitian(A::BlockDiagonalMap{<:Real}) = all(issymmetric, A.maps) LinearAlgebra.ishermitian(A::BlockDiagonalMap) = all(ishermitian, A.maps) diff --git a/src/composition.jl b/src/composition.jl index eb70bdec..844382b8 100644 --- a/src/composition.jl +++ b/src/composition.jl @@ -17,6 +17,7 @@ CompositeMap{T}(maps::As) where {T, As<:Tuple{Vararg{LinearMap}}} = CompositeMap # basic methods Base.size(A::CompositeMap) = (size(A.maps[end], 1), size(A.maps[1], 2)) Base.isreal(A::CompositeMap) = all(isreal, A.maps) # sufficient but not necessary +Base.parent(A::CompositeMap) = A.maps # the following rules are sufficient but not necessary for (f, _f, g) in ((:issymmetric, :_issymmetric, :transpose), diff --git a/src/functionmap.jl b/src/functionmap.jl index 52c7a069..8a7f97aa 100644 --- a/src/functionmap.jl +++ b/src/functionmap.jl @@ -23,6 +23,7 @@ FunctionMap{T}(f, fc, M::Int; kwargs...) where {T} = FunctionMap{T}(f, fc, M # properties Base.size(A::FunctionMap) = (A.M, A.N) +Base.parent(A::FunctionMap) = (A.f, A.fc) LinearAlgebra.issymmetric(A::FunctionMap) = A._issymmetric LinearAlgebra.ishermitian(A::FunctionMap) = A._ishermitian LinearAlgebra.isposdef(A::FunctionMap) = A._isposdef diff --git a/src/kronecker.jl b/src/kronecker.jl index 8c513859..5837bdc0 100644 --- a/src/kronecker.jl +++ b/src/kronecker.jl @@ -88,6 +88,8 @@ Base.:(^)(A::MapOrMatrix, ::KronPower{p}) where {p} = Base.size(A::KroneckerMap) = map(*, size.(A.maps)...) +Base.parent(A::KroneckerMap) = A.maps + LinearAlgebra.issymmetric(A::KroneckerMap) = all(issymmetric, A.maps) LinearAlgebra.ishermitian(A::KroneckerMap{<:Real}) = issymmetric(A) LinearAlgebra.ishermitian(A::KroneckerMap) = all(ishermitian, A.maps) @@ -123,7 +125,7 @@ end if nb*ma < mb*na _unsafe_mul!(Y, B, Matrix(X*At)) else - _unsafe_mul!(Y, Matrix(B*X), At isa MatrixMap ? At.lmap : At.λ) + _unsafe_mul!(Y, Matrix(B*X), parent(At)) end return y end @@ -248,6 +250,7 @@ Base.:(^)(A::MapOrMatrix, ::KronSumPower{p}) where {p} = kronsum(ntuple(n -> con Base.size(A::KroneckerSumMap, i) = prod(size.(A.maps, i)) Base.size(A::KroneckerSumMap) = (size(A, 1), size(A, 2)) +Base.parent(A::KroneckerSumMap) = A.maps LinearAlgebra.issymmetric(A::KroneckerSumMap) = all(issymmetric, A.maps) LinearAlgebra.ishermitian(A::KroneckerSumMap{<:Real}) = all(issymmetric, A.maps) diff --git a/src/linearcombination.jl b/src/linearcombination.jl index 526a330a..13fa9abc 100644 --- a/src/linearcombination.jl +++ b/src/linearcombination.jl @@ -18,6 +18,7 @@ MulStyle(A::LinearCombination) = MulStyle(A.maps...) # basic methods Base.size(A::LinearCombination) = size(A.maps[1]) +Base.parent(A::LinearCombination) = A.maps LinearAlgebra.issymmetric(A::LinearCombination) = all(issymmetric, A.maps) # sufficient but not necessary LinearAlgebra.ishermitian(A::LinearCombination) = all(ishermitian, A.maps) # sufficient but not necessary LinearAlgebra.isposdef(A::LinearCombination) = all(isposdef, A.maps) # sufficient but not necessary diff --git a/src/scaledmap.jl b/src/scaledmap.jl index fbf17575..ef80f59b 100644 --- a/src/scaledmap.jl +++ b/src/scaledmap.jl @@ -13,6 +13,7 @@ ScaledMap(λ::S, lmap::A) where {S<:RealOrComplex,A<:LinearMap} = # basic methods Base.size(A::ScaledMap) = size(A.lmap) +Base.parent(A::ScaledMap) = (A.λ, A.lmap) Base.isreal(A::ScaledMap) = isreal(A.λ) && isreal(A.lmap) LinearAlgebra.issymmetric(A::ScaledMap) = issymmetric(A.lmap) LinearAlgebra.ishermitian(A::ScaledMap) = ishermitian(A.lmap) diff --git a/src/transpose.jl b/src/transpose.jl index ed631582..e4e30361 100644 --- a/src/transpose.jl +++ b/src/transpose.jl @@ -11,6 +11,8 @@ MulStyle(A::Union{TransposeMap,AdjointMap}) = MulStyle(A.lmap) LinearAlgebra.transpose(A::TransposeMap) = A.lmap LinearAlgebra.adjoint(A::AdjointMap) = A.lmap +Base.parent(A::Union{AdjointMap,TransposeMap}) = A.lmap + """ transpose(A::LinearMap) diff --git a/src/uniformscalingmap.jl b/src/uniformscalingmap.jl index 823c7700..32d83081 100644 --- a/src/uniformscalingmap.jl +++ b/src/uniformscalingmap.jl @@ -15,6 +15,7 @@ MulStyle(::UniformScalingMap) = FiveArg() # properties Base.size(A::UniformScalingMap) = (A.M, A.M) +Base.parent(A::UniformScalingMap) = A.λ Base.isreal(A::UniformScalingMap) = isreal(A.λ) LinearAlgebra.issymmetric(::UniformScalingMap) = true LinearAlgebra.ishermitian(A::UniformScalingMap) = isreal(A) diff --git a/src/wrappedmap.jl b/src/wrappedmap.jl index 3fe34fe5..9a5f77ef 100644 --- a/src/wrappedmap.jl +++ b/src/wrappedmap.jl @@ -32,6 +32,7 @@ Base.:(==)(A::MatrixMap, B::MatrixMap) = # properties Base.size(A::WrappedMap) = size(A.lmap) +Base.parent(A::WrappedMap) = A.lmap LinearAlgebra.issymmetric(A::WrappedMap) = A._issymmetric LinearAlgebra.ishermitian(A::WrappedMap) = A._ishermitian LinearAlgebra.isposdef(A::WrappedMap) = A._isposdef diff --git a/test/blockmap.jl b/test/blockmap.jl index d32cf53b..7582c851 100644 --- a/test/blockmap.jl +++ b/test/blockmap.jl @@ -7,6 +7,7 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays, BenchmarkTools, Interactive A12 = rand(elty, 10, n2) v = rand(elty, 10) L = @inferred hcat(LinearMap(A11), LinearMap(A12)) + @test parent(L) == (LinearMap(A11), LinearMap(A12)) @test occursin("10×$(10+n2) LinearMaps.BlockMap{$elty}", sprint((t, s) -> show(t, "text/plain", s), L)) @test @inferred(LinearMaps.MulStyle(L)) === matrixstyle @test L isa LinearMaps.BlockMap{elty} @@ -31,6 +32,10 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays, BenchmarkTools, Interactive x = rand(elty, 61) @test L isa LinearMaps.BlockMap{elty} @test L * x ≈ A * x + L = @inferred hcat(I, I, I, LinearMap(A11), A11, A11, v, v, v, v) + @test occursin("10×64 LinearMaps.BlockMap{$elty}", sprint((t, s) -> show(t, "text/plain", s), L)) + L = @inferred hcat(I, I, I, LinearMap(A11), A11, A11, v, v, v, v, v, v, v) + @test occursin("10×67 LinearMaps.BlockMap{$elty}", sprint((t, s) -> show(t, "text/plain", s), L)) A11 = rand(elty, 11, 10) A12 = rand(elty, 10, n2) @test_throws DimensionMismatch hcat(LinearMap(A11), LinearMap(A12)) @@ -195,6 +200,7 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays, BenchmarkTools, Interactive @test (@which cat(M1, M2, M3, M2, M1; dims=(1,2))).module != LinearMaps x = randn(elty, size(Md, 2)) Bd = @inferred blockdiag(L1, L2, L3, L2, L1) + @test parent(Bd) == (L1, L2, L3, L2, L1) @test occursin("25×39 LinearMaps.BlockDiagonalMap{$elty}", sprint((t, s) -> show(t, "text/plain", s), Bd)) @test Matrix(Bd) == Md @test convert(AbstractMatrix, Bd) isa SparseMatrixCSC diff --git a/test/composition.jl b/test/composition.jl index 39eb8082..3a538254 100644 --- a/test/composition.jl +++ b/test/composition.jl @@ -20,6 +20,7 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays @test @inferred (A * F) * v == @inferred A * (F * v) @test @inferred A * (F * F) * v == @inferred A * (F * (F * v)) F2 = F*F + @test parent(F2) == (F, F) FC2 = FC*FC F4 = FC2 * F2 @test occursin("10×10 LinearMaps.CompositeMap{$(eltype(F4))}", sprint((t, s) -> show(t, "text/plain", s), F4)) diff --git a/test/functionmap.jl b/test/functionmap.jl index 8c55ea47..9f277350 100644 --- a/test/functionmap.jl +++ b/test/functionmap.jl @@ -18,6 +18,7 @@ using Test, LinearMaps, LinearAlgebra, BenchmarkTools U = Matrix(MyFT) # will be a unitary matrix @test @inferred U'U ≈ Matrix{eltype(U)}(I, N, N) @test occursin("$N×$N LinearMaps.FunctionMap{$(eltype(MyFT))}", sprint((t, s) -> show(t, "text/plain", s), MyFT)) + @test parent(LinearMap{ComplexF64}(myft, N)) === (myft, nothing) CS = @inferred LinearMap(cumsum, 2) @test size(CS) == (2, 2) diff --git a/test/kronecker.jl b/test/kronecker.jl index 88b6dc38..f9031a62 100644 --- a/test/kronecker.jl +++ b/test/kronecker.jl @@ -8,6 +8,7 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays LA = LinearMap(A) LB = LinearMap(B) LK = @inferred kron(LA, LB) + @test parent(LK) == (LA, LB) @test_throws AssertionError LinearMaps.KroneckerMap{Float64}((LA, LB)) @test occursin("6×6 LinearMaps.KroneckerMap{$(eltype(LK))}", sprint((t, s) -> show(t, "text/plain", s), LK)) @test @inferred size(LK) == size(K) @@ -69,6 +70,7 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays LA = LinearMap(A) LB = LinearMap(B) KS = @inferred kronsum(LA, B) + @test parent(KS) == (LA, LB) @test occursin("6×6 LinearMaps.KroneckerSumMap{$elty}", sprint((t, s) -> show(t, "text/plain", s), KS)) @test_throws ArgumentError kronsum(LA, [B B]) # non-square map KSmat = kron(A, Matrix(I, 2, 2)) + kron(Matrix(I, 3, 3), B) diff --git a/test/linearcombination.jl b/test/linearcombination.jl index 9d128caf..bff12f7c 100644 --- a/test/linearcombination.jl +++ b/test/linearcombination.jl @@ -12,6 +12,7 @@ using Test, LinearMaps, LinearAlgebra, BenchmarkTools L = sum(fill(CS!, n)) @test_throws AssertionError LinearMaps.LinearCombination{Float64}((CS!, CS!)) @test occursin("10×10 LinearMaps.LinearCombination{$(eltype(L))}", sprint((t, s) -> show(t, "text/plain", s), L)) + @test parent(L) == ntuple(_ -> CS!, 10) @test mul!(u, L, v) ≈ n * cumsum(v) b = @benchmarkable mul!($u, $L, $v, 2, 2) @test run(b, samples=5).allocs <= 1 diff --git a/test/linearmaps.jl b/test/linearmaps.jl index c8ce5a21..7ea67f2a 100644 --- a/test/linearmaps.jl +++ b/test/linearmaps.jl @@ -47,6 +47,7 @@ LinearAlgebra.mul!(y::AbstractVector, A::Union{SimpleFunctionMap,SimpleComplexFu @testset "new LinearMap type" begin F = SimpleFunctionMap(cumsum, 10) + @test parent(F) === F FC = SimpleComplexFunctionMap(cumsum, 10) @test @inferred ndims(F) == 2 @test @inferred size(F, 1) == 10 diff --git a/test/scaledmap.jl b/test/scaledmap.jl index 1105093c..2948b908 100644 --- a/test/scaledmap.jl +++ b/test/scaledmap.jl @@ -9,6 +9,7 @@ using Test, LinearMaps, LinearAlgebra, BenchmarkTools α = float(π) B = @inferred α * A @test occursin("7×7 LinearMaps.ScaledMap{Float64} with scale: $α", sprint((t, s) -> show(t, "text/plain", s), B)) + @test parent(B) == (α, A) x = rand(N) @test @inferred size(B) == size(A) diff --git a/test/transpose.jl b/test/transpose.jl index b86c9873..08e25f87 100644 --- a/test/transpose.jl +++ b/test/transpose.jl @@ -10,6 +10,8 @@ using Test, LinearMaps, LinearAlgebra, SparseArrays end @test occursin("10×10 LinearMaps.TransposeMap{$(eltype(CS))}", sprint((t, s) -> show(t, "text/plain", s), transpose(CS))) @test occursin("10×10 LinearMaps.AdjointMap{$(eltype(CS))}", sprint((t, s) -> show(t, "text/plain", s), adjoint(CS))) + @test parent(transpose(CS)) === CS + @test parent(adjoint(CS)) === CS @test !(transpose(CS) == adjoint(CS)) @test !(adjoint(CS) == transpose(CS)) M = Matrix(CS) diff --git a/test/uniformscalingmap.jl b/test/uniformscalingmap.jl index 357d694a..6ae4f304 100644 --- a/test/uniformscalingmap.jl +++ b/test/uniformscalingmap.jl @@ -11,6 +11,7 @@ using Test, LinearMaps, LinearAlgebra, BenchmarkTools w = similar(v) Id = @inferred LinearMap(I, 10) @test occursin("10×10 LinearMaps.UniformScalingMap{Bool}", sprint((t, s) -> show(t, "text/plain", s), Id)) + @test parent(Id) == true @test_throws ErrorException LinearMaps.UniformScalingMap(1, 10, 20) @test_throws ErrorException LinearMaps.UniformScalingMap(1, (10, 20)) @test size(Id) == (10, 10) diff --git a/test/wrappedmap.jl b/test/wrappedmap.jl index db36fb1b..5cb26d5c 100644 --- a/test/wrappedmap.jl +++ b/test/wrappedmap.jl @@ -7,6 +7,7 @@ using Test, LinearMaps, LinearAlgebra SB = B'B + I L = @inferred LinearMap{Float64}(A) @test occursin("10×20 LinearMaps.WrappedMap{Float64}", sprint((t, s) -> show(t, "text/plain", s), L)) + @test parent(L) === A MA = @inferred LinearMap(SA) MB = @inferred LinearMap(SB) @test eltype(Matrix{Complex{Float32}}(LinearMap(A))) <: Complex From f8914991026228876b3b8e2153d59bce482f9804 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Wed, 7 Oct 2020 15:41:27 +0200 Subject: [PATCH 09/10] minor show edis --- src/show.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/show.jl b/src/show.jl index e899fc58..2aca5477 100644 --- a/src/show.jl +++ b/src/show.jl @@ -20,7 +20,7 @@ function _show(io::IO, A::Union{CompositeMap,LinearCombination,KroneckerMap,Kron print_maps(io, A.maps) end function _show(io::IO, A::Union{AdjointMap,TransposeMap,WrappedMap}) - println(io, " of") + print(io, " of ") L = A.lmap if A isa MatrixMap # summary(io, L) @@ -68,11 +68,11 @@ function print_maps(io::IO, maps::Tuple{Vararg{LinearMap}}) for i in s # print(io, ' ') show(io, maps[i]) + println(io, "") end - println(io, "⋮") + print(io, "⋮") for i in e println(io, "") - # print(io, ' ') show(io, maps[i]) end else From c1355eec3e4ea1ce2cbed32d0005a250c4e818a5 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Wed, 7 Oct 2020 15:41:41 +0200 Subject: [PATCH 10/10] add docs --- docs/src/types.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/src/types.md b/docs/src/types.md index a5ab814c..81be9cc2 100644 --- a/docs/src/types.md +++ b/docs/src/types.md @@ -14,6 +14,12 @@ Abstract supertype LinearMaps.LinearMap ``` +Unwrapping function + +```@docs +Base.parent +``` + ### `FunctionMap` Type for wrapping an arbitrary function that is supposed to implement the