From 62e31e15360f920dd2d17abf07af55283939b8e6 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Tue, 3 Aug 2021 22:40:04 +0200 Subject: [PATCH 01/38] Mention function bridges. --- docs/src/submodules/Bridges/overview.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/src/submodules/Bridges/overview.md b/docs/src/submodules/Bridges/overview.md index 33718113f5..c7215bbfb6 100644 --- a/docs/src/submodules/Bridges/overview.md +++ b/docs/src/submodules/Bridges/overview.md @@ -52,8 +52,13 @@ form supported by the solver. The equivalent formulation may add constraints (and possibly also variables) in the underlying model. +In particular, constraint bridges can focus on rewriting the function of a +constraint, and do not change the set. + Read the [list of implemented constraint bridges](@ref constraint_bridges_ref) for more details on the types of transformations that are available. +Function bridges are [ScalarFunctionizeBridge](@ref) and +[VectorFunctionizeBridge](@ref). ### [Variable bridges](@id variable_bridges) @@ -62,7 +67,7 @@ Variable bridges convert variables added by the user, either free with [`add_constrained_variable`](@ref)/[`add_constrained_variables`](@ref), into an equivalent form supported by the solver. -Te equivalent formulation may add constraints (and possibly also variables) in +The equivalent formulation may add constraints (and possibly also variables) in the underlying model. Read the [list of implemented variable bridges](@ref variable_bridges_ref) for From 36c604e592ff79194daa19996d553409e19c6655 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Tue, 3 Aug 2021 22:43:57 +0200 Subject: [PATCH 02/38] Add pointer to top of hierarchy for each type of bridge. --- docs/src/submodules/Bridges/overview.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/src/submodules/Bridges/overview.md b/docs/src/submodules/Bridges/overview.md index c7215bbfb6..4f72e7be9a 100644 --- a/docs/src/submodules/Bridges/overview.md +++ b/docs/src/submodules/Bridges/overview.md @@ -47,25 +47,28 @@ There are three types of bridges in MathOptInterface: ### Constraint bridges Constraint bridges convert constraints formulated by the user into an equivalent -form supported by the solver. +form supported by the solver. Constraint bridges are subtypes of +[`Bridges.Constraint.AbstractBridge`](@ref). The equivalent formulation may add constraints (and possibly also variables) in the underlying model. In particular, constraint bridges can focus on rewriting the function of a -constraint, and do not change the set. +constraint, and do not change the set. Function bridges are subtypes of +[`Bridges.Constraint.AbstractFunctionConversionBridge`](@ref). Read the [list of implemented constraint bridges](@ref constraint_bridges_ref) for more details on the types of transformations that are available. -Function bridges are [ScalarFunctionizeBridge](@ref) and -[VectorFunctionizeBridge](@ref). +Function bridges are [`Bridges.Constraint.ScalarFunctionizeBridge`](@ref) and +[`Bridges.Constraint.VectorFunctionizeBridge`](@ref). ### [Variable bridges](@id variable_bridges) Variable bridges convert variables added by the user, either free with [`add_variable`](@ref)/[`add_variables`](@ref), or constrained with [`add_constrained_variable`](@ref)/[`add_constrained_variables`](@ref), -into an equivalent form supported by the solver. +into an equivalent form supported by the solver. Variable bridges are +subtypes of [`Bridges.Variable.AbstractBridge`](@ref). The equivalent formulation may add constraints (and possibly also variables) in the underlying model. @@ -76,9 +79,10 @@ more details on the types of transformations that are available. ### Objective bridges Objective bridges convert the [`ObjectiveFunction`](@ref) set by the user into -an equivalent form supported by the solver. +an equivalent form supported by the solver. Objective bridges are +subtypes of [`Bridges.Objective.AbstractBridge`](@ref). -Te equivalent formulation may add constraints (and possibly also variables) in +The equivalent formulation may add constraints (and possibly also variables) in the underlying model. Read the [list of implemented objective bridges](@ref objective_bridges_ref) for From 8dfb1c66909b432fef361761484417ca510f8740 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Tue, 3 Aug 2021 22:46:51 +0200 Subject: [PATCH 03/38] Mention that several bridges can be used in combination. --- docs/src/submodules/Bridges/overview.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/src/submodules/Bridges/overview.md b/docs/src/submodules/Bridges/overview.md index 4f72e7be9a..85717a6ae1 100644 --- a/docs/src/submodules/Bridges/overview.md +++ b/docs/src/submodules/Bridges/overview.md @@ -37,6 +37,11 @@ Because these bridges are included in MathOptInterface, they can be re-used by any optimizer. Some bridges also implement constraint modifications and constraint primal and dual translations. +Several bridges can be used in combination to transform a single constraint +into a form that the solver may understand. Choosing the bridges to use +takes the form of finding a shortest path in the hypergraph of bridges. The +methodology is detailed in [the MOI paper](https://arxiv.org/abs/2002.03447). + ## The three types of bridges There are three types of bridges in MathOptInterface: From 0c391fb060c8f8c64152b2c435de65a72a72e725 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Tue, 3 Aug 2021 23:06:53 +0200 Subject: [PATCH 04/38] Start tutorial for bridges. --- docs/src/tutorials/bridging_constraint.md | 51 +++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 docs/src/tutorials/bridging_constraint.md diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md new file mode 100644 index 0000000000..ac6029a544 --- /dev/null +++ b/docs/src/tutorials/bridging_constraint.md @@ -0,0 +1,51 @@ +```@meta +CurrentModule = MathOptInterface +DocTestSetup = quote + using MathOptInterface + const MOI = MathOptInterface +end +DocTestFilters = [r"MathOptInterface|MOI"] +``` + +# Implementing a constraint bridge + +This guide outlines the basic steps to create a new bridge from a constraint +expressed in the formalism `Function`-in-`Set`. + +## Preliminaries + +First, decide on the set you want to bridge. Then, study its properties: the +most important one is whether the set is scalar or vector, which impacts the +dimensionality of the functions that can be used with the set. + +* A scalar function only has one dimension. MOI defines three types of scalar + functions: a variable ([`SingleVariable`](@ref)), an affine function + ([`ScalarAffineFunction`](@ref)), or a quadratic function + ([`QuadraticAffineFunction`](@ref)). +* A vector function has several dimensions (at least one). MOI defines three + types of vector functions: several variables ([`VectorOfVariables`](@ref)), + an affine function ([`VectorAffineFunction`](@ref)), or a quadratic function + ([`VectorAffineFunction`](@ref)). The main difference with scalar functions + is that the order of dimensions can be very important: for instance, in an + indicator constraint ([`Indicator`](@ref)), the first dimension indicates + whether the constraint about the second dimension is active. + +## Four parts in a constraint bridge + +The first part of a constraint bridge is a new concrete type that inherits from +[`Bridges.Constraint.AbstractBridge`](@ref). This type must have fields to +store all the new variables and constraints that the bridge will add. + +Then, three sets of functions must be defined: + +1. `Bridges.Constraint.bridge_constraint`: this function implements the bridge + and creates the required variables and constraints. +2. `supports_constraint`: these functions should return `true` when the + combination of function and set is supported by the bridge. By default, the + base implementation always returns `false` and the bridge does not have to + provide this implementation. +3. `Bridges.added_constrained_variable_types` and + `Bridges.added_constraint_types`: these functions return the types of + variables and constraints that this bridge adds. They are used to compute + the set of other bridges that are required to use the one you are defining, + if need be. From d303e39b107513a1dd49f9fdc0a3df9d247d652b Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Tue, 3 Aug 2021 23:07:26 +0200 Subject: [PATCH 05/38] Add the bridge tutorial in the docs. --- docs/make.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/make.jl b/docs/make.jl index 3d8d953291..d6774c32f6 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -28,6 +28,7 @@ makedocs( "tutorials/example.md", "tutorials/implementing.md", "tutorials/mathprogbase.md", + "tutorials/bridging_constraint.md", ], "Manual" => [ "manual/standard_form.md", From 7cb64ae75e1ceb9a45615ac52952367634d8c0da Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Tue, 3 Aug 2021 23:08:54 +0200 Subject: [PATCH 06/38] Update bridging_constraint.md --- docs/src/tutorials/bridging_constraint.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index ac6029a544..4c5af51fb3 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -35,6 +35,8 @@ dimensionality of the functions that can be used with the set. The first part of a constraint bridge is a new concrete type that inherits from [`Bridges.Constraint.AbstractBridge`](@ref). This type must have fields to store all the new variables and constraints that the bridge will add. +Typically, these types are parametrized by the type of the coefficients in the +model. Then, three sets of functions must be defined: From 5261650c3d5dc97e3ac73cf67720798638dc0d40 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Tue, 3 Aug 2021 23:16:58 +0200 Subject: [PATCH 07/38] Update bridging_constraint.md --- docs/src/tutorials/bridging_constraint.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 4c5af51fb3..7a50757ac9 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -21,11 +21,11 @@ dimensionality of the functions that can be used with the set. * A scalar function only has one dimension. MOI defines three types of scalar functions: a variable ([`SingleVariable`](@ref)), an affine function ([`ScalarAffineFunction`](@ref)), or a quadratic function - ([`QuadraticAffineFunction`](@ref)). + ([`ScalarQuadraticFunction`](@ref)). * A vector function has several dimensions (at least one). MOI defines three types of vector functions: several variables ([`VectorOfVariables`](@ref)), an affine function ([`VectorAffineFunction`](@ref)), or a quadratic function - ([`VectorAffineFunction`](@ref)). The main difference with scalar functions + ([`VectorQuadraticFunction`](@ref)). The main difference with scalar functions is that the order of dimensions can be very important: for instance, in an indicator constraint ([`Indicator`](@ref)), the first dimension indicates whether the constraint about the second dimension is active. From 2e99c787164d36ae21e5defc734475d87dff9e7c Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Tue, 3 Aug 2021 23:41:56 +0200 Subject: [PATCH 08/38] Add docstrings. --- docs/src/tutorials/bridging_constraint.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 7a50757ac9..9a714a883f 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -40,14 +40,14 @@ model. Then, three sets of functions must be defined: -1. `Bridges.Constraint.bridge_constraint`: this function implements the bridge - and creates the required variables and constraints. +1. [`Bridges.Constraint.bridge_constraint`](@ref): this function implements the + bridge and creates the required variables and constraints. 2. `supports_constraint`: these functions should return `true` when the combination of function and set is supported by the bridge. By default, the base implementation always returns `false` and the bridge does not have to provide this implementation. -3. `Bridges.added_constrained_variable_types` and - `Bridges.added_constraint_types`: these functions return the types of - variables and constraints that this bridge adds. They are used to compute +3. [`Bridges.added_constrained_variable_types`](@ref) and + [`Bridges.added_constraint_types`](@ref): these functions return the types + of variables and constraints that this bridge adds. They are used to compute the set of other bridges that are required to use the one you are defining, if need be. From b3bb62b199c612cdd3362dd9da3c5e32d8f46d3f Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Tue, 3 Aug 2021 23:43:16 +0200 Subject: [PATCH 09/38] Update reference.md --- 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 3d134a30bc..c9b2cba3a9 100644 --- a/docs/src/submodules/Bridges/reference.md +++ b/docs/src/submodules/Bridges/reference.md @@ -37,6 +37,7 @@ Bridges.Variable.unbridged_map ```@docs Bridges.Constraint.AbstractBridge +Bridges.Constraint.AbstractFunctionConversionBridge Bridges.Constraint.SingleBridgeOptimizer Bridges.Constraint.add_all_bridges ``` From 78f8705c45951ab14689f8dd35b362232fa5ec2b Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 00:06:15 +0200 Subject: [PATCH 10/38] Update bridging_constraint.md --- docs/src/tutorials/bridging_constraint.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 9a714a883f..3a607deb7c 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -42,7 +42,7 @@ Then, three sets of functions must be defined: 1. [`Bridges.Constraint.bridge_constraint`](@ref): this function implements the bridge and creates the required variables and constraints. -2. `supports_constraint`: these functions should return `true` when the +2. [`supports_constraint`](@ref): these functions should return `true` when the combination of function and set is supported by the bridge. By default, the base implementation always returns `false` and the bridge does not have to provide this implementation. From 704c30a6822afe013a9987a60e6b56a936b08845 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 01:26:55 +0200 Subject: [PATCH 11/38] Introduce an example for the tutorial. --- docs/src/tutorials/bridging_constraint.md | 46 ++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 3a607deb7c..1e4b60b729 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -30,7 +30,11 @@ dimensionality of the functions that can be used with the set. indicator constraint ([`Indicator`](@ref)), the first dimension indicates whether the constraint about the second dimension is active. -## Four parts in a constraint bridge +In this tutorial, we will cover the creation of a bridge from `<=` +([`LessThan`](@ref)) to `>=` ([`GreaterThan`](@ref)), i.e. creating a +constraint with reversed signs, only for scalar affine functions. + +## Four mandatory parts in a constraint bridge The first part of a constraint bridge is a new concrete type that inherits from [`Bridges.Constraint.AbstractBridge`](@ref). This type must have fields to @@ -51,3 +55,43 @@ Then, three sets of functions must be defined: of variables and constraints that this bridge adds. They are used to compute the set of other bridges that are required to use the one you are defining, if need be. + +More functions can be implemented, for instance to retrieve properties from the +bridge or deleting a bridged constraint. + +### 1. Structure for the bridge + +A typical `struct` behind a bridge depends on the type of the coefficients that +are used for the model (typically `Float64`, but coefficients might also be +integers or complex numbers). + +This structure must hold a reference to all the variables and the constraints +that are created as part of the bridge. + +In our example, the bridge should be able to map any +`ScalarAffineFunction{T}`-in-`LessThan{T}` constraint to a single +`ScalarAffineFunction{T}`-in-`GreaterThan{T}` constraint. The affine function +has coefficients of type `T`. The bridge is parametrized with `T`, so that the +constraint that the bridge creates also has coefficients of type `T`. + +```julia +struct SignBridge{T <: Number} <: Bridges.Constraint.AbstractBridge + constraint::ConstraintIndex{ScalarAffineFunction{T}, GreaterThan{T}} +end +``` + +### 2. Bridge creation + +### 3. Supported constraint types + +### 4. Metadata about the bridge + +## Bridge registration + +## Bridge improvements + +### Attribute retrieval + +Like models, bridges have attributes that can be retrieved using [`get`](@ref) +and [`set`](@ref). The most important ones are the number of variables and +constraints, but also the lists of variables and constraints. From e945fc9d857311e259fd3d172fb91657f48083e7 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 02:02:07 +0200 Subject: [PATCH 12/38] Main part of the tutorial. --- docs/src/tutorials/bridging_constraint.md | 84 +++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 1e4b60b729..1872b18832 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -68,6 +68,9 @@ integers or complex numbers). This structure must hold a reference to all the variables and the constraints that are created as part of the bridge. +The type of this structure is used throughout MOI as an identifier for the +bridge. It is passed as argument to most functions related to bridges. + In our example, the bridge should be able to map any `ScalarAffineFunction{T}`-in-`LessThan{T}` constraint to a single `ScalarAffineFunction{T}`-in-`GreaterThan{T}` constraint. The affine function @@ -82,10 +85,91 @@ end ### 2. Bridge creation +The function [`Bridges.Constraint.bridge_constraint`](@ref) is called whenever +the bridge should be instantiated for a specific model, with the given function +and set. The arguments to `bridge_constraint` are highly similar to +[`add_constraint`](@ref), with the exception of the first argument: it is the +type of the structure defined in the first step. + +`bridge_constraint` returns an object whose type is the structure defined in +the first step. + +In our example, the bridge constraint could be defined as: + +```julia +function Bridges.Constraint.bridge_constraint( + ::Type{SignBridge{T}}, # Bridge to use. + model, # Model to which the constraint is being added. + f::ScalarAffineFunction{T}, # Function to rewrite. + s::LessThan{T}, # Set to rewrite. +) where {T} + # Create the variables and constraints required for the bridge. + con = add_constraint(model, -f, GreaterThan(-s.upper)) + + # Return an instance of the bridge type with a reference to all the + # variables and constraints that were created in this function. + return SignBridge(con) +end +``` + ### 3. Supported constraint types +The function [`supports_constraint`](@ref) determines whether the bridge type +supports a given combination of function and set. + +This function must closely match `bridge_constraint`, because it will not be +called if `supports_constraint` returns `false`. + +```julia +function supports_constraint( + ::Type{SignBridge{T}}, # Bridge to use. + ::Type{ScalarAffineFunction{T}}, # Function to rewrite. + ::Type{LessThan{T}}, # Set to rewrite. +) where {T} + # Do some computation to ensure that the constraint is supported. + # Typically, you can directly return true. + return true +end +``` + ### 4. Metadata about the bridge +To determine whether a bridge can be used, MOI uses a shortest-path algorithm +that uses the variable types and the constraints that the bridge can create. +This information is communicated from the bridge to MOI using the functions +[`Bridges.added_constrained_variable_types`](@ref) and +[`Bridges.added_constraint_types`](@ref). Both return lists of tuples: +either a list of 1-tuples containing the variable types (typically, `ZeroOne` +or `Integer`) or a list of 2-tuples contained the functions and sets (like +`ScalarAffineFunction{T}`-`GreaterThan`). + +For our example, the bridge does not create any constrained variables, and +only `ScalarAffineFunction{T}`-in-`GreaterThan{T}` constraints: + +```julia +function Bridges.added_constrained_variable_types(::Type{SignBridge{T}}) where {T} + # The bridge does not create variables, return an empty list of tuples: + return Tuple{DataType}[] +end + +function Bridges.added_constraint_types(::Type{SignBridge{T}}) where {T} + return [ + # One element per F-in-S the bridge creates. + (ScalarAffineFunction{T}, GreaterThan{T}), + ] +end +``` + +A bridge that creates binary variables would rather have this definition of +`added_constrained_variable_types`: + +```julia +function Bridges.added_constrained_variable_types(::Type{Bridge{T}}) where {T} + # The bridge only creates binary variables: + return [(MOI.ZeroOne,)] +end +``` + ## Bridge registration ## Bridge improvements From 659a003091b2c7c7349f1953bb290d6804c0a87d Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 02:11:00 +0200 Subject: [PATCH 13/38] Single-bridge optimizer. --- docs/src/tutorials/bridging_constraint.md | 30 ++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 1872b18832..ec88c3a92e 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -71,6 +71,8 @@ that are created as part of the bridge. The type of this structure is used throughout MOI as an identifier for the bridge. It is passed as argument to most functions related to bridges. +The best practice is to have the name of this type end with `Bridge`. + In our example, the bridge should be able to map any `ScalarAffineFunction{T}`-in-`LessThan{T}` constraint to a single `ScalarAffineFunction{T}`-in-`GreaterThan{T}` constraint. The affine function @@ -164,7 +166,7 @@ A bridge that creates binary variables would rather have this definition of `added_constrained_variable_types`: ```julia -function Bridges.added_constrained_variable_types(::Type{Bridge{T}}) where {T} +function Bridges.added_constrained_variable_types(::Type{SomeBridge{T}}) where {T} # The bridge only creates binary variables: return [(MOI.ZeroOne,)] end @@ -172,6 +174,32 @@ end ## Bridge registration +For a bridge to be used by MOI, it must be known by MOI. + +### Single-bridge optimizer + +The first way to do so is to create a single-bridge optimizer. This type of +optimizer wraps another optimizer and adds the possibility to use only one +bridge. It is especially useful when unit testing bridges. + +It is common practice to use the same name as the type defined for the bridge +(`SignBridge`, in our example) without the suffix `Bridge`. + +```julia +const Sign{T, OT <: MOI.ModelLike} = + SingleBridgeOptimizer{SignBridge{T}, OT} +``` + +In the context of unit tests, this bridge is used in conjunction with a +[`MockOptimizer`](@ref): + +```julia +mock = Utilities.MockOptimizer( + Utilities.UniversalFallback(Utilities.Model{Float64}()), +) +bridged_mock = Sign{Float64}(mock) +``` + ## Bridge improvements ### Attribute retrieval From 3abc5bd49a6fbb2d58a8c54da9938744e72ce372 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 02:19:52 +0200 Subject: [PATCH 14/38] LazyBridgeOptimizer. --- docs/src/tutorials/bridging_constraint.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index ec88c3a92e..3a044d7e0e 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -176,7 +176,7 @@ end For a bridge to be used by MOI, it must be known by MOI. -### Single-bridge optimizer +### `SingleBridgeOptimizer` The first way to do so is to create a single-bridge optimizer. This type of optimizer wraps another optimizer and adds the possibility to use only one @@ -200,6 +200,19 @@ mock = Utilities.MockOptimizer( bridged_mock = Sign{Float64}(mock) ``` +### New bridge for a `LazyBridgeOptimizer` + +Typical user-facing models for MOI are based on +[`Bridges.LazyBridgeOptimizer`](@ref). For instance, this type of model is +returned by [`Bridges.full_bridge_optimizer`](@ref). These models can be +added more bridges by using [`Bridges.add_bridge`](@ref): + +```julia +inner_optimizer = Utilities.Model{Float64}() +optimizer = Bridges.full_bridge_optimizer(inner_optimizer, Float64) +Bridges.add_bridge(optimizer, SignBridge{Float64}) +``` + ## Bridge improvements ### Attribute retrieval From c1bdfcd25fb050ce74de1fdb8c6953442e269309 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 02:26:04 +0200 Subject: [PATCH 15/38] Number/list of constraints/variables. --- docs/src/tutorials/bridging_constraint.md | 54 +++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 3a044d7e0e..a87ec8ab63 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -220,3 +220,57 @@ Bridges.add_bridge(optimizer, SignBridge{Float64}) Like models, bridges have attributes that can be retrieved using [`get`](@ref) and [`set`](@ref). The most important ones are the number of variables and constraints, but also the lists of variables and constraints. + +In our example, we only have one constraint and only have to implement the +[`NumberOfConstraints`](@ref) and [`ListOfConstraints`](@ref) attributes: + +```julia +function get( + ::SignBridge{T}, + ::NumberOfConstraints{ + ScalarAffineFunction{T}, + GreaterThan{T}, + }, +) where {T} + return 1 +end + +function get( + bridge::SignBridge{T}, + ::ListOfConstraints{ + ScalarAffineFunction{T}, + GreaterThan{T}, + }, +) where {T} + return [bridge.constraint] +end +``` + +You must implement one such pair of functions for each type of constraint the +bridge adds to the model. + +!!! warning + Avoid returning a list from the bridge object without copying it. Users + should be able to change the contents of the returned list without altering + the bridge object. + +For variables, the situation is simpler. If your bridge creates new variables, +you should implement the [`NumberOfVariables`](@ref) and +[`ListOfVariables`](@ref) attributes. However, these attributes do not have +parameters, unlike their constraint counterparts. Only two functions suffice: + +```julia +function get( + ::SignBridge{T}, + ::NumberOfVariables, +) where {T} + return … +end + +function get( + ::SignBridge{T}, + ::ListOfVariables, +) where {T} + return … +end +``` From 74f610b4ee8700255deb2d1181caf34ff0b87188 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 02:32:45 +0200 Subject: [PATCH 16/38] Modifications. --- docs/src/tutorials/bridging_constraint.md | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index a87ec8ab63..b14bc11bc6 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -274,3 +274,29 @@ function get( return … end ``` + +### Model modifications + +When the user requests a change to a constraint, MOI does its best to avoid +copying the model, whence the modification API. Bridges can also implement +this API to allow certain changes, such as coefficient changes. + +In our case, a modification of a coefficient in the original constraint +(i.e. replacing the value of the coefficient of a variable in the affine +function) should be transmitted to the constraint created by the bridge, +but with a sign change. + +```julia +function MOI.modify( + model::MOI.ModelLike, + bridge::SignBridge, + change::ScalarCoefficientChange, +) + MOI.modify( + model, + bridge.constraint, + MOI.ScalarCoefficientChange(change.variable, -change.new_coefficient), + ) + return +end +``` From bd7bd2e0d31c7966380ca320142a700f95412194 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 02:35:57 +0200 Subject: [PATCH 17/38] Update bridging_constraint.md --- docs/src/tutorials/bridging_constraint.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index b14bc11bc6..1261f0c8c7 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -288,7 +288,7 @@ but with a sign change. ```julia function MOI.modify( - model::MOI.ModelLike, + model, bridge::SignBridge, change::ScalarCoefficientChange, ) @@ -300,3 +300,14 @@ function MOI.modify( return end ``` + +### Bridge deletion + +When a bridge is deleted, the constraints it added should be deleted too. + +```julia +function delete(model, bridge::SignBridge) + delete(model, bridge.constraint) + return +end +``` From b5d485c470adef9f2dc519adba1fad3978455b72 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 02:42:56 +0200 Subject: [PATCH 18/38] ListOfConstraint deprecated. --- docs/src/tutorials/bridging_constraint.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 1261f0c8c7..4adeede029 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -222,7 +222,8 @@ and [`set`](@ref). The most important ones are the number of variables and constraints, but also the lists of variables and constraints. In our example, we only have one constraint and only have to implement the -[`NumberOfConstraints`](@ref) and [`ListOfConstraints`](@ref) attributes: +[`NumberOfConstraints`](@ref) and [`ListOfConstraintTypesPresent`](@ref) +attributes: ```julia function get( @@ -237,7 +238,7 @@ end function get( bridge::SignBridge{T}, - ::ListOfConstraints{ + ::ListOfConstraintTypesPresent{ ScalarAffineFunction{T}, GreaterThan{T}, }, From 7124f493f2322a33f900601f9ca64846ae2e38dd Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 02:44:31 +0200 Subject: [PATCH 19/38] Update bridging_constraint.md --- docs/src/tutorials/bridging_constraint.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 4adeede029..bf3c379255 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -257,7 +257,7 @@ bridge adds to the model. For variables, the situation is simpler. If your bridge creates new variables, you should implement the [`NumberOfVariables`](@ref) and -[`ListOfVariables`](@ref) attributes. However, these attributes do not have +[`ListOfVariableIndices`](@ref) attributes. However, these attributes do not have parameters, unlike their constraint counterparts. Only two functions suffice: ```julia @@ -270,7 +270,7 @@ end function get( ::SignBridge{T}, - ::ListOfVariables, + ::ListOfVariableIndices, ) where {T} return … end From 6e1e4df3d3a905fc29a16f3e71178d28d391173a Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 02:45:01 +0200 Subject: [PATCH 20/38] Update bridging_constraint.md --- docs/src/tutorials/bridging_constraint.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index bf3c379255..59c3134363 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -191,7 +191,7 @@ const Sign{T, OT <: MOI.ModelLike} = ``` In the context of unit tests, this bridge is used in conjunction with a -[`MockOptimizer`](@ref): +[`Utilities.MockOptimizer`](@ref): ```julia mock = Utilities.MockOptimizer( From abe612150c67cde50058260566f95b4ef57c1ce1 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 02:48:43 +0200 Subject: [PATCH 21/38] Inconsistency. --- docs/src/tutorials/bridging_constraint.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 59c3134363..3d2a909741 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -222,8 +222,7 @@ and [`set`](@ref). The most important ones are the number of variables and constraints, but also the lists of variables and constraints. In our example, we only have one constraint and only have to implement the -[`NumberOfConstraints`](@ref) and [`ListOfConstraintTypesPresent`](@ref) -attributes: +[`NumberOfConstraints`](@ref) and [`ListOfConstraintIndices`](@ref) attributes: ```julia function get( @@ -238,7 +237,7 @@ end function get( bridge::SignBridge{T}, - ::ListOfConstraintTypesPresent{ + ::ListOfConstraintIndices{ ScalarAffineFunction{T}, GreaterThan{T}, }, From ddd453bf717fad0452f0fc974bd14e6d946b08a4 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 03:11:45 +0200 Subject: [PATCH 22/38] Style @odow. --- docs/src/tutorials/bridging_constraint.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 3d2a909741..cb06c33468 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -277,9 +277,9 @@ end ### Model modifications -When the user requests a change to a constraint, MOI does its best to avoid -copying the model, whence the modification API. Bridges can also implement -this API to allow certain changes, such as coefficient changes. +To avoid copying the model when the user request to change a constraint, MOI +provides [`MOI.modify`](@ref). Bridges can also implement this API to allow +certain changes, such as coefficient changes. In our case, a modification of a coefficient in the original constraint (i.e. replacing the value of the coefficient of a variable in the affine From a4a2aa900c0ad3752d48bfb55f90335cc7fb6c3b Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 03:16:41 +0200 Subject: [PATCH 23/38] Update docs/src/tutorials/bridging_constraint.md Co-authored-by: Oscar Dowson --- docs/src/tutorials/bridging_constraint.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index cb06c33468..626aa213ec 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -80,7 +80,7 @@ has coefficients of type `T`. The bridge is parametrized with `T`, so that the constraint that the bridge creates also has coefficients of type `T`. ```julia -struct SignBridge{T <: Number} <: Bridges.Constraint.AbstractBridge +struct SignBridge{T<:Number} <: Bridges.Constraint.AbstractBridge constraint::ConstraintIndex{ScalarAffineFunction{T}, GreaterThan{T}} end ``` From 6e163911a46fedfce90b3ab3ae2e8faf90c97934 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 03:16:50 +0200 Subject: [PATCH 24/38] Update docs/src/tutorials/bridging_constraint.md Co-authored-by: Oscar Dowson --- docs/src/tutorials/bridging_constraint.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 626aa213ec..15d409dee3 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -89,7 +89,7 @@ end The function [`Bridges.Constraint.bridge_constraint`](@ref) is called whenever the bridge should be instantiated for a specific model, with the given function -and set. The arguments to `bridge_constraint` are highly similar to +and set. The arguments to `bridge_constraint` are similar to [`add_constraint`](@ref), with the exception of the first argument: it is the type of the structure defined in the first step. From e7ec89a586181558fef74d1f3ae7d3a7c4258a07 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 03:17:04 +0200 Subject: [PATCH 25/38] Update docs/src/tutorials/bridging_constraint.md Co-authored-by: Oscar Dowson --- docs/src/tutorials/bridging_constraint.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 15d409dee3..76a892b5d3 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -93,7 +93,7 @@ and set. The arguments to `bridge_constraint` are similar to [`add_constraint`](@ref), with the exception of the first argument: it is the type of the structure defined in the first step. -`bridge_constraint` returns an object whose type is the structure defined in +`bridge_constraint` returns an instance of the struct defined in the first step. the first step. In our example, the bridge constraint could be defined as: From c01a45075fa8aeae28bf8ed3d2ef6f7677556d91 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 03:17:13 +0200 Subject: [PATCH 26/38] Update docs/src/tutorials/bridging_constraint.md Co-authored-by: Oscar Dowson --- docs/src/tutorials/bridging_constraint.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 76a892b5d3..beb5fccee9 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -101,7 +101,7 @@ In our example, the bridge constraint could be defined as: ```julia function Bridges.Constraint.bridge_constraint( ::Type{SignBridge{T}}, # Bridge to use. - model, # Model to which the constraint is being added. + model::MOI.ModelLike, # Model to which the constraint is being added. f::ScalarAffineFunction{T}, # Function to rewrite. s::LessThan{T}, # Set to rewrite. ) where {T} From 2a5e7c9a9f29955a6723e20f9d26e374a2bdfbb3 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 03:17:59 +0200 Subject: [PATCH 27/38] Update docs/src/tutorials/bridging_constraint.md Co-authored-by: Oscar Dowson --- docs/src/tutorials/bridging_constraint.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index beb5fccee9..f20e3bd2c2 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -186,7 +186,7 @@ It is common practice to use the same name as the type defined for the bridge (`SignBridge`, in our example) without the suffix `Bridge`. ```julia -const Sign{T, OT <: MOI.ModelLike} = +const Sign{T,OT<: MOI.ModelLike} = SingleBridgeOptimizer{SignBridge{T}, OT} ``` From a7fbd9161629e44edf9964aca53c11c5ece6ec41 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 03:18:05 +0200 Subject: [PATCH 28/38] Update docs/src/tutorials/bridging_constraint.md Co-authored-by: Oscar Dowson --- docs/src/tutorials/bridging_constraint.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index f20e3bd2c2..fc5752c666 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -151,7 +151,7 @@ only `ScalarAffineFunction{T}`-in-`GreaterThan{T}` constraints: ```julia function Bridges.added_constrained_variable_types(::Type{SignBridge{T}}) where {T} # The bridge does not create variables, return an empty list of tuples: - return Tuple{DataType}[] + return Tuple{Type}[] end function Bridges.added_constraint_types(::Type{SignBridge{T}}) where {T} From b626f6678c61ca636f99496250892c9f1625baf4 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 03:18:46 +0200 Subject: [PATCH 29/38] Add some types for the model. --- docs/src/tutorials/bridging_constraint.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index fc5752c666..415927f3d7 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -288,7 +288,7 @@ but with a sign change. ```julia function MOI.modify( - model, + model::MOI.ModelLike, bridge::SignBridge, change::ScalarCoefficientChange, ) @@ -306,7 +306,7 @@ end When a bridge is deleted, the constraints it added should be deleted too. ```julia -function delete(model, bridge::SignBridge) +function delete(model::MOI.ModelLike, bridge::SignBridge) delete(model, bridge.constraint) return end From 24d659687467f2f9d6a6925209b9255dc12257e6 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Wed, 4 Aug 2021 14:49:47 +1200 Subject: [PATCH 30/38] Apply suggestions from code review --- docs/src/tutorials/bridging_constraint.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 415927f3d7..b5331fcb8f 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -91,7 +91,7 @@ The function [`Bridges.Constraint.bridge_constraint`](@ref) is called whenever the bridge should be instantiated for a specific model, with the given function and set. The arguments to `bridge_constraint` are similar to [`add_constraint`](@ref), with the exception of the first argument: it is the -type of the structure defined in the first step. +`Type` of the struct defined in the first step. `bridge_constraint` returns an instance of the struct defined in the first step. the first step. @@ -155,7 +155,7 @@ function Bridges.added_constrained_variable_types(::Type{SignBridge{T}}) where { end function Bridges.added_constraint_types(::Type{SignBridge{T}}) where {T} - return [ + return Tuple{Type,Type}[ # One element per F-in-S the bridge creates. (ScalarAffineFunction{T}, GreaterThan{T}), ] @@ -168,7 +168,7 @@ A bridge that creates binary variables would rather have this definition of ```julia function Bridges.added_constrained_variable_types(::Type{SomeBridge{T}}) where {T} # The bridge only creates binary variables: - return [(MOI.ZeroOne,)] + return Tuple{Type}[(MOI.ZeroOne,)] end ``` @@ -264,14 +264,14 @@ function get( ::SignBridge{T}, ::NumberOfVariables, ) where {T} - return … + return 0 end function get( ::SignBridge{T}, ::ListOfVariableIndices, ) where {T} - return … + return MOI.VariableIndex[] end ``` From 8d154e830e57e63e5073fb1ae03c611b77f292ae Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 18:37:57 +0200 Subject: [PATCH 31/38] Update bridging_constraint.md --- docs/src/tutorials/bridging_constraint.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index b5331fcb8f..f7275f6c92 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -91,7 +91,8 @@ The function [`Bridges.Constraint.bridge_constraint`](@ref) is called whenever the bridge should be instantiated for a specific model, with the given function and set. The arguments to `bridge_constraint` are similar to [`add_constraint`](@ref), with the exception of the first argument: it is the -`Type` of the struct defined in the first step. +`Type` of the struct defined in the first step (for our example, +`Type{SignBridge{T}}`). `bridge_constraint` returns an instance of the struct defined in the first step. the first step. From 6f9428e7ef762ecf1d8502fb9492a869f9093db6 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 18:54:43 +0200 Subject: [PATCH 32/38] Update bridging_constraint.md --- docs/src/tutorials/bridging_constraint.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index f7275f6c92..1e66901589 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -30,9 +30,13 @@ dimensionality of the functions that can be used with the set. indicator constraint ([`Indicator`](@ref)), the first dimension indicates whether the constraint about the second dimension is active. -In this tutorial, we will cover the creation of a bridge from `<=` -([`LessThan`](@ref)) to `>=` ([`GreaterThan`](@ref)), i.e. creating a -constraint with reversed signs, only for scalar affine functions. +To explain how to implement a bridge, we present the example of +[`Bridges.Constraint.FlipSignBridge`](@ref). This bridge maps `<=` +([`LessThan`](@ref)) constraints to `>=` ([`GreaterThan`](@ref)) constraints. +This corresponds to reversing the sign of the inequality. We focus on scalar +affine functions (we disregard the cases of a single variable or of quadratic +functions). This example is a simplified version of the code included +in MOI. ## Four mandatory parts in a constraint bridge From 30afd4484fc3df23501f8593ff4e376db1b1bc77 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 18:55:15 +0200 Subject: [PATCH 33/38] Update bridging_constraint.md --- docs/src/tutorials/bridging_constraint.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 1e66901589..1358d2af49 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -40,7 +40,7 @@ in MOI. ## Four mandatory parts in a constraint bridge -The first part of a constraint bridge is a new concrete type that inherits from +The first part of a constraint bridge is a new concrete subtype of [`Bridges.Constraint.AbstractBridge`](@ref). This type must have fields to store all the new variables and constraints that the bridge will add. Typically, these types are parametrized by the type of the coefficients in the From d863c29c000375e2d440c3442233aab2d220dcc8 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 19:02:22 +0200 Subject: [PATCH 34/38] Update bridging_constraint.md --- docs/src/tutorials/bridging_constraint.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/src/tutorials/bridging_constraint.md b/docs/src/tutorials/bridging_constraint.md index 1358d2af49..8e13c725ce 100644 --- a/docs/src/tutorials/bridging_constraint.md +++ b/docs/src/tutorials/bridging_constraint.md @@ -106,7 +106,7 @@ In our example, the bridge constraint could be defined as: ```julia function Bridges.Constraint.bridge_constraint( ::Type{SignBridge{T}}, # Bridge to use. - model::MOI.ModelLike, # Model to which the constraint is being added. + model::ModelLike, # Model to which the constraint is being added. f::ScalarAffineFunction{T}, # Function to rewrite. s::LessThan{T}, # Set to rewrite. ) where {T} @@ -173,7 +173,7 @@ A bridge that creates binary variables would rather have this definition of ```julia function Bridges.added_constrained_variable_types(::Type{SomeBridge{T}}) where {T} # The bridge only creates binary variables: - return Tuple{Type}[(MOI.ZeroOne,)] + return Tuple{Type}[(ZeroOne,)] end ``` @@ -191,7 +191,7 @@ It is common practice to use the same name as the type defined for the bridge (`SignBridge`, in our example) without the suffix `Bridge`. ```julia -const Sign{T,OT<: MOI.ModelLike} = +const Sign{T,OT<: ModelLike} = SingleBridgeOptimizer{SignBridge{T}, OT} ``` @@ -276,14 +276,14 @@ function get( ::SignBridge{T}, ::ListOfVariableIndices, ) where {T} - return MOI.VariableIndex[] + return VariableIndex[] end ``` ### Model modifications To avoid copying the model when the user request to change a constraint, MOI -provides [`MOI.modify`](@ref). Bridges can also implement this API to allow +provides [`modify`](@ref). Bridges can also implement this API to allow certain changes, such as coefficient changes. In our case, a modification of a coefficient in the original constraint @@ -292,15 +292,15 @@ function) should be transmitted to the constraint created by the bridge, but with a sign change. ```julia -function MOI.modify( - model::MOI.ModelLike, +function modify( + model::ModelLike, bridge::SignBridge, change::ScalarCoefficientChange, ) - MOI.modify( + modify( model, bridge.constraint, - MOI.ScalarCoefficientChange(change.variable, -change.new_coefficient), + ScalarCoefficientChange(change.variable, -change.new_coefficient), ) return end @@ -311,7 +311,7 @@ end When a bridge is deleted, the constraints it added should be deleted too. ```julia -function delete(model::MOI.ModelLike, bridge::SignBridge) +function delete(model::ModelLike, bridge::SignBridge) delete(model, bridge.constraint) return end From 68aa48415b6ff93a41d5e65e2ef75edcfa1c8b9d Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 19:03:47 +0200 Subject: [PATCH 35/38] Update reference.md --- 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 c9b2cba3a9..6c4e52bc78 100644 --- a/docs/src/submodules/Bridges/reference.md +++ b/docs/src/submodules/Bridges/reference.md @@ -58,6 +58,7 @@ Bridges.inverse_adjoint_map_function ### [Bridges implemented](@id constraint_bridges_ref) ```@docs +Bridges.Constraint.FlipSignBridge Bridges.Constraint.GreaterToIntervalBridge Bridges.Constraint.GreaterToLessBridge Bridges.Constraint.LessToIntervalBridge From a4ca0da4ef2947f1384eb1bad13d2510b28b2f3b Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 19:04:41 +0200 Subject: [PATCH 36/38] Update reference.md --- 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 6c4e52bc78..6a4f13c882 100644 --- a/docs/src/submodules/Bridges/reference.md +++ b/docs/src/submodules/Bridges/reference.md @@ -106,6 +106,7 @@ Bridges.Variable.add_all_bridges ### [Bridges implemented](@id variable_bridges_ref) ```@docs +Bridges.Variable.FlipSignBridge Bridges.Variable.ZerosBridge Bridges.Variable.FreeBridge Bridges.Variable.NonposToNonnegBridge From 99812fdb1b75da5f7754c95f95008353741da973 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 21:43:45 +0200 Subject: [PATCH 37/38] Add doc for MockOptimizer. --- docs/src/submodules/Utilities/reference.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/src/submodules/Utilities/reference.md b/docs/src/submodules/Utilities/reference.md index 552b27ef47..fcd88befeb 100644 --- a/docs/src/submodules/Utilities/reference.md +++ b/docs/src/submodules/Utilities/reference.md @@ -49,6 +49,12 @@ Utilities.state Utilities.mode ``` +### Mock optimizer + +```@docs +Utilities.MockOptimizer +``` + ## Printing ```@docs From 159befb297b27377d2b05660c9aaba5600a12cd8 Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Wed, 4 Aug 2021 21:50:36 +0200 Subject: [PATCH 38/38] Update mockoptimizer.jl --- src/Utilities/mockoptimizer.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Utilities/mockoptimizer.jl b/src/Utilities/mockoptimizer.jl index dd2c7e80d5..a661af2507 100644 --- a/src/Utilities/mockoptimizer.jl +++ b/src/Utilities/mockoptimizer.jl @@ -8,6 +8,13 @@ struct MockVariableAttribute <: MOI.AbstractVariableAttribute end struct MockConstraintAttribute <: MOI.AbstractConstraintAttribute end # A mock optimizer used for testing. +""" + MockOptimizer + +`MockOptimizer` is a fake optimizer especially useful for testing. Its main +feature is that it can store the values that should be returned for each +attribute. +""" mutable struct MockOptimizer{MT<:MOI.ModelLike} <: MOI.AbstractOptimizer inner_model::MT # Flags