From a31440dd2450304635f7fc799191c61e4e7b2c97 Mon Sep 17 00:00:00 2001 From: odow Date: Wed, 1 Nov 2023 10:39:25 +1300 Subject: [PATCH 1/4] [docs] add more docs for implementing a bridge --- docs/make.jl | 1 + docs/src/submodules/Bridges/implementation.md | 123 ++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 docs/src/submodules/Bridges/implementation.md diff --git a/docs/make.jl b/docs/make.jl index c45d431c78..1a35a2ea8e 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -63,6 +63,7 @@ const _PAGES = [ ], "Bridges" => [ "Overview" => "submodules/Bridges/overview.md", + "Implementation" => "submodules/Bridges/implementation.md", "List of bridges" => "submodules/Bridges/list_of_bridges.md", "API Reference" => "submodules/Bridges/reference.md", ], diff --git a/docs/src/submodules/Bridges/implementation.md b/docs/src/submodules/Bridges/implementation.md new file mode 100644 index 0000000000..aba4be2a03 --- /dev/null +++ b/docs/src/submodules/Bridges/implementation.md @@ -0,0 +1,123 @@ +```@meta +CurrentModule = MathOptInterface +DocTestSetup = quote + import MathOptInterface as MOI +end +DocTestFilters = [r"MathOptInterface|MOI"] +``` + +# Implementing a bridge + +The easiest way to implement a bridge is to follow an existing example. There +are three locations of bridges in the source code: + + * Constraint bridges are stored in `src/Bridges/Constraint/bridges` + * Objective bridges are stored in `src/Bridges/Objective/bridges` + * Variable bridges are stored in `src/Bridges/Variable/bridges` + +The [Implementing a constraint bridge](@ref) tutorial has a more detailed guide +on what is required to implement a bridge. + +When opening a pull request that adds a new bridge, use the checklist +[Adding a new bridge](@ref). + +If you need help or advice, please contact the [Developer Chatroom](https://jump.dev/chatroom/). + +## SetMap bridges + +For constraint and variable bridges, a common reformulation is that ``f(x) \in F`` +is reformulated to ``g(x) \in G``. In this case, no additional variables and +constraints are added, and the bridge needs only a way to map between the +functions `f` and `g` and the sets `F` and `G`. + +To implementation a bridge of this form, subtype the abstract type +[`Bridges.Constraint.SetMapBridge`](@ref) or +[`Bridges.Variable.SetMapBridge`](@ref) and implement the API described in the +docstring of each type. + +## `final_touch` + +Some bridges require information from other parts of the model. One set of +examples are the various combinatorial `ToMILP` bridges, such as +[`Bridges.Constraint.SOS1ToMILPBridge`](@ref), which require knowledge of the +variable bounds. + +Bridges requiring information from other parts of the model should implement +[`Bridges.final_touch`](@ref) and [`Bridges.needs_final_touch`](@ref). + +During the bridge's construction, store the function and set and make no changes +to the underlying model. Then, in [`Bridges.final_touch`](@ref), query the +additional information and add the reformulated problem to the `model`. + +When implementing, you must consider that: + + * [`Bridges.final_touch`](@ref) may be called multiple times, so that your + reformulation should be applied only if necessary. Sometimes the additional + data will be the same, and sometimes it may be different. + * We do not currently support `final_touch` bridges that introduce constraints + which also require a `final_touch` bridge. Therefore, you should implement + `final_touch` only if necessary, and we recommend that you contact the + [Developer Chatroom](https://jump.dev/chatroom/) for advice before doing so. + +## Testing + +Use the [`Bridges.runtests`](@ref) function to test a bridge. It takes three +arguments: the type of the bridge, the input model as a string, and the output +model as a string. + +Here is an example: +```jldoctest +julia> MOI.Bridges.runtests( + MOI.Bridges.Constraint.GreaterToLessBridge, + """ + variables: x + x >= 1.0 + """, + """ + variables: x + -1.0 * x <= -1.0 + """, + ) +``` + +There are a number of other useful keyword arguments. + + * `eltype` can be used to specify the element type of the model (and bridge). + It defaults to `Float64`. + * `variable_start` and `constraint_start` are used as the values to set the + [`VariablePrimalStart`](@ref) and [`ConstraintPrimalStart`](@ref) attributes + to. They default to `1.2`. If you use a different `eltype`, you must set + appropriate starting values of the same type. The default `1.2` was chosen to + minimize the risk that the starting point is undefined, which could happen + for common situations like `0.0` and `1.0`. The tests associated with the + starting values do not necessarily check for correctness, only that they can + be `set` and `get` to produce the same result. + * `print_inner_model` can be used to print the reformulated ouput model from + the bridge. This is especially helpful during debugging to see what the + bridge is doing, and to spot mistakes. It defaults to `false`. + +Here is an example: + +```jldoctest +julia> MOI.Bridges.runtests( + MOI.Bridges.Constraint.GreaterToLessBridge, + """ + variables: x + x >= 1 + """, + """ + variables: x + ::Int: -1 * x <= -1 + """; + eltype = Int, + print_inner_model = true, + variable_start = 2, + constraint_start = 2, + ) +Feasibility + +Subject to: + +ScalarAffineFunction{Int64}-in-LessThan{Int64} + (0) - (1) x <= (-1) +``` From 2af843b92c159fd0ecade6d7f75e96526294c5e6 Mon Sep 17 00:00:00 2001 From: odow Date: Wed, 1 Nov 2023 11:39:07 +1300 Subject: [PATCH 2/4] Fix docs --- docs/src/submodules/Bridges/reference.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/submodules/Bridges/reference.md b/docs/src/submodules/Bridges/reference.md index 44d9a1855e..90adb6f4df 100644 --- a/docs/src/submodules/Bridges/reference.md +++ b/docs/src/submodules/Bridges/reference.md @@ -21,6 +21,7 @@ get(::Bridges.AbstractBridge, ::ListOfConstraintIndices) Bridges.needs_final_touch Bridges.final_touch Bridges.bridging_cost +Bridges.runtests ``` ## Constraint bridge API From 6b45589bda0220eb063f36215f2abcd1995f09a6 Mon Sep 17 00:00:00 2001 From: odow Date: Wed, 1 Nov 2023 16:16:31 +1300 Subject: [PATCH 3/4] Fix --- docs/src/submodules/Utilities/reference.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/submodules/Utilities/reference.md b/docs/src/submodules/Utilities/reference.md index c555d6c92f..9fd6a1af7f 100644 --- a/docs/src/submodules/Utilities/reference.md +++ b/docs/src/submodules/Utilities/reference.md @@ -79,6 +79,7 @@ Utilities.default_copy_to Utilities.IndexMap Utilities.identity_index_map Utilities.ModelFilter +Utilities.loadfromstring! ``` ## Penalty relaxation From 91e1edda4a5955bc8eab057d8686caa9df8a0c07 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Thu, 2 Nov 2023 08:22:59 +1300 Subject: [PATCH 4/4] Update docs/src/submodules/Bridges/implementation.md --- docs/src/submodules/Bridges/implementation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/submodules/Bridges/implementation.md b/docs/src/submodules/Bridges/implementation.md index aba4be2a03..3782edd7a4 100644 --- a/docs/src/submodules/Bridges/implementation.md +++ b/docs/src/submodules/Bridges/implementation.md @@ -92,7 +92,7 @@ There are a number of other useful keyword arguments. for common situations like `0.0` and `1.0`. The tests associated with the starting values do not necessarily check for correctness, only that they can be `set` and `get` to produce the same result. - * `print_inner_model` can be used to print the reformulated ouput model from + * `print_inner_model` can be used to print the reformulated output model from the bridge. This is especially helpful during debugging to see what the bridge is doing, and to spot mistakes. It defaults to `false`.