Skip to content

Commit 3d8c9be

Browse files
author
Andy Ferris
committed
Tests for inv() and hacky workarounds for Unsigned
Partially address #29
1 parent 4da8330 commit 3d8c9be

File tree

4 files changed

+64
-43
lines changed

4 files changed

+64
-43
lines changed

src/inv.jl

Lines changed: 42 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,49 @@
1+
@inline inv(A::StaticMatrix) = _inv(Size(A), A)
12

2-
@generated function inv{T}(A::StaticMatrix{T})
3+
@inline _inv(::Size{(1,1)}, A) = similar_type(typeof(A), typeof(inv(one(eltype(A)))))(inv(A[1]))
4+
5+
@inline function _inv(::Size{(2,2)}, A)
6+
T = eltype(A)
7+
S = typeof((one(T)*zero(T) + zero(T))/one(T))
8+
newtype = similar_type(A, S)
9+
10+
d = det(A)
11+
@inbounds return newtype((A[4]/d, -(A[2]/d), -(A[3]/d), A[1]/d))
12+
end
13+
14+
@inline function _inv(::Size{(3,3)}, A)
15+
T = eltype(A)
316
S = typeof((one(T)*zero(T) + zero(T))/one(T))
417
newtype = similar_type(A, S)
518

6-
if size(A) == (1,1)
7-
return quote
8-
$(Expr(:meta, :inline))
9-
@inbounds return $newtype((inv(A[1]),))
10-
end
11-
elseif size(A) == (2,2)
12-
return quote
13-
$(Expr(:meta, :inline))
14-
d = A[1]*A[4] - A[3]*A[2]
15-
@inbounds return $newtype((A[4]/d, -A[2]/d, -A[3]/d, A[1]/d))
16-
end
17-
elseif size(A) == (3,3)
18-
return quote
19-
$(Expr(:meta, :inline))
20-
@inbounds x0 = SVector(A[1], A[2], A[3])
21-
@inbounds x1 = SVector(A[4], A[5], A[6])
22-
@inbounds x2 = SVector(A[7], A[8], A[9])
23-
24-
y0 = cross(x1,x2)
25-
d = vecdot(x0, y0)
26-
x0 = x0 / d
27-
y0 = y0 / d
28-
y1 = cross(x2,x0)
29-
y2 = cross(x0,x1)
30-
31-
@inbounds return $newtype((y0[1], y1[1], y2[1], y0[2], y1[2], y2[2], y0[3], y1[3], y2[3]))
32-
end
19+
@inbounds x0 = SVector(A[1], A[2], A[3])
20+
@inbounds x1 = SVector(A[4], A[5], A[6])
21+
@inbounds x2 = SVector(A[7], A[8], A[9])
22+
23+
y0 = cross(x1,x2)
24+
d = vecdot(x0, y0)
25+
x0 = x0 / d
26+
y0 = y0 / d
27+
y1 = cross(x2,x0)
28+
y2 = cross(x0,x1)
29+
30+
@inbounds return newtype((y0[1], y1[1], y2[1], y0[2], y1[2], y2[2], y0[3], y1[3], y2[3]))
31+
end
32+
33+
@inline function _inv(::Size, A)
34+
T = eltype(A)
35+
S = typeof((one(T)*zero(T) + zero(T))/one(T))
36+
AA = convert(Array{S}, A) # lufact() doesn't work with StaticArrays at the moment... and the branches below must be type-stable
37+
if istriu(A)
38+
Ai_ut = inv(UpperTriangular(AA))
39+
# TODO double check these routines leave the parent in a clean (upper triangular) state
40+
return Size(A)(parent(Ai_ut)) # Return a `SizedArray`
41+
elseif istril(A)
42+
Ai_lt = inv(LowerTriangular(AA))
43+
# TODO double check these routines leave the parent in a clean (lower triangular) state
44+
return Size(A)(parent(Ai_lt)) # Return a `SizedArray`
3345
else
34-
return quote # Implementation from Base
35-
AA = convert(Array{$S}, A) # lufact() doesn't work with StaticArrays at the moment... and the branches below must be type-stable
36-
if istriu(A)
37-
Ai = inv(UpperTriangular(AA))
38-
elseif istril(A)
39-
Ai = inv(LowerTriangular(AA))
40-
else
41-
Ai = inv(lufact(AA))
42-
end
43-
# Return a `SizedArray`
44-
return $(Size(A))(convert(typeof(parent(Ai)), Ai))
45-
end
46+
Ai_lu = inv(lufact(AA))
47+
return Size(A)(Ai_lu) # Return a `SizedArray`
4648
end
4749
end

src/linalg.jl

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,18 @@ end
282282
end
283283

284284
@generated function cross(a::StaticVector, b::StaticVector)
285+
S = typeof(zero(eltype(a))*zero(eltype(b)))
285286
if length(a) === 3 && length(b) === 3
286-
return quote
287-
$(Expr(:meta, :inline))
288-
similar_type(a, promote_type(eltype(a), eltype(b)))((a[2]*b[3]-a[3]*b[2], a[3]*b[1]-a[1]*b[3], a[1]*b[2]-a[2]*b[1]))
287+
if S <: Unsigned
288+
return quote
289+
$(Expr(:meta, :inline))
290+
similar_type(a, $(typeof(Signed(zero(eltype(a))*zero(eltype(b))))))((Signed(a[2]*b[3])-Signed(a[3]*b[2]), Signed(a[3]*b[1])-Signed(a[1]*b[3]), Signed(a[1]*b[2])-Signed(a[2]*b[1])))
291+
end
292+
else
293+
return quote
294+
$(Expr(:meta, :inline))
295+
similar_type(a, $S)((a[2]*b[3]-a[3]*b[2], a[3]*b[1]-a[1]*b[3], a[1]*b[2]-a[2]*b[1]))
296+
end
289297
end
290298
else
291299
error("Cross product only defined for 3-vectors")

test/inv.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@testset "Matrix inverse" begin
2+
@test inv(@SMatrix [2])::SMatrix @SMatrix [0.5]
3+
@test inv(@SMatrix [1 2; 2 1])::SMatrix [-1/3 2/3; 2/3 -1/3]
4+
@test inv(@SMatrix [1 2 0; 2 1 0; 0 0 1])::SMatrix [-1/3 2/3 0; 2/3 -1/3 0; 0 0 1]
5+
m = randn(Float64, 4,4) + eye(4) # well conditioned
6+
@test inv(SMatrix{4,4}(m))::StaticMatrix inv(m)
7+
8+
@test inv(@SMatrix [0x01 0x02; 0x02 0x01])::SMatrix [-1/3 2/3; 2/3 -1/3]
9+
@test inv(@SMatrix [0x01 0x02 0x00; 0x02 0x01 0x00; 0x00 0x00 0x01])::SMatrix [-1/3 2/3 0; 2/3 -1/3 0; 0 0 1]
10+
end

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ using Base.Test
1919
include("linalg.jl")
2020
include("matrix_multiply.jl")
2121
include("det.jl")
22+
include("inv.jl")
2223
include("solve.jl")
2324
include("eigen.jl")
2425
include("deque.jl")

0 commit comments

Comments
 (0)