Skip to content

Commit 888e808

Browse files
authored
Add tutorial benchmarking subsolvers (#139)
1 parent 0b2f32c commit 888e808

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[deps]
2+
ADNLPModels = "54578032-b7ea-4c30-94aa-7cbd1cce6c9a"
3+
JSOSolvers = "10dff2fc-5484-5881-a0e0-c90441020f8a"
4+
Krylov = "ba0b0d4f-ebba-5204-a429-3ac8c609bfb7"
5+
OptimizationProblems = "5049e819-d29b-5fba-b941-0eee7e64c1c6"
6+
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
7+
SolverBenchmark = "581a75fa-a23a-52d0-a590-d6201de2218a"
8+
9+
[compat]
10+
ADNLPModels = "0.7"
11+
JSOSolvers = "0.11"
12+
Krylov = "0.9"
13+
OptimizationProblems = "0.7"
14+
Plots = "1"
15+
SolverBenchmark = "0.6"
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
title: "Comparing subsolvers for NLS solvers"
3+
tags: ["solvers", "krylov", "benchmark", "least squares"]
4+
author: "Tangi Migot"
5+
---
6+
7+
# Comparing subsolvers for nonlinear least squares JSOSolvers solvers
8+
9+
This tutorial showcases some advanced features of solvers in JSOSolvers.
10+
11+
```julia
12+
using JSOSolvers
13+
```
14+
15+
We benchmark different subsolvers used in the solvers TRUNK for unconstrained nonlinear least squares problems.
16+
The first step is to select a set of problems that are nonlinear least squares.
17+
18+
```julia
19+
using ADNLPModels
20+
using OptimizationProblems
21+
using OptimizationProblems.ADNLPProblems
22+
df = OptimizationProblems.meta
23+
names = df[(df.objtype .== :least_squares) .& (df.contype .== :unconstrained), :name]
24+
ad_problems = (eval(Meta.parse(problem))(use_nls = true) for problem ∈ names)
25+
```
26+
27+
These problems are [`ADNLSModel`](https://github.com/JuliaSmoothOptimizers/ADNLPModels.jl) so derivatives are generated using automatic differentiation.
28+
29+
```julia
30+
nls = first(ad_problems)
31+
typeof(nls)
32+
```
33+
34+
The solvers TRON and TRUNK are trust-region based methods that compute a search direction by means of solving iteratively a linear least squares problem.
35+
For this task, several solvers are available.
36+
37+
```julia
38+
JSOSolvers.trunkls_allowed_subsolvers
39+
```
40+
41+
This benchmark could also be followed for the solver TRON where the following subsolver are available.
42+
43+
```julia
44+
JSOSolvers.tronls_allowed_subsolvers
45+
```
46+
47+
These linear least squares solvers are implemented in the package [Krylov.jl](https://github.com/JuliaSmoothOptimizers/Krylov.jl).
48+
49+
```julia
50+
using Krylov
51+
```
52+
53+
We define a dictionary of the different solvers that will be benchmarked.
54+
We consider here four variants of TRUNK using the different subsolvers.
55+
56+
```julia
57+
solvers = Dict(
58+
:trunk_cgls => model -> trunk(model, subsolver_type = CglsSolver),
59+
:trunk_crls => model -> trunk(model, subsolver_type = CrlsSolver),
60+
:trunk_lsqr => model -> trunk(model, subsolver_type = LsqrSolver),
61+
:trunk_lsmr => model -> trunk(model, subsolver_type = LsmrSolver)
62+
)
63+
```
64+
65+
Using [`SolverBenchmark.jl`](https://github.com/JuliaSmoothOptimizers/SolverBenchmark.jl) functionalities, the solvers are executed over all the test problems.
66+
67+
```julia
68+
using SolverBenchmark
69+
stats = bmark_solvers(solvers, ad_problems)
70+
```
71+
72+
The result is stored in a dictionary of `DataFrame` that can be used to analyze the results.
73+
74+
```julia
75+
first_order(df) = df.status .== :first_order
76+
unbounded(df) = df.status .== :unbounded
77+
solved(df) = first_order(df) .| unbounded(df)
78+
79+
costnames = ["time"]
80+
costs = [df -> .!solved(df) .* Inf .+ df.elapsed_time]
81+
```
82+
83+
We compare the four variants based on their execution time.
84+
More advanced comparisons could include the number of evaluations of the objective, gradient, or Hessian-vector products.
85+
86+
```julia
87+
using Plots
88+
gr()
89+
90+
profile_solvers(stats, costs, costnames)
91+
```
92+
93+
The CRLS and CGLS variants are the ones solving more problems, and even though the difference is rather small the CGLS variant is consistently faster which seems to indicate that it is the most appropriate subsolver for TRUNK.
94+
The size of the problems were rather small here, so this should be confirmed on larger instance.
95+
Moreover, the results may vary depending on the origin of the test problems.

0 commit comments

Comments
 (0)