From cef40dfbca27ee9d6e6248f94314f16619e5a8be Mon Sep 17 00:00:00 2001 From: odow Date: Fri, 27 Aug 2021 10:47:25 +1200 Subject: [PATCH 1/9] Document interface expected by subtypes --- docs/src/manual/models.md | 95 ++++++++++++++++++++++----------------- src/MathOptInterface.jl | 60 ++++++++++++++++++++++--- 2 files changed, 108 insertions(+), 47 deletions(-) diff --git a/docs/src/manual/models.md b/docs/src/manual/models.md index cca29e34de..86d5d2823d 100644 --- a/docs/src/manual/models.md +++ b/docs/src/manual/models.md @@ -62,50 +62,65 @@ functions. Consult the docstsrings of each attribute for information on what it represents. -## Model attributes +## ModelLike API -The following attributes are available for models: +Objects subtyping [`ModelLike`](ref) must implement: + + * [`isempty`](@ref) + * [`empty!`](@ref) + +The following attributes are available. Some are required by all +implementations, and others are optional. + +**Required** + + * [`ListOfConstraintAttributesSet`](@ref) + * [`ListOfConstraintIndices`](@ref) + * [`ListOfConstraintTypesPresent`](@ref) + * [`ListOfModelAttributesSet`](@ref) + * [`ListOfVariableAttributesSet`](@ref) + * [`ListOfVariableIndices`](@ref) + * [`NumberOfConstraints`](@ref) + * [`NumberOfVariables`](@ref) + +**Optional** * [`Name`](@ref) * [`ObjectiveFunction`](@ref) * [`ObjectiveFunctionType`](@ref) * [`ObjectiveSense`](@ref) - * [`NumberOfVariables`](@ref) - * [`ListOfVariableIndices`](@ref) - * [`ListOfConstraintTypesPresent`](@ref) - * [`NumberOfConstraints`](@ref) - * [`ListOfConstraintIndices`](@ref) - * [`ListOfOptimizerAttributesSet`](@ref) - * [`ListOfModelAttributesSet`](@ref) - * [`ListOfVariableAttributesSet`](@ref) - * [`ListOfConstraintAttributesSet`](@ref) -## Optimizer attributes - -The following attributes are available for optimizers: - - - [`SolverName`](@ref) - - [`RawOptimizerAttribute`](@ref) - - [`Silent`](@ref) - - [`TimeLimitSec`](@ref) - - [`NumberOfThreads`](@ref) - - [`RawSolver`](@ref) - -In addition, optimizers should implement the following attributes to provide -access to solutions: - - - [`TerminationStatus`](@ref) - - [`TerminationStatusCode`](@ref) - - [`PrimalStatus`](@ref) - - [`DualStatus`](@ref) - - [`ResultStatusCode`](@ref) - - [`RawStatusString`](@ref) - - [`ResultCount`](@ref) - - [`ObjectiveValue`](@ref) - - [`DualObjectiveValue`](@ref) - - [`ObjectiveBound`](@ref) - - [`RelativeGap`](@ref) - - [`SolveTimeSec`](@ref) - - [`SimplexIterations`](@ref) - - [`BarrierIterations`](@ref) - - [`NodeCount`](@ref) +## AbstractOptimizer API + +In addition to implementing the [ModelLike API](@ref), objects subtyping [`AbstractOptimizer`](ref) must implement: + + * [`optimize!`](@ref) + +The following attributes are available. Some are required by all +implementations, and others are optional. + +**Required** + + * [`DualStatus`](@ref) + * [`ListOfOptimizerAttributesSet`](@ref) + * [`PrimalStatus`](@ref) + * [`RawStatusString`](@ref) + * [`ResultCount`](@ref) + * [`TerminationStatus`](@ref) + +**Optional** + + * [`BarrierIterations`](@ref) + * [`DualObjectiveValue`](@ref) + * [`NodeCount`](@ref) + * [`NumberOfThreads`](@ref) + * [`ObjectiveBound`](@ref) + * [`ObjectiveValue`](@ref) + * [`RelativeGap`](@ref) + * [`RawOptimizerAttribute`](@ref) + * [`RawSolver`](@ref) + * [`Silent`](@ref) + * [`SimplexIterations`](@ref) + * [`SolverName`](@ref) + * [`SolveTimeSec`](@ref) + * [`TimeLimitSec`](@ref) diff --git a/src/MathOptInterface.jl b/src/MathOptInterface.jl index ac6b80cef6..097742167e 100644 --- a/src/MathOptInterface.jl +++ b/src/MathOptInterface.jl @@ -5,6 +5,29 @@ module MathOptInterface Abstract supertype for objects that implement the "Model" interface for defining an optimization problem. + +## Interface + +The API of MathOptInterface is large. At a minimum, objects subtyping +`ModelLike` should implement [`get`](@ref) for the following attributes: + + * [`ListOfConstraintAttributesSet`](@ref) + * [`ListOfConstraintIndices`](@ref) + * [`ListOfConstraintTypesPresent`](@ref) + * [`ListOfModelAttributesSet`](@ref) + * [`ListOfVariableAttributesSet`](@ref) + * [`ListOfVariableIndices`](@ref) + * [`NumberOfConstraints`](@ref) + * [`NumberOfVariables`](@ref) + +and the functions: + + * [`isempty`](@ref) + * [`empty!`](@ref) + +!!! warning + This is the _minimal_ API required. Consult the documentation for more + details on how to interface the full API. """ abstract type ModelLike end @@ -17,12 +40,32 @@ function Base.show(io::IO, model::ModelLike) end """ - AbstractOptimizer + AbstractOptimizer <: ModelLike + +Abstract supertype for objects representing an instance of an optimization +problem tied to a particular solver. This is typically a solver's in-memory +representation. In addition to `ModelLike`, `AbstractOptimizer` objects let you +solve the model and query the solution. -Abstract supertype for objects representing an instance of an optimization problem -tied to a particular solver. This is typically a solver's in-memory representation. -In addition to `ModelLike`, `AbstractOptimizer` objects let you solve the -model and query the solution. +## Interface + +The API of MathOptInterface is large. At a minimum, objects subtyping +`AbstractOptimizer` should implement the [`ModelLike`](@ref) API, plus: + + * [`optimize!`](@ref) + +and [`get`](@ref) for the following attributes: + + * [`DualStatus`](@ref) + * [`ListOfOptimizerAttributesSet`](@ref) + * [`PrimalStatus`](@ref) + * [`RawStatusString`](@ref) + * [`ResultCount`](@ref) + * [`TerminationStatus`](@ref) + +!!! warning + This is the _minimal_ API required. Consult the documentation for more + details on how to interface the full API. """ abstract type AbstractOptimizer <: ModelLike end @@ -82,7 +125,9 @@ function read_from_file end """ is_empty(model::ModelLike) -Returns `false` if the `model` has any model attribute set or has any variables or constraints. +Returns `false` if the `model` has any model attribute set or has any variables +or constraints. + Note that an empty model can have optimizer attributes set. """ function is_empty end @@ -90,7 +135,8 @@ function is_empty end """ empty!(model::ModelLike) -Empty the model, that is, remove all variables, constraints and model attributes but not optimizer attributes. +Empty the model, that is, remove all variables, constraints and model attributes +but not optimizer attributes. """ function empty! end From 86ba628d797b2728990307d05bc63c1402a28053 Mon Sep 17 00:00:00 2001 From: odow Date: Fri, 27 Aug 2021 11:27:31 +1200 Subject: [PATCH 2/9] Fix docs --- docs/src/manual/models.md | 5 +++-- src/MathOptInterface.jl | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/src/manual/models.md b/docs/src/manual/models.md index 86d5d2823d..2c9f64fe61 100644 --- a/docs/src/manual/models.md +++ b/docs/src/manual/models.md @@ -66,7 +66,7 @@ Consult the docstsrings of each attribute for information on what it represents. Objects subtyping [`ModelLike`](ref) must implement: - * [`isempty`](@ref) + * [`is_empty`](@ref) * [`empty!`](@ref) The following attributes are available. Some are required by all @@ -92,7 +92,8 @@ implementations, and others are optional. ## AbstractOptimizer API -In addition to implementing the [ModelLike API](@ref), objects subtyping [`AbstractOptimizer`](ref) must implement: +In addition to implementing the [ModelLike API](@ref), objects subtyping +[`AbstractOptimizer`](ref) must implement: * [`optimize!`](@ref) diff --git a/src/MathOptInterface.jl b/src/MathOptInterface.jl index 097742167e..f45545d4a9 100644 --- a/src/MathOptInterface.jl +++ b/src/MathOptInterface.jl @@ -22,7 +22,7 @@ The API of MathOptInterface is large. At a minimum, objects subtyping and the functions: - * [`isempty`](@ref) + * [`is_empty`](@ref) * [`empty!`](@ref) !!! warning From fc937c0f3f3f603d08af4bab17f2c4bdb8136e9e Mon Sep 17 00:00:00 2001 From: odow Date: Fri, 27 Aug 2021 13:37:12 +1200 Subject: [PATCH 3/9] Updates --- docs/src/tutorials/implementing.md | 119 ++++++++++++----------------- src/MathOptInterface.jl | 4 +- 2 files changed, 52 insertions(+), 71 deletions(-) diff --git a/docs/src/tutorials/implementing.md b/docs/src/tutorials/implementing.md index f7217ead4b..a23473c80f 100644 --- a/docs/src/tutorials/implementing.md +++ b/docs/src/tutorials/implementing.md @@ -241,9 +241,14 @@ Base.unsafe_convert(::Type{Ptr{Cvoid}}, model::Optimizer) = model.ptr ### Implement methods for `Optimizer` -Now that we have an `Optimizer`, we need to implement a few basic methods. +All `Optimizer`s must implement the following methods: -* [`empty!`](@ref) and [`is_empty`](@ref) + * [`empty!`](@ref) + * [`is_empty`](@ref) + * [`optimize!`](@ref) + +Other methods, detailed below, are optional or depend on how you implement the +itnerface. !!! tip For this and all future methods, read the docstrings to understand what each @@ -261,8 +266,7 @@ end ### Implement attributes -You also need to implement the model and optimizer attributes in the following -table. +MathOptInterface uses attributes to manage different aspects of the problem. For each attribute * [`get`](@ref) gets the current value of the attribute @@ -276,36 +280,16 @@ For each attribute attribute. You should make sure that your [`get`](@ref) function correctly infers to this type (or a subtype of it). -Each column in the table indicates whether you need to implement the particular -method for each attribute. +All `Optimizer`s must implement [`get`](@ref) for the the following attributes: -| Attribute | [`get`](@ref) | [`set`](@ref) | [`supports`](@ref) | -| ---------------------- | --------------| ------------- | ------------------ | -| [`SolverName`](@ref) | Yes | No | No | -| [`RawSolver`](@ref) | Yes | No | No | -| [`Name`](@ref) | Yes | Yes | Yes | -| [`Silent`](@ref) | Yes | Yes | Yes | -| [`TimeLimitSec`](@ref) | Yes | Yes | Yes | -| [`RawOptimizerAttribute`](@ref) | Yes | Yes | Yes | -| [`NumberOfThreads`](@ref) | Yes | Yes | Yes | - -For example: -```julia -function MOI.get(model::Optimizer, ::MOI.Silent) - return # true if MOI.Silent is set -end - -function MOI.set(model::Optimizer, ::MOI.Silent, v::Bool) - if v - # Set a parameter to turn off printing - else - # Restore the default printing - end - return -end - -MOI.supports(::Optimizer, ::MOI.Silent) = true -``` + * [`ListOfConstraintAttributesSet`](@ref) + * [`ListOfConstraintTypesPresent`](@ref) + * [`ListOfConstraintIndices`](@ref) + * [`ListOfModelAttributesSet`](@ref) + * [`ListOfVariableAttributesSet`](@ref) + * [`ListOfVariableIndices`](@ref) + * [`NumberOfConstraints`](@ref) + * [`NumberOfVariables`](@ref) ### Define `supports_constraint` @@ -402,36 +386,30 @@ To implement the incremental interface, implement the following functions: in the function. Throw [`ScalarFunctionConstantNotZero`](@ref) if the function constant is not zero. -In addition, you should implement the following model attributes: - -| Attribute | [`get`](@ref) | [`set`](@ref) | [`supports`](@ref) | -| ---------------------- | --------------| ------------- | ------------------ | -| [`ListOfModelAttributesSet`](@ref) | Yes | No | No | -| [`ObjectiveFunctionType`](@ref) | Yes | No | No | -| [`ObjectiveFunction`](@ref) | Yes | Yes | Yes | -| [`ObjectiveSense`](@ref) | Yes | Yes | Yes | - -Variable-related attributes: - -| Attribute | [`get`](@ref) | [`set`](@ref) | [`supports`](@ref) | -| ---------------------- | --------------| ------------- | ------------------ | -| [`ListOfVariableAttributesSet`](@ref) | Yes | No | No | -| [`NumberOfVariables`](@ref) | Yes | No | No | -| [`ListOfVariableIndices`](@ref) | Yes | No | No | - -Constraint-related attributes: +In addition, you should implement the following model attributes if applicable. +Each column in the table indicates whether you need to implement the particular +method for each attribute. | Attribute | [`get`](@ref) | [`set`](@ref) | [`supports`](@ref) | | ---------------------- | --------------| ------------- | ------------------ | -| [`ListOfConstraintAttributesSet`](@ref) | Yes | No | No | -| [`NumberOfConstraints`](@ref) | Yes | No | No | -| [`ListOfConstraintTypesPresent`](@ref) | Yes | No | No | -| [`ConstraintFunction`](@ref) | Yes | Yes | No | -| [`ConstraintSet`](@ref) | Yes | Yes | No | - -If your solver supports modifying data in-place, implement: +| [`ConstraintFunction`](@ref) | Yes | Yes | No | +| [`ConstraintSet`](@ref) | Yes | Yes | No | +| [`Name`](@ref) | Yes | Yes | Yes | +| [`NumberOfThreads`](@ref) | Yes | Yes | Yes | +| [`ObjectiveFunctionType`](@ref) | Yes | No | No | +| [`ObjectiveFunction`](@ref) | Yes | Yes | Yes | +| [`ObjectiveSense`](@ref) | Yes | Yes | Yes | +| [`RawOptimizerAttribute`](@ref) | Yes | Yes | Yes | +| [`RawSolver`](@ref) | Yes | No | No | +| [`Silent`](@ref) | Yes | Yes | Yes | +| [`SolverName`](@ref) | Yes | No | No | +| [`TimeLimitSec`](@ref) | Yes | Yes | Yes | + +#### Modifications + +If your solver supports modifying data in-place, implement [`modify`](@ref) for +the following `AbstractModification`s: -* [`modify`](@ref) * [`ScalarConstantChange`](@ref) * [`ScalarCoefficientChange`](@ref) * [`VectorConstantChange`](@ref) @@ -466,8 +444,8 @@ fallback: ```julia MOI.supports_incremental_interface(::Optimizer) = true -function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike; kwargs...) - return MOI.Utilities.default_copy_to(dest, src; kwargs...) +function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike) + return MOI.Utilities.default_copy_to(dest, src) end ``` @@ -481,7 +459,8 @@ the `Name` attribute for variables and constraints: | [`VariableName`](@ref) | Yes | Yes | Yes | | [`ConstraintName`](@ref) | Yes | Yes | Yes | -If you implement names, you should also implement the following three methods: +If you implement names, you must also implement the following three methods: + ```julia function MOI.get(model::Optimizer, ::Type{MOI.VariableIndex}, name::String) return # The variable named `name`. @@ -536,17 +515,13 @@ Implement [`optimize!`](@ref) to solve the model: * [`optimize!`](@ref) -At a minimum, implement the following attributes to allow the user to access -solution information. +All `Optimizer`s must implement the following attributes: -* [`TerminationStatus`](@ref) -* [`PrimalStatus`](@ref) * [`DualStatus`](@ref) +* [`PrimalStatus`](@ref) * [`RawStatusString`](@ref) * [`ResultCount`](@ref) -* [`ObjectiveValue`](@ref) -* [`VariablePrimal`](@ref) -* [`SolveTimeSec`](@ref) +* [`TerminationStatus`](@ref) !!! info You only need to implement [`get`](@ref) for solution attributes. Don't @@ -558,6 +533,12 @@ solution information. designed to be used when the solver explicitly indicates that relaxed tolerances are satisfied or the returned point is infeasible, respectively. +You should also implement the following attributes: + +* [`ObjectiveValue`](@ref) +* [`SolveTimeSec`](@ref) +* [`VariablePrimal`](@ref) + !!! tip Attributes like [`VariablePrimal`](@ref) and [`ObjectiveValue`](@ref) are indexed by the result count. Use diff --git a/src/MathOptInterface.jl b/src/MathOptInterface.jl index f45545d4a9..34d7d7ed9b 100644 --- a/src/MathOptInterface.jl +++ b/src/MathOptInterface.jl @@ -9,7 +9,7 @@ an optimization problem. ## Interface The API of MathOptInterface is large. At a minimum, objects subtyping -`ModelLike` should implement [`get`](@ref) for the following attributes: +`ModelLike` must implement [`get`](@ref) for the following attributes: * [`ListOfConstraintAttributesSet`](@ref) * [`ListOfConstraintIndices`](@ref) @@ -50,7 +50,7 @@ solve the model and query the solution. ## Interface The API of MathOptInterface is large. At a minimum, objects subtyping -`AbstractOptimizer` should implement the [`ModelLike`](@ref) API, plus: +`AbstractOptimizer` must implement the [`ModelLike`](@ref) API, plus: * [`optimize!`](@ref) From df474737147b1d1af6d3c8e83bac895744d80df8 Mon Sep 17 00:00:00 2001 From: odow Date: Tue, 31 Aug 2021 15:22:52 +1200 Subject: [PATCH 4/9] Updates --- docs/src/manual/models.md | 14 ++++++++++---- src/MathOptInterface.jl | 11 ++++++----- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/docs/src/manual/models.md b/docs/src/manual/models.md index 2c9f64fe61..6a5b8c81d8 100644 --- a/docs/src/manual/models.md +++ b/docs/src/manual/models.md @@ -90,12 +90,19 @@ implementations, and others are optional. * [`ObjectiveFunctionType`](@ref) * [`ObjectiveSense`](@ref) +!!! note + To be useful, a [`ModelLike`](@ref) should, in most cases, also implement + [`copy_to`](@ref) or the incremental interface ([`add_variable`](@ref), + [`add_constraint`](@ref), etc.) See [Implementing a solver interface](@ref) + for more details. + ## AbstractOptimizer API -In addition to implementing the [ModelLike API](@ref), objects subtyping -[`AbstractOptimizer`](ref) must implement: +There are two options for [`AbstractOptimizer`](@ref)s: - * [`optimize!`](@ref) + 1. Implement the required portion of the [ModelLike API](@ref), plus + [`optimize!`](@ref) + 2. Implement [`copy_to_and_optimize!`](@ref) The following attributes are available. Some are required by all implementations, and others are optional. @@ -103,7 +110,6 @@ implementations, and others are optional. **Required** * [`DualStatus`](@ref) - * [`ListOfOptimizerAttributesSet`](@ref) * [`PrimalStatus`](@ref) * [`RawStatusString`](@ref) * [`ResultCount`](@ref) diff --git a/src/MathOptInterface.jl b/src/MathOptInterface.jl index 34d7d7ed9b..885594bb6c 100644 --- a/src/MathOptInterface.jl +++ b/src/MathOptInterface.jl @@ -49,15 +49,16 @@ solve the model and query the solution. ## Interface -The API of MathOptInterface is large. At a minimum, objects subtyping -`AbstractOptimizer` must implement the [`ModelLike`](@ref) API, plus: +The API of MathOptInterface is large. There are two options for +[`AbstractOptimizer`](@ref)s: - * [`optimize!`](@ref) + 1. Implement the required portion of the [`ModelLike`](@ref) API, plus + [`optimize!`](@ref) + 2. Implement [`copy_to_and_optimize!`](@ref) -and [`get`](@ref) for the following attributes: +In addition, they must implement [`get`](@ref) for the following attributes: * [`DualStatus`](@ref) - * [`ListOfOptimizerAttributesSet`](@ref) * [`PrimalStatus`](@ref) * [`RawStatusString`](@ref) * [`ResultCount`](@ref) From db31894bb98ec477866ca51f22f3b938deb23b04 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Tue, 31 Aug 2021 15:38:55 +1200 Subject: [PATCH 5/9] Update models.md --- docs/src/reference/models.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/reference/models.md b/docs/src/reference/models.md index d6956536d9..a7a0005042 100644 --- a/docs/src/reference/models.md +++ b/docs/src/reference/models.md @@ -60,6 +60,7 @@ AbstractOptimizer OptimizerWithAttributes optimize! instantiate +copy_to_and_optimize! ``` ## Optimizer attributes From 0980ceb71720d8870ac34894ff49b5721e309c94 Mon Sep 17 00:00:00 2001 From: odow Date: Wed, 1 Sep 2021 12:00:26 +1200 Subject: [PATCH 6/9] Updates --- docs/src/tutorials/implementing.md | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/docs/src/tutorials/implementing.md b/docs/src/tutorials/implementing.md index a23473c80f..c7bdd56ca2 100644 --- a/docs/src/tutorials/implementing.md +++ b/docs/src/tutorials/implementing.md @@ -245,7 +245,7 @@ All `Optimizer`s must implement the following methods: * [`empty!`](@ref) * [`is_empty`](@ref) - * [`optimize!`](@ref) + * [`optimize!`](@ref) (or [`copy_to_and_optimize!`](@ref)) Other methods, detailed below, are optional or depend on how you implement the itnerface. @@ -280,16 +280,8 @@ For each attribute attribute. You should make sure that your [`get`](@ref) function correctly infers to this type (or a subtype of it). -All `Optimizer`s must implement [`get`](@ref) for the the following attributes: - - * [`ListOfConstraintAttributesSet`](@ref) - * [`ListOfConstraintTypesPresent`](@ref) - * [`ListOfConstraintIndices`](@ref) - * [`ListOfModelAttributesSet`](@ref) - * [`ListOfVariableAttributesSet`](@ref) - * [`ListOfVariableIndices`](@ref) - * [`NumberOfConstraints`](@ref) - * [`NumberOfVariables`](@ref) +All `Optimizer`s must implement the [ModelLike API](@ref). See that section for +details. ### Define `supports_constraint` From e8ce144d62d66cc661a8749d9975bc16c90ba43f Mon Sep 17 00:00:00 2001 From: odow Date: Fri, 3 Sep 2021 10:39:41 +1200 Subject: [PATCH 7/9] Updates --- docs/src/manual/models.md | 34 +--------- docs/src/tutorials/implementing.md | 100 +++++++++++++++++++++++------ src/MathOptInterface.jl | 44 ------------- 3 files changed, 83 insertions(+), 95 deletions(-) diff --git a/docs/src/manual/models.md b/docs/src/manual/models.md index 6a5b8c81d8..7e5b0467b2 100644 --- a/docs/src/manual/models.md +++ b/docs/src/manual/models.md @@ -64,15 +64,7 @@ Consult the docstsrings of each attribute for information on what it represents. ## ModelLike API -Objects subtyping [`ModelLike`](ref) must implement: - - * [`is_empty`](@ref) - * [`empty!`](@ref) - -The following attributes are available. Some are required by all -implementations, and others are optional. - -**Required** +The following attributes are available: * [`ListOfConstraintAttributesSet`](@ref) * [`ListOfConstraintIndices`](@ref) @@ -82,41 +74,19 @@ implementations, and others are optional. * [`ListOfVariableIndices`](@ref) * [`NumberOfConstraints`](@ref) * [`NumberOfVariables`](@ref) - -**Optional** - * [`Name`](@ref) * [`ObjectiveFunction`](@ref) * [`ObjectiveFunctionType`](@ref) * [`ObjectiveSense`](@ref) - -!!! note - To be useful, a [`ModelLike`](@ref) should, in most cases, also implement - [`copy_to`](@ref) or the incremental interface ([`add_variable`](@ref), - [`add_constraint`](@ref), etc.) See [Implementing a solver interface](@ref) - for more details. - ## AbstractOptimizer API -There are two options for [`AbstractOptimizer`](@ref)s: - - 1. Implement the required portion of the [ModelLike API](@ref), plus - [`optimize!`](@ref) - 2. Implement [`copy_to_and_optimize!`](@ref) - -The following attributes are available. Some are required by all -implementations, and others are optional. - -**Required** +The following attributes are available: * [`DualStatus`](@ref) * [`PrimalStatus`](@ref) * [`RawStatusString`](@ref) * [`ResultCount`](@ref) * [`TerminationStatus`](@ref) - -**Optional** - * [`BarrierIterations`](@ref) * [`DualObjectiveValue`](@ref) * [`NodeCount`](@ref) diff --git a/docs/src/tutorials/implementing.md b/docs/src/tutorials/implementing.md index c7bdd56ca2..7cd449560c 100644 --- a/docs/src/tutorials/implementing.md +++ b/docs/src/tutorials/implementing.md @@ -20,6 +20,32 @@ MathOptInterface for a new solver. not answered by this guide, please ask them in the [Developer chatroom](https://gitter.im/JuliaOpt/JuMP-dev) so we can improve this guide! +## A note on the API + +The API of MathOptInterface is large and varied. In order to support the +diversity of solvers and use-cases, we make heavy use of +[duck-typing](https://en.wikipedia.org/wiki/Duck_typing). That is, solvers are +not expected to implement the full API, nor is there a well-defined minimal +subset of what must be implemented. Instead, you should implement the API as +necessary in order to make the solver function as you require. + +The main reason for using duck-typing over a well-defined API is that solvers +work in different ways and target different use-cases. + +For example: + + * Some solvers support incremental problem construction, support modification + after a solve, and have native support for things like variable names. + * Other solvers are "one-shot" solvers that require all of the problem data to + construct and solve the problem in a single function call. They do not + support modification or things like variable names. + * Other "solvers" are not solvers at all, but things like file readers. These + may only support functions like [`read_from_file`](@ref), and may not even + support the ability to add variables or constraints directly! + * Finally, some "solvers" are layers which take a problem as input, transform + it according to some rules, and pass the transformed problem to an inner + solver. + ## Preliminaries ### Decide if MathOptInterface is right for you @@ -51,8 +77,8 @@ has a good list of solvers, along with the problem classes they support. ### Create a low-level interface -Before writing a MathOptInterface wrapper, you first need to be able to call the solver -from Julia. +Before writing a MathOptInterface wrapper, you first need to be able to call the +solver from Julia. #### Wrapping solvers written in Julia @@ -280,9 +306,36 @@ For each attribute attribute. You should make sure that your [`get`](@ref) function correctly infers to this type (or a subtype of it). -All `Optimizer`s must implement the [ModelLike API](@ref). See that section for -details. +Each column in the table indicates whether you need to implement the particular +method for each attribute. + +| Attribute | [`get`](@ref) | [`set`](@ref) | [`supports`](@ref) | +| ---------------------- | --------------| ------------- | ------------------ | +| [`SolverName`](@ref) | Yes | No | No | +| [`RawSolver`](@ref) | Yes | No | No | +| [`Name`](@ref) | Yes | Yes | Yes | +| [`Silent`](@ref) | Yes | Yes | Yes | +| [`TimeLimitSec`](@ref) | Yes | Yes | Yes | +| [`RawOptimizerAttribute`](@ref) | Yes | Yes | Yes | +| [`NumberOfThreads`](@ref) | Yes | Yes | Yes | + +For example: +```julia +function MOI.get(model::Optimizer, ::MOI.Silent) + return # true if MOI.Silent is set +end + +function MOI.set(model::Optimizer, ::MOI.Silent, v::Bool) + if v + # Set a parameter to turn off printing + else + # Restore the default printing + end + return +end +MOI.supports(::Optimizer, ::MOI.Silent) = true +``` ### Define `supports_constraint` The next step is to define which constraints and objective functions you plan to @@ -378,24 +431,33 @@ To implement the incremental interface, implement the following functions: in the function. Throw [`ScalarFunctionConstantNotZero`](@ref) if the function constant is not zero. -In addition, you should implement the following model attributes if applicable. -Each column in the table indicates whether you need to implement the particular -method for each attribute. +In addition, you should implement the following model attributes: | Attribute | [`get`](@ref) | [`set`](@ref) | [`supports`](@ref) | | ---------------------- | --------------| ------------- | ------------------ | -| [`ConstraintFunction`](@ref) | Yes | Yes | No | -| [`ConstraintSet`](@ref) | Yes | Yes | No | -| [`Name`](@ref) | Yes | Yes | Yes | -| [`NumberOfThreads`](@ref) | Yes | Yes | Yes | -| [`ObjectiveFunctionType`](@ref) | Yes | No | No | -| [`ObjectiveFunction`](@ref) | Yes | Yes | Yes | -| [`ObjectiveSense`](@ref) | Yes | Yes | Yes | -| [`RawOptimizerAttribute`](@ref) | Yes | Yes | Yes | -| [`RawSolver`](@ref) | Yes | No | No | -| [`Silent`](@ref) | Yes | Yes | Yes | -| [`SolverName`](@ref) | Yes | No | No | -| [`TimeLimitSec`](@ref) | Yes | Yes | Yes | +| [`ListOfModelAttributesSet`](@ref) | Yes | No | No | +| [`ObjectiveFunctionType`](@ref) | Yes | No | No | +| [`ObjectiveFunction`](@ref) | Yes | Yes | Yes | +| [`ObjectiveSense`](@ref) | Yes | Yes | Yes | +| [`Name`](@ref) | Yes | Yes | Yes | + +Variable-related attributes: + +| Attribute | [`get`](@ref) | [`set`](@ref) | [`supports`](@ref) | +| ---------------------- | --------------| ------------- | ------------------ | +| [`ListOfVariableAttributesSet`](@ref) | Yes | No | No | +| [`NumberOfVariables`](@ref) | Yes | No | No | +| [`ListOfVariableIndices`](@ref) | Yes | No | No | + +Constraint-related attributes: + +| Attribute | [`get`](@ref) | [`set`](@ref) | [`supports`](@ref) | +| ---------------------- | --------------| ------------- | ------------------ | +| [`ListOfConstraintAttributesSet`](@ref) | Yes | No | No | +| [`NumberOfConstraints`](@ref) | Yes | No | No | +| [`ListOfConstraintTypesPresent`](@ref) | Yes | No | No | +| [`ConstraintFunction`](@ref) | Yes | Yes | No | +| [`ConstraintSet`](@ref) | Yes | Yes | No | #### Modifications diff --git a/src/MathOptInterface.jl b/src/MathOptInterface.jl index 885594bb6c..58970f82f0 100644 --- a/src/MathOptInterface.jl +++ b/src/MathOptInterface.jl @@ -5,29 +5,6 @@ module MathOptInterface Abstract supertype for objects that implement the "Model" interface for defining an optimization problem. - -## Interface - -The API of MathOptInterface is large. At a minimum, objects subtyping -`ModelLike` must implement [`get`](@ref) for the following attributes: - - * [`ListOfConstraintAttributesSet`](@ref) - * [`ListOfConstraintIndices`](@ref) - * [`ListOfConstraintTypesPresent`](@ref) - * [`ListOfModelAttributesSet`](@ref) - * [`ListOfVariableAttributesSet`](@ref) - * [`ListOfVariableIndices`](@ref) - * [`NumberOfConstraints`](@ref) - * [`NumberOfVariables`](@ref) - -and the functions: - - * [`is_empty`](@ref) - * [`empty!`](@ref) - -!!! warning - This is the _minimal_ API required. Consult the documentation for more - details on how to interface the full API. """ abstract type ModelLike end @@ -46,27 +23,6 @@ Abstract supertype for objects representing an instance of an optimization problem tied to a particular solver. This is typically a solver's in-memory representation. In addition to `ModelLike`, `AbstractOptimizer` objects let you solve the model and query the solution. - -## Interface - -The API of MathOptInterface is large. There are two options for -[`AbstractOptimizer`](@ref)s: - - 1. Implement the required portion of the [`ModelLike`](@ref) API, plus - [`optimize!`](@ref) - 2. Implement [`copy_to_and_optimize!`](@ref) - -In addition, they must implement [`get`](@ref) for the following attributes: - - * [`DualStatus`](@ref) - * [`PrimalStatus`](@ref) - * [`RawStatusString`](@ref) - * [`ResultCount`](@ref) - * [`TerminationStatus`](@ref) - -!!! warning - This is the _minimal_ API required. Consult the documentation for more - details on how to interface the full API. """ abstract type AbstractOptimizer <: ModelLike end From f3faa3dfb27847062995f83dc68325a347e14b04 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Fri, 3 Sep 2021 17:38:39 +1200 Subject: [PATCH 8/9] Update docs/src/tutorials/implementing.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: BenoƮt Legat --- docs/src/tutorials/implementing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/tutorials/implementing.md b/docs/src/tutorials/implementing.md index 7cd449560c..b7f0f21926 100644 --- a/docs/src/tutorials/implementing.md +++ b/docs/src/tutorials/implementing.md @@ -274,7 +274,7 @@ All `Optimizer`s must implement the following methods: * [`optimize!`](@ref) (or [`copy_to_and_optimize!`](@ref)) Other methods, detailed below, are optional or depend on how you implement the -itnerface. +interface. !!! tip For this and all future methods, read the docstrings to understand what each From 3ad480e434d63420f44ad9337328b06538c84210 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Sun, 5 Sep 2021 15:03:27 +1200 Subject: [PATCH 9/9] Update implementing.md --- docs/src/tutorials/implementing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/tutorials/implementing.md b/docs/src/tutorials/implementing.md index b7f0f21926..953ee50f68 100644 --- a/docs/src/tutorials/implementing.md +++ b/docs/src/tutorials/implementing.md @@ -29,8 +29,8 @@ not expected to implement the full API, nor is there a well-defined minimal subset of what must be implemented. Instead, you should implement the API as necessary in order to make the solver function as you require. -The main reason for using duck-typing over a well-defined API is that solvers -work in different ways and target different use-cases. +The main reason for using duck-typing is that solvers work in different ways and +target different use-cases. For example: