@@ -36,7 +36,6 @@ In addition to this structures which are circurlarly update when `k` reaches `m`
3636- `inverse_intermediate_2`: a R²ᵏˣ²ᵏ matrix;
3737- `intermediary_vector`: a vector ∈ Rᵏ to store intermediate solutions;
3838- `sol`: a vector ∈ Rᵏ to store intermediate solutions;
39- - `intermediate_structure_updated`: inform if the intermediate structures are up-to-date or not.
4039This implementation is designed to work either on CPU or GPU.
4140"""
4241mutable struct CompressedLBFGS{T, M<: AbstractMatrix{T} , V<: AbstractVector{T} }
@@ -50,26 +49,26 @@ mutable struct CompressedLBFGS{T, M<:AbstractMatrix{T}, V<:AbstractVector{T}}
5049 Lₖ:: LowerTriangular{T,M} # m * m
5150
5251 chol_matrix:: M # 2m * 2m
52+ intermediate_diagonal:: Diagonal{T,V} # m * m
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
5858 sol:: V # m
59- intermediate_structure_updated:: Bool
6059end
6160
6261default_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}
6564
6665"""
6766 CompressedLBFGS(n::Int; [T=Float64, m=5], gpu:Bool)
6867
6968A implementation of a LBFGS operator (forward), representing a `nxn` linear application.
7069It considers at most `k` BFGS iterates, and fit the architecture depending if it is launched on a CPU or a GPU.
7170"""
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))
7372 α = (T)(1 )
7473 k = 0
7574 Sₖ = M (undef, n, m)
@@ -78,14 +77,14 @@ function CompressedLBFGS(n::Int; m::Int=5, T=Float64, gpu=default_gpu(), M=defau
7877 Lₖ = LowerTriangular (M (undef, m, m))
7978
8079 chol_matrix = M (undef, m, m)
80+ intermediate_diagonal = Diagonal (V (undef, m))
8181 intermediate_1 = UpperTriangular (M (undef, 2 * m, 2 * m))
8282 intermediate_2 = LowerTriangular (M (undef, 2 * m, 2 * m))
8383 inverse_intermediate_1 = UpperTriangular (M (undef, 2 * m, 2 * m))
8484 inverse_intermediate_2 = LowerTriangular (M (undef, 2 * m, 2 * m))
8585 intermediary_vector = V (undef, 2 * m)
8686 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)
8988end
9089
9190function 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
109108 # for the time being, reinstantiate completely the Lₖ matrix
110109 for j in 1 : op. k
111110 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) )
113112 end
114113 end
115114 end
115+
116+ # step 4 and 6
117+ precompile_iterated_structure! (op)
118+
116119 # secant equation fails if uncommented
117120 # op.α = dot(y,s)/dot(s,s)
118- op. intermediate_structure_updated = false
119121 return op
120122end
121123
141143
142144# Algorithm 3.2 (p15)
143145# 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+
146158 cholesky! (Symmetric (view (op. chol_matrix, 1 : op. k, 1 : op. k)))
147159 Jₖ = transpose (UpperTriangular (view (op. chol_matrix, 1 : op. k, 1 : op. k)))
148160 return Jₖ
@@ -152,29 +164,32 @@ end
152164function precompile_iterated_structure! (op:: CompressedLBFGS )
153165 Jₖ = inverse_cholesky (op)
154166
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
157168 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 )
161169 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ₖ )
163171 view (op. intermediate_2, op. k+ 1 : 2 * op. k, op. k+ 1 : 2 * op. k) .= Jₖ
164172
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+
165186 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])
166187 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
169188end
170189
171190# Algorithm 3.2 (p15)
172191function 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!
178193 # step 5
179194 mul! (view (op. sol, 1 : op. k), transpose (view (op. Yₖ, :, 1 : op. k)), v)
180195 mul! (view (op. sol, op. k+ 1 : 2 * op. k), transpose (view (op. Sₖ, :, 1 : op. k)), v)
0 commit comments