77DocTestFilters = [r"MathOptInterface|MOI"]
88```
99
10- # The ` Bridges ` submodule
10+ # The Bridges submodule
11+
12+ The ` Bridges ` module simplifies the process of converting models between
13+ equivalent formulations.
14+
15+ !!! tip
16+ [ Read our paper] ( https://arxiv.org/abs/2002.03447 ) for more details on how
17+ bridges are implemented.
18+
19+ ## Why bridges?
1120
1221A constraint can often be written in a number of equivalent formulations. For
1322example, the constraint `` l \le a^\top x \le u ``
@@ -19,63 +28,164 @@ re-formulation is to add a dummy variable `y` with the constraints ``l \le y \le
1928([ ` ScalarAffineFunction ` ] ( @ref ) -in-[ ` EqualTo ` ] ( @ref ) ).
2029
2130To avoid each solver having to code these transformations manually,
22- MathOptInterface provides * bridges* . A bridge is a small transformation from one
23- constraint type to another (potentially collection of) constraint type. Because
24- these bridges are included in MathOptInterface, they can be re-used by any
25- optimizer. Some bridges also implement constraint modifications and constraint
26- primal and dual translations.
27-
28- For example, the ` SplitIntervalBridge ` defines the reformulation of a
29- ` ScalarAffineFunction ` -in-` Interval ` constraint into a
30- ` ScalarAffineFunction ` -in-` GreaterThan ` and a
31- ` ScalarAffineFunction ` -in-` LessThan ` constraint. ` SplitInterval ` is the
32- bridge optimizer that applies the ` SplitIntervalBridge ` rewriting rule. Given
33- an optimizer ` optimizer ` implementing ` ScalarAffineFunction ` -in-` GreaterThan `
34- and ` ScalarAffineFunction ` -in-` LessThan ` , the optimizer
35- ``` jldoctest; setup=:(model = MOI.Utilities.Model{Float64}())
36- optimizer = MOI.Bridges.Constraint.SplitInterval{Float64}(model)
37- MOI.supports_constraint(
38- optimizer, MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}
39- )
40-
41- # output
42-
43- true
31+ MathOptInterface provides * bridges* .
32+
33+ A bridge is a small transformation from one constraint type to another
34+ (potentially collection of) constraint type.
35+
36+ Because these bridges are included in MathOptInterface, they can be re-used by
37+ any optimizer. Some bridges also implement constraint modifications and
38+ constraint primal and dual translations.
39+
40+ ## The three types of bridges
41+
42+ There are three types of bridges in MathOptInterface:
43+ 1 . Constraint bridges
44+ 2 . Variable bridges
45+ 3 . Objective bridges
46+
47+ ### Constraint bridges
48+
49+ Constraint bridges convert constraints formulated by the user into an equivalent
50+ form supported by the solver.
51+
52+ The equivalent formulation may add constraints (and possibly also variables) in
53+ the underlying model.
54+
55+ Read the [ list of implemented constraint bridges] (@ref constraint_bridges_ref)
56+ for more details on the types of transformations that are available.
57+
58+ ### [ Variable bridges] (@id variable_bridges)
59+
60+ Variable bridges convert variables added by the user, either free with
61+ [ ` add_variable ` ] ( @ref ) /[ ` add_variables ` ] ( @ref ) , or constrained with
62+ [ ` add_constrained_variable ` ] ( @ref ) /[ ` add_constrained_variables ` ] ( @ref ) ,
63+ into an equivalent form supported by the solver.
64+
65+ Te equivalent formulation may add constraints (and possibly also variables) in
66+ the underlying model.
67+
68+ Read the [ list of implemented variable bridges] (@ref variable_bridges_ref) for
69+ more details on the types of transformations that are available.
70+
71+ ### Objective bridges
72+
73+ Objective bridges convert the [ ` ObjectiveFunction ` ] ( @ref ) set by the user into
74+ an equivalent form supported by the solver.
75+
76+ Te equivalent formulation may add constraints (and possibly also variables) in
77+ the underlying model.
78+
79+ Read the [ list of implemented objective bridges] (@ref objective_bridges_ref) for
80+ more details on the types of transformations that are available.
81+
82+ ## Bridges.` full_bridge_optimizer `
83+
84+ !!! tip
85+ Unless you have an advanced use-case, this is probably the only function you
86+ need to care about.
87+
88+ To enable the full power of MathOptInterface's bridges, wrap an ` optimizer `
89+ in a [ ` Bridges.full_bridge_optimizer ` ] ( @ref ) .
90+
91+ ``` jldoctest
92+ julia> inner_optimizer = MOI.Utilities.Model{Float64}()
93+ MOIU.Model{Float64}
94+
95+ julia> optimizer = MOI.Bridges.full_bridge_optimizer(inner_optimizer, Float64)
96+ MOIB.LazyBridgeOptimizer{MOIU.Model{Float64}}
97+ with 0 variable bridges
98+ with 0 constraint bridges
99+ with 0 objective bridges
100+ with inner model MOIU.Model{Float64}
44101```
45- will additionally support [ ` ScalarAffineFunction ` ] ( @ref ) -in-[ ` Interval ` ] ( @ref ) .
46- Note that these [ ` Bridges.Constraint.SingleBridgeOptimizer ` ] ( @ref ) s are mainly
47- used for testing bridges.
48-
49- It is recommended to rather use [ ` Bridges.full_bridge_optimizer ` ] ( @ref ) which
50- automatically selects the appropriate constraint bridges for unsupported
51- constraints.
52- ``` julia
53- optimizer = MOI. Bridges. full_bridge_optimizer (model, Float64)
102+
103+ That's all you have to do! Use ` optimizer ` as normal, and bridging will happen
104+ lazily behind the scenes. By lazily, we mean that bridging will only happen if
105+ the constraint is not supported by the ` inner_optimizer ` .
106+
107+ !!! info
108+ Most bridges are added by default in [ ` Bridges.full_bridge_optimizer ` ] ( @ref ) .
109+ However, for technical reasons, some bridges are not added by default. Three
110+ examples include [ ` Bridges.Constraint.SOCtoPSDBridge ` ] ( @ref ) ,
111+ [ ` Bridges.Constraint.SOCtoNonConvexQuadBridge ` ] ( @ref ) and
112+ [ ` Bridges.Constraint.RSOCtoNonConvexQuadBridge ` ] ( @ref ) . See the docs of
113+ those bridges for more information.
114+
115+ ## Add a single bridge
116+
117+ If you don't want to use [ ` Bridges.full_bridge_optimizer ` ] ( @ref ) , you can wrap
118+ an optimizer in a single bridge.
119+
120+ However, this will force the constraint to be bridged, even if the
121+ ` inner_optimizer ` supports it.
122+
123+ ``` jldoctest
124+ julia> inner_optimizer = MOI.Utilities.Model{Float64}()
125+ MOIU.Model{Float64}
126+
127+ julia> optimizer = MOI.Bridges.Constraint.SplitInterval{Float64}(inner_optimizer)
128+ MOIB.Constraint.SingleBridgeOptimizer{MOIB.Constraint.SplitIntervalBridge{Float64,F,S,LS,US} where US<:MOI.AbstractSet where LS<:MOI.AbstractSet where S<:MOI.AbstractSet where F<:MOI.AbstractFunction,MOIU.Model{Float64}}
129+ with 0 constraint bridges
130+ with inner model MOIU.Model{Float64}
131+
132+ julia> x = MOI.add_variable(optimizer)
133+ MOI.VariableIndex(1)
134+
135+ julia> MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.Interval(0.0, 1.0))
136+ MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.Interval{Float64}}(1)
137+
138+ julia> MOI.get(optimizer, MOI.ListOfConstraints())
139+ 1-element Array{Tuple{DataType,DataType},1}:
140+ (MathOptInterface.SingleVariable, MathOptInterface.Interval{Float64})
141+
142+ julia> MOI.get(inner_optimizer, MOI.ListOfConstraints())
143+ 2-element Array{Tuple{DataType,DataType},1}:
144+ (MathOptInterface.SingleVariable, MathOptInterface.GreaterThan{Float64})
145+ (MathOptInterface.SingleVariable, MathOptInterface.LessThan{Float64})
54146```
55147
56- ### Variable reformulations
148+ ## Bridges.LazyBridgeOptimizer
149+
150+ If you don't want to use [ ` Bridges.full_bridge_optimizer ` ] ( @ref ) , but you need
151+ more than a single bridge (or you want the bridging to happen lazily), you can
152+ manually construct a [ ` Bridges.LazyBridgeOptimizer ` ] ( @ref ) .
153+
154+ First, wrap an inner optimizer:
155+ ``` jldoctest lazy_bridge_optimizer
156+ julia> inner_optimizer = MOI.Utilities.Model{Float64}()
157+ MOIU.Model{Float64}
57158
58- A variable is often created constrained in a set unsupported by the solver while
59- it could be parametrized by variables constrained in supported sets.
60- For example, the [ ` Bridges.Variable.VectorizeBridge ` ] ( @ref ) defines the
61- reformulation of a constrained variable in [ ` GreaterThan ` ] ( @ref ) into a
62- constrained vector of one variable in [ ` Nonnegatives ` ] ( @ref ) .
63- The ` Bridges.Variable.Vectorize ` is the bridge optimizer that applies the
64- [ ` Bridges.Variable.VectorizeBridge ` ] ( @ref ) rewriting rule. Given an optimizer
65- ` optimizer ` implementing constrained variables in [ ` Nonnegatives ` ] ( @ref ) ,
66- the optimizer
67- ``` jldoctest; setup=:(model = MOI.Utilities.Model{Float64}())
68- optimizer = MOI.Bridges.Variable.Vectorize{Float64}(model)
69- MOI.supports_add_constrained_variable(optimizer, MOI.GreaterThan{Float64})
159+ julia> optimizer = MOI.Bridges.LazyBridgeOptimizer(inner_optimizer)
160+ MOIB.LazyBridgeOptimizer{MOIU.Model{Float64}}
161+ with 0 variable bridges
162+ with 0 constraint bridges
163+ with 0 objective bridges
164+ with inner model MOIU.Model{Float64}
165+ ```
70166
71- # output
167+ Then use [ ` Bridges.add_bridge ` ] ( @ref ) to add individual bridges:
168+ ``` jldoctest lazy_bridge_optimizer
169+ julia> MOI.Bridges.add_bridge(optimizer, MOI.Bridges.Constraint.SplitIntervalBridge{Float64})
170+ Dict{Any,DataType} with 0 entries
72171
73- true
172+ julia> MOI.Bridges.add_bridge(optimizer, MOI.Bridges.Objective.FunctionizeBridge{Float64})
173+ Dict{Any,DataType} with 0 entries
74174```
75- will additionally support constrained variables in [ ` GreaterThan ` ] ( @ref ) .
76- Note that these [ ` Bridges.Variable.SingleBridgeOptimizer ` ] ( @ref ) are mainly
77- used for testing bridges.
78175
79- It is recommended to rather use [ ` Bridges.full_bridge_optimizer ` ] ( @ref ) , which
80- automatically selects the appropriate bridges for unsupported constrained
81- variables.
176+ Now the constraints will be bridged only if needed:
177+ ``` jldoctest lazy_bridge_optimizer
178+ julia> x = MOI.add_variable(optimizer)
179+ MOI.VariableIndex(1)
180+
181+ julia> MOI.add_constraint(optimizer, MOI.SingleVariable(x), MOI.Interval(0.0, 1.0))
182+ MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.Interval{Float64}}(1)
183+
184+ julia> MOI.get(optimizer, MOI.ListOfConstraints())
185+ 1-element Array{Tuple{DataType,DataType},1}:
186+ (MathOptInterface.SingleVariable, MathOptInterface.Interval{Float64})
187+
188+ julia> MOI.get(inner_optimizer, MOI.ListOfConstraints())
189+ 1-element Array{Tuple{DataType,DataType},1}:
190+ (MathOptInterface.SingleVariable, MathOptInterface.Interval{Float64})
191+ ```
0 commit comments