diff --git a/tutorials/advanced-jsosolvers/figures/index_11_1.png b/tutorials/advanced-jsosolvers/figures/index_11_1.png new file mode 100644 index 00000000..ca779151 Binary files /dev/null and b/tutorials/advanced-jsosolvers/figures/index_11_1.png differ diff --git a/tutorials/advanced-jsosolvers/index.md b/tutorials/advanced-jsosolvers/index.md index 24958b1d..5fd4c6f5 100644 --- a/tutorials/advanced-jsosolvers/index.md +++ b/tutorials/advanced-jsosolvers/index.md @@ -5,16 +5,16 @@ \preamble{Tangi Migot} -[![OptimizationProblems 0.7.3](https://img.shields.io/badge/OptimizationProblems-0.7.3-8b0000?style=flat-square&labelColor=cb3c33)](https://jso.dev/OptimizationProblems.jl/stable/) -[![SolverBenchmark 0.6.0](https://img.shields.io/badge/SolverBenchmark-0.6.0-006400?style=flat-square&labelColor=389826)](https://jso.dev/SolverBenchmark.jl/stable/) -![Plots 1.39.0](https://img.shields.io/badge/Plots-1.39.0-000?style=flat-square&labelColor=999) -[![ADNLPModels 0.7.0](https://img.shields.io/badge/ADNLPModels-0.7.0-8b0000?style=flat-square&labelColor=cb3c33)](https://jso.dev/ADNLPModels.jl/stable/) -[![Krylov 0.9.5](https://img.shields.io/badge/Krylov-0.9.5-4b0082?style=flat-square&labelColor=9558b2)](https://jso.dev/Krylov.jl/stable/) -[![JSOSolvers 0.11.0](https://img.shields.io/badge/JSOSolvers-0.11.0-006400?style=flat-square&labelColor=389826)](https://jso.dev/JSOSolvers.jl/stable/) +[![OptimizationProblems 0.7.4](https://img.shields.io/badge/OptimizationProblems-0.7.4-8b0000?style=flat-square&labelColor=cb3c33)](https://jso.dev/OptimizationProblems.jl/stable/) +[![SolverBenchmark 0.6.2](https://img.shields.io/badge/SolverBenchmark-0.6.2-006400?style=flat-square&labelColor=389826)](https://jso.dev/SolverBenchmark.jl/stable/) +![Plots 1.41.1](https://img.shields.io/badge/Plots-1.41.1-000?style=flat-square&labelColor=999) +[![ADNLPModels 0.7.2](https://img.shields.io/badge/ADNLPModels-0.7.2-8b0000?style=flat-square&labelColor=cb3c33)](https://jso.dev/ADNLPModels.jl/stable/) +[![Krylov 0.10.2](https://img.shields.io/badge/Krylov-0.10.2-4b0082?style=flat-square&labelColor=9558b2)](https://jso.dev/Krylov.jl/stable/) +[![JSOSolvers 0.14.3](https://img.shields.io/badge/JSOSolvers-0.14.3-006400?style=flat-square&labelColor=389826)](https://jso.dev/JSOSolvers.jl/stable/) -# Comparing subsolvers for nonlinear least squares JSOSolvers solvers +# Comparing subsolvers for nonlinear least squares in JSOSolvers This tutorial showcases some advanced features of solvers in JSOSolvers. @@ -25,7 +25,7 @@ using JSOSolvers -We benchmark different subsolvers used in the solvers TRUNK for unconstrained nonlinear least squares problems. +We benchmark different subsolvers used in the solver TRUNK for unconstrained nonlinear least squares problems. The first step is to select a set of problems that are nonlinear least squares. ```julia @@ -33,12 +33,12 @@ using ADNLPModels using OptimizationProblems using OptimizationProblems.ADNLPProblems df = OptimizationProblems.meta -names = df[(df.objtype .== :least_squares) .& (df.contype .== :unconstrained), :name] -ad_problems = (eval(Meta.parse(problem))(use_nls = true) for problem ∈ names) +problem_names = df[(df.objtype .== :least_squares) .& (df.contype .== :unconstrained), :name] +ad_problems = (eval(Meta.parse(problem))(use_nls = true) for problem ∈ problem_names) ``` ```plaintext -Base.Generator{Vector{String}, Main.var"##WeaveSandBox#292".var"#1#2"}(Main.var"##WeaveSandBox#292".var"#1#2"(), ["arglina", "arglinb", "bard", "bdqrtic", "beale", "bennett5", "boxbod", "brownal", "br +Base.Generator{Vector{String}, Main.var"##WeaveSandBox#277".var"#2#3"}(Main.var"##WeaveSandBox#277".var"#2#3"(), ["arglina", "arglinb", "bard", "bdqrtic", "beale", "bennett5", "boxbod", "brownal", "br ownbs", "brownden" … "power", "rat42", "rat43", "rozman1", "sbrybnd", "spmsrtls", "thurber", "tquartic", "vibrbeam", "watson"]) ``` @@ -69,29 +69,21 @@ JSOSolvers.trunkls_allowed_subsolvers ``` ```plaintext -4-element Vector{UnionAll}: - Krylov.CglsSolver - Krylov.CrlsSolver - Krylov.LsqrSolver - Krylov.LsmrSolver +(:cgls, :crls, :lsqr, :lsmr) ``` -This benchmark could also be followed for the solver TRON where the following subsolver are available. +This benchmark could also be followed for the solver TRON where the following subsolvers are available. ```julia JSOSolvers.tronls_allowed_subsolvers ``` ```plaintext -4-element Vector{UnionAll}: - Krylov.CglsSolver - Krylov.CrlsSolver - Krylov.LsqrSolver - Krylov.LsmrSolver +(:cgls, :crls, :lsqr, :lsmr) ``` @@ -99,32 +91,56 @@ JSOSolvers.tronls_allowed_subsolvers These linear least squares solvers are implemented in the package [Krylov.jl](https://github.com/JuliaSmoothOptimizers/Krylov.jl). +For detailed descriptions of each subsolver's algorithm and when to use it, see the [Krylov.jl documentation](https://jso.dev/Krylov.jl/stable/). + +We define a dictionary of the different solvers that will be benchmarked. +We consider here four variants of TRUNK using the different subsolvers. + +For example, to call TRUNK with an explicit subsolver: ```julia -using Krylov +stats = trunk(nls, subsolver = :cgls) ``` +```plaintext +"Execution stats: first-order stationary" +``` -We define a dictionary of the different solvers that will be benchmarked. -We consider here four variants of TRUNK using the different subsolvers. + + +The same subsolver selection pattern applies to TRON's least-squares specialization: + +```julia +stats_tron = tron(nls, subsolver = :lsmr) +``` + +```plaintext +"Execution stats: first-order stationary" +``` + + + + + +Now we define the solver dictionary for benchmarking: ```julia solvers = Dict( - :trunk_cgls => model -> trunk(model, subsolver_type = CglsSolver), - :trunk_crls => model -> trunk(model, subsolver_type = CrlsSolver), - :trunk_lsqr => model -> trunk(model, subsolver_type = LsqrSolver), - :trunk_lsmr => model -> trunk(model, subsolver_type = LsmrSolver) + :trunk_cgls => model -> trunk(model, subsolver = :cgls), + :trunk_crls => model -> trunk(model, subsolver = :crls), + :trunk_lsqr => model -> trunk(model, subsolver = :lsqr), + :trunk_lsmr => model -> trunk(model, subsolver = :lsmr) ) ``` ```plaintext Dict{Symbol, Function} with 4 entries: - :trunk_lsqr => #5 - :trunk_cgls => #3 - :trunk_crls => #4 - :trunk_lsmr => #6 + :trunk_lsqr => #12 + :trunk_cgls => #8 + :trunk_crls => #10 + :trunk_lsmr => #14 ``` @@ -140,10 +156,10 @@ stats = bmark_solvers(solvers, ad_problems) ```plaintext Dict{Symbol, DataFrames.DataFrame} with 4 entries: - :trunk_lsqr => 66×39 DataFrame… - :trunk_cgls => 66×39 DataFrame… - :trunk_crls => 66×39 DataFrame… - :trunk_lsmr => 66×39 DataFrame… + :trunk_lsqr => 66×40 DataFrame… + :trunk_cgls => 66×40 DataFrame… + :trunk_crls => 66×40 DataFrame… + :trunk_lsmr => 66×40 DataFrame… ``` @@ -162,8 +178,8 @@ costs = [df -> .!solved(df) .* Inf .+ df.elapsed_time] ``` ```plaintext -1-element Vector{Main.var"##WeaveSandBox#292".var"#11#12"}: - #11 (generic function with 1 method) +1-element Vector{Main.var"##WeaveSandBox#277".var"#17#18"}: + #17 (generic function with 1 method) ``` @@ -180,10 +196,10 @@ gr() profile_solvers(stats, costs, costnames) ``` -![](figures/index_10_1.png) +![](figures/index_11_1.png) 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. -The size of the problems were rather small here, so this should be confirmed on larger instance. +The size of the problems was rather small here, so this should be confirmed on larger instances. Moreover, the results may vary depending on the origin of the test problems.