Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

solve_shifted_system! method for LBFGS solving step in recursive way #338

Merged
merged 34 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
786bc0d
solve_shifted_system!
farhadrclass Sep 23, 2024
f95d210
Update src/utilities.jl
farhadrclass Sep 23, 2024
bac9f6f
Update src/utilities.jl
farhadrclass Sep 23, 2024
62d35f6
Update src/utilities.jl
farhadrclass Sep 23, 2024
186b6c5
Update src/utilities.jl
farhadrclass Sep 23, 2024
0d4f952
Update src/utilities.jl
farhadrclass Sep 23, 2024
4672bd3
Update src/utilities.jl
farhadrclass Sep 23, 2024
f3ea738
Update src/utilities.jl
farhadrclass Sep 23, 2024
4bf8f55
Update src/utilities.jl
farhadrclass Sep 23, 2024
025645e
Update src/utilities.jl
farhadrclass Sep 23, 2024
94fb35f
changes after review
farhadrclass Sep 23, 2024
ded60c1
Update src/lbfgs.jl
farhadrclass Sep 28, 2024
e5b054a
Update src/lbfgs.jl
farhadrclass Sep 28, 2024
6c40d0a
Update src/utilities.jl
farhadrclass Sep 28, 2024
773f2fd
Update src/utilities.jl
farhadrclass Sep 28, 2024
13162dc
Update src/utilities.jl
farhadrclass Sep 28, 2024
2cf4246
updated according to the PR review
farhadrclass Oct 2, 2024
5c1eeae
updated according to PR, renamed variable
farhadrclass Oct 2, 2024
1323a98
added ldiv!
farhadrclass Oct 3, 2024
d1da6ef
Update src/utilities.jl
farhadrclass Oct 4, 2024
ad9567f
Update src/utilities.jl
farhadrclass Oct 4, 2024
d5c1cfd
Update src/utilities.jl
farhadrclass Oct 4, 2024
759ab02
Update src/utilities.jl
farhadrclass Oct 4, 2024
3094644
Update src/utilities.jl
farhadrclass Oct 4, 2024
88479e5
Update src/utilities.jl
farhadrclass Oct 4, 2024
bc6ba12
Update src/utilities.jl
farhadrclass Oct 4, 2024
5a173ef
Update src/utilities.jl
farhadrclass Oct 4, 2024
4ad62e6
Update src/utilities.jl
farhadrclass Oct 4, 2024
17ffb34
Update src/utilities.jl
farhadrclass Oct 4, 2024
87bd7b6
Update src/utilities.jl
farhadrclass Oct 4, 2024
e039299
Update test/test_solve_shifted_system.jl
farhadrclass Oct 4, 2024
89d28d6
Update test/test_solve_shifted_system.jl
farhadrclass Oct 4, 2024
aa4c8a3
added the example
farhadrclass Oct 4, 2024
90084b9
Update utilities.jl
farhadrclass Oct 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ Function | Description
`size` | Return the size of a linear operator
`symmetric` | Determine whether the operator is symmetric
`normest` | Estimate the 2-norm
`solve_shifted_system!` | Solves linear system $(B + \sigma I) x = b$, where $B$ is a forward L-BFGS operator and $\sigma \geq 0$.


## Other Operations on Operators
Expand Down
6 changes: 6 additions & 0 deletions src/lbfgs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ mutable struct LBFGSData{T, I <: Integer}
b::Vector{Vector{T}}
insert::I
Ax::Vector{T}
shifted_p::Matrix{T} # Temporary matrix used in the computation solve_shifted_system!
shifted_v::Vector{T}
shifted_u::Vector{T}
end

