Skip to content

Commit

Permalink
Add tests, fix bugs.
Browse files Browse the repository at this point in the history
  • Loading branch information
tkoolen committed Jan 17, 2018
1 parent abf067c commit c071796
Show file tree
Hide file tree
Showing 3 changed files with 277 additions and 22 deletions.
44 changes: 22 additions & 22 deletions src/SSymmetricCompact.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ end
end
quote
@_inline_meta
@inbounds return SSymmetricCompact{N, T, L}(SVector{L, T}($(expr...)))
@inbounds return SSymmetricCompact{N, T, L}(SVector{L, T}(tuple($(expr...))))
end
end

Expand All @@ -51,24 +51,12 @@ end
@inline SSymmetricCompact(a::StaticMatrix{N, N, T}) where {N, T} = SSymmetricCompact{N, T}(a)

@inline (::Type{SSC})(a::SSymmetricCompact) where {SSC <: SSymmetricCompact} = SSC(a.lowertriangle)
@inline (::Type{SSC})(a::SSC) where {SSC <: SSymmetricCompact} = SSC(a.lowertriangle)
@inline (::Type{SSC})(a::SSC) where {SSC <: SSymmetricCompact} = a

@inline (::Type{SSC})(a::AbstractVector) where {SSC <: SSymmetricCompact} = SSC(convert(lowertriangletype(SSC), a))
@inline (::Type{SSC})(a::Tuple) where {SSC <: SSymmetricCompact} = SSymmetricCompact(convert(lowertriangletype(SSC), a))

convert(::Type{SSC}, a::SSC) where {SSC <: SSymmetricCompact} = a # TODO: needed?
# TODO: more convert methods?

# TODO: is the following a good idea?
@inline function similar_type(::Type{SSC}, ::Type{T}, ::Size{S}) where {SSC <: SSymmetricCompact, T, S <: Tuple{Int, Int}}
if S[1] === S[2]
N = S[1]
L = triangularnumber(N)
SSymmetricCompact{N, T, L}
else
default_similar_type(T, S, length_val(S))
end
end
# TODO: similar_type overload?

@inline indextuple(::T) where {T <: SSymmetricCompact} = indextuple(T)
@generated function indextuple(::Type{<:SSymmetricCompact{N}}) where N
Expand Down Expand Up @@ -117,7 +105,7 @@ LinAlg.ishermitian(a::SSymmetricCompact{N, T}) where {N,T <: Real} = true
LinAlg.ishermitian(a::SSymmetricCompact) = all(isreal, a.lowertriangle)
LinAlg.issymmetric(a::SSymmetricCompact) = true

# TODO: factorize
# TODO: factorize?

# TODO: a.lowertriangle == b.lowertriangle is slow (used by SDiagonal). SMatrix etc. actually use AbstractArray fallback (also slow)
@inline ==(a::SSymmetricCompact, b::SSymmetricCompact) = mapreduce(==, (x, y) -> x && y, a.lowertriangle, b.lowertriangle)
Expand All @@ -126,7 +114,7 @@ LinAlg.issymmetric(a::SSymmetricCompact) = true
L = triangularnumber(N)
exprs = Vector{Expr}(L)
for i 1:L
tmp = [:(a[$j][$i]) for j 1:length(a)]
tmp = [:(a[$j].lowertriangle[$i]) for j 1:length(a)]
exprs[i] = :(f($(tmp...)))
end
return quote
Expand All @@ -148,13 +136,25 @@ end
@inline /(a::SSymmetricCompact, b::Number) = SSymmetricCompact(a.lowertriangle / b)
@inline \(a::Number, b::SSymmetricCompact) = SSymmetricCompact(a \ b.lowertriangle)

# TODO: operations With UniformScaling
@generated function _plus_uniform(::Size{S}, a::SSymmetricCompact{N, T, L}, λ) where {S, N, T, L}
@assert S[1] == N
@assert S[2] == N
exprs = Vector{Expr}(L)
i = 0
for col = 1 : N, row = col : N
i += 1
exprs[i] = row == col ? :(a.lowertriangle[$i] + λ) : :(a.lowertriangle[$i])
end
return quote
@_inline_meta
T = promote_type(eltype(a), typeof(λ))
SSymmetricCompact{N, T, L}(SVector{L, T}(tuple($(exprs...))))
end
end

@inline transpose(a::SSymmetricCompact) = SSymmetricCompact(transpose.(a.lowertriangle))
@inline transpose(a::SSymmetricCompact) = SSymmetricCompact((a.lowertriangle))
@inline adjoint(a::SSymmetricCompact) = conj(a)

#TODO: one, eye

@generated function _one(::Size{S}, ::Type{SSC}) where {S, SSC <: SSymmetricCompact}
N = S[1]
L = triangularnumber(N)
Expand All @@ -173,7 +173,7 @@ end
end
end

