Skip to content

Commit

Permalink
matrix power
Browse files Browse the repository at this point in the history
  • Loading branch information
schillic committed Jan 27, 2020
1 parent a19910f commit c50de31
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/IntervalMatrices.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ include("matrix.jl")
# Arithmetic for interval matrices
# =================================
include("arithmetic.jl")
include("power.jl")

# =======================================================
# Methods to handle the exponential of an interval matrix
Expand Down
86 changes: 86 additions & 0 deletions src/power.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import Base: ^, show

# helper types representing factors

abstract type AbstractFactor{T<:Integer} end

struct OneFactor{T} <: AbstractFactor{T} end

show(io::IO, ::OneFactor) = print(io, 1)

int(::OneFactor{T}) where {T} = one(T)

struct DoubledFactor{T} <: AbstractFactor{T}
a::T
end

show(io::IO, df::DoubledFactor) = print(io, df.a, "·2")

function int(df::DoubledFactor)
return df.a * 2
end

# binary decomposition

function binary_decomposition(k::T) where {T<:Integer}
factor2source = Dict{T, Vector{AbstractFactor{T}}}()
binary_decomposition!(factor2source, k)
return factor2source
end

function binary_decomposition!(factor2source, k::T) where {T<:Integer}
factors = Vector{AbstractFactor{T}}()
@assert !haskey(factor2source, k)
factor2source[k] = factors
if k == 1
push!(factors, OneFactor{T}())
return
else
b = div(k, 2)
push!(factors, DoubledFactor(b))
if !haskey(factor2source, b)
binary_decomposition!(factor2source, b)
end
if mod(k, 2) == 1
# k = 2 * b + 1
push!(factors, OneFactor{T}())
end
end
return factor2source
end

# matrix power

function matpow!(factor2matrix, factor2source, k::Integer)
if haskey(factor2matrix, k)
return factor2matrix[k]
end
A = nothing
for a in factor2source[k]
nₐ = int(a)
if !haskey(factor2matrix, nₐ)
@assert a isa DoubledFactor
# B = C² where C needs to be computed recursively
C = matpow!(factor2matrix, factor2source, a.a)
B = square(C)
@assert !haskey(factor2matrix, nₐ)
factor2matrix[nₐ] = B
else
B = factor2matrix[nₐ]
end
if A == nothing
A = B
else
A *= B
end
end
factor2matrix[k] = A
return A
end

function ^(M::IntervalMatrix{T1}, k::T2) where {T1, T2<:Integer}
factor2source = binary_decomposition(k)
factor2source[1] = [OneFactor{T2}()]
factor2matrix = Dict{T2, IntervalMatrix{T1}}(1 => M)
return matpow!(factor2matrix, factor2source, k)
end
23 changes: 23 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,26 @@ end
f = IntervalMatrices.correction_hull(m, 1e-3, 5)
f2 = IntervalMatrices.input_correction(m, 1e-3, 5)
end

@testset "Binary decomposition" begin
bd = IntervalMatrices.binary_decomposition
DF = IntervalMatrices.DoubledFactor
OF = IntervalMatrices.OneFactor{Int}()
@test Dict(1 => [OF]) == bd(1)
@test Dict(2 => [DF(1)], 1 => [OF]) == bd(2)
@test Dict(3 => [DF(1), OF], 1 => [OF]) == bd(3)
@test Dict(9 => [DF(4), OF], 4 => [DF(2)], 2 => [DF(1)], 1 => [OF]) == bd(9)
@test Dict(65 => [DF(32), OF], 32 => [DF(16)], 16 => [DF(8)], 8 => [DF(4)],
4 => [DF(2)], 2 => [DF(1)], 1 => [OF]) == bd(65)
end

@testset "Matrix power" begin
# flat intervals
B = IntervalMatrix([2.0±0 0.0±0; 0.0±0 3.0±0])
C = [2.0 0.0; 0.0 3.0]
@test all(mid(B^k) == C^k for k in 1:20)

# proper intervals
D = IntervalMatrix([2.0±0.1 0.0±0.1; 0.0±0.1 3.0±0.1])
D^4
end

0 comments on commit c50de31

Please sign in to comment.