function LBFGSData(
Expand Down Expand Up @@ -43,6 +46,9 @@ function LBFGSData(
inverse ? Vector{T}(undef, 0) : [zeros(T, n) for _ = 1:mem],
1,
Vector{T}(undef, n),
Array{T}(undef, (n, 2*mem)),
Vector{T}(undef, 2*mem),
Vector{T}(undef, n)
)
end

Expand Down
114 changes: 113 additions & 1 deletion src/utilities.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export check_ctranspose, check_hermitian, check_positive_definite, normest
export check_ctranspose, check_hermitian, check_positive_definite, normest, solve_shifted_system!, ldiv!
import LinearAlgebra.ldiv!

"""
normest(S) estimates the matrix 2-norm of S.
Expand Down Expand Up @@ -145,3 +146,114 @@ end

check_positive_definite(M::AbstractMatrix; kwargs...) =
check_positive_definite(LinearOperator(M); kwargs...)


"""
solve_shifted_system!(x,
B,
b,
σ,
)

farhadrclass marked this conversation as resolved.
Show resolved Hide resolved
Solves linear system (B + σI) x = b, where B is a forward L-BFGS operator and σ ≥ 0.

farhadrclass marked this conversation as resolved.
Show resolved Hide resolved
### Parameters

farhadrclass marked this conversation as resolved.
Show resolved Hide resolved
- `x::AbstractVector{T}`: A preallocated vector a vector of length n that is used to store the solution x.
- `B::LBFGSOperator{T,I,F1,F2,F3}`: forward L-BFGS operator, a LinearOperator that models a matrix of dimension nxn;
farhadrclass marked this conversation as resolved.
Show resolved Hide resolved
- `b::AbstractVector{T}`: The vector of length n.
farhadrclass marked this conversation as resolved.
Show resolved Hide resolved
- `σ::T`: Nonnegative shift scalar.
farhadrclass marked this conversation as resolved.
Show resolved Hide resolved

farhadrclass marked this conversation as resolved.
Show resolved Hide resolved
### Returns

- `x::AbstractVector{T}`: The solution vector `x` size n, the solution to `(B + σI) x = b`.

farhadrclass marked this conversation as resolved.
Show resolved Hide resolved
### Method

The method uses a two-loop recursion-like approach with modifications to handle the shift `σ`.

### References
Erway, J. B., Jain, V., & Marcia, R. F. (2014). Shifted L-BFGS Systems. Optimization Methods and Software, 29(5), 992-1004.
"""
farhadrclass marked this conversation as resolved.
Show resolved Hide resolved
function solve_shifted_system!(
x::AbstractVector{T},
B::LBFGSOperator{T, I, F1, F2, F3},
b::AbstractVector{T},
σ::T,
) where {T, I, F1, F2, F3}
farhadrclass marked this conversation as resolved.
Show resolved Hide resolved

# check if σ < 0
if σ < 0
farhadrclass marked this conversation as resolved.
Show resolved Hide resolved
throw(ArgumentError("σ must be nonnegative"))
end
data = B.data
insert = data.insert

γ_inv = 1 / data.scaling_factor
x_0 = 1 / (γ_inv + σ)
@. x = x_0 * b

max_i = 2 * data.mem
sign_i = 1

for i = 1:max_i
j = (i + 1) ÷ 2
k = mod(insert + j - 1, data.mem) + 1
data.shifted_u .= ((sign_i == -1) ? data.b[k] : data.a[k])

@. data.shifted_p[:, i] = x_0 * data.shifted_u

sign_t = 1
for t = 1:(i - 1)
c0 = dot(view(data.shifted_p, :, t), data.shifted_u)
c1= sign_t .*data.shifted_v[t]
c2 = c1 * c0
view(data.shifted_p, :, i) .+= c2 .* view(data.shifted_p, :, t)
sign_t = -sign_t
end

data.shifted_v[i] = 1 / (1 - sign_i * dot(data.shifted_u, view(data.shifted_p, :, i)))
x .+= sign_i *data.shifted_v[i] * (view(data.shifted_p, :, i)' * b) .* view(data.shifted_p, :, i)
sign_i = -sign_i
end
return x
end


"""
ldiv!(x::AbstractVector{T}, B::LBFGSOperator{T, I, F1, F2, F3}, b::AbstractVector{T}) where {T, I, F1, F2, F3}

farhadrclass marked this conversation as resolved.
Show resolved Hide resolved
Solves the linear system defined by the L-BFGS operator `B` and the right-hand side vector `b`, storing the solution in the vector `x`.

farhadrclass marked this conversation as resolved.
Show resolved Hide resolved
### Arguments:

- `x::AbstractVector{T}`: The solution vector, which will be modified in-place.
- `B::LBFGSOperator{T, I, F1, F2, F3}`: The L-BFGS operator that defines the linear system.
farhadrclass marked this conversation as resolved.
Show resolved Hide resolved
- `b::AbstractVector{T}`: The right-hand side vector of the linear system.

### Returns:

- `x::AbstractVector{T}`: The modified solution vector containing the solution to the linear system.

### Examples:

```julia

# Create an L-BFGS operator
B = LBFGSOperator(10)

farhadrclass marked this conversation as resolved.
Show resolved Hide resolved
# Generate random vectors
x = rand(10)
b = rand(10)

# Solve the linear system
ldiv!(x, B, b)

# The vector `x` now contains the solution
"""

function ldiv!(x::AbstractVector{T}, B::LBFGSOperator{T, I, F1, F2, F3}, b::AbstractVector{T}) where {T, I, F1, F2, F3}
# Call solve_shifted_system! with σ = 0
solve_shifted_system!(x, B, b, T(0.0))
return x
end
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ include("test_deprecated.jl")
include("test_normest.jl")
include("test_diag.jl")
include("test_chainrules.jl")
include("test_solve_shifted_system.jl")
67 changes: 67 additions & 0 deletions test/test_solve_shifted_system.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using Test
using LinearOperators
using LinearAlgebra

function setup_test_val(; M = 5, n = 100, scaling = false, σ = 0.1)
B = LBFGSOperator(n, mem = M, scaling = scaling)
H = InverseLBFGSOperator(n, mem = M, scaling = false)

for _ = 1:10
s = rand(n)
y = rand(n)
push!(B, s, y)
push!(H, s, y)
end

x = randn(n)
b = B * x + σ .* x # so we know the true answer is x

return B, H , b, σ, zeros(n), x
end

function test_solve_shifted_system()
@testset "solve_shifted_system! Default setup test" begin
# Setup Test Case 1: Default setup from setup_test_val
B,_, b, σ, x_sol, x_true = setup_test_val(n = 100, M = 5)

result = solve_shifted_system!(x_sol, B, b, σ)

# Test 1: Check if result is a vector of the same size as z
@test length(result) == length(b)

# Test 2: Verify that x_sol (result) is modified in place
@test result === x_sol

# Test 3: Check if the function produces finite values
@test all(isfinite, result)

# Test 4: Check if x_sol is close to the known solution x
@test isapprox(x_sol, x_true, atol = 1e-6, rtol = 1e-6)
end
@testset "solve_shifted_system! Negative σ test" begin
# Setup Test Case 2: Negative σ
B,_, b, _, x_sol, _ = setup_test_val(n = 100, M = 5)
σ = -0.1

# Expect an ArgumentError to be thrown
@test_throws ArgumentError solve_shifted_system!(x_sol, B, b, σ)
end

@testset "ldiv! test" begin
# Setup Test Case 1: Default setup from setup_test_val
B, H, b, _, x_sol, x_true = setup_test_val(n = 100, M = 5, σ = 0.0)


farhadrclass marked this conversation as resolved.
Show resolved Hide resolved
# Solve the system using solve_shifted_system!
result = ldiv!(x_sol, B, b)

# Check consistency with operator-vector product using H
x_H = H * b
@test isapprox(x_sol, x_H, atol = 1e-6, rtol = 1e-6)
@test isapprox(x_sol, x_true, atol = 1e-6, rtol = 1e-6)
end


farhadrclass marked this conversation as resolved.
Show resolved Hide resolved
end

test_solve_shifted_system()
dpo marked this conversation as resolved.
Show resolved Hide resolved
Loading