Skip to content

Commit f0884c8

Browse files
author
RAYNAUD Paul (raynaudp)
committed
m -> mem, CompressedLBFGS -> CompressedLBFGSOperator + add vectorshift!
1 parent 050d219 commit f0884c8

File tree

2 files changed

+42
-42
lines changed

2 files changed

+42
-42
lines changed

src/compressed_lbfgs.jl

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,25 @@ Implemented by Paul Raynaud (supervised by Dominique Orban)
1010
using LinearAlgebra, LinearAlgebra.BLAS
1111
using CUDA
1212

13-
export CompressedLBFGS
13+
export CompressedLBFGSOperator
1414

1515
"""
16-
CompressedLBFGS{T, M<:AbstractMatrix{T}, V<:AbstractVector{T}}
16+
CompressedLBFGSOperator{T, M<:AbstractMatrix{T}, V<:AbstractVector{T}}
1717
1818
A LBFGS limited-memory operator.
19-
It represents a linear application Rⁿˣⁿ, considering at most `m` BFGS updates.
19+
It represents a linear application Rⁿˣⁿ, considering at most `mem` BFGS updates.
2020
This implementation considers the bloc matrices reoresentation of the BFGS (forward) update.
2121
It follows the algorithm described in [REPRESENTATIONS OF QUASI-NEWTON MATRICES AND THEIR USE IN LIMITED MEMORY METHODS](https://link.springer.com/article/10.1007/BF01582063) from Richard H. Byrd, Jorge Nocedal and Robert B. Schnabel (1994).
2222
This operator considers several fields directly related to the bloc representation of the operator:
23-
- `m`: the maximal memory of the operator;
23+
- `mem`: the maximal memory of the operator;
2424
- `n`: the dimension of the linear application;
2525
- `k`: the current memory's size of the operator;
2626
- `α`: scalar for `B₀ = α I`;
2727
- `Sₖ`: retain the `k`-th last vectors `s` from the updates parametrized by `(s,y)`;
2828
- `Yₖ`: retain the `k`-th last vectors `y` from the updates parametrized by `(s,y)`;;
2929
- `Dₖ`: a diagonal matrix mandatory to perform the linear application and to form the matrix;
3030
- `Lₖ`: a lower diagonal mandatory to perform the linear application and to form the matrix.
31-
In addition to this structures which are circurlarly update when `k` reaches `m`, we consider other intermediate data structures renew at each update:
31+
In addition to this structures which are circurlarly update when `k` reaches `mem`, we consider other intermediate data structures renew at each update:
3232
- `chol_matrix`: a matrix required to store a Cholesky factorization of a Rᵏˣᵏ matrix;
3333
- `intermediate_1`: a R²ᵏˣ²ᵏ matrix;
3434
- `intermediate_2`: a R²ᵏˣ²ᵏ matrix;
@@ -38,24 +38,24 @@ In addition to this structures which are circurlarly update when `k` reaches `m`
3838
- `sol`: a vector ∈ Rᵏ to store intermediate solutions;
3939
This implementation is designed to work either on CPU or GPU.
4040
"""
41-
mutable struct CompressedLBFGS{T, M<:AbstractMatrix{T}, V<:AbstractVector{T}}
42-
m::Int # memory of the operator
41+
mutable struct CompressedLBFGSOperator{T, M<:AbstractMatrix{T}, V<:AbstractVector{T}}
42+
mem::Int # memory of the operator
4343
n::Int # vector size
44-
k::Int # k ≤ m, active memory of the operator
44+
k::Int # k ≤ mem, active memory of the operator
4545
α::T # B₀ = αI
4646
Sₖ::M # gather all sₖ₋ₘ
4747
Yₖ::M # gather all yₖ₋ₘ
48-
Dₖ::Diagonal{T,V} # m * m
49-
Lₖ::LowerTriangular{T,M} # m * m
48+
Dₖ::Diagonal{T,V} # mem * mem
49+
Lₖ::LowerTriangular{T,M} # mem * mem
5050

5151
chol_matrix::M # 2m * 2m
52-
intermediate_diagonal::Diagonal{T,V} # m * m
52+
intermediate_diagonal::Diagonal{T,V} # mem * mem
5353
intermediate_1::UpperTriangular{T,M} # 2m * 2m
5454
intermediate_2::LowerTriangular{T,M} # 2m * 2m
5555
inverse_intermediate_1::UpperTriangular{T,M} # 2m * 2m
5656
inverse_intermediate_2::LowerTriangular{T,M} # 2m * 2m
5757
intermediary_vector::V # 2m
58-
sol::V # m
58+
sol::V # mem
5959
end
6060

