Skip to content

Commit d56d086

Browse files
Merge pull request #986 from ParamThakkar123/refactor-lbfgs
New Subpackage for LBFGS
2 parents a7946a3 + acfb510 commit d56d086

File tree

7 files changed

+118
-51
lines changed

7 files changed

+118
-51
lines changed

.github/workflows/CI.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ jobs:
2424
- OptimizationCMAEvolutionStrategy
2525
- OptimizationEvolutionary
2626
- OptimizationGCMAES
27+
- OptimizationLBFGSB
2728
- OptimizationIpopt
2829
- OptimizationManopt
2930
- OptimizationMetaheuristics

Project.toml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "Optimization"
22
uuid = "7f7a1694-90dd-40f0-9382-eb1efda571ba"
3-
version = "5.0.0"
3+
version = "4.8.0"
44

55
[deps]
66
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
@@ -39,7 +39,6 @@ Flux = "0.13, 0.14, 0.15, 0.16"
3939
ForwardDiff = "0.10, 1"
4040
Ipopt = "1"
4141
IterTools = "1.3"
42-
LBFGSB = "0.4.1"
4342
LinearAlgebra = "1.10"
4443
Logging = "1.10"
4544
LoggingExtras = "0.4, 1"
@@ -48,6 +47,7 @@ MLUtils = "0.4"
4847
ModelingToolkit = "10.23"
4948
Mooncake = "0.4.138"
5049
Optim = ">= 1.4.1"
50+
Optimisers = ">= 0.2.5"
5151
OptimizationBase = "2"
5252
OptimizationMOI = "0.5"
5353
OptimizationOptimJL = "0.4"
@@ -56,7 +56,7 @@ OrdinaryDiffEqTsit5 = "1"
5656
Pkg = "1"
5757
Printf = "1.10"
5858
ProgressLogging = "0.1"
59-
Random = "1.10"
59+
Random = "1.10"
6060
Reexport = "1.2"
6161
ReverseDiff = "1"
6262
SafeTestsets = "0.1"
@@ -67,7 +67,6 @@ Symbolics = "6"
6767
TerminalLoggers = "0.1"
6868
Test = "1.10"
6969
Tracker = "0.2"
70-
Optimisers = ">= 0.2.5"
7170
Zygote = "0.6, 0.7"
7271
julia = "1.10"
7372

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name = "OptimizationLBFGSB"
2+
uuid = "22f7324a-a79d-40f2-bebe-3af60c77bd15"
3+
authors = ["paramthakkar123 <[email protected]>"]
4+
version = "0.1.0"
5+
6+
[deps]
7+
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
8+
LBFGSB = "5be7bae1-8223-5378-bac3-9e7378a2f6e6"
9+
Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba"
10+
OptimizationBase = "bca83a33-5cc9-4baa-983d-23429ab6bcbb"
11+
12+
[extras]
13+
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
14+
MLUtils = "f1d291b0-491e-4a28-83b9-f70985020b54"
15+
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
16+
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
17+
18+
[compat]
19+
DocStringExtensions = "0.9.5"
20+
ForwardDiff = "1.0.1"
21+
LBFGSB = "0.4.1"
22+
MLUtils = "0.4.8"
23+
Optimization = "4.4.0"
24+
OptimizationBase = "2.10.0"
25+
Zygote = "0.7.10"
26+
27+
[targets]
28+
test = ["Test", "ForwardDiff", "MLUtils", "Zygote"]

src/lbfgsb.jl renamed to lib/OptimizationLBFGSB/src/OptimizationLBFGSB.jl

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
using Optimization.SciMLBase, LBFGSB
1+
module OptimizationLBFGSB
2+
3+
using Optimization
4+
using DocStringExtensions
5+
import LBFGSB as LBFGSBJL
6+
using OptimizationBase.SciMLBase: OptimizationStats, OptimizationFunction
7+
using OptimizationBase: ReturnCode
8+
using OptimizationBase.LinearAlgebra: norm
9+
using Optimization: deduce_retcode
210

