Skip to content

Commit 918431b

Browse files
author
Andy Ferris
committed
Added a Size trait and SizeOf trait class
Implemented a "traitor" style trait system for convenient dispatch on type. The system supports implementing statically sized algorithms on dynamically sized arrays.
1 parent f7add73 commit 918431b

File tree

3 files changed

+102
-32
lines changed

3 files changed

+102
-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, SizeOf
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(SizeOf(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(::Type{Size{(1,1)}}, A::AbstractMatrix) = @inbounds return A[1]
10+
11+
@inline function det(::Type{Size{(2,2)}}, A::AbstractMatrix)
12+
@inbounds return A[1]*A[4] - A[3]*A[2]
13+
end
14+
15+
@inline function det(::Type{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}(::Type{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: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""
2+
SizeOf(static_array)
3+
4+
Returns the size of a static array, wrapped in a `Size` trait such as
5+
`Size{(2,3)}` for a 2×3 matrix.
6+
7+
`SizeOf` implements the "traitor" paradigm for traits, whereby an abstract trait
8+
class `SizeOf` returns a direct subtype, in this case `Size`.
9+
10+
For example,
11+
```
12+
det(x::StaticMatrix) = det(SizeOf(x), x)
13+
det(::Type{Size{1,1}}, x::AbstractMatrix) = x[1,1]
14+
det(::Type{Size{2,2}}, x::AbstractMatrix) = x[1,1]*x[2,2] - x[1,2]*x[2,1]
15+
# and other definitions as necessary
16+
```
17+
"""
18+
abstract SizeOf
19+
20+
21+
"""
22+
Size{(dims...)} <: SizeOf
23+
24+
A trait type allowing convenient trait-based dispatch on the size of a statically
25+
sized array.
26+
27+
`Size` implements the "traitor" paradigm for traits, whereby an abstract trait
28+
class `SizeOf` returns a direct subtype, in this case `Size`.
29+
30+
For example,
31+
```
32+
det(x::StaticMatrix) = det(SizeOf(x), x)
33+
det(::Type{Size{1,1}}, x::AbstractMatrix) = x[1,1]
34+
det(::Type{Size{2,2}}, x::AbstractMatrix) = x[1,1]*x[2,2] - x[1,2]*x[2,1]
35+
# and other definitions as necessary
36+
```
37+
"""
38+
immutable Size{S} <: SizeOf
39+
end
40+
41+
@pure SizeOf{SA<:StaticArray}(::Type{SA}) = Size{size(SA)}
42+
@inline SizeOf(a::StaticArray) = Size(typeof(a))
43+
44+
# Also define these, since may be more convenient than SizeOf
45+
"""
46+
Size(static_array)
47+
Size(StaticArrayType)
48+
49+
Convenience constructor for the `Size` of a static array. See also `SizeOf`.
50+
"""
51+
@pure Size{SA<:StaticArray}(::Type{SA}) = Size{size(SA)}
52+
@inline Size(a::StaticArray) = Size(typeof(a))
53+
54+
"""
55+
Size((dims...))
56+
Size(dims...)
57+
58+
Pure function that constructs a compile-time constant `Size` of an array. This
59+
allows for dispatch of standard (dynamically-sized) arrays to faster, specialized
60+
*StaticArrays* library methods when the programmer knows or can reasonably infer
61+
the size. For example,
62+
```
63+
mat = [1.0 2.0; 3.0 4.0]
64+
det(Size(2,2), mat) # Faster than det(mat)
65+
```
66+
"""
67+
@pure Size(s::Tuple{Vararg{Int}}) = Size{s}
68+
@pure Size(s::Int...) = Size{s}
69+
70+
@pure getindex{S}(::Type{Size{S}}, i::Int) = S[i]

0 commit comments

Comments
 (0)