@@ -36,7 +36,6 @@ In addition to this structures which are circurlarly update when `k` reaches `m`
36
36
- `inverse_intermediate_2`: a R²ᵏˣ²ᵏ matrix;
37
37
- `intermediary_vector`: a vector ∈ Rᵏ to store intermediate solutions;
38
38
- `sol`: a vector ∈ Rᵏ to store intermediate solutions;
39
- - `intermediate_structure_updated`: inform if the intermediate structures are up-to-date or not.
40
39
This implementation is designed to work either on CPU or GPU.
41
40
"""
42
41
mutable struct CompressedLBFGS{T, M<: AbstractMatrix{T} , V<: AbstractVector{T} }
@@ -50,26 +49,26 @@ mutable struct CompressedLBFGS{T, M<:AbstractMatrix{T}, V<:AbstractVector{T}}
50
49
Lₖ:: LowerTriangular{T,M} # m * m
51
50
52
51
chol_matrix:: M # 2m * 2m
52
+ intermediate_diagonal:: Diagonal{T,V} # m * m
53
53
intermediate_1:: UpperTriangular{T,M} # 2m * 2m
54
54
intermediate_2:: LowerTriangular{T,M} # 2m * 2m
55
55
inverse_intermediate_1:: UpperTriangular{T,M} # 2m * 2m
56
56
inverse_intermediate_2:: LowerTriangular{T,M} # 2m * 2m
57
57
intermediary_vector:: V # 2m
58
58
sol:: V # m
59
- intermediate_structure_updated:: Bool
60
59
end
61
60
62
61
default_gpu () = CUDA. functional () ? true : false
63
- default_matrix_type (gpu:: Bool , T:: DataType ) = gpu ? CuMatrix{T} : Matrix{T}
64
- default_vector_type (gpu:: Bool , T:: DataType ) = gpu ? CuVector{T} : Vector{T}
62
+ default_matrix_type (gpu:: Bool ; T:: DataType = Float64 ) = gpu ? CuMatrix{T} : Matrix{T}
63
+ default_vector_type (gpu:: Bool ; T:: DataType = Float64 ) = gpu ? CuVector{T} : Vector{T}
65
64
66
65
"""
67
66
CompressedLBFGS(n::Int; [T=Float64, m=5], gpu:Bool)
68
67
69
68
A implementation of a LBFGS operator (forward), representing a `nxn` linear application.
70
69
It considers at most `k` BFGS iterates, and fit the architecture depending if it is launched on a CPU or a GPU.
71
70
"""
72
- function CompressedLBFGS (n:: Int ; m:: Int = 5 , T= Float64, gpu= default_gpu (), M= default_matrix_type (gpu, T), V= default_vector_type (gpu, T))
71
+ function CompressedLBFGS (n:: Int ; m:: Int = 5 , T= Float64, gpu= default_gpu (), M= default_matrix_type (gpu; T), V= default_vector_type (gpu; T))
73
72
α = (T)(1 )
74
73
k = 0
75
74
Sₖ = M (undef, n, m)
@@ -78,14 +77,14 @@ function CompressedLBFGS(n::Int; m::Int=5, T=Float64, gpu=default_gpu(), M=defau
78
77
Lₖ = LowerTriangular (M (undef, m, m))
79
78
80
79
chol_matrix = M (undef, m, m)
80
+ intermediate_diagonal = Diagonal (V (undef, m))
81
81
intermediate_1 = UpperTriangular (M (undef, 2 * m, 2 * m))
82
82
intermediate_2 = LowerTriangular (M (undef, 2 * m, 2 * m))
83
83
inverse_intermediate_1 = UpperTriangular (M (undef, 2 * m, 2 * m))
84
84
inverse_intermediate_2 = LowerTriangular (M (undef, 2 * m, 2 * m))
85
85
intermediary_vector = V (undef, 2 * m)
86
86
sol = V (undef, 2 * m)
87
- intermediate_structure_updated = false
88
- return CompressedLBFGS {T,M,V} (m, n, k, α, Sₖ, Yₖ, Dₖ, Lₖ, chol_matrix, intermediate_1, intermediate_2, inverse_intermediate_1, inverse_intermediate_2, intermediary_vector, sol, intermediate_structure_updated)
87
+ 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)
89
88
end
90
89
91
90
function Base. push! (op:: CompressedLBFGS{T,M,V} , s:: V , y:: V ) where {T,M,V<: AbstractVector{T} }
@@ -109,13 +108,16 @@ function Base.push!(op::CompressedLBFGS{T,M,V}, s::V, y::V) where {T,M,V<:Abstra
109
108
# for the time being, reinstantiate completely the Lₖ matrix
110
109
for j in 1 : op. k
111
110
for i in 1 : j- 1
112
- op. Lₖ. data[j, i] = dot (op. Sₖ[ :, j], op. Yₖ[ :, i] )
111
+ op. Lₖ. data[j, i] = dot (view ( op. Sₖ, :, j), view ( op. Yₖ, :, i) )
113
112
end
114
113
end
115
114
end
115
+
116
+ # step 4 and 6
117
+ precompile_iterated_structure! (op)
118
+
116
119
# secant equation fails if uncommented
117
120
# op.α = dot(y,s)/dot(s,s)
118
- op. intermediate_structure_updated = false
119
121
return op
120
122
end
121
123
141
143
142
144
# Algorithm 3.2 (p15)
143
145
# step 4, Jₖ is computed only if needed
144
- function inverse_cholesky (op:: CompressedLBFGS )
145
- view (op. chol_matrix, 1 : op. k, 1 : op. k) .= op. α .* (transpose (view (op. Sₖ, :, 1 : op. k)) * view (op. Sₖ, :, 1 : op. k)) .+ view (op. Lₖ, 1 : op. k, 1 : op. k) * inv (Diagonal (op. Dₖ[1 : op. k, 1 : op. k])) * transpose (view (op. Lₖ, 1 : op. k, 1 : op. k))
146
+ function inverse_cholesky (op:: CompressedLBFGS{T,M,V} ) where {T,M,V}
147
+ view (op. intermediate_diagonal. diag, 1 : op. k) .= inv .(view (op. Dₖ. diag, 1 : op. k))
148
+
149
+ # view(op.Lₖ, 1:op.k, 1:op.k) * inv(Diagonal(op.Dₖ[1:op.k, 1:op.k])) * transpose(view(op.Lₖ, 1:op.k, 1:op.k))
150
+ 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)))
151
+ mul! (view (op. chol_matrix, 1 : op. k, 1 : op. k), view (op. Lₖ, 1 : op. k, 1 : op. k), view (op. inverse_intermediate_1, 1 : op. k, 1 : op. k))
152
+
153
+ # view(op.chol_matrix, 1:op.k, 1:op.k) .= op.α .* (transpose(view(op.Sₖ, :, 1:op.k)) * view(op.Sₖ, :, 1:op.k))
154
+ mul! (view (op. chol_matrix, 1 : op. k, 1 : op. k), transpose (view (op. Sₖ, :, 1 : op. k)), view (op. Sₖ, :, 1 : op. k), op. α, (T)(1 ))
155
+
156
+ # view(op.chol_matrix, 1:op.k, 1:op.k) .= op.α .* (transpose(view(op.Sₖ, :, 1:op.k)) * view(op.Sₖ, :, 1:op.k)) .+ view(op.Lₖ, 1:op.k, 1:op.k) * inv(Diagonal(op.Dₖ[1:op.k, 1:op.k])) * transpose(view(op.Lₖ, 1:op.k, 1:op.k))
157
+
146
158
cholesky! (Symmetric (view (op. chol_matrix, 1 : op. k, 1 : op. k)))
147
159
Jₖ = transpose (UpperTriangular (view (op. chol_matrix, 1 : op. k, 1 : op. k)))
148
160
return Jₖ
@@ -152,29 +164,32 @@ end
152
164
function precompile_iterated_structure! (op:: CompressedLBFGS )
153
165
Jₖ = inverse_cholesky (op)
154
166
155
- view (op. intermediate_1, 1 : op. k,1 : op. k) .= .- view (op. Dₖ, 1 : op. k, 1 : op. k)^ (1 / 2 )
156
- view (op. intermediate_1, 1 : op. k,op. k+ 1 : 2 * op. k) .= view (op. Dₖ, 1 : op. k, 1 : op. k)^ (- 1 / 2 ) * transpose (view (op. Lₖ, 1 : op. k, 1 : op. k))
167
+ # constant update
157
168
view (op. intermediate_1, op. k+ 1 : 2 * op. k, 1 : op. k) .= 0
158
- view (op. intermediate_1, op. k+ 1 : 2 * op. k, op. k+ 1 : 2 * op. k) .= transpose (Jₖ)
159
-
160
- view (op. intermediate_2, 1 : op. k, 1 : op. k) .= view (op. Dₖ, 1 : op. k, 1 : op. k)^ (1 / 2 )
161
169
view (op. intermediate_2, 1 : op. k, op. k+ 1 : 2 * op. k) .= 0
162
- view (op. intermediate_2 , op. k+ 1 : 2 * op. k, 1 : op. k) . = .- view (op . Lₖ, 1 : op. k, 1 : op . k) * view (op . Dₖ, 1 : op . k, 1 : op . k) ^ ( - 1 / 2 )
170
+ view (op. intermediate_1 , op. k+ 1 : 2 * op. k, op. k+ 1 : 2 * op. k) . = transpose (Jₖ )
163
171
view (op. intermediate_2, op. k+ 1 : 2 * op. k, op. k+ 1 : 2 * op. k) .= Jₖ
164
172
173
+ # updates related to D^(1/2)
174
+ view (op. intermediate_diagonal. diag, 1 : op. k) .= sqrt .(view (op. Dₖ. diag, 1 : op. k))
175
+ view (op. intermediate_1, 1 : op. k,1 : op. k) .= .- view (op. intermediate_diagonal, 1 : op. k, 1 : op. k)
176
+ view (op. intermediate_2, 1 : op. k, 1 : op. k) .= view (op. intermediate_diagonal, 1 : op. k, 1 : op. k)
177
+
178
+ # updates related to D^(-1/2)
179
+ view (op. intermediate_diagonal. diag, 1 : op. k) .= (x -> 1 / sqrt (x)). (view (op. Dₖ. diag, 1 : op. k))
180
+ mul! (view (op. intermediate_1, 1 : op. k,op. k+ 1 : 2 * op. k), view (op. intermediate_diagonal, 1 : op. k, 1 : op. k), transpose (view (op. Lₖ, 1 : op. k, 1 : op. k)))
181
+ # view(op.intermediate_1, 1:op.k,op.k+1:2*op.k) .= view(op.Dₖ, 1:op.k, 1:op.k)^(-1/2) * transpose(view(op.Lₖ, 1:op.k, 1:op.k))
182
+ mul! (view (op. intermediate_2, op. k+ 1 : 2 * op. k, 1 : op. k), view (op. Lₖ, 1 : op. k, 1 : op. k), view (op. intermediate_diagonal, 1 : op. k, 1 : op. k))
183
+ view (op. intermediate_2, op. k+ 1 : 2 * op. k, 1 : op. k) .= view (op. intermediate_2, op. k+ 1 : 2 * op. k, 1 : op. k) .* - 1
184
+ # view(op.intermediate_2, op.k+1:2*op.k, 1:op.k) .= .- view(op.Lₖ, 1:op.k, 1:op.k) * view(op.Dₖ, 1:op.k, 1:op.k)^(-1/2)
185
+
165
186
view (op. inverse_intermediate_1, 1 : 2 * op. k, 1 : 2 * op. k) .= inv (op. intermediate_1[1 : 2 * op. k, 1 : 2 * op. k])
166
187
view (op. inverse_intermediate_2, 1 : 2 * op. k, 1 : 2 * op. k) .= inv (op. intermediate_2[1 : 2 * op. k, 1 : 2 * op. k])
167
-
168
- op. intermediate_structure_updated = true
169
188
end
170
189
171
190
# Algorithm 3.2 (p15)
172
191
function LinearAlgebra. mul! (Bv:: V , op:: CompressedLBFGS{T,M,V} , v:: V ) where {T,M,V<: AbstractVector{T} }
173
- # step 1-3 mainly done by Base.push!
174
-
175
- # steps 4 and 6, in case the intermediary structures required are not up to date
176
- (! op. intermediate_structure_updated) && (precompile_iterated_structure! (op))
177
-
192
+ # step 1-4 and 6 mainly done by Base.push!
178
193
# step 5
179
194
mul! (view (op. sol, 1 : op. k), transpose (view (op. Yₖ, :, 1 : op. k)), v)
180
195
mul! (view (op. sol, op. k+ 1 : 2 * op. k), transpose (view (op. Sₖ, :, 1 : op. k)), v)
0 commit comments