311
"""
412
$(TYPEDEF)
@@ -12,7 +20,7 @@ References
1220
- C. Zhu, R. H. Byrd and J. Nocedal. L-BFGS-B: Algorithm 778: L-BFGS-B, FORTRAN routines for large scale bound constrained optimization (1997), ACM Transactions on Mathematical Software, Vol 23, Num. 4, pp. 550 - 560.
1321
- J.L. Morales and J. Nocedal. L-BFGS-B: Remark on Algorithm 778: L-BFGS-B, FORTRAN routines for large scale bound constrained optimization (2011), to appear in ACM Transactions on Mathematical Software.
1422
"""
15-
@kwdef struct LBFGS
23+
@kwdef struct LBFGSB
1624
m::Int = 10
1725
τ = 0.5
1826
γ = 10.0
@@ -24,21 +32,21 @@ References
2432
end
2533

2634
@static if isdefined(SciMLBase, :supports_opt_cache_interface)
27-
SciMLBase.supports_opt_cache_interface(::LBFGS) = true
35+
SciMLBase.supports_opt_cache_interface(::LBFGSB) = true
2836
end
2937
@static if isdefined(OptimizationBase, :supports_opt_cache_interface)
30-
OptimizationBase.supports_opt_cache_interface(::LBFGS) = true
38+
OptimizationBase.supports_opt_cache_interface(::LBFGSB) = true
3139
end
32-
SciMLBase.allowsbounds(::LBFGS) = true
33-
SciMLBase.requiresgradient(::LBFGS) = true
34-
SciMLBase.allowsconstraints(::LBFGS) = true
35-
SciMLBase.requiresconsjac(::LBFGS) = true
40+
SciMLBase.allowsbounds(::LBFGSB) = true
41+
SciMLBase.requiresgradient(::LBFGSB) = true
42+
SciMLBase.allowsconstraints(::LBFGSB) = true
43+
SciMLBase.requiresconsjac(::LBFGSB) = true
3644

3745
function task_message_to_string(task::Vector{UInt8})
3846
return String(task)
3947
end
4048

