Skip to content

Commit

Permalink
Add JSO-compliant solver documentation [draft] (#81)
Browse files Browse the repository at this point in the history
  • Loading branch information
tmigot authored Dec 26, 2023
1 parent ca1ce4b commit aebe012
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 1 deletion.
6 changes: 5 additions & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ makedocs(
prettyurls = get(ENV, "CI", nothing) == "true",
),
sitename = "SolverCore.jl",
pages = ["Home" => "index.md", "Reference" => "reference.md"],
pages = [
"Home" => "index.md",
"JSO-compliant solvers" => "jso-compliant.md",
"Reference" => "reference.md",
],
)

deploydocs(
Expand Down
32 changes: 32 additions & 0 deletions docs/src/jso-compliant.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# JSO-compliant solvers

The following are JSO-compliance expectations and recommendations that are implemented in JuliaSmoothOptimizers.

## Mandatory

- Create a function `solver_name(nlp::AbstractNLPModel; kwargs...)` that returns a `GenericExecutionStats`.

## Recommended

- Create a solver object `SolverName <: SolverCore.AbstractOptimizationSolver`.
- Store all memory-allocating things inside this object. This includes vectors, matrices, and possibly other objects.
- One of these objects should be `solver.x`, that stores the current iterate.
- Implement a constructor `SolverName(nlp; kwargs...)`.
- Implement `SolverCore.solve!(solver, nlp::AbstractNLPModel, stats::GenericExecutionStats)` and change `solver_name` to create a `SolverName` object and call `solve!`.
- Make sure that `solve!` is not allocating.
- Accept the following keyword arguments (`T` is float type and `V` is the container type):
- `x::V = nlp.meta.x0`: The starting point.
- `atol::T = sqrt(eps(T))`: Absolute tolerance for the gradient. Use in conjunction with the relative tolerance below to check $\Vert \nabla f(x_k)\Vert \leq \epsilon_a + \epsilon_r\Vert \nabla f(x_0)\Vert$.
- `rtol::T = sqrt(eps(T))`: Relative tolerance for the gradient. See `atol` above.
- `max_eval::Int = -1`: Maximum number of objective function evaluation plus constraint function evaluations. Negative number means unlimited.
- `max_iter::Int = typemax(Int)`: Maximum number of iterations.
- `max_time::Float64 = 30.0`: Maximum elapsed time.
- `verbose::Int = 0`: Verbosity level. `0` means nothing and `1` means something. There are no rules on the level of verbosity yet.
- `callback = (nlp, solver, stats) -> nothing`: A callback function to be called at the end of an iteration, before exit status are defined.
- Use `set_status!` and `get_status` to update `stats` before starting the method loop, and at the end of every iteration.
- Call the `callback` after running `set_status!` in both places.
- Define `done = stats.status != :unknown` and loop with `while !done`.
- To check for logic errors and stop the method use `set_status!(stats, ...)`, `done = true`, and `continue`, where the second argument of `set_status!` is one of the statuses available in SolverCore.STATUSES. You can call `SolverCore.show_statuses()` to see them. If you need more specific statuses, create an issue.
- Use the `set_...!(stats, ...)` functions from `SolverCore` to update the `stats`. For instance, `set_objective!(stats, f)`, `set_time!(stats, time() - start_time)`, and `set_dual_residual!(stats, gnorm)`.
- Don't log when `verbose == 0`. When logging, use `@info log_header(...)` and `@info log_row(...)`.
- Write docstrings for `SolverName`. The format is still a bit loose.

0 comments on commit aebe012

Please sign in to comment.