Skip to content

Commit 870564a

Browse files
authored
Merge pull request #58 from JuliaArrays/traits
`Size` traits
2 parents a6f2983 + acfff71 commit 870564a

File tree

3 files changed

+80
-32
lines changed

3 files changed

+80
-32
lines changed

src/StaticArrays.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export Scalar, SArray, SVector, SMatrix
1313
export MArray, MVector, MMatrix
1414
export FieldVector, MutableFieldVector
1515

16+
export Size
17+
1618
export @SVector, @SMatrix, @SArray
1719
export @MVector, @MMatrix, @MArray
1820

@@ -21,6 +23,7 @@ export similar_type
2123
include("util.jl")
2224

2325
include("core.jl")
26+
include("traits.jl")
2427
include("Scalar.jl")
2528
include("SVector.jl")
2629
include("FieldVector.jl")
@@ -30,7 +33,6 @@ include("MVector.jl")
3033
include("MMatrix.jl")
3134
include("MArray.jl")
3235

33-
3436
include("indexing.jl")
3537
include("abstractarray.jl")
3638
include("mapreduce.jl")

src/det.jl

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,34 @@
1+
@inline det(A::StaticMatrix) = _det(Size(A), A)
12

2-
@generated function det{T}(A::StaticMatrix{T})
3-
if size(A) == (1,1)
4-
return quote
5-
$(Expr(:meta, :inline))
6-
@inbounds return A[1]
7-
end
8-
elseif size(A) == (2,2)
9-
return quote
10-
$(Expr(:meta, :inline))
11-
@inbounds return A[1]*A[4] - A[3]*A[2]
12-
end
13-
elseif size(A) == (3,3)
14-
return quote
15-
$(Expr(:meta, :inline))
16-
#@inbounds a = A[5]*A[9] - A[8]*A[6]
17-
#@inbounds b = A[8]*A[3] - A[2]*A[9]
18-
#@inbounds c = A[2]*A[6] - A[5]*A[3]
19-
#@inbounds return A[1]*a + A[4]*b + A[7]*c
3+
"""
4+
det(Size(m,m), mat)
205
21-
@inbounds x0 = SVector(A[1], A[2], A[3])
22-
@inbounds x1 = SVector(A[4], A[5], A[6])
23-
@inbounds x2 = SVector(A[7], A[8], A[9])
24-
return vecdot(x0, cross(x1, x2))
25-
end
26-
else
27-
S = typeof((one(T)*zero(T) + zero(T))/one(T))
28-
return quote # Implementation from Base
29-
if istriu(A) || istril(A)
30-
return convert($S, det(UpperTriangular(A)))::$S # Is this a Julia bug that a convert is not type stable??
31-
end
32-
AA = convert(Array{$S}, A)
33-
return det(lufact(AA))
6+
Calculate the matrix determinate using an algorithm specialized on the size of
7+
the `m`×`m` matrix `mat`, which is much faster for small matrices.
8+
"""
9+
@inline _det(::Size{(1,1)}, A::AbstractMatrix) = @inbounds return A[1]
10+
11+
@inline function _det(::Size{(2,2)}, A::AbstractMatrix)
12+
@inbounds return A[1]*A[4] - A[3]*A[2]
13+
end
14+
15+
@inline function _det(::Size{(3,3)}, A::AbstractMatrix)
16+
@inbounds x0 = SVector(A[1], A[2], A[3])
17+
@inbounds x1 = SVector(A[4], A[5], A[6])
18+
@inbounds x2 = SVector(A[7], A[8], A[9])
19+
return vecdot(x0, cross(x1, x2))
20+
end
21+
22+
@generated function _det{S,T}(::Size{S}, A::AbstractMatrix{T})
23+
if S[1] != S[2]
24+
throw(DimensionMismatch("matrix is not square"))
25+
end
26+
T2 = typeof((one(T)*zero(T) + zero(T))/one(T))
27+
return quote # Implementation from Base
28+
if istriu(A) || istril(A)
29+
return convert($T2, det(UpperTriangular(A)))::$T2 # Is this a Julia bug that a convert is not type stable??
3430
end
31+
AA = convert(Array{$T2}, A)
32+
return det(lufact(AA))
3533
end
3634
end

src/traits.jl

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
"""
2+
Size(static_array)
3+
Size(StaticArrayType)
4+
Size(dims...)
5+
6+
A trait type allowing convenient trait-based dispatch on the size of a statically
7+
sized array. The dimensions are stored as a type parameter and are statically
8+
propagated by the compiler.
9+
10+
For example,
11+
```
12+
det(x::StaticMatrix) = _det(Size(x), x)
13+
_det(::Size{(1,1)}, x::StaticMatrix) = x[1,1]
14+
_det(::Size{(2,2)}, x::StaticMatrix) = x[1,1]*x[2,2] - x[1,2]*x[2,1]
15+
# and other definitions as necessary
16+
```
17+
"""
18+
immutable Size{S}
19+
function Size()
20+
check_size(S)
21+
new()
22+
end
23+
end
24+
25+
@pure check_size(S::Tuple{Vararg{Int}}) = nothing
26+
check_size(S) = error("Size was expected to be a tuple of `Int`s")
27+
28+
@pure Size{SA<:StaticArray}(::Type{SA}) = Size{size(SA)}()
29+
@inline Size(a::StaticArray) = Size(typeof(a))
30+
31+
@pure Size(s::Tuple{Vararg{Int}}) = Size{s}()
32+
@pure Size(s::Int...) = Size{s}()
33+
34+
Base.show{S}(io::IO, ::Size{S}) = print(io, "Size", S)
35+
36+
37+
# Some @pure convenience functions.
38+
39+
# (This type could *probably* be returned from the `size()` function.
40+
# This might enable some generic programming, e.g. with `similar(A, size(A))`.)
41+
42+
@pure getindex{S}(::Size{S}, i::Int) = S[i]
43+
44+
@pure Base.:(==){S}(::Size{S}, s::Tuple{Vararg{Int}}) = S == s
45+
@pure Base.:(==){S}(s::Tuple{Vararg{Int}}, ::Size{S}) = s == S
46+
47+
@pure Base.:(!=){S}(::Size{S}, s::Tuple{Vararg{Int}}) = S != s
48+
@pure Base.:(!=){S}(s::Tuple{Vararg{Int}}, ::Size{S}) = s != S

0 commit comments

Comments
 (0)