Skip to content

Commit 134b4b2

Browse files
author
Pawel Latawiec
committed
Add limited memory U and L matrices
1 parent 9109d5c commit 134b4b2

File tree

3 files changed

+213
-49
lines changed

3 files changed

+213
-49
lines changed

src/lal.jl

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ mutable struct LookAheadLanczosDecomp{OpT, OptT, VecT, MatT, ElT, ElRT}
8787

8888
# Eq. 3.9
8989
# need to keep previous columns of U for G checks
90-
U::UpperTriangular{ElT, Matrix{ElT}}
90+
U::LimitedMemoryUpperTriangular{ElT, Matrix{ElT}}
9191
# need to keep previous columns of L for H checks
92-
L::UpperHessenberg{ElT, Matrix{ElT}}
92+
L::LimitedMemoryUpperHessenberg{ElT, Matrix{ElT}}
9393

9494
# Indices tracking location in block and sequence
9595
n::Int
@@ -188,8 +188,8 @@ function LookAheadLanczosDecomp(
188188
Flastrow = Vector{elT}()
189189
F̃lastcol = Vector{elT}()
190190

191-
U = UpperTriangular(Matrix{elT}(undef, 0, 0))
192-
L = UpperHessenberg(Matrix{elT}(undef, 0, 0))
191+
U = LimitedMemoryUpperTriangular{elT, Matrix{elT}}(max_memory)
192+
L = LimitedMemoryUpperHessenberg{elT, Matrix{elT}}(max_memory)
193193

194194
# Alg 5.2.0
195195
n = 1
@@ -473,12 +473,9 @@ function _update_U!(ld, innerp)
473473
# U is upper triangular matrix in decomposition of recurrence relation for P-Q sequence
474474
# updates last column of U
475475
n, mk, k, kstar = ld.n, ld.mk, ld.k, ld.kstar
476-
ld.U = UpperTriangular(
477-
[
478-
ld.U fill(0.0, n-1, 1)
479-
fill(0.0, 1, n-1) 1.0
480-
]
481-
)
476+
uvec = fill(0, n)
477+
uvec[end] = 1
478+
_grow_hcat!(ld.U, uvec)
482479

483480
for i = kstar:k-1
484481
block_start = mk[i]
@@ -639,17 +636,8 @@ function _update_L!(ld, innerv)
639636
if !innerv
640637
Llastcol[nl[l]:end] .= blocks(ld.D)[end] \ ld.Flastcol[nl[l]:end]
641638
end
642-
if isone(n)
643-
ld.L = UpperHessenberg(
644-
reshape([Llastcol[1]
645-
0.0], 2, 1)
646-
)
647-
else
648-
ld.L = UpperHessenberg(
649-
[ld.L Llastcol
650-
fill(0.0, 1, n)]
651-
)
652-
end
639+
lvec = [Llastcol; 0]
640+
_grow_hcat!(ld.L, lvec)
653641
return ld
654642
end
655643

src/limited_memory_matrices.jl

Lines changed: 160 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,34 @@
44
A matrix which keeps only the last `memory` columns. Access outside these columns throws an error. Thus, the underlying storage is a matrix of size `(N, memory)` where `N` is the size of the first dimension
55
"""
66
mutable struct LimitedMemoryMatrix{T, V<:AbstractMatrix{T}} <: AbstractMatrix{T}
7-
value::V
7+
data::V
88
memory::Int
99
hsize::Int
1010

11-
function LimitedMemoryMatrix{T, V}(value::V, memory, hsize) where {T, V<:AbstractMatrix{T}}
12-
@assert Base.require_one_based_indexing(value)
13-
return new{T, V}(value, memory, hsize)
11+
function LimitedMemoryMatrix{T, V}(data::V, memory, hsize) where {T, V<:AbstractMatrix{T}}
12+
@assert Base.require_one_based_indexing(data)
13+
return new{T, V}(data, memory, hsize)
1414
end
1515
end
1616

1717
function LimitedMemoryMatrix(mat::AbstractMatrix{T}, memory) where T
18-
value = similar(mat, size(mat, 1), memory)
19-
value[:, end-size(mat, 2)+1:end] .= mat
20-
return LimitedMemoryMatrix{T, typeof(value)}(value, memory, size(mat, 2))
18+
data = similar(mat, size(mat, 1), memory)
19+
data[:, end-size(mat, 2)+1:end] .= mat
20+
return LimitedMemoryMatrix{T, typeof(data)}(data, memory, size(mat, 2))
2121
end
2222
function LimitedMemoryMatrix(vec::AbstractVector{T}, memory) where T
23-
value = similar(vec, size(vec, 1), memory)
24-
value[:, end] .= vec
25-
return LimitedMemoryMatrix{T, typeof(value)}(value, memory, 1)
23+
data = similar(vec, size(vec, 1), memory)
24+
data[:, end] .= vec
25+
return LimitedMemoryMatrix{T, typeof(data)}(data, memory, 1)
2626
end
2727

28-
Base.size(A::LimitedMemoryMatrix) = (size(A.value, 1), A.hsize)
29-
Base.similar(A::LimitedMemoryMatrix) = LimitedMemoryMatrix(similar(A.value), A.memory, A.hsize)
30-
Base.similar(A::LimitedMemoryMatrix, ::Type{T}) where T = LimitedMemoryMatrix(similar(A.value, T), A.memory, A.hsize)
28+
Base.size(A::LimitedMemoryMatrix) = (size(A.data, 1), A.hsize)
29+
Base.similar(A::LimitedMemoryMatrix) = LimitedMemoryMatrix(similar(A.data), A.memory, A.hsize)
30+
Base.similar(A::LimitedMemoryMatrix, ::Type{T}) where T = LimitedMemoryMatrix(similar(A.data, T), A.memory, A.hsize)
3131
Base.isempty(A::LimitedMemoryMatrix) = size(A, 1) == 0 || size(A, 2) == 0
3232

3333
Base.@propagate_inbounds function Base.setindex!(A::LimitedMemoryMatrix, v, i::Integer, j::Integer)
34+
@boundscheck checkbounds(A, i, j)
3435
lowest_stored_index = size(A, 2) - A.memory + 1
3536
if j < lowest_stored_index || j > size(A, 2)
3637
throw(
@@ -40,12 +41,13 @@ Base.@propagate_inbounds function Base.setindex!(A::LimitedMemoryMatrix, v, i::I
4041
)
4142
else
4243
jj = j - lowest_stored_index + 1
43-
A.value[i, jj] = v
44+
A.data[i, jj] = v
4445
end
4546
return v
4647
end
4748

4849
Base.@propagate_inbounds function Base.getindex(A::LimitedMemoryMatrix, i::Integer, j::Integer)
50+
@boundscheck checkbounds(A, i, j)
4951
lowest_stored_index = size(A, 2) - A.memory + 1
5052
if j < lowest_stored_index || j > size(A, 2)
5153
throw(
@@ -54,19 +56,19 @@ Base.@propagate_inbounds function Base.getindex(A::LimitedMemoryMatrix, i::Integ
5456
)
5557
)
5658
else
57-
@inbounds v = A.value[i, j - lowest_stored_index + 1]
59+
@inbounds v = A.data[i, j - lowest_stored_index + 1]
5860
end
5961
return v
6062
end
6163

6264
function Base.show(io::IO, ::MIME"text/plain", A::LimitedMemoryMatrix) where {T}
6365
print(io, Base.dims2string(size(A)), " ")
64-
Base.showarg(io, A.value, true)
66+
Base.showarg(io, A.data, true)
6567
end
6668

6769
function Base.show(io::IO, A::LimitedMemoryMatrix) where {T}
6870
print(io, Base.dims2string(size(A)), " ")
69-
Base.showarg(io, A.value, true)
71+
Base.showarg(io, A.data, true)
7072
end
7173

7274
"""
@@ -78,22 +80,152 @@ size of `A`
7880
function hcat!(A::LimitedMemoryMatrix, B::AbstractVector)
7981
@assert size(B, 1) == size(A, 1)
8082
A.hsize += 1
81-
A.value[:, 1:end-1] .= A.value[:, 2:end]
82-
A.value[:, end] .= B
83+
A.data[:, 1:end-1] .= A.data[:, 2:end]
84+
A.data[:, end] .= B
8385
return A
8486
end
8587

88+
8689
"""
87-
LimitedMemoryBandedMatrix
90+
LimitedMemoryUpperTriangularMatrix
8891
89-
A matrix which keeps only the last `memory` columns. Access outside these columns throws an
90-
error. Additionally, the matrix is understood to be banded, such that only values
91-
`band_offset` from the diagonal are non-zero, where the band is of width `band_width`. Thus, the underlying storage is a matrix of size `(band_width, memory)`
92+
A matrix which keeps only the last `memory` columns. `setindex!` outside these columns
93+
throws an error, otherwise entries are set to 0.
9294
"""
93-
mutable struct LimitedMemoryBandedMatrix{T, V<:AbstractMatrix{T}} <: AbstractMatrix{T}
94-
value::V
95+
mutable struct LimitedMemoryUpperTriangular{T, V<:AbstractMatrix{T}} <: AbstractMatrix{T}
96+
data::V
9597
memory::Int
96-
size::Tuple{Int, Int}
97-
band_offset::Int
98-
band_width::Int
98+
hsize::Int
99+
100+
function LimitedMemoryUpperTriangular{T, V}(data::AbstractMatrix{T}, memory, hsize) where {T, V<:AbstractMatrix{T}}
101+
@assert Base.require_one_based_indexing(data)
102+
return new{T, typeof(data)}(data, memory, hsize)
103+
end
104+
end
105+
106+
Base.size(A::LimitedMemoryUpperTriangular) = (A.hsize, A.hsize)
107+
function LimitedMemoryUpperTriangular(mat::AbstractMatrix{T}, memory) where T
108+
data = similar(mat, memory, memory)
109+
fill!(data, 0)
110+
data[:, end-size(mat, 2)+1:end] .= mat
111+
return LimitedMemoryUpperTriangular{T, typeof(data)}(data, memory, size(mat, 2))
112+
end
113+
function LimitedMemoryUpperTriangular(vec::AbstractVector{T}, memory) where T
114+
data = similar(vec, memory, memory)
115+
fill!(data, 0)
116+
data[:, end] .= vec
117+
return LimitedMemoryUpperTriangular{T, typeof(data)}(data, memory, 1)
118+
end
119+
function LimitedMemoryUpperTriangular{T, V}(memory) where {T, V<:AbstractMatrix{T}}
120+
data = V(undef, memory, memory)
121+
fill!(data, 0)
122+
return LimitedMemoryUpperTriangular{T, typeof(data)}(data, memory, 0)
123+
end
124+
125+
Base.@propagate_inbounds function Base.setindex!(A::LimitedMemoryUpperTriangular, v, i::Integer, j::Integer)
126+
@boundscheck checkbounds(A, i, j)
127+
lowest_stored_index = size(A, 2) - A.memory + 1
128+
if j < lowest_stored_index || (i > j) || (j-A.memory) >= i
129+
throw(
130+
ArgumentError(
131+
"Cannot set index ($i, $j) out of memory range, memory kept from $(max(1, lowest_stored_index)) to $(size(A, 2)))"
132+
)
133+
)
134+
else
135+
jj = j - lowest_stored_index + 1
136+
ii = i - lowest_stored_index + 1 - (size(A, 2) - j)
137+
A.data[ii, jj] = v
138+
end
139+
return v
140+
end
141+
142+
Base.@propagate_inbounds function Base.getindex(A::LimitedMemoryUpperTriangular, i::Integer, j::Integer)
143+
@boundscheck checkbounds(A, i, j)
144+
lowest_stored_index_j = size(A, 2) - A.memory + 1
145+
if j < lowest_stored_index_j || (i > j) || (j-A.memory) >= i
146+
v = zero(eltype(A))
147+
else
148+
jj = j - lowest_stored_index_j + 1
149+
ii = i - lowest_stored_index_j + 1 + (size(A, 2) - j)
150+
@inbounds v = A.data[ii, jj]
151+
end
152+
return v
153+
end
154+
155+
"""
156+
LimitedMemoryUpperHessenberg
157+
158+
A matrix which keeps only the last `memory` columns. `setindex!` outside these columns
159+
throws an error, otherwise entries are set to 0.
160+
"""
161+
mutable struct LimitedMemoryUpperHessenberg{T, V<:AbstractMatrix{T}} <: AbstractMatrix{T}
162+
data::V
163+
memory::Int
164+
hsize::Int
165+
166+
function LimitedMemoryUpperHessenberg{T, V}(data::AbstractMatrix{T}, memory, hsize) where {T, V<:AbstractMatrix{T}}
167+
@assert Base.require_one_based_indexing(data)
168+
return new{T, typeof(data)}(data, memory, hsize)
169+
end
170+
end
171+
172+
Base.size(A::LimitedMemoryUpperHessenberg) = (A.hsize+1, A.hsize)
173+
function LimitedMemoryUpperHessenberg(mat::AbstractMatrix{T}, memory) where T
174+
data = similar(mat, memory, memory)
175+
fill!(data, 0)
176+
data[end-memory+1:end, end-size(mat, 2)+1:end] .= mat
177+
return LimitedMemoryUpperHessenberg{T, typeof(data)}(data, memory, size(mat, 2))
178+
end
179+
function LimitedMemoryUpperHessenberg(vec::AbstractVector{T}, memory) where T
180+
data = similar(vec, memory, memory)
181+
fill!(data, 0)
182+
data[:, end] .= vec[end-memory+1:end]
183+
return LimitedMemoryUpperHessenberg{T, typeof(data)}(data, memory, 1)
184+
end
185+
function LimitedMemoryUpperHessenberg{T, V}(memory) where {T, V<:AbstractMatrix{T}}
186+
data = V(undef, memory, memory)
187+
fill!(data, 0)
188+
return LimitedMemoryUpperHessenberg{T, typeof(data)}(data, memory, 0)
189+
end
190+
191+
Base.@propagate_inbounds function Base.setindex!(A::LimitedMemoryUpperHessenberg, v, i::Integer, j::Integer)
192+
@boundscheck checkbounds(A, i, j)
193+
lowest_stored_index = size(A, 2) - A.memory + 1
194+
if j < lowest_stored_index || (i > j+1) || (j+1-A.memory) >= i
195+
throw(
196+
ArgumentError(
197+
"Cannot set index ($i, $j) out of memory range, memory kept from $(max(1, lowest_stored_index)) to $(size(A, 2)))"
198+
)
199+
)
200+
else
201+
jj = j - lowest_stored_index + 1
202+
ii = i - lowest_stored_index - (size(A, 2) - j)
203+
A.data[ii, jj] = v
204+
end
205+
return v
206+
end
207+
208+
Base.@propagate_inbounds function Base.getindex(A::LimitedMemoryUpperHessenberg, i::Integer, j::Integer)
209+
@boundscheck checkbounds(A, i, j)
210+
lowest_stored_index_j = size(A, 2) - A.memory + 1
211+
if j < lowest_stored_index_j || (i > j+1) || (j+1-A.memory) >= i
212+
v = zero(eltype(A))
213+
else
214+
jj = j - lowest_stored_index_j + 1
215+
ii = i - lowest_stored_index_j + (size(A, 2) - j)
216+
@inbounds v = A.data[ii, jj]
217+
end
218+
return v
219+
end
220+
221+
function _grow_hcat!(A, v)
222+
if !isempty(A)
223+
@assert size(v, 1) == size(A, 1)+1
224+
end
225+
@assert sum(abs, v[1:end-A.memory]) < eps(real(eltype(A)))
226+
mem = min(A.memory, length(v))
227+
A.hsize += 1
228+
A.data[:, 1:end-1] .= A.data[:, 2:end]
229+
A.data[end-mem+1:end, end] .= v[end-mem+1:end]
230+
return A
99231
end

test/limited_memory_matrices.jl

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,48 @@ using Test
2525
@test A[3, 3] == 3
2626
@test A[3, 4] == 4
2727
@test A[3, 5] == 5
28+
end
29+
30+
@testset "LimitedMemoryUpperTriangular" begin
31+
A = IS.LimitedMemoryUpperTriangular{Float64, Matrix{Float64}}(3)
32+
IS._grow_hcat!(A, fill(1.0, 1))
33+
IS._grow_hcat!(A, fill(2.0, 2))
34+
@test A [
35+
1.0 2.0
36+
0.0 2.0
37+
]
38+
IS._grow_hcat!(A, fill(3.0, 3))
39+
v = fill(4.0, 4)
40+
v[1] = 0
41+
IS._grow_hcat!(A, v)
42+
@test A [
43+
0.0 2.0 3.0 0.0
44+
0.0 2.0 3.0 4.0
45+
0.0 0.0 3.0 4.0
46+
0.0 0.0 0.0 4.0
47+
]
48+
end
49+
50+
@testset "LimitedMemoryUpperHessenberg" begin
51+
A = IS.LimitedMemoryUpperHessenberg{Float64, Matrix{Float64}}(3)
52+
IS._grow_hcat!(A, fill(1.0, 2))
53+
IS._grow_hcat!(A, fill(2.0, 3))
54+
@test A [
55+
1.0 2.0
56+
1.0 2.0
57+
0.0 2.0
58+
]
59+
v = fill(3.0, 4)
60+
v[1] = 0
61+
IS._grow_hcat!(A, v)
62+
v = fill(4.0, 5)
63+
v[1:2] .= 0
64+
IS._grow_hcat!(A, v)
65+
@test A [
66+
0.0 2.0 0.0 0.0
67+
0.0 2.0 3.0 0.0
68+
0.0 2.0 3.0 4.0
69+
0.0 0.0 3.0 4.0
70+
0.0 0.0 0.0 4.0
71+
]
2872
end

0 commit comments

Comments
 (0)