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

Add JSO-compliant solver documentation [draft] #81

Merged
merged 1 commit into from
Dec 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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.
Loading