Skip to content

Commit 30d126e

Browse files
authored
Merge pull request #161 from Godisemo/matrix-exponential-master
Add matrix exponential for 1x1 and 2x2, and fallback to Base
2 parents 699d028 + b31a48e commit 30d126e

File tree

4 files changed

+56
-1
lines changed

4 files changed

+56
-1
lines changed

src/StaticArrays.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Base: getindex, setindex!, size, similar, vec, show,
88
length, convert, promote_op, map, map!, reduce, reducedim, mapreducedim,
99
mapreduce, broadcast, broadcast!, conj, transpose, ctranspose,
1010
hcat, vcat, ones, zeros, eye, one, cross, vecdot, reshape, fill,
11-
fill!, det, inv, eig, eigvals, trace, vecnorm, norm, dot, diagm,
11+
fill!, det, inv, eig, eigvals, expm, trace, vecnorm, norm, dot, diagm,
1212
sum, diff, prod, count, any, all, sumabs, sumabs2, minimum,
1313
maximum, extrema, mean, copy, rand, randn, randexp, rand!, randn!,
1414
randexp!, normalize, normalize!, read, read!, write
@@ -90,6 +90,7 @@ include("det.jl")
9090
include("inv.jl")
9191
include("solve.jl")
9292
include("eigen.jl")
93+
include("expm.jl")
9394
include("cholesky.jl")
9495
include("deque.jl")
9596
include("io.jl")

src/expm.jl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
@inline expm(A::StaticMatrix) = _expm(Size(A), A)
2+
3+
@inline function _expm(::Size{(1,1)}, A::StaticMatrix)
4+
T = typeof(exp(zero(eltype(A))))
5+
newtype = similar_type(A,T)
6+
7+
(newtype)((exp(A[1]), ))
8+
end
9+
10+
@inline function _expm(::Size{(2,2)}, A::StaticMatrix{<:Any,<:Any,<:Real})
11+
T = typeof(exp(zero(eltype(A))))
12+
newtype = similar_type(A,T)
13+
14+
@inbounds a = A[1]
15+
@inbounds c = A[2]
16+
@inbounds b = A[3]
17+
@inbounds d = A[4]
18+
19+
v = (a-d)^2 + 4*b*c
20+
21+
if v > 0
22+
z = sqrt(v)
23+
z1 = cosh(z / 2)
24+
z2 = sinh(z / 2) / z
25+
elseif v < 0
26+
z = sqrt(-v)
27+
z1 = cos(z / 2)
28+
z2 = sin(z / 2) / z
29+
else # if v == 0
30+
z1 = T(1.0)
31+
z2 = T(0.5)
32+
end
33+
34+
r = exp((a + d) / 2)
35+
m11 = r * (z1 + (a - d) * z2)
36+
m12 = r * 2b * z2
37+
m21 = r * 2c * z2
38+
m22 = r * (z1 - (a - d) * z2)
39+
40+
(newtype)((m11, m21, m12, m22))
41+
end
42+
43+
# TODO add complex valued expm
44+
# TODO add special case for 3x3 matrices
45+
46+
@inline _expm(s::Size, A::StaticArray) = s(Base.expm(Array(A)))

test/expm.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@testset "Matrix exponential" begin
2+
@test expm(@SMatrix [2])::SMatrix SMatrix{1,1}(expm(2))
3+
@test expm(@SMatrix [5 2; -2 1])::SMatrix expm([5 2; -2 1])
4+
@test expm(@SMatrix [4 2; -2 1])::SMatrix expm([4 2; -2 1])
5+
@test expm(@SMatrix [4 2; 2 1])::SMatrix expm([4 2; 2 1])
6+
@test expm(@SMatrix [1 2 0; 2 1 0; 0 0 1])::SizedArray{Tuple{3,3}} expm([1 2 0; 2 1 0; 0 0 1])
7+
end

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ using Base.Test
2525
include("inv.jl")
2626
include("solve.jl") # Strange inference / world-age error
2727
include("eigen.jl")
28+
include("expm.jl")
2829
include("chol.jl")
2930
include("deque.jl")
3031
include("io.jl")

0 commit comments

Comments
 (0)