Skip to content

Commit 45291ed

Browse files
committed
Finish bridges doc
1 parent 8edd432 commit 45291ed

11 files changed

Lines changed: 102 additions & 25 deletions

File tree

docs/src/apireference.md

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -430,19 +430,59 @@ DeleteNotAllowed
430430

431431
## Bridges
432432

433-
Bridges can be used for automatic reformulation of a certain constraint type into equivalent constraints.
433+
Bridges can be used for automatic reformulation of a certain constrained
434+
variables or constraints into equivalent formulations using constrained
435+
variables and constraints of different types.
436+
There are two important concepts to distinguish:
437+
* [`Bridges.AbstractBridge`](@ref)s are recipes implementing a specific
438+
reformulation. Bridges are not directly subtypes of
439+
[`Bridges.AbstractBridge`](@ref), they are either
440+
[`Bridges.Variable.AbstractBridge`](@ref) or
441+
[`Bridges.Constraint.AbstractBridge`](@ref).
442+
* [`Bridges.AbstractBridgeOptimizer`](@ref)s is a layer that can applied to
443+
another [`ModelLike`](@ref) to apply the reformulation. The
444+
[`Bridges.LazyBridgeOptimizer`](@ref) automatically choose the appropriate
445+
bridges to use when a constrained variable or constraint is not supported
446+
using the list of bridges that were added to it by [`Bridges.add_bridge`](@ref).
447+
[`Bridges.full_bridge_optimizer`](@ref) wraps a model in a
448+
[`Bridges.LazyBridgeOptimizer`](@ref) where all the bridges defined in MOI
449+
are added. This is the recommended way to use bridges in the
450+
[Testing guideline](@ref) and JuMP automatically calls this function when
451+
attaching an optimizer.
452+
434453
```@docs
435454
Bridges.AbstractBridge
436455
Bridges.AbstractBridgeOptimizer
437-
Bridges.Constraint.SingleBridgeOptimizer
438456
Bridges.LazyBridgeOptimizer
439457
Bridges.add_bridge
458+
Bridges.full_bridge_optimizer
440459
```
441460

442461
### Variable bridges
443462

463+
When variables are added, either free with
464+
[`add_variable`](@ref)/[`add_variables`](@ref),
465+
or constrained with
466+
[`add_constrained_variable`](@ref)/[`add_constrained_variables`](@ref),
467+
variable bridges allow to return *bridged variables* that do not correspond to
468+
variables of the underlying model. These variables are parametrized by
469+
variables of the underlying model and this parametrization can be obtained with
470+
[`Bridges.variable_bridged_function`](@ref). Similarly, the variables of the
471+
underlying model that were created by the bridge can be expressed in terms of
472+
the bridged variables and this expression can be obtained with
473+
[`Bridges.variable_unbridged_function`](@ref).
474+
475+
!!! note
476+
A notable exception is with [`Bridges.Variable.ZerosBridge`](@ref) where no
477+
variable is created in the underlying model as the variables are simply
478+
transformed to zeros. When this bridge is used, it is not possible to
479+
recover functions with bridged variables from functions of the underlying
480+
model.
481+
444482
```@docs
445483
Bridges.Variable.AbstractBridge
484+
Bridges.variable_bridged_function
485+
Bridges.variable_unbridged_function
446486
```
447487