41-
function __map_optimizer_args(cache::Optimization.OptimizationCache, opt::LBFGS;
49+
function __map_optimizer_args(cache::OptimizationCache, opt::LBFGSB;
4250
callback = nothing,
4351
maxiters::Union{Number, Nothing} = nothing,
4452
maxtime::Union{Number, Nothing} = nothing,
@@ -91,7 +99,7 @@ function SciMLBase.__solve(cache::OptimizationCache{
9199
UC,
92100
S,
93101
O <:
94-
LBFGS,
102+
LBFGSB,
95103
D,
96104
P,
97105
C
@@ -130,7 +138,7 @@ function SciMLBase.__solve(cache::OptimizationCache{
130138
cons_tmp[eq_inds] .= cons_tmp[eq_inds] - cache.lcons[eq_inds]
131139
cons_tmp[ineq_inds] .= cons_tmp[ineq_inds] .- cache.ucons[ineq_inds]
132140
opt_state = Optimization.OptimizationState(
133-
u = θ, objective = x[1], p = cache.p, iter = iter_count[])
141+
u = θ, objective = x[1])
134142
if cache.callback(opt_state, x...)
135143
error("Optimization halted by callback.")
136144
end
@@ -172,11 +180,11 @@ function SciMLBase.__solve(cache::OptimizationCache{
172180

173181
if cache.lb === nothing
174182
optimizer,
175-
bounds = LBFGSB._opt_bounds(
183+
bounds = LBFGSBJL._opt_bounds(
176184
n, cache.opt.m, [-Inf for i in 1:n], [Inf for i in 1:n])
177185
else
178186
optimizer,
179-
bounds = LBFGSB._opt_bounds(
187+
bounds = LBFGSBJL._opt_bounds(
180188
n, cache.opt.m, solver_kwargs.lb, solver_kwargs.ub)
181189
end
182190

@@ -209,7 +217,7 @@ function SciMLBase.__solve(cache::OptimizationCache{
209217
end
210218
end
211219

212-
stats = Optimization.OptimizationStats(; iterations = maxiters,
220+
stats = OptimizationStats(; iterations = maxiters,
213221
time = 0.0, fevals = maxiters, gevals = maxiters)
214222
return SciMLBase.build_solution(
215223
cache, cache.opt, res[2], cache.f(res[2], cache.p)[1],
@@ -220,7 +228,7 @@ function SciMLBase.__solve(cache::OptimizationCache{
220228
x = cache.f(θ, cache.p)
221229
iter_count[] += 1
222230
opt_state = Optimization.OptimizationState(
223-
u = θ, objective = x[1], p = cache.p, iter = iter_count[])
231+
u = θ, objective = x[1])
224232
if cache.callback(opt_state, x...)
225233
error("Optimization halted by callback.")
226234
end
@@ -231,11 +239,11 @@ function SciMLBase.__solve(cache::OptimizationCache{
231239

232240
if cache.lb === nothing
233241
optimizer,
234-
bounds = LBFGSB._opt_bounds(
242+
bounds = LBFGSBJL._opt_bounds(
235243
n, cache.opt.m, [-Inf for i in 1:n], [Inf for i in 1:n])
236244
else
237245
optimizer,
238-
bounds = LBFGSB._opt_bounds(
246+
bounds = LBFGSBJL._opt_bounds(
239247
n, cache.opt.m, solver_kwargs.lb, solver_kwargs.ub)
240248
end
241249

@@ -261,3 +269,7 @@ function SciMLBase.__solve(cache::OptimizationCache{
261269
retcode = opt_ret, original = optimizer)
262270
end
263271
end
272+
273+
export LBFGSB
274+
275+
end
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using OptimizationBase
2+
using OptimizationBase: ReturnCode
3+
using OptimizationBase.SciMLBase: OptimizationFunction, OptimizationProblem
4+
using ForwardDiff, Zygote
5+
using OptimizationLBFGSB
6+
using MLUtils
7+
using LBFGSB
8+
using Test
9+
10+
@testset "OptimizationLBFGSB.jl" begin
11+
x0 = zeros(2)
12+
rosenbrock(x, p = nothing) = (1 - x[1])^2 + 100 * (x[2] - x[1]^2)^2
13+
l1 = rosenbrock(x0)
14+
15+
optf = OptimizationFunction(rosenbrock, OptimizationBase.AutoForwardDiff())
16+
prob = OptimizationProblem(optf, x0)
17+
@time res = solve(prob, OptimizationLBFGSB.LBFGSB(), maxiters = 100)
18+
@test res.retcode == ReturnCode.Success
19+
20+
prob = OptimizationProblem(optf, x0, lb = [-1.0, -1.0], ub = [1.0, 1.0])
21+
@time res = solve(prob, OptimizationLBFGSB.LBFGSB(), maxiters = 100)
22+
@test res.retcode == ReturnCode.Success
23+
24+
function con2_c(res, x, p)
25+
res .= [x[1]^2 + x[2]^2, (x[2] * sin(x[1]) + x[1]) - 5]
26+
end
27+
28+
optf = OptimizationFunction(rosenbrock, OptimizationBase.AutoZygote(), cons = con2_c)
29+
prob = OptimizationProblem(optf, x0, lcons = [1.0, -Inf],
30+
ucons = [1.0, 0.0], lb = [-1.0, -1.0],
31+
ub = [1.0, 1.0])
32+
@time res = solve(prob, OptimizationLBFGSB.LBFGSB(), maxiters = 100)
33+
@test res.retcode == SciMLBase.ReturnCode.Success
34+
35+
x0 = (-pi):0.001:pi
36+
y0 = sin.(x0)
37+
data = MLUtils.DataLoader((x0, y0), batchsize = 126)
38+
function loss(coeffs, data)
39+
ypred = [evalpoly(data[1][i], coeffs) for i in eachindex(data[1])]
40+
return sum(abs2, ypred .- data[2])
41+
end
42+
43+
function cons1(res, coeffs, p = nothing)
44+
res[1] = coeffs[1] * coeffs[5] - 1
45+
return nothing
46+
end
47+
48+
optf = OptimizationFunction(loss, AutoSparseForwardDiff(), cons = cons1)
49+
callback = (st, l) -> (@show l; return false)
50+
51+
initpars = rand(5)
52+
l0 = optf(initpars, (x0, y0))
53+
prob = OptimizationProblem(optf, initpars, (x0, y0), lcons = [-Inf], ucons = [0.5],
54+
lb = [-10.0, -10.0, -10.0, -10.0, -10.0], ub = [10.0, 10.0, 10.0, 10.0, 10.0])
55+
opt1 = solve(prob, OptimizationLBFGSB.LBFGSB(), maxiters = 1000, callback = callback)
56+
@test opt1.objective < l0
57+
end

src/Optimization.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ export ObjSense, MaxSense, MinSense
2222

2323
include("utils.jl")
2424
include("state.jl")
25-
include("lbfgsb.jl")
2625
include("sophia.jl")
2726

2827
export solve

test/native.jl

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,6 @@
11
using Optimization
22
using ForwardDiff, Zygote, ReverseDiff, FiniteDiff
33
using Test
4-
5-
x0 = zeros(2)
6-
rosenbrock(x, p = nothing) = (1 - x[1])^2 + 100 * (x[2] - x[1]^2)^2
7-
l1 = rosenbrock(x0)
8-
9-
optf = OptimizationFunction(rosenbrock, AutoForwardDiff())
10-
prob = OptimizationProblem(optf, x0)
11-
@time res = solve(prob, Optimization.LBFGS(), maxiters = 100)
12-
@test res.retcode == Optimization.SciMLBase.ReturnCode.Success
13-
14-
prob = OptimizationProblem(optf, x0, lb = [-1.0, -1.0], ub = [1.0, 1.0])
15-
@time res = solve(prob, Optimization.LBFGS(), maxiters = 100)
16-
@test res.retcode == Optimization.SciMLBase.ReturnCode.Success
17-
18-
function con2_c(res, x, p)
19-
res .= [x[1]^2 + x[2]^2, (x[2] * sin(x[1]) + x[1]) - 5]
20-
end
21-
22-
optf = OptimizationFunction(rosenbrock, AutoZygote(), cons = con2_c)
23-
prob = OptimizationProblem(optf, x0, lcons = [1.0, -Inf],
24-
ucons = [1.0, 0.0], lb = [-1.0, -1.0],
25-
ub = [1.0, 1.0])
26-
@time res = solve(prob, Optimization.LBFGS(), maxiters = 100)
27-
@test res.retcode == SciMLBase.ReturnCode.Success
28-
294
using MLUtils, OptimizationOptimisers
305

316
x0 = (-pi):0.001:pi
@@ -46,10 +21,6 @@ callback = (st, l) -> (@show l; return false)
4621

4722
initpars = rand(5)
4823
l0 = optf(initpars, (x0, y0))
49-
prob = OptimizationProblem(optf, initpars, (x0, y0), lcons = [-Inf], ucons = [0.5],
50-
lb = [-10.0, -10.0, -10.0, -10.0, -10.0], ub = [10.0, 10.0, 10.0, 10.0, 10.0])
51-
opt1 = solve(prob, Optimization.LBFGS(), maxiters = 1000, callback = callback)
52-
@test opt1.objective < l0
5324

5425
optf1 = OptimizationFunction(loss, AutoSparseForwardDiff())
5526
prob1 = OptimizationProblem(optf1, rand(5), data)

0 commit comments

Comments
 (0)