From 06ab49a0e0d92eae9041b6242810c4fb46a93767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 3 Jun 2019 20:52:36 +0200 Subject: [PATCH 01/10] Add variable bridges --- docs/src/apimanual.md | 51 +++++++- docs/src/apireference.md | 246 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 278 insertions(+), 19 deletions(-) diff --git a/docs/src/apimanual.md b/docs/src/apimanual.md index 0bf04755d0..5fda09208c 100644 --- a/docs/src/apimanual.md +++ b/docs/src/apimanual.md @@ -4,6 +4,7 @@ DocTestSetup = quote using MathOptInterface const MOI = MathOptInterface end +DocTestFilters = [r"MathOptInterface|MOI"] ``` # Manual @@ -931,6 +932,31 @@ between `y_i` and the vector of scalar-valued quadratic functions. ### Automatic reformulation +#### Variable reformulation + +A variable is often created constrained in a set unsupported by the solver while +it could be parametrized by variables constrained in supported sets. +For example, the [`Bridges.Variable.VectorizeBridge`](@ref) defines the +reformulation of a constrained variable in [`GreaterThan`](@ref) into a +constrained vector of one variable in [`Nonnegatives`](@ref). +The `Bridges.Variable.Vectorize` is the bridge optimizer that applies the +[`Bridges.Variable.VectorizeBridge`](@ref) rewritting rule. Given an optimizer +`optimizer` implementing constrained variables in [`Nonnegatives`](@ref) and, +the optimizer +```jldoctest; setup=:(optimizer = MOI.Utilities.Model{Float64}()) +bridged_optimizer = MOI.Bridges.Variable.Vectorize{Float64}(optimizer) +MOI.supports_constraint(bridged_optimizer, MOI.SingleVariable, MOI.GreaterThan{Float64}) + +# output + +true +``` +will additionally support constrained variables in [`GreaterThan`](@ref). +Note that these [`Bridges.Variable.SingleBridgeOptimizer`](@ref) are mainly +used for testing bridges. It is recommended to rather use +[`Bridges.full_bridge_optimizer`](@ref) which automatically select the +appropriate bridges for unsupported constrained variables. + #### Constraint reformulation A constraint often possess different equivalent formulations, but a solver may only support one of them. @@ -938,13 +964,28 @@ It would be duplicate work to implement rewritting rules in every solver wrapper Constraint bridges provide a way to define a rewritting rule on top of the MOI interface which can be used by any optimizer. Some rules also implement constraint modifications and constraint primal and duals translations. -For example, the `SplitIntervalBridge` defines the reformulation of a `ScalarAffineFunction`-in-`Interval` constraint into a `ScalarAffineFunction`-in-`GreaterThan` and a `ScalarAffineFunction`-in-`LessThan` constraint. -The `SplitInterval` is the bridge optimizer that applies the `SplitIntervalBridge` rewritting rule. -Given an optimizer `optimizer` implementing `ScalarAffineFunction`-in-`GreaterThan` and `ScalarAffineFunction`-in-`LessThan`, the optimizer -``` -bridgedoptimizer = SplitInterval(optimizer) +For example, the [`Bridges.Constraint.SplitIntervalBridge`](@ref) defines the +reformulation of a [`ScalarAffineFunction`](@ref)-in-[`Interval`](@ref) +constraint into a [`ScalarAffineFunction`](@ref)-in-[`GreaterThan`](@ref) and a +[`ScalarAffineFunction`](@ref)-in-[`LessThan`](@ref) constraint. +The `Bridges.Constraint.SplitInterval` is the bridge optimizer that applies the +[`Bridges.Constraint.SplitIntervalBridge`](@ref) rewritting rule. Given an +optimizer `optimizer` implementing [`ScalarAffineFunction`](@ref)-in-[`GreaterThan`](@ref) +and [`ScalarAffineFunction`](@ref)-in-[`LessThan`](@ref), the optimizer +```jldoctest; setup=:(optimizer = MOI.Utilities.Model{Float64}()) +bridged_optimizer = MOI.Bridges.Constraint.SplitInterval{Float64}(optimizer) +MOI.supports_constraint(bridged_optimizer, MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) + +# output + +true ``` will additionally support `ScalarAffineFunction`-in-`Interval`. +Note that these [`Bridges.Constraint.SingleBridgeOptimizer`](@ref) are mainly +used for testing bridges. It is recommended to rather use +[`Bridges.full_bridge_optimizer`](@ref) which automatically select the +appropriate constraint bridges for unsupported constraints. + ## Implementing a solver interface diff --git a/docs/src/apireference.md b/docs/src/apireference.md index ee8ef286ce..98de938ca1 100644 --- a/docs/src/apireference.md +++ b/docs/src/apireference.md @@ -74,7 +74,6 @@ AbstractSubmittable submit ``` - ## Model Interface ```@docs @@ -192,8 +191,8 @@ delete(::ModelLike, ::Index) [`add_variables`](@ref) while *constrained variables* are the variables created with [`add_constrained_variable`](@ref) or [`add_constrained_variables`](@ref). Adding constrained variables instead of -constraining free variables with [`add_constraint`](@ref) allows Variable -bridges to be used. +constraining free variables with [`add_constraint`](@ref) allows +[Variable bridges](@ref) to be used. Note further that free variables that are constrained with [`add_constraint`](@ref) may be copied by [`copy_to`](@ref) with [`add_constrained_variable`](@ref) or [`add_constrained_variables`](@ref) by the @@ -481,17 +480,219 @@ Utilities.@model ## Bridges -Bridges can be used for automatic reformulation of a certain constraint type into equivalent constraints. +Bridges can be used for automatic reformulation of constrained variables or +constraints into equivalent formulations using constrained variables and +constraints of different types. There are two important concepts to distinguish: +* [`Bridges.AbstractBridge`](@ref)s are recipes implementing a specific + reformulation. Bridges are not directly subtypes of + [`Bridges.AbstractBridge`](@ref), they are either + [`Bridges.Variable.AbstractBridge`](@ref) or + [`Bridges.Constraint.AbstractBridge`](@ref). +* [`Bridges.AbstractBridgeOptimizer`](@ref) is a layer that can be applied to + another [`ModelLike`](@ref) to apply the reformulation. The + [`Bridges.LazyBridgeOptimizer`](@ref) automatically chooses the appropriate + bridges to use when a constrained variable or constraint is not supported + by using the list of bridges that were added to it by + [`Bridges.add_bridge`](@ref). [`Bridges.full_bridge_optimizer`](@ref) wraps a + model in a [`Bridges.LazyBridgeOptimizer`](@ref) where all the bridges defined + in MOI are added. This is the recommended way to use bridges in the + [Testing guideline](@ref), and JuMP automatically calls this function when + attaching an optimizer. + ```@docs Bridges.AbstractBridge -Bridges.Constraint.AbstractBridge Bridges.AbstractBridgeOptimizer -Bridges.Constraint.SingleBridgeOptimizer Bridges.LazyBridgeOptimizer Bridges.add_bridge +Bridges.full_bridge_optimizer +``` + +### Variable bridges + +When variables are added, either free with +[`add_variable`](@ref)/[`add_variables`](@ref), +or constrained with +[`add_constrained_variable`](@ref)/[`add_constrained_variables`](@ref), +variable bridges allow to return *bridged variables* that do not correspond to +variables of the underlying model. These variables are parametrized by +variables of the underlying model and this parametrization can be obtained with +[`Bridges.bridged_variable_function`](@ref). Similarly, the variables of the +underlying model that were created by the bridge can be expressed in terms of +the bridged variables and this expression can be obtained with +[`Bridges.unbridged_variable_function`](@ref). +For instance, consider a model bridged by the +[`Bridges.Variable.VectorizeBridge`](@ref): +```jldoctest bridged_variable_function +model = MOI.Utilities.Model{Float64}() +bridged_model = MOI.Bridges.Variable.Vectorize{Float64}(model) +bridged_variable, bridged_constraint = MOI.add_constrained_variable(bridged_model, MOI.GreaterThan(1.0)) + +# output + +(MOI.VariableIndex(-1), MOI.ConstraintIndex{MOI.SingleVariable,MOI.GreaterThan{Float64}}(-1)) +``` +The constrained variable in `MOI.GreaterThan(1.0)` returned is a bridged +variable as its index in negative. In `model`, a constrained variable in +`MOI.Nonnegatives` is created: +```jldoctest bridged_variable_function +inner_variables = MOI.get(model, MOI.ListOfVariableIndices()) + +# output + +1-element Array{MOI.VariableIndex,1}: + MOI.VariableIndex(1) +``` +In the functions used for adding constraints or setting the objective to +`bridged_model`, `bridged_variable` is substituted for `inner_variables[1]` plus +1: +```jldoctest bridged_variable_function +MOI.Bridges.bridged_variable_function(bridged_model, bridged_variable) + +# output + +MOI.ScalarAffineFunction{Float64}(MOI.ScalarAffineTerm{Float64}[ScalarAffineTerm{Float64}(1.0, VariableIndex(1))], 1.0) +``` +When getting [`ConstraintFunction`](@ref) or [`ObjectiveFunction`](@ref), +`inner_variables[1]` is substituted for `bridged_variable` minus 1: +```jldoctest bridged_variable_function +MOI.Bridges.unbridged_variable_function(bridged_model, inner_variables[1]) + +# output + +MOI.ScalarAffineFunction{Float64}(MOI.ScalarAffineTerm{Float64}[ScalarAffineTerm{Float64}(1.0, VariableIndex(-1))], -1.0) +``` + + +!!! note + A notable exception is with [`Bridges.Variable.ZerosBridge`](@ref) where no + variable is created in the underlying model as the variables are simply + transformed to zeros. When this bridge is used, it is not possible to + recover functions with bridged variables from functions of the inner + model. Consider for instance that we create two zero variables: + ```jldoctest cannot_unbridge_zero + model = MOI.Utilities.Model{Float64}() + bridged_model = MOI.Bridges.Variable.Zeros{Float64}(model) + bridged_variables, bridged_constraint = MOI.add_constrained_variables(bridged_model, MOI.Zeros(2)) + + # output + + (MOI.VariableIndex[VariableIndex(-1), VariableIndex(-2)], MOI.ConstraintIndex{MOI.VectorOfVariables,MOI.Zeros}(-1)) + ``` + Consider the following functions in the variables of `bridged_model`: + ```jldoctest cannot_unbridge_zero + func = MOI.Utilities.operate(+, Float64, MOI.SingleVariable.(bridged_variables)...) + + # output + + MOI.ScalarAffineFunction{Float64}(MOI.ScalarAffineTerm{Float64}[ScalarAffineTerm{Float64}(1.0, VariableIndex(-1)), ScalarAffineTerm{Float64}(1.0, VariableIndex(-2))], 0.0) + ``` + We can obtain the equivalent function in the variables of `model` as follows: + ```jldoctest cannot_unbridge_zero + inner_func = MOI.Bridges.bridged_function(bridged_model, func) + + # output + + MOI.ScalarAffineFunction{Float64}(MOI.ScalarAffineTerm{Float64}[], 0.0) + ``` + However, it's not possible to invert this operations. Indeed, since the + bridged variables are substituted for zeros, we cannot deduce whether + they were present in the initial function. + ```jldoctest cannot_unbridge_zero; filter = r"Stacktrace:.*"s + MOI.Bridges.unbridged_function(bridged_model, inner_func) + + # output + + ERROR: Cannot unbridge function because some variables are bridged by variable bridges that do not support reverse mapping, e.g., `ZerosBridge`. + Stacktrace: + [1] error(::String, ::String, ::String) at ./error.jl:42 + [2] throw_if_cannot_unbridge at /home/blegat/.julia/dev/MathOptInterface/src/Bridges/Variable/map.jl:343 [inlined] + [3] unbridged_function(::MOI.Bridges.Variable.SingleBridgeOptimizer{MOI.Bridges.Variable.ZerosBridge{Float64},MOI.Utilities.Model{Float64}}, ::MOI.ScalarAffineFunction{Float64}) at /home/blegat/.julia/dev/MOI/src/Bridges/bridge_optimizer.jl:920 + [4] top-level scope at none:0 + ``` + +```@docs +Bridges.Variable.AbstractBridge +Bridges.bridged_variable_function +Bridges.unbridged_variable_function ``` -Below is the list of bridges implemented in this package. +Below is the list of variable bridges implemented in this package. +```@docs +Bridges.Variable.ZerosBridge +Bridges.Variable.FreeBridge +Bridges.Variable.NonposToNonnegBridge +Bridges.Variable.VectorizeBridge +Bridges.Variable.RSOCtoPSDBridge +``` + +For each bridge defined in this package, a corresponding +[`Bridges.Variable.SingleBridgeOptimizer`](@ref) is available with the same +name without the "Bridge" suffix, e.g., `SplitInterval` is a +`SingleBridgeOptimizer` for the `SplitIntervalBridge`. Moreover, they are all +added in the [`Bridges.LazyBridgeOptimizer`](@ref) returned by +[`Bridges.full_bridge_optimizer`](@ref) as it calls +[`Bridges.Variable.add_all_bridges`](@ref). +```@docs +Bridges.Variable.SingleBridgeOptimizer +Bridges.Variable.add_all_bridges +``` + +### Constraint bridges + +When constraints are added with [`add_constraint`](@ref), constraint bridges +allow to return *bridged constraints* that do not correspond to +constraints of the underlying model. These constraints were enforced by an +equivalent formulation that added constraints (and possibly also variables) in +the underlying model. +For instance, consider a model bridged by the +[`Bridges.Constraint.SplitIntervalBridge`](@ref): +```jldoctest split_interval +model = MOI.Utilities.Model{Float64}() +bridged_model = MOI.Bridges.Constraint.SplitInterval{Float64}(model) +x, y = MOI.add_variables(bridged_model, 2) +func = MOI.Utilities.operate(+, Float64, MOI.SingleVariable(x), MOI.SingleVariable(y)) +c = MOI.add_constraint(bridged_model, func, MOI.Interval(1.0, 2.0)) + +# output + +MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64},MOI.Interval{Float64}}(1) +``` +We can see the constraint was bridged to two constraints, one for each bound, +in the inner model. +```jldoctest split_interval +MOI.get(model, MOI.ListOfConstraints()) + +# output + +2-element Array{Tuple{DataType,DataType},1}: + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) +``` +However, `bridged_model` hides transparently hides these constraints and create the +illusion that an interval constraint was created. +```jldoctest split_interval +MOI.get(bridged_model, MOI.ListOfConstraints()) + +# output + +1-element Array{Tuple{DataType,DataType},1}: + (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) +``` +It is nevertheless possible to differentiate this constraint from a constraint +added to the inner model by asking whether it is bridged: +```jldoctest split_interval +MOI.Bridges.is_bridged(bridged_model, c) + +# output + +true +``` + +```@docs +Bridges.Constraint.AbstractBridge +``` + +Below is the list of constraint bridges implemented in this package. ```@docs Bridges.Constraint.GreaterToLessBridge Bridges.Constraint.LessToGreaterBridge @@ -514,20 +715,36 @@ Bridges.Constraint.SOCtoPSDBridge Bridges.Constraint.RSOCtoPSDBridge Bridges.Constraint.IndicatorActiveOnFalseBridge ``` -For each bridge defined in this package, a corresponding bridge optimizer is available with the same name without the "Bridge" suffix, e.g., `SplitInterval` is an `SingleBridgeOptimizer` for the `SplitIntervalBridge`. -Moreover, a `LazyBridgeOptimizer` with all the bridges defined in this package can be obtained with +For each bridge defined in this package, a corresponding +[`Bridges.Constraint.SingleBridgeOptimizer`](@ref) is available with the same +name without the "Bridge" suffix, e.g., `SplitInterval` is a +`SingleBridgeOptimizer` for the `SplitIntervalBridge`. Moreover, they are all +added in the [`Bridges.LazyBridgeOptimizer`](@ref) returned by +[`Bridges.full_bridge_optimizer`](@ref) as it calls +[`Bridges.Constraint.add_all_bridges`](@ref). ```@docs -Bridges.full_bridge_optimizer +Bridges.Constraint.SingleBridgeOptimizer +Bridges.Constraint.add_all_bridges ``` ### Bridge interface A bridge should implement the following functions to be usable by a bridge optimizer: ```@docs +Bridges.added_constrained_variable_types +Bridges.added_constraint_types +``` +Additionally, variable bridges should implement: +```@docs +Bridges.Variable.supports_constrained_variable +Bridges.Variable.concrete_bridge_type +Bridges.Variable.bridge_constrained_variable +``` +and constraint bridges should implement +```@docs supports_constraint(::Type{<:Bridges.Constraint.AbstractBridge}, ::Type{<:AbstractFunction}, ::Type{<:AbstractSet}) Bridges.Constraint.concrete_bridge_type Bridges.Constraint.bridge_constraint -Bridges.added_constraint_types ``` When querying the [`NumberOfVariables`](@ref), [`NumberOfConstraints`](@ref) @@ -538,8 +755,9 @@ constraints it has creates by implemented the following methods of [`get`](@ref): ```@docs get(::Bridges.Constraint.AbstractBridge, ::NumberOfVariables) -get(::Bridges.Constraint.AbstractBridge, ::NumberOfConstraints) -get(::Bridges.Constraint.AbstractBridge, ::ListOfConstraintIndices) +get(::Bridges.Constraint.AbstractBridge, ::ListOfVariableIndices) +get(::Bridges.AbstractBridge, ::NumberOfConstraints) +get(::Bridges.AbstractBridge, ::ListOfConstraintIndices) ``` ## Copy utilities @@ -645,7 +863,7 @@ is set to `AUTOMATIC` or to `MANUAL`. a constraint) results in a drop to the state `EMPTY_OPTIMIZER`. When calling [`Utilities.attach_optimizer`](@ref), the `CachingOptimizer` copies -the cached model to the optimizer with [`MathOptInterface.copy_to`](@ref). +the cached model to the optimizer with [`copy_to`](@ref). We refer to [Implementing copy](@ref) for more details. ```@docs From 5fce11647832c853a9f6d9e3459c8431956daa90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sat, 10 Aug 2019 15:18:49 +0200 Subject: [PATCH 02/10] rewritting -> rewriting Co-Authored-By: Chris C. --- docs/src/apimanual.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/apimanual.md b/docs/src/apimanual.md index 5fda09208c..b90ccb80a4 100644 --- a/docs/src/apimanual.md +++ b/docs/src/apimanual.md @@ -940,7 +940,7 @@ For example, the [`Bridges.Variable.VectorizeBridge`](@ref) defines the reformulation of a constrained variable in [`GreaterThan`](@ref) into a constrained vector of one variable in [`Nonnegatives`](@ref). The `Bridges.Variable.Vectorize` is the bridge optimizer that applies the -[`Bridges.Variable.VectorizeBridge`](@ref) rewritting rule. Given an optimizer +[`Bridges.Variable.VectorizeBridge`](@ref) rewriting rule. Given an optimizer `optimizer` implementing constrained variables in [`Nonnegatives`](@ref) and, the optimizer ```jldoctest; setup=:(optimizer = MOI.Utilities.Model{Float64}()) From 26e8f95cd337179f7484d8c944ba0aaff203017d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sat, 10 Aug 2019 15:20:04 +0200 Subject: [PATCH 03/10] possess -> possesses Co-Authored-By: Chris C. --- docs/src/apimanual.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/apimanual.md b/docs/src/apimanual.md index b90ccb80a4..081c89538f 100644 --- a/docs/src/apimanual.md +++ b/docs/src/apimanual.md @@ -959,7 +959,7 @@ appropriate bridges for unsupported constrained variables. #### Constraint reformulation -A constraint often possess different equivalent formulations, but a solver may only support one of them. +A constraint often possesses different equivalent formulations, but a solver may only support one of them. It would be duplicate work to implement rewritting rules in every solver wrapper for every different formulation of the constraint to express it in the form supported by the solver. Constraint bridges provide a way to define a rewritting rule on top of the MOI interface which can be used by any optimizer. Some rules also implement constraint modifications and constraint primal and duals translations. From e46bb7ae1c37649f7f09056b321b65d28e6ba451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sat, 10 Aug 2019 15:20:31 +0200 Subject: [PATCH 04/10] rewritting -> rewriting Co-Authored-By: Chris C. --- docs/src/apimanual.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/apimanual.md b/docs/src/apimanual.md index 081c89538f..dd44dc8abe 100644 --- a/docs/src/apimanual.md +++ b/docs/src/apimanual.md @@ -960,7 +960,7 @@ appropriate bridges for unsupported constrained variables. #### Constraint reformulation A constraint often possesses different equivalent formulations, but a solver may only support one of them. -It would be duplicate work to implement rewritting rules in every solver wrapper for every different formulation of the constraint to express it in the form supported by the solver. +It would be duplicate work to implement rewriting rules in every solver wrapper for every different formulation of the constraint to express it in the form supported by the solver. Constraint bridges provide a way to define a rewritting rule on top of the MOI interface which can be used by any optimizer. Some rules also implement constraint modifications and constraint primal and duals translations. From b9f665014cdd0580705a92a29e264559f3d30ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sat, 10 Aug 2019 15:26:42 +0200 Subject: [PATCH 05/10] select -> selects Co-Authored-By: Chris C. --- docs/src/apimanual.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/apimanual.md b/docs/src/apimanual.md index dd44dc8abe..13aa854171 100644 --- a/docs/src/apimanual.md +++ b/docs/src/apimanual.md @@ -954,7 +954,7 @@ true will additionally support constrained variables in [`GreaterThan`](@ref). Note that these [`Bridges.Variable.SingleBridgeOptimizer`](@ref) are mainly used for testing bridges. It is recommended to rather use -[`Bridges.full_bridge_optimizer`](@ref) which automatically select the +[`Bridges.full_bridge_optimizer`](@ref), which automatically selects the appropriate bridges for unsupported constrained variables. #### Constraint reformulation From 6d5df0054bb0af70b4ce6baa220dd7f765f420aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sat, 10 Aug 2019 15:28:33 +0200 Subject: [PATCH 06/10] Address comments --- docs/src/apimanual.md | 8 ++++---- docs/src/apireference.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/src/apimanual.md b/docs/src/apimanual.md index 13aa854171..d2e97dfa0e 100644 --- a/docs/src/apimanual.md +++ b/docs/src/apimanual.md @@ -941,7 +941,7 @@ reformulation of a constrained variable in [`GreaterThan`](@ref) into a constrained vector of one variable in [`Nonnegatives`](@ref). The `Bridges.Variable.Vectorize` is the bridge optimizer that applies the [`Bridges.Variable.VectorizeBridge`](@ref) rewriting rule. Given an optimizer -`optimizer` implementing constrained variables in [`Nonnegatives`](@ref) and, +`optimizer` implementing constrained variables in [`Nonnegatives`](@ref), the optimizer ```jldoctest; setup=:(optimizer = MOI.Utilities.Model{Float64}()) bridged_optimizer = MOI.Bridges.Variable.Vectorize{Float64}(optimizer) @@ -961,7 +961,7 @@ appropriate bridges for unsupported constrained variables. A constraint often possesses different equivalent formulations, but a solver may only support one of them. It would be duplicate work to implement rewriting rules in every solver wrapper for every different formulation of the constraint to express it in the form supported by the solver. -Constraint bridges provide a way to define a rewritting rule on top of the MOI interface which can be used by any optimizer. +Constraint bridges provide a way to define a rewriting rule on top of the MOI interface which can be used by any optimizer. Some rules also implement constraint modifications and constraint primal and duals translations. For example, the [`Bridges.Constraint.SplitIntervalBridge`](@ref) defines the @@ -969,7 +969,7 @@ reformulation of a [`ScalarAffineFunction`](@ref)-in-[`Interval`](@ref) constraint into a [`ScalarAffineFunction`](@ref)-in-[`GreaterThan`](@ref) and a [`ScalarAffineFunction`](@ref)-in-[`LessThan`](@ref) constraint. The `Bridges.Constraint.SplitInterval` is the bridge optimizer that applies the -[`Bridges.Constraint.SplitIntervalBridge`](@ref) rewritting rule. Given an +[`Bridges.Constraint.SplitIntervalBridge`](@ref) rewriting rule. Given an optimizer `optimizer` implementing [`ScalarAffineFunction`](@ref)-in-[`GreaterThan`](@ref) and [`ScalarAffineFunction`](@ref)-in-[`LessThan`](@ref), the optimizer ```jldoctest; setup=:(optimizer = MOI.Utilities.Model{Float64}()) @@ -983,7 +983,7 @@ true will additionally support `ScalarAffineFunction`-in-`Interval`. Note that these [`Bridges.Constraint.SingleBridgeOptimizer`](@ref) are mainly used for testing bridges. It is recommended to rather use -[`Bridges.full_bridge_optimizer`](@ref) which automatically select the +[`Bridges.full_bridge_optimizer`](@ref) which automatically selects the appropriate constraint bridges for unsupported constraints. diff --git a/docs/src/apireference.md b/docs/src/apireference.md index 98de938ca1..53520caf49 100644 --- a/docs/src/apireference.md +++ b/docs/src/apireference.md @@ -192,7 +192,7 @@ delete(::ModelLike, ::Index) the variables created with [`add_constrained_variable`](@ref) or [`add_constrained_variables`](@ref). Adding constrained variables instead of constraining free variables with [`add_constraint`](@ref) allows -[Variable bridges](@ref) to be used. +[variable bridges](@ref Variable bridges) to be used. Note further that free variables that are constrained with [`add_constraint`](@ref) may be copied by [`copy_to`](@ref) with [`add_constrained_variable`](@ref) or [`add_constrained_variables`](@ref) by the From 97d084a36df603e387397316728f781a7c65cf36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sat, 10 Aug 2019 16:07:26 +0200 Subject: [PATCH 07/10] create -> creates Co-Authored-By: Chris C. --- docs/src/apireference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/apireference.md b/docs/src/apireference.md index 53520caf49..a734e15875 100644 --- a/docs/src/apireference.md +++ b/docs/src/apireference.md @@ -668,7 +668,7 @@ MOI.get(model, MOI.ListOfConstraints()) (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) ``` -However, `bridged_model` hides transparently hides these constraints and create the +However, `bridged_model` transparently hides these constraints and creates the illusion that an interval constraint was created. ```jldoctest split_interval MOI.get(bridged_model, MOI.ListOfConstraints()) From 402e5119f509f30929e9716b1125cff751e7eadb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sat, 10 Aug 2019 16:07:53 +0200 Subject: [PATCH 08/10] operations -> operation Co-Authored-By: Chris C. --- docs/src/apireference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/apireference.md b/docs/src/apireference.md index a734e15875..82fd255e42 100644 --- a/docs/src/apireference.md +++ b/docs/src/apireference.md @@ -594,7 +594,7 @@ MOI.ScalarAffineFunction{Float64}(MOI.ScalarAffineTerm{Float64}[ScalarAffineTerm MOI.ScalarAffineFunction{Float64}(MOI.ScalarAffineTerm{Float64}[], 0.0) ``` - However, it's not possible to invert this operations. Indeed, since the + However, it's not possible to invert this operation. Indeed, since the bridged variables are substituted for zeros, we cannot deduce whether they were present in the initial function. ```jldoctest cannot_unbridge_zero; filter = r"Stacktrace:.*"s From c5c8edcef8ff29802315038e0d5153a831721b66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sat, 10 Aug 2019 16:11:30 +0200 Subject: [PATCH 09/10] Address comments --- docs/src/apireference.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/src/apireference.md b/docs/src/apireference.md index 82fd255e42..efe6973e3a 100644 --- a/docs/src/apireference.md +++ b/docs/src/apireference.md @@ -480,8 +480,9 @@ Utilities.@model ## Bridges -Bridges can be used for automatic reformulation of constrained variables or -constraints into equivalent formulations using constrained variables and +Bridges can be used for automatic reformulation of constrained variables (i.e. +variables added with [`add_constrained_variable`](@ref)/[`add_constrained_variables`](@ref)) +or constraints into equivalent formulations using constrained variables and constraints of different types. There are two important concepts to distinguish: * [`Bridges.AbstractBridge`](@ref)s are recipes implementing a specific reformulation. Bridges are not directly subtypes of @@ -496,8 +497,8 @@ constraints of different types. There are two important concepts to distinguish: [`Bridges.add_bridge`](@ref). [`Bridges.full_bridge_optimizer`](@ref) wraps a model in a [`Bridges.LazyBridgeOptimizer`](@ref) where all the bridges defined in MOI are added. This is the recommended way to use bridges in the - [Testing guideline](@ref), and JuMP automatically calls this function when - attaching an optimizer. + [Testing guideline](@ref), and JuMP automatically calls + [`Bridges.full_bridge_optimizer`](@ref) when attaching an optimizer. ```@docs Bridges.AbstractBridge From 71437ddb0d3526af03393d7377e9f9e418125d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sat, 10 Aug 2019 22:04:19 +0200 Subject: [PATCH 10/10] Fix doc link --- docs/src/apireference.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/apireference.md b/docs/src/apireference.md index efe6973e3a..90275a08de 100644 --- a/docs/src/apireference.md +++ b/docs/src/apireference.md @@ -192,7 +192,7 @@ delete(::ModelLike, ::Index) the variables created with [`add_constrained_variable`](@ref) or [`add_constrained_variables`](@ref). Adding constrained variables instead of constraining free variables with [`add_constraint`](@ref) allows -[variable bridges](@ref Variable bridges) to be used. +[variable bridges](@ref variable_bridges) to be used. Note further that free variables that are constrained with [`add_constraint`](@ref) may be copied by [`copy_to`](@ref) with [`add_constrained_variable`](@ref) or [`add_constrained_variables`](@ref) by the @@ -508,7 +508,7 @@ Bridges.add_bridge Bridges.full_bridge_optimizer ``` -### Variable bridges +### [Variable bridges](@id variable_bridges) When variables are added, either free with [`add_variable`](@ref)/[`add_variables`](@ref),