Skip to content

Commit c435822

Browse files
authored
refactor tests (#67)
1 parent 03960a9 commit c435822

File tree

10 files changed

+624
-588
lines changed

10 files changed

+624
-588
lines changed

test/blockmap.jl

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
using Test, LinearMaps, LinearAlgebra
2+
3+
@testset "block maps" begin
4+
@testset "hcat" begin
5+
for elty in (Float32, Float64, ComplexF64)
6+
A11 = rand(elty, 10, 10)
7+
A12 = rand(elty, 10, 20)
8+
L = @inferred hcat(LinearMap(A11), LinearMap(A12))
9+
@test L isa LinearMaps.BlockMap{elty}
10+
A = [A11 A12]
11+
x = rand(30)
12+
@test size(L) == size(A)
13+
@test Matrix(L) A
14+
@test L * x A * x
15+
L = @inferred hcat(LinearMap(A11), LinearMap(A12), LinearMap(A11))
16+
A = [A11 A12 A11]
17+
@test Matrix(L) A
18+
A = [I I I A11 A11 A11]
19+
L = @inferred hcat(I, I, I, LinearMap(A11), LinearMap(A11), LinearMap(A11))
20+
@test L == [I I I LinearMap(A11) LinearMap(A11) LinearMap(A11)]
21+
x = rand(elty, 60)
22+
@test L isa LinearMaps.BlockMap{elty}
23+
@test L * x A * x
24+
A11 = rand(elty, 11, 10)
25+
A12 = rand(elty, 10, 20)
26+
@test_throws DimensionMismatch hcat(LinearMap(A11), LinearMap(A12))
27+
end
28+
end
29+
30+
@testset "vcat" begin
31+
for elty in (Float32, Float64, ComplexF64)
32+
A11 = rand(elty, 10, 10)
33+
L = @inferred vcat(LinearMap(A11))
34+
@test L == [LinearMap(A11);]
35+
@test Matrix(L) A11
36+
A21 = rand(elty, 20, 10)
37+
L = @inferred vcat(LinearMap(A11), LinearMap(A21))
38+
@test L isa LinearMaps.BlockMap{elty}
39+
A = [A11; A21]
40+
x = rand(10)
41+
@test size(L) == size(A)
42+
@test Matrix(L) A
43+
@test L * x A * x
44+
A = [I; I; I; A11; A11; A11]
45+
L = @inferred vcat(I, I, I, LinearMap(A11), LinearMap(A11), LinearMap(A11))
46+
@test L == [I; I; I; LinearMap(A11); LinearMap(A11); LinearMap(A11)]
47+
x = rand(elty, 10)
48+
@test L isa LinearMaps.BlockMap{elty}
49+
@test L * x A * x
50+
A11 = rand(elty, 10, 11)
51+
A21 = rand(elty, 20, 10)
52+
@test_throws DimensionMismatch vcat(LinearMap(A11), LinearMap(A21))
53+
end
54+
end
55+
56+
@testset "hvcat" begin
57+
for elty in (Float32, Float64, ComplexF64)
58+
A11 = rand(elty, 10, 10)
59+
A12 = rand(elty, 10, 20)
60+
A21 = rand(elty, 20, 10)
61+
A22 = rand(elty, 20, 20)
62+
A = [A11 A12; A21 A22]
63+
@inferred hvcat((2,2), LinearMap(A11), LinearMap(A12), LinearMap(A21), LinearMap(A22))
64+
L = [LinearMap(A11) LinearMap(A12); LinearMap(A21) LinearMap(A22)]
65+
@test @inferred !issymmetric(L)
66+
@test @inferred !ishermitian(L)
67+
x = rand(30)
68+
@test L isa LinearMaps.BlockMap{elty}
69+
@test size(L) == size(A)
70+
@test L * x A * x
71+
@test Matrix(L) A
72+
A = [I A12; A21 I]
73+
@inferred hvcat((2,2), I, LinearMap(A12), LinearMap(A21), I)
74+
L = @inferred hvcat((2,2), I, LinearMap(A12), LinearMap(A21), I)
75+
@test L isa LinearMaps.BlockMap{elty}
76+
@test size(L) == (30, 30)
77+
@test Matrix(L) A
78+
@test L * x A * x
79+
A = rand(elty, 10,10); LA = LinearMap(A)
80+
B = rand(elty, 20,30); LB = LinearMap(B)
81+
@test [LA LA LA; LB] isa LinearMaps.BlockMap{elty}
82+
@test Matrix([LA LA LA; LB]) [A A A; B]
83+
@test [LB; LA LA LA] isa LinearMaps.BlockMap{elty}
84+
@test Matrix([LB; LA LA LA]) [B; A A A]
85+
@test [I; LA LA LA] isa LinearMaps.BlockMap{elty}
86+
@test Matrix([I; LA LA LA]) [I; A A A]
87+
A12 = LinearMap(rand(elty, 10, 21))
88+
A21 = LinearMap(rand(elty, 20, 10))
89+
@test_throws DimensionMismatch A = [I A12; A21 I]
90+
@test_throws DimensionMismatch A = [I A21; A12 I]
91+
@test_throws DimensionMismatch A = [A12 A12; A21 A21]
92+
@test_throws DimensionMismatch A = [A12 A21; A12 A21]
93+
94+
# basic test of "misaligned" blocks
95+
M = ones(elty, 3, 2) # non-square
96+
A = LinearMap(M)
97+
B = [I A; A I]
98+
C = [I M; M I]
99+
@test B isa LinearMaps.BlockMap{elty}
100+
@test Matrix(B) == C
101+
@test Matrix(transpose(B)) == transpose(C)
102+
@test Matrix(adjoint(B)) == C'
103+
end
104+
end
105+
106+
@testset "adjoint/transpose" begin
107+
for elty in (Float32, Float64, ComplexF64), transform in (transpose, adjoint)
108+
A12 = rand(elty, 10, 10)
109+
A = [I A12; transform(A12) I]
110+
L = [I LinearMap(A12); transform(LinearMap(A12)) I]
111+
if elty <: Complex
112+
if transform == transpose
113+
@test @inferred issymmetric(L)
114+
else
115+
@test @inferred ishermitian(L)
116+
end
117+
end
118+
if elty <: Real
119+
@test @inferred ishermitian(L)
120+
@test @inferred issymmetric(L)
121+
end
122+
x = rand(elty, 20)
123+
@test L isa LinearMaps.LinearMap{elty}
124+
@test size(L) == size(A)
125+
@test L * x A * x
126+
@test Matrix(L) A
127+
Lt = @inferred transform(L)
128+
@test Lt isa LinearMaps.LinearMap{elty}
129+
@test Lt * x transform(A) * x
130+
Lt = @inferred transform(LinearMap(L))
131+
@test Lt * x transform(A) * x
132+
@test Matrix(Lt) Matrix(transform(A))
133+
A21 = rand(elty, 10, 10)
134+
A = [I A12; A21 I]
135+
L = [I LinearMap(A12); LinearMap(A21) I]
136+
Lt = @inferred transform(L)
137+
@test Lt isa LinearMaps.LinearMap{elty}
138+
@test Lt * x transform(A) * x
139+
@test Matrix(Lt) Matrix(transform(A))
140+
end
141+
end
142+
end

test/composition.jl

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
using Test, LinearMaps, LinearAlgebra
2+
3+
# new type
4+
struct SimpleFunctionMap <: LinearMap{Float64}
5+
f::Function
6+
N::Int
7+
end
8+
struct SimpleComplexFunctionMap <: LinearMap{Complex{Float64}}
9+
f::Function
10+
N::Int
11+
end
12+
Base.size(A::Union{SimpleFunctionMap,SimpleComplexFunctionMap}) = (A.N, A.N)
13+
Base.:(*)(A::Union{SimpleFunctionMap,SimpleComplexFunctionMap}, v::Vector) = A.f(v)
14+
LinearAlgebra.mul!(y::Vector, A::Union{SimpleFunctionMap,SimpleComplexFunctionMap}, x::Vector) = copyto!(y, *(A, x))
15+
16+
@testset "composition" begin
17+
F = @inferred LinearMap(cumsum, y -> reverse(cumsum(reverse(x))), 10; ismutating=false)
18+
A = 2 * rand(ComplexF64, (10, 10)) .- 1
19+
B = rand(size(A)...)
20+
M = @inferred 1 * LinearMap(A)
21+
N = @inferred LinearMap(B)
22+
v = rand(ComplexF64, 10)
23+
@test @inferred (F * F) * v == @inferred F * (F * v)
24+
@test @inferred (F * A) * v == @inferred F * (A * v)
25+
@test @inferred (A * F) * v == @inferred A * (F * v)
26+
@test @inferred A * (F * F) * v == @inferred A * (F * (F * v))
27+
@test @inferred (F * F) * (F * F) * v == @inferred F * (F * (F * (F * v)))
28+
@test @inferred Matrix(M * transpose(M)) A * transpose(A)
29+
@test @inferred !isposdef(M * transpose(M))
30+
@test @inferred isposdef(M * M')
31+
@test @inferred issymmetric(N * N')
32+
@test @inferred ishermitian(N * N')
33+
@test @inferred !issymmetric(M' * M)
34+
@test @inferred ishermitian(M' * M)
35+
@test @inferred isposdef(transpose(F) * F * 3)
36+
@test @inferred isposdef(transpose(F) * 3 * F)
37+
@test @inferred !isposdef(-5*transpose(F) * F)
38+
@test @inferred isposdef((M * F)' * M * 4 * F)
39+
@test @inferred transpose(M * F) == @inferred transpose(F) * transpose(M)
40+
@test @inferred (4*((-3*M)*2)) == @inferred -12M*2
41+
@test @inferred (4*((3*(-M))*2)*(-5)) == @inferred -12M*(-10)
42+
L = @inferred 3 * F + 1im * A + F * M' * F
43+
LF = 3 * Matrix(F) + 1im * A + Matrix(F) * Matrix(M)' * Matrix(F)
44+
@test Array(L) LF
45+
R1 = rand(ComplexF64, 10, 10); L1 = LinearMap(R1)
46+
R2 = rand(ComplexF64, 10, 10); L2 = LinearMap(R2)
47+
R3 = rand(ComplexF64, 10, 10); L3 = LinearMap(R3)
48+
CompositeR = prod(R -> LinearMap(R), [R1, R2, R3])
49+
@test @inferred L1 * L2 * L3 == CompositeR
50+
@test @inferred transpose(CompositeR) == transpose(L3) * transpose(L2) * transpose(L1)
51+
@test @inferred adjoint(CompositeR) == L3' * L2' * L1'
52+
@test @inferred adjoint(adjoint((CompositeR))) == CompositeR
53+
@test transpose(transpose((CompositeR))) == CompositeR
54+
Lt = @inferred transpose(LinearMap(CompositeR))
55+
@test Lt * v transpose(R3) * transpose(R2) * transpose(R1) * v
56+
Lc = @inferred adjoint(LinearMap(CompositeR))
57+
@test Lc * v R3' * R2' * R1' * v
58+
59+
# test inplace operations
60+
w = similar(v)
61+
mul!(w, L, v)
62+
@test w LF * v
63+
64+
# test new type
65+
F = SimpleFunctionMap(cumsum, 10)
66+
FC = SimpleComplexFunctionMap(cumsum, 10)
67+
@test @inferred ndims(F) == 2
68+
@test @inferred size(F, 1) == 10
69+
@test @inferred length(F) == 100
70+
@test @inferred !issymmetric(F)
71+
@test @inferred !ishermitian(F)
72+
@test @inferred !ishermitian(FC)
73+
@test @inferred !isposdef(F)
74+
w = similar(v)
75+
mul!(w, F, v)
76+
@test w == F * v
77+
@test_throws MethodError F' * v
78+
@test_throws MethodError transpose(F) * v
79+
@test_throws MethodError mul!(w, adjoint(F), v)
80+
@test_throws MethodError mul!(w, transpose(F), v)
81+
82+
# test composition of several maps with shared data #31
83+
global sizes = ( (5, 2), (3, 3), (3, 2), (2, 2), (9, 2), (7, 1) )
84+
N = length(sizes) - 1
85+
global Lf = []
86+
global Lt = []
87+
global Lc = []
88+
89+
# build list of operators [LN, ..., L2, L1] for each mode
90+
for (fi, i) in [ (Symbol("f$i"), i) for i in 1:N]
91+
@eval begin
92+
function ($fi)(source)
93+
dest = ones(prod(sizes[$i + 1]))
94+
tmp = reshape(source, sizes[$i])
95+
return conj.($i * dest)
96+
end
97+
insert!(Lf, 1, LinearMap($fi, prod(sizes[$i + 1]), prod(sizes[$i])))
98+
insert!(Lt, 1, LinearMap(x -> x, $fi, prod(sizes[$i]), prod(sizes[$i + 1])))
99+
insert!(Lc, 1, LinearMap{ComplexF64}(x -> x, $fi, prod(sizes[$i]), prod(sizes[$i + 1])))
100+
end
101+
end
102+
@test size(prod(Lf[1:N])) == (prod(sizes[end]), prod(sizes[1]))
103+
@test isreal(prod(Lf[1:N]))
104+
# multiply as composition and as recursion
105+
v1 = ones(prod(sizes[1]))
106+
u1 = ones(prod(sizes[1]))
107+
w1 = im.*ones(ComplexF64, prod(sizes[1]))
108+
for i = N:-1:1
109+
v2 = prod(Lf[i:N]) * ones(prod(sizes[1]))
110+
u2 = transpose(LinearMap(prod(Lt[N:-1:i]))) * ones(prod(sizes[1]))
111+
w2 = adjoint(LinearMap(prod(Lc[N:-1:i]))) * ones(prod(sizes[1]))
112+
113+
v1 = Lf[i] * v1
114+
u1 = transpose(Lt[i]) * u1
115+
w1 = adjoint(Lc[i]) * w1
116+
117+
@test v1 == v2
118+
@test u1 == u2
119+
@test w1 == w2
120+
end
121+
end

test/functionmap.jl

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using Test, LinearMaps, LinearAlgebra
2+
3+
@testset "function maps" begin
4+
N = 100
5+
function myft(v::AbstractVector)
6+
# not so fast fourier transform
7+
N = length(v)
8+
w = zeros(complex(eltype(v)), N)
9+
for k = 1:N
10+
kappa = (2*(k-1)/N)*pi
11+
for n = 1:N
12+
w[k] += v[n]*exp(kappa*(n-1)*im)
13+
end
14+
end
15+
return w
16+
end
17+
MyFT = @inferred LinearMap{ComplexF64}(myft, N) / sqrt(N)
18+
U = Matrix(MyFT) # will be a unitary matrix
19+
@test @inferred U'U Matrix{eltype(U)}(I, N, N)
20+
21+
CS = @inferred LinearMap(cumsum, 2)
22+
@test size(CS) == (2, 2)
23+
@test @inferred !issymmetric(CS)
24+
@test @inferred !ishermitian(CS)
25+
@test @inferred !isposdef(CS)
26+
@test @inferred !(LinearMaps.ismutating(CS))
27+
@test @inferred Matrix(CS) == [1. 0.; 1. 1.]
28+
@test @inferred Array(CS) == [1. 0.; 1. 1.]
29+
CS = @inferred LinearMap(cumsum, 10; ismutating=false)
30+
v = rand(10)
31+
cv = cumsum(v)
32+
@test CS * v == cv
33+
@test *(CS, v) == cv
34+
@test_throws ErrorException CS' * v
35+
CS = @inferred LinearMap(cumsum, x -> reverse(cumsum(reverse(x))), 10; ismutating=false)
36+
cv = cumsum(v)
37+
@test @inferred CS * v == cv
38+
@test @inferred *(CS, v) == cv
39+
@test @inferred CS' * v == reverse!(cumsum(reverse(v)))
40+
@test @inferred mul!(similar(v), transpose(CS), v) == reverse!(cumsum(reverse(v)))
41+
42+
CS! = @inferred LinearMap(cumsum!, 10; ismutating=true)
43+
@test @inferred LinearMaps.ismutating(CS!)
44+
@test @inferred CS! * v == cv
45+
@test @inferred *(CS!, v) == cv
46+
@test @inferred mul!(similar(v), CS!, v) == cv
47+
@test_throws ErrorException CS!'v
48+
@test_throws ErrorException transpose(CS!) * v
49+
50+
CS! = @inferred LinearMap{ComplexF64}(cumsum!, 10; ismutating=true)
51+
v = rand(ComplexF64, 10)
52+
cv = cumsum(v)
53+
@test @inferred LinearMaps.ismutating(CS!)
54+
@test @inferred CS! * v == cv
55+
@test @inferred *(CS!, v) == cv
56+
@test @inferred mul!(similar(v), CS!, v) == cv
57+
@test_throws ErrorException CS!'v
58+
@test_throws ErrorException adjoint(CS!) * v
59+
CS! = LinearMap{ComplexF64}(cumsum!, (y, x) -> (copyto!(y, x); reverse!(y); cumsum!(y, y)), 10; ismutating=true)
60+
@test @inferred LinearMaps.ismutating(CS!)
61+
@test @inferred CS! * v == cv
62+
@test @inferred *(CS!, v) == cv
63+
@test @inferred mul!(similar(v), CS!, v) == cv
64+
@test @inferred CS' * v == reverse!(cumsum(reverse(v)))
65+
@test @inferred mul!(similar(v), transpose(CS), v) == reverse!(cumsum(reverse(v)))
66+
@test @inferred mul!(similar(v), adjoint(CS), v) == reverse!(cumsum(reverse(v)))
67+
68+
# Test fallback methods:
69+
L = @inferred LinearMap(x -> x, x -> x, 10)
70+
v = randn(10)
71+
@test @inferred (2 * L)' * v 2 * v
72+
@test @inferred transpose(2 * L) * v 2 * v
73+
L = @inferred LinearMap{ComplexF64}(x -> x, x -> x, 10)
74+
v = rand(ComplexF64, 10)
75+
@test @inferred (2 * L)' * v 2 * v
76+
@test @inferred transpose(2 * L) * v 2 * v
77+
end

test/linearcombination.jl

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using Test, LinearMaps, LinearAlgebra, BenchmarkTools
2+
3+
@testset "linear combinations" begin
4+
CS! = LinearMap{ComplexF64}(cumsum!,
5+
(y, x) -> (copyto!(y, x); reverse!(y); cumsum!(y, y)), 10;
6+
ismutating=true)
7+
v = rand(10)
8+
u = similar(v)
9+
b = @benchmarkable mul!($u, $CS!, $v)
10+
@test run(b, samples=3).allocs == 0
11+
n = 10
12+
L = sum(fill(CS!, n))
13+
@test mul!(u, L, v) n * cumsum(v)
14+
b = @benchmarkable mul!($u, $L, $v)
15+
@test run(b, samples=5).allocs <= 1
16+
17+
A = 2 * rand(ComplexF64, (10, 10)) .- 1
18+
B = rand(size(A)...)
19+
M = @inferred LinearMap(A)
20+
N = @inferred LinearMap(B)
21+
LC = @inferred M + N
22+
v = rand(ComplexF64, 10)
23+
w = similar(v)
24+
b = @benchmarkable mul!($w, $M, $v)
25+
@test run(b, samples=3).allocs == 0
26+
# @test_throws ErrorException LinearMaps.LinearCombination{ComplexF64}((M, N), (1, 2, 3))
27+
@test @inferred size(3M + 2.0N) == size(A)
28+
# addition
29+
@test @inferred convert(Matrix, LC) == A + B
30+
@test @inferred convert(Matrix, LC + LC) 2A + 2B
31+
@test @inferred convert(Matrix, M + LC) 2A + B
32+
@test @inferred convert(Matrix, M + M) 2A
33+
# subtraction
34+
@test @inferred Matrix(LC - LC) == zeros(size(LC))
35+
@test @inferred Matrix(LC - M) == B
36+
@test @inferred Matrix(N - LC) == -A
37+
@test @inferred Matrix(M - M) == zeros(size(M))
38+
# scalar multiplication
39+
@test @inferred Matrix(-M) == -A
40+
@test @inferred Matrix(-LC) == -A - B
41+
@test @inferred Matrix(3 * M) == 3 * A
42+
@test @inferred Matrix(M * 3) == 3 * A
43+
@test Matrix(3.0 * LC) Matrix(LC * 3) == 3A + 3B
44+
@test @inferred Matrix(3 \ M) A/3
45+
@test @inferred Matrix(M / 3) A/3
46+
@test @inferred Matrix(3 \ LC) (A + B) / 3
47+
@test @inferred Matrix(LC / 3) (A + B) / 3
48+
@test @inferred Array(3 * M' - CS!) == 3 * A' - Array(CS!)
49+
@test (3M - 1im*CS!)' == (3M + ((-1im)*CS!))' == M'*3 + CS!'*1im
50+
@test @inferred Array(M + A) == 2 * A
51+
@test @inferred Array(A + M) == 2 * A
52+
@test @inferred Array(M - A) == 0 * A
53+
@test Array(A - M) == 0 * A
54+
end

0 commit comments

Comments
 (0)