@inline _eye(s::Size{S}, t::Type{SSC}) where {S, SM <: SSymmetricCompact} = _one(s, t)
@inline _eye(s::Size{S}, t::Type{SSC}) where {S, SSC <: SSymmetricCompact} = _one(s, t)

# _fill covers fill, zeros, and ones:
@generated function _fill(val, ::Size{s}, ::Type{SSC}) where {s, SSC <: SSymmetricCompact}
Expand Down
254 changes: 254 additions & 0 deletions test/SSymmetricCompact.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
module SSymmetricCompactTest

using Compat
using StaticArrays
using Base.Test

macro test_noalloc(ex)
esc(quote
$ex
@test(@allocated($ex) == 0)
end)
end

function check_lower_triangle(a::SSymmetricCompact, triangle::SVector)
N = size(a, 1)
i = 0
for col = 1 : N, row = 1 : N
if row >= col
i += 1
@test a[row, col] == triangle[i]
else
@test a[row, col] == a[col, row]
end
end
end

function check_lower_triangle(a::SSymmetricCompact{3}, triangle::SVector)
# because the generic check_lower_triangle uses almost the same code as what's being tested
@test a[1, 1] == triangle[1]
@test a[2, 1] == triangle[2]
@test a[3, 1] == triangle[3]
@test a[1, 2] == a[2, 1]
@test a[2, 2] == triangle[4]
@test a[3, 2] == triangle[5]
@test a[1, 3] == a[3, 1]
@test a[2, 3] == a[3, 2]
@test a[3, 3] == triangle[6]
end

fill3(x) = fill(3, x)

@testset "SSymmetricCompact" begin
@testset "Inner Constructor" begin
for (N, L) in ((3, 6), (4, 10), (6, 21))
for T in (Int32, Int64)
@eval begin
let lowertriangle = rand(SVector{$L, Int32})
a = SSymmetricCompact{$N, $T, $L}(lowertriangle)
check_lower_triangle(a, lowertriangle)
@test a isa SSymmetricCompact{$N, $T, $L}
@test(@allocated(SSymmetricCompact{$N, $T, $L}(lowertriangle)) == 0)
end
end
end
end
@test_throws ArgumentError SSymmetricCompact{3, Int64, 7}(rand(SVector{7, Int32}))
end

@testset "Outer Constructors" begin
for (N, L) in ((3, 6), (4, 10), (6, 21))
for T in (Int32, Int64)
@eval begin
let lowertriangle = rand(SVector{$L, Int32})
a1 = SSymmetricCompact{$N, $T}(lowertriangle)
check_lower_triangle(a1, $T.(lowertriangle))
@test a1 isa SSymmetricCompact{$N, $T, $L}
@test_noalloc SSymmetricCompact{$N, $T}(lowertriangle)

a2 = SSymmetricCompact{$N}(lowertriangle)
check_lower_triangle(a2, lowertriangle)
@test a2 isa SSymmetricCompact{$N, Int32, $L}
@test_noalloc SSymmetricCompact{$N}(lowertriangle)

a3 = SSymmetricCompact(lowertriangle)
check_lower_triangle(a3, lowertriangle)
@test a3 isa SSymmetricCompact{$N, Int32, $L}
@test_noalloc SSymmetricCompact(lowertriangle)

a4 = SSymmetricCompact{$N, $T}(a3)
@test a4 === a1
@test_noalloc SSymmetricCompact{$N, $T}(a3)
end
let a = rand(SMatrix{$N, $N, Int32})
@test SSymmetricCompact{$N, $T, $L}(a) isa SSymmetricCompact{$N, $T, $L}
@test_noalloc SSymmetricCompact{$N, $T, $L}(a)
@test SSymmetricCompact{$N, $T, $L}(a) == Symmetric($T.(a), :L)

@test SSymmetricCompact{$N, $T}(a) isa SSymmetricCompact{$N, $T, $L}
@test_noalloc SSymmetricCompact{$N, $T}(a)
@test SSymmetricCompact{$N, $T}(a) == Symmetric($T.(a), :L)

@test SSymmetricCompact{$N}(a) isa SSymmetricCompact{$N, Int32, $L}
@test_noalloc SSymmetricCompact{$N}(a)
@test SSymmetricCompact{$N}(a) == Symmetric(a, :L)

@test SSymmetricCompact(a) isa SSymmetricCompact{$N, Int32, $L}
@test_noalloc SSymmetricCompact(a)
@test SSymmetricCompact(a) == Symmetric(a, :L)
end
end
end
end
end

@testset "convert" begin
a = SSymmetricCompact(SMatrix{3, 3}(1 : 9))
@test convert(typeof(a), a) === a
@test convert(SSymmetricCompact{3, Float64}, a) isa SSymmetricCompact{3, Float64, 6}
@test convert(SSymmetricCompact{3, Float64}, a) == Float64.(Array(a))
@test convert(SSymmetricCompact{3, Float64, 6}, a) isa SSymmetricCompact{3, Float64, 6}
end