6161
default_gpu() = CUDA.functional() ? true : false
@@ -67,53 +67,54 @@ function columnshift!(A::AbstractMatrix{T}; direction::Int=-1, indicemax::Int=si
6767
return A
6868
end
6969

70-
function columnshift!(A::AbstractMatrix{T}; direction::Int=-1, indicemax::Int=size(A)[1]) where T
71-
map(i-> view(A,:,i+direction) .= view(A,:,i), 1-direction:indicemax)
72-
return A
70+
function vectorshift!(v::AbstractVector{T}; direction::Int=-1, indicemax::Int=length(v)) where T
71+
view(v, 1:indicemax+direction) .= view(v,1-direction:indicemax)
72+
return v
7373
end
7474

7575
"""
76-
CompressedLBFGS(n::Int; [T=Float64, m=5], gpu:Bool)
76+
CompressedLBFGSOperator(n::Int; [T=Float64, mem=5], gpu:Bool)
7777
7878
A implementation of a LBFGS operator (forward), representing a `nxn` linear application.
7979
It considers at most `k` BFGS iterates, and fit the architecture depending if it is launched on a CPU or a GPU.
8080
"""
81-
function CompressedLBFGS(n::Int; m::Int=5, T=Float64, gpu=default_gpu(), M=default_matrix_type(gpu; T), V=default_vector_type(gpu; T))
81+
function CompressedLBFGSOperator(n::Int; mem::Int=5, T=Float64, gpu=default_gpu(), M=default_matrix_type(gpu; T), V=default_vector_type(gpu; T))
8282
α = (T)(1)
8383
k = 0
84-
Sₖ = M(undef, n, m)
85-
Yₖ = M(undef, n, m)
86-
Dₖ = Diagonal(V(undef, m))
87-
Lₖ = LowerTriangular(M(undef, m, m))
84+
Sₖ = M(undef, n, mem)
85+
Yₖ = M(undef, n, mem)
86+
Dₖ = Diagonal(V(undef, mem))
87+
Lₖ = LowerTriangular(M(undef, mem, mem))
8888
Lₖ .= (T)(0)
8989

90-
chol_matrix = M(undef, m, m)
91-
intermediate_diagonal = Diagonal(V(undef, m))
92-
intermediate_1 = UpperTriangular(M(undef, 2*m, 2*m))
93-
intermediate_2 = LowerTriangular(M(undef, 2*m, 2*m))
94-
inverse_intermediate_1 = UpperTriangular(M(undef, 2*m, 2*m))
95-
inverse_intermediate_2 = LowerTriangular(M(undef, 2*m, 2*m))
96-
intermediary_vector = V(undef, 2*m)
97-
sol = V(undef, 2*m)
98-
return CompressedLBFGS{T,M,V}(m, n, k, α, Sₖ, Yₖ, Dₖ, Lₖ, chol_matrix, intermediate_diagonal, intermediate_1, intermediate_2, inverse_intermediate_1, inverse_intermediate_2, intermediary_vector, sol)
90+
chol_matrix = M(undef, mem, mem)
91+
intermediate_diagonal = Diagonal(V(undef, mem))
92+
intermediate_1 = UpperTriangular(M(undef, 2*mem, 2*mem))
93+
intermediate_2 = LowerTriangular(M(undef, 2*mem, 2*mem))
94+
inverse_intermediate_1 = UpperTriangular(M(undef, 2*mem, 2*mem))
95+
inverse_intermediate_2 = LowerTriangular(M(undef, 2*mem, 2*mem))
96+
intermediary_vector = V(undef, 2*mem)
97+
sol = V(undef, 2*mem)
98+
return CompressedLBFGSOperator{T,M,V}(mem, n, k, α, Sₖ, Yₖ, Dₖ, Lₖ, chol_matrix, intermediate_diagonal, intermediate_1, intermediate_2, inverse_intermediate_1, inverse_intermediate_2, intermediary_vector, sol)
9999
end
100100

101-
function Base.push!(op::CompressedLBFGS{T,M,V}, s::V, y::V) where {T,M,V<:AbstractVector{T}}
102-
if op.k < op.m # still some place in the structures
101+
function Base.push!(op::CompressedLBFGSOperator{T,M,V}, s::V, y::V) where {T,M,V<:AbstractVector{T}}
102+
if op.k < op.mem # still some place in the structures
103103
op.k += 1
104104
view(op.Sₖ, :, op.k) .= s
105105
view(op.Yₖ, :, op.k) .= y
106106
view(op.Dₖ.diag, op.k) .= dot(s, y)
107107
mul!(view(op.Lₖ.data, op.k, 1:op.k-1), transpose(view(op.Yₖ, :, 1:op.k-1)), view(op.Sₖ, :, op.k) )
108-
else # k == m update circurlarly the intermediary structures
108+
else # k == mem update circurlarly the intermediary structures
109109
columnshift!(op.Sₖ; indicemax=op.k)
110110
columnshift!(op.Yₖ; indicemax=op.k)
111-
op.Dₖ .= circshift(op.Dₖ, (-1, -1))
111+
# op.Dₖ .= circshift(op.Dₖ, (-1, -1))
112+
vectorshift!(op.Dₖ.diag; indicemax=op.k)
112113
view(op.Sₖ, :, op.k) .= s
113114
view(op.Yₖ, :, op.k) .= y
114115
view(op.Dₖ.diag, op.k) .= dot(s, y)
115116

116-
map(i-> view(op.Lₖ, i:op.m-1, i-1) .= view(op.Lₖ, i+1:op.m, i), 2:op.m)
117+
map(i-> view(op.Lₖ, i:op.mem-1, i-1) .= view(op.Lₖ, i+1:op.mem, i), 2:op.mem)
117118
mul!(view(op.Lₖ.data, op.k, 1:op.k-1), transpose(view(op.Yₖ, :, 1:op.k-1)), view(op.Sₖ, :, op.k) )
118119
end
119120

@@ -127,7 +128,7 @@ end
127128

128129
# Algorithm 3.2 (p15)
129130
# Theorem 2.3 (p6)
130-
function Base.Matrix(op::CompressedLBFGS{T,M,V}) where {T,M,V}
131+
function Base.Matrix(op::CompressedLBFGSOperator{T,M,V}) where {T,M,V}
131132
B₀ = M(zeros(T, op.n, op.n))
132133
map(i -> B₀[i, i] = op.α, 1:op.n)
133134

@@ -147,7 +148,7 @@ end
147148

148149
# Algorithm 3.2 (p15)
149150
# step 4, Jₖ is computed only if needed
150-
function inverse_cholesky(op::CompressedLBFGS{T,M,V}) where {T,M,V}
151+
function inverse_cholesky(op::CompressedLBFGSOperator{T,M,V}) where {T,M,V}
151152
view(op.intermediate_diagonal.diag, 1:op.k) .= inv.(view(op.Dₖ.diag, 1:op.k))
152153

153154
mul!(view(op.inverse_intermediate_1, 1:op.k, 1:op.k), view(op.intermediate_diagonal, 1:op.k, 1:op.k), transpose(view(op.Lₖ, 1:op.k, 1:op.k)))
@@ -161,7 +162,7 @@ function inverse_cholesky(op::CompressedLBFGS{T,M,V}) where {T,M,V}
161162
end
162163

163164
# step 6, must be improve
164-
function precompile_iterated_structure!(op::CompressedLBFGS)
165+
function precompile_iterated_structure!(op::CompressedLBFGSOperator)
165166
Jₖ = inverse_cholesky(op)
166167

167168
# constant update
@@ -186,7 +187,7 @@ function precompile_iterated_structure!(op::CompressedLBFGS)
186187
end
187188

188189
# Algorithm 3.2 (p15)
189-
function LinearAlgebra.mul!(Bv::V, op::CompressedLBFGS{T,M,V}, v::V) where {T,M,V<:AbstractVector{T}}
190+
function LinearAlgebra.mul!(Bv::V, op::CompressedLBFGSOperator{T,M,V}, v::V) where {T,M,V<:AbstractVector{T}}
190191
# step 1-4 and 6 mainly done by Base.push!
191192
# step 5
192193
mul!(view(op.sol, 1:op.k), transpose(view(op.Yₖ, :, 1:op.k)), v)

test/test_clbfgs.jl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
@testset "CompressedLBFGS operator" begin
1+
@testset "CompressedLBFGSOperator operator" begin
22
iter=50
33
n=100
44
n=5
5-
lbfgs = CompressedLBFGS(n) # m=5
5+
lbfgs = CompressedLBFGSOperator(n) # m=5
66
V = LinearOperators.default_vector_type(LinearOperators.default_gpu())
77
Bv = V(rand(n))
88
s = V(rand(n))
@@ -11,7 +11,6 @@
1111
s = V(rand(n))
1212
y = V(rand(n))
1313
push!(lbfgs, s, y)
14-
# warmp-up computing the mandatory intermediate structures
1514
allocs = @allocated mul!(Bv, lbfgs, s)
1615
@test allocs == 0
1716
@test Bv y

0 commit comments

Comments
 (0)