448488
Below is the list of variable bridges implemented in this package.
@@ -454,8 +494,25 @@ Bridges.Variable.VectorizeBridge
454494
Bridges.Variable.RSOCtoPSDBridge
455495
```
456496

497+
For each bridge defined in this package, a corresponding
498+
[`Bridges.Variable.SingleBridgeOptimizer`](@ref) is available with the same
499+
name without the "Bridge" suffix, e.g., `SplitInterval` is a
500+
`SingleBridgeOptimizer` for the `SplitIntervalBridge`. Moreover, they are all
501+
added in the [`Bridges.LazyBridgeOptimizer`](@ref) returned by
502+
[`Bridges.full_bridge_optimizer`](@ref) as it calls
503+
[`Bridges.Variable.add_all_bridges`](@ref).
504+
```@docs
505+
Bridges.Variable.SingleBridgeOptimizer
506+
Bridges.Variable.add_all_bridges
507+
```
508+
457509
### Constraint bridges
458510

511+
When constraints are added with [`add_constraint`](@ref), constraint bridges
512+
allow to return *bridged constraints* that do not correspond to
513+
constraints of the underlying model. These constraints were enforced by an
514+
equivalent formulation that added constraints (and possibly also variables) in
515+
the underlying model.
459516
```@docs
460517
Bridges.Constraint.AbstractBridge
461518
```
@@ -483,27 +540,34 @@ Bridges.Constraint.SOCtoPSDBridge
483540
Bridges.Constraint.RSOCtoPSDBridge
484541
Bridges.Constraint.IndicatorActiveOnFalseBridge
485542
```
486-
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`.
487-
Moreover, a `LazyBridgeOptimizer` with all the bridges defined in this package can be obtained with
543+
For each bridge defined in this package, a corresponding
544+
[`Bridges.Constraint.SingleBridgeOptimizer`](@ref) is available with the same
545+
name without the "Bridge" suffix, e.g., `SplitInterval` is a
546+
`SingleBridgeOptimizer` for the `SplitIntervalBridge`. Moreover, they are all
547+
added in the [`Bridges.LazyBridgeOptimizer`](@ref) returned by
548+
[`Bridges.full_bridge_optimizer`](@ref) as it calls
549+
[`Bridges.Constraint.add_all_bridges`](@ref).
488550
```@docs
489-
Bridges.full_bridge_optimizer
551+
Bridges.Constraint.SingleBridgeOptimizer
552+
Bridges.Constraint.add_all_bridges
490553
```
491554

492555
### Bridge interface
493556

494557
A bridge should implement the following functions to be usable by a bridge optimizer:
495558
```@docs
496-
supports_constraint(::Type{<:Bridges.Constraint.AbstractBridge}, ::Type{<:AbstractFunction}, ::Type{<:AbstractSet})
497559
Bridges.added_constrained_variable_types
498560
Bridges.added_constraint_types
499561
```
500562
Additionally, variable bridges should implement:
501563
```@docs
564+
Bridges.Variable.supports_constrained_variable
502565
Bridges.Variable.concrete_bridge_type
503566
Bridges.Variable.bridge_constrained_variable
504567
```
505568
and constraint bridges should implement
506569
```@docs
570+
supports_constraint(::Type{<:Bridges.Constraint.AbstractBridge}, ::Type{<:AbstractFunction}, ::Type{<:AbstractSet})
507571
Bridges.Constraint.concrete_bridge_type
508572
Bridges.Constraint.bridge_constraint
509573
```

src/Bridges/Variable/bridge.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,13 @@ function MOI.get(::MOI.ModelLike, attr::MOI.AbstractVariableAttribute,
5151
end
5252

5353
"""
54-
supports_constrained_variables(::Type{<:AbstractBridge},
54+
supports_constrained_variable(::Type{<:AbstractBridge},
5555
::Type{<:MOI.AbstractSet})::Bool
5656
5757
Return a `Bool` indicating whether the bridges of type `BT` support bridging
5858
constrained variables in `S`.
5959
"""
60-
function supports_constrained_variables(::Type{<:AbstractBridge},
60+
function supports_constrained_variable(::Type{<:AbstractBridge},
6161
::Type{<:MOI.AbstractSet})
6262
return false
6363
end
@@ -128,7 +128,7 @@ end
128128
S::Type{<:MOI.AbstractSet})::DataType
129129
130130
Return the concrete type of the bridge supporting variables in `S` constraints.
131-
This function can only be called if `MOI.supports_constrained_variables(BT, S)`
131+
This function can only be called if `MOI.supports_constrained_variable(BT, S)`
132132
is `true`.
133133
134134
## Examples

src/Bridges/Variable/flip_sign.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ stored in the `flipped_constraint` field by convention.
99
abstract type FlipSignBridge{
1010
T, S1<:MOI.AbstractSet, S2<:MOI.AbstractSet} <: AbstractBridge end
1111

12-
function supports_constrained_variables(
12+
function supports_constrained_variable(
1313
::Type{<:FlipSignBridge{T, S1}}, ::Type{S1}) where {T, S1<:MOI.AbstractVectorSet}
1414
return true
1515
end

src/Bridges/Variable/free.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ function bridge_constrained_variable(::Type{FreeBridge{T}},
2222
nonpos_variables, nonpos_constraint)
2323
end
2424

25-
function supports_constrained_variables(
25+
function supports_constrained_variable(
2626
::Type{<:FreeBridge}, ::Type{MOI.Reals})
2727
return true
2828
end

src/Bridges/Variable/map.jl

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -261,20 +261,28 @@ function function_for(map::Map, ci::MOI.ConstraintIndex{MOI.VectorOfVariables})
261261
end
262262

263263
"""
264-
unbridged_function(map::Map, vi::MOI.VariableIndex)
264+
throw_if_cannot_unbridge(map::Map)
265265
266-
Return the expression of `vi` in terms of bridged variables.
266+
Throw an error if some bridged variables do not have any reverse mapping.
267267
"""
268-
function unbridged_function(map::Map, vi::MOI.VariableIndex)
268+
function throw_if_cannot_unbridge(map::Map)
269269
if map.unbridged_function === nothing
270270
error("Cannot unbridge function because some variables are bridged by",
271271
" variable bridges that do not support reverse mapping, e.g.,",
272272
" `ZerosBridge`.")
273-
else
274-
return get(map.unbridged_function, vi, nothing)
275273
end
276274
end
277275

276+
"""
277+
unbridged_function(map::Map, vi::MOI.VariableIndex)
278+
279+
Return the expression of `vi` in terms of bridged variables.
280+
"""
281+
function unbridged_function(map::Map, vi::MOI.VariableIndex)
282+
throw_if_cannot_unbridge(map)
283+
return get(map.unbridged_function, vi, nothing)
284+
end
285+
278286
"""
279287
EmptyMap <: AbstractDict{MOI.VariableIndex, AbstractBridge}
280288

src/Bridges/Variable/rsoc_to_psd.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ function bridge_constrained_variable(::Type{RSOCtoPSDBridge{T}},
4040
return RSOCtoPSDBridge{T}(variables, psd, off_diag, diag)
4141
end
4242

43-
function supports_constrained_variables(
43+
function supports_constrained_variable(
4444
::Type{<:RSOCtoPSDBridge}, ::Type{MOI.RotatedSecondOrderCone})
4545
return true
4646
end

src/Bridges/Variable/single_bridge_optimizer.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ bridges(bridge::SingleBridgeOptimizer) = bridge.map
2525
function MOIB.supports_bridging_constraint(
2626
b::SingleBridgeOptimizer{BT}, ::Type{MOI.SingleVariable},
2727
S::Type{<:MOI.AbstractScalarSet}) where BT
28-
return supports_constrained_variables(BT, S)
28+
return supports_constrained_variable(BT, S)
2929
end
3030
function MOIB.supports_bridging_constraint(
3131
b::SingleBridgeOptimizer{BT}, ::Type{MOI.VectorOfVariables},
3232
S::Type{<:MOI.AbstractVectorSet}) where BT
33-
return supports_constrained_variables(BT, S)
33+
return supports_constrained_variable(BT, S)
3434
end
3535
function MOIB.is_bridged(b::SingleBridgeOptimizer, S::Type{<:MOI.AbstractScalarSet})
3636
return MOIB.supports_bridging_constraint(b, MOI.SingleVariable, S)

src/Bridges/Variable/vectorize.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function bridge_constrained_variable(
1717
return VectorizeBridge{T, S}(variables[1], vector_constraint, set_constant)
1818
end
1919

20-
function supports_constrained_variables(
20+
function supports_constrained_variable(
2121
::Type{VectorizeBridge{T}}, ::Type{<:MOIU.ScalarLinearSet{T}}) where T
2222
return true
2323
end

src/Bridges/Variable/zeros.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ function bridge_constrained_variable(::Type{ZerosBridge{T}},
2222
return ZerosBridge{T}(MOI.dimension(set))
2323
end
2424

25-
function supports_constrained_variables(
25+
function supports_constrained_variable(
2626
::Type{<:ZerosBridge}, ::Type{MOI.Zeros})
2727
return true
2828
end

src/Bridges/bridge_optimizer.jl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -828,15 +828,16 @@ end
828828
bridged_function(bridge::AbstractBridgeOptimizer, value) = value
829829

830830
"""
831-
variable_bridged_function(b::AbstractBridgeOptimizer,
831+
variable_unbridged_function(b::AbstractBridgeOptimizer,
832832
vi::MOI.VariableIndex)
833833
834834
Return a `MOI.AbstractScalarFunction` of variables of `b` that equals `vi`.
835835
That is, if the variable `vi` is an internal variable of `b.model` created by a
836836
but not visible to the user, it returns its expression in terms of the variables
837837
of bridged variables. Otherwise, it returns `MOI.SingleVariable(vi)`.
838838
"""
839-
function variable_unbridged_function(b, vi::MOI.VariableIndex)
839+
function variable_unbridged_function(b::AbstractBridgeOptimizer,
840+
vi::MOI.VariableIndex)
840841
func = Variable.unbridged_function(Variable.bridges(b), vi)
841842
if func === nothing
842843
return MOI.SingleVariable(vi)
@@ -860,6 +861,10 @@ function unbridged_function(b::AbstractBridgeOptimizer,
860861
if !Variable.has_bridges(Variable.bridges(b))
861862
return func
862863
end
864+
# If `func` does not contain any variable, this will never call
865+
# `variable_unbridged_function` hence it might silently return an incorrect
866+
# function so we call `throw_if_cannot_unbridge` here.
867+
Variable.throw_if_cannot_unbridge(Variable.bridges(b))
863868
return MOIU.substitute_variables(
864869
vi -> variable_unbridged_function(b, vi),
865870
func)::typeof(func)

0 commit comments

Comments
 (0)