@testset "setindex" begin
for (N, L) in ((3, 6), (4, 10), (6, 21))
@eval begin
let lowertriangle = zero(SVector{$L, Int32})
a = SSymmetricCompact(lowertriangle)
@test_noalloc setindex(a, 2., 1, 1)
for col = 1 : $N, row = 1 : $N
x = Float64(rand(Int32))
a2 = setindex(a, x, row, col)
@test a2[row, col] === Int32(x)
@test setindex(a2, 0, row, col) === a
end
end
end
end
end

@testset "ishermitian / issymmetric" begin
a = rand(SSymmetricCompact{5, Float64})
@test ishermitian(a)
@test issymmetric(a)

b = rand(SSymmetricCompact{5, Complex128})
@test !ishermitian(b)
@test issymmetric(b)

c = b + conj(b)
@test ishermitian(c)
@test issymmetric(c)
@test_noalloc ishermitian(c)
end

@testset "==" begin
a = SSymmetricCompact(SVector{6}(-5 : 0))
b = setindex(a, 5, 3)
@test a == a
@test !(a == b)
@test_noalloc a == a
end

@testset "Arithmetic" begin
a = SSymmetricCompact(SVector{6, Int}(1 : 6))
b = SSymmetricCompact(SVector(-4, 5, 4, 8, -10, 11))
c = SMatrix{3, 3}(-9 : -1)

let a = a
@test -a == -SMatrix(a)
@test -a isa SSymmetricCompact{3, Int, 6}
@test_noalloc -a
end
for (x, y) in ((a, b), (a, c), (c, a))
@eval begin
let x = $x, y = $y
@test x + y == SMatrix(x) + SMatrix(y)
@test_noalloc x + y

@test x - y == SMatrix(x) - SMatrix(y)
@test_noalloc x - y

if x isa SSymmetricCompact && y isa SSymmetricCompact
@test x + y isa SSymmetricCompact{3, Int, 6}
@test x - y isa SSymmetricCompact{3, Int, 6}
end
end
end
end
end

@testset "Scalar-array" begin
x = SSymmetricCompact(SVector{6, Int}(1 : 6))
y = -5
for op in (:-, :+, :*, :/, :\)
if op != :\
@eval begin
@test $op($x, $y) == $op(SMatrix($x), $y)
@test_noalloc $op($x, $y)
end
end

if op != :/
@eval begin
@test $op($y, $x) == $op($y, SMatrix($x))
@test_noalloc $op($y, $x)
end
end
end
end

@testset "UniformScaling" begin
let a = SSymmetricCompact(SVector{21, Int}(1 : 21))
@test a + 3I == SMatrix(a) + 3I
@test a + 3I isa typeof(a)
@test_noalloc a + 3I

@test a - 4I == SMatrix(a) - 4I
@test a - 4I isa typeof(a)
@test_noalloc a - 4I

@test a * 3I === a * 3
@test 3I * a === 3 * a
@test 3I \ a == 3 \ a
@test a / 3I == a / 3
end
end

@testset "transpose/adjoint" begin
a = Symmetric([[rand(Complex{Int}) for i = 1 : 2] for row = 1 : 3, col = 1 : 3])
@test transpose(SSymmetricCompact{3}(a)) == transpose(a)
# @test adjoint(SSymmetricCompact{3}(a)) == adjoint(a) # doesn't even work for a...

b = Symmetric([rand(Complex{Int}) for i = 1 : 3, j = 1 : 3])
@test adjoint(SSymmetricCompact{3}(b)) == adjoint(b)
end

@testset "one/eye/ones/zeros/fill" begin
for N = 3 : 5, f in (:one, :eye, :ones, :zeros, :fill3)
@eval begin
@test $f(SSymmetricCompact{$N, Int}) == $f(SMatrix{$N, $N, Int})
@test $f(SSymmetricCompact{$N, Int}) isa SSymmetricCompact{$N, Int}
@test_noalloc $f(SSymmetricCompact{$N, Int})

@test $f(SSymmetricCompact{$N}) == $f(SMatrix{$N, $N})
@test $f(SSymmetricCompact{$N}) isa SSymmetricCompact{$N, eltype($f(SMatrix{$N, $N}))}
@test_noalloc $f(SSymmetricCompact{$N})
end
end
end

@testset "rand" begin
for N = 3 : 5, f in (:rand, :randn, :randexp)
@eval begin
@test_noalloc $f(SSymmetricCompact{$N, Float32})
@test $f(SSymmetricCompact{$N, Float32}) isa SSymmetricCompact{$N, Float32}

@test_noalloc $f(SSymmetricCompact{$N})
@test $f(SSymmetricCompact{$N}) isa SSymmetricCompact{$N, Float64}
end
end
end
end

end # module
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ include("Scalar.jl")
include("SUnitRange.jl")
include("SizedArray.jl")
include("SDiagonal.jl")
include("SSymmetricCompact.jl")

include("custom_types.jl")
include("core.jl")
Expand Down

0 comments on commit c071796

Please sign in to comment.