Skip to content

Commit cd1958c

Browse files
authored
Merge pull request #658 from JuliaOpt/bl/flipsign
✨ Add FlipSign bridges
2 parents 9e49ea1 + fea3408 commit cd1958c

File tree

5 files changed

+418
-40
lines changed

5 files changed

+418
-40
lines changed

src/Bridges/Bridges.jl

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ include("lazybridgeoptimizer.jl")
2727
MOIU.@model(AllBridgedConstraints,
2828
(),
2929
(MOI.EqualTo, MOI.LessThan, MOI.GreaterThan, MOI.Interval,),
30-
(MOI.SecondOrderCone, MOI.RotatedSecondOrderCone, MOI.GeometricMeanCone,
30+
(MOI.Nonnegatives, MOI.Nonpositives, MOI.SecondOrderCone,
31+
MOI.RotatedSecondOrderCone, MOI.GeometricMeanCone,
3132
MOI.PositiveSemidefiniteConeSquare,
3233
MOI.LogDetConeTriangle, MOI.RootDetConeTriangle),
3334
(),
@@ -43,22 +44,31 @@ this package and for the coefficient type `T`.
4344
"""
4445
function full_bridge_optimizer(model::MOI.ModelLike, ::Type{T}) where T
4546
cache = MOIU.UniversalFallback(AllBridgedConstraints{T}())
46-
bridgedmodel = MOIB.LazyBridgeOptimizer(model, cache)
47-
add_bridge(bridgedmodel, MOIB.VectorizeBridge{T})
48-
add_bridge(bridgedmodel, MOIB.ScalarSlackBridge{T})
49-
add_bridge(bridgedmodel, MOIB.VectorSlackBridge{T})
50-
add_bridge(bridgedmodel, MOIB.SplitIntervalBridge{T})
51-
add_bridge(bridgedmodel, MOIB.QuadtoSOCBridge{T})
52-
add_bridge(bridgedmodel, MOIB.GeoMeanBridge{T})
53-
add_bridge(bridgedmodel, MOIB.SquarePSDBridge{T})
54-
add_bridge(bridgedmodel, MOIB.LogDetBridge{T})
55-
add_bridge(bridgedmodel, MOIB.RootDetBridge{T})
56-
add_bridge(bridgedmodel, MOIB.RSOCBridge{T})
57-
add_bridge(bridgedmodel, MOIB.RSOCtoPSDBridge{T})
58-
add_bridge(bridgedmodel, MOIB.SOCtoPSDBridge{T})
59-
bridgedmodel
47+
bridged_model = LazyBridgeOptimizer(model, cache)
48+
add_bridge(bridged_model, GreaterToLessBridge{T})
49+
add_bridge(bridged_model, LessToGreaterBridge{T})
50+
add_bridge(bridged_model, NonnegToNonposBridge{T})
51+
add_bridge(bridged_model, NonposToNonnegBridge{T})
52+
add_bridge(bridged_model, VectorizeBridge{T})
53+
add_bridge(bridged_model, ScalarSlackBridge{T})
54+
add_bridge(bridged_model, VectorSlackBridge{T})
55+
add_bridge(bridged_model, SplitIntervalBridge{T})
56+
add_bridge(bridged_model, QuadtoSOCBridge{T})
57+
add_bridge(bridged_model, GeoMeanBridge{T})
58+
add_bridge(bridged_model, SquarePSDBridge{T})
59+
add_bridge(bridged_model, LogDetBridge{T})
60+
add_bridge(bridged_model, RootDetBridge{T})
61+
add_bridge(bridged_model, RSOCBridge{T})
62+
add_bridge(bridged_model, RSOCtoPSDBridge{T})
63+
add_bridge(bridged_model, SOCtoPSDBridge{T})
64+
return bridged_model
6065
end
6166

67+
include("flip_sign_bridge.jl")
68+
@bridge GreaterToLess GreaterToLessBridge () (MOI.GreaterThan,) () () (MOI.SingleVariable,) (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction) () ()
69+
@bridge LessToGreater LessToGreaterBridge () (MOI.LessThan,) () () (MOI.SingleVariable,) (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction) () ()
70+
@bridge NonnegToNonpos NonnegToNonposBridge () () (MOI.Nonnegatives,) () () () (MOI.VectorOfVariables,) (MOI.VectorAffineFunction, MOI.VectorQuadraticFunction)
71+
@bridge NonposToNonneg NonposToNonnegBridge () () (MOI.Nonpositives,) () () () (MOI.VectorOfVariables,) (MOI.VectorAffineFunction, MOI.VectorQuadraticFunction)
6272
include("vectorizebridge.jl")
6373
@bridge Vectorize VectorizeBridge () (MOI.EqualTo, MOI.LessThan, MOI.GreaterThan,) () () (MOI.SingleVariable,) (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction) () ()
6474
include("slackbridge.jl")

src/Bridges/flip_sign_bridge.jl

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
"""
2+
FlipSignBridge{S1, S2, F}
3+
4+
Bridge a `G`-in-`S1` constraint into an `F`-in-`S2` constraint by multiplying
5+
the function by `-1` and taking the point reflection of the set across the
6+
origin. The flipped `F`-in-`S` constraint is stored in the `flipped_constraint`
7+
field by convention.
8+
"""
9+
abstract type FlipSignBridge{
10+
S1<:MOI.AbstractSet, S2<:MOI.AbstractSet,
11+
F<:MOI.AbstractFunction} <: AbstractBridge end
12+
13+
function MOI.supports_constraint(::Type{<:FlipSignBridge{S1}},
14+
::Type{<:MOI.AbstractScalarFunction},
15+
::Type{S1}) where {S1<:MOI.AbstractSet}
16+
return true
17+
end
18+
function added_constraint_types(
19+
::Type{<:FlipSignBridge{S1, S2, F}}) where {S1, S2, F}
20+
return [(F, S2)]
21+
end
22+
23+
# Attributes, Bridge acting as an model
24+
function MOI.get(::FlipSignBridge{S1, S2, F},
25+
::MOI.NumberOfConstraints{F, S2}) where {S1, S2, F}
26+
return 1
27+
end
28+
function MOI.get(bridge::FlipSignBridge{S1, S2, F},
29+
::MOI.ListOfConstraintIndices{F, S2}) where {S1, S2, F}
30+
return [bridge.flipped_constraint]
31+
end
32+
33+
# References
34+
function MOI.delete(model::MOI.ModelLike, bridge::FlipSignBridge)
35+
MOI.delete(model, bridge.flipped_constraint)
36+
end
37+
38+
# Attributes, Bridge acting as a constraint
39+
function MOI.get(model::MOI.ModelLike,
40+
attr::Union{MOI.ConstraintPrimal, MOI.ConstraintDual},
41+
bridge::FlipSignBridge)
42+
return -MOI.get(model, attr, bridge.flipped_constraint)
43+
end
44+
45+
function MOI.modify(model::MOI.ModelLike, bridge::FlipSignBridge,
46+
change::MOI.ScalarCoefficientChange)
47+
MOI.modify(
48+
model, bridge.flipped_constraint,
49+
MOI.ScalarCoefficientChange(change.variable, -change.new_coefficient))
50+
end
51+
52+
function MOI.modify(model::MOI.ModelLike, bridge::FlipSignBridge,
53+
change::MOI.MultirowChange{T}) where T
54+
new_coefficients = Tuple{Int64, T}[
55+
(index, -coef) for (index, coef) in change.new_coefficients]
56+
MOI.modify(model, bridge.flipped_constraint,
57+
MOI.MultirowChange(change.variable,
58+
new_coefficients))
59+
end
60+
function MOI.modify(model::MOI.ModelLike, bridge::FlipSignBridge,
61+
change::MOI.VectorConstantChange)
62+
MOI.modify(model, bridge.flipped_constraint,
63+
MOI.VectorConstantChange(-change.new_constant))
64+
end
65+
66+
"""
67+
GreaterToLessBridge{T, F<:MOI.AbstractScalarFunction} <:
68+
FlipSignBridge{MOI.GreaterThan{T}, MOI.LessThan{T}, F}
69+
70+
Transforms a `G`-in-`GreaterThan{T}` constraint into an `F`-in-`LessThan{T}`
71+
constraint.
72+
"""
73+
struct GreaterToLessBridge{T, F<:MOI.AbstractScalarFunction} <:
74+
FlipSignBridge{MOI.GreaterThan{T}, MOI.LessThan{T}, F}
75+
flipped_constraint::CI{F, MOI.LessThan{T}}
76+
end
77+
function GreaterToLessBridge{T, F}(model::MOI.ModelLike,
78+
g::MOI.AbstractScalarFunction,
79+
s::MOI.GreaterThan) where {T, F}
80+
f = MOIU.operate(-, T, g)
81+
flipped_constraint = MOI.add_constraint(model, f, MOI.LessThan(-s.lower))
82+
return GreaterToLessBridge{T, F}(flipped_constraint)
83+
end
84+
function concrete_bridge_type(::Type{<:GreaterToLessBridge{T}},
85+
G::Type{<:MOI.AbstractScalarFunction},
86+
::Type{MOI.GreaterThan{T}}) where T
87+
F = MOIU.promote_operation(-, T, G)
88+
return GreaterToLessBridge{T, F}
89+
end
90+
function MOI.set(model::MOI.ModelLike, attr::MOI.ConstraintSet,
91+
bridge::GreaterToLessBridge, new_set::MOI.GreaterThan)
92+
MOI.set(model, attr, bridge.flipped_constraint,
93+
MOI.LessThan(-new_set.lower))
94+
end
95+
96+
"""
97+
LessToGreaterBridge{T, F<:MOI.AbstractScalarFunction} <:
98+
FlipSignBridge{MOI.LessThan{T}, MOI.GreaterThan{T}, F}
99+
100+
Transforms a `G`-in-`LessThan{T}` constraint into an `F`-in-`GreaterThan{T}`
101+
constraint.
102+
"""
103+
struct LessToGreaterBridge{T, F<:MOI.AbstractScalarFunction} <:
104+
FlipSignBridge{MOI.LessThan{T}, MOI.GreaterThan{T}, F}
105+
flipped_constraint::CI{F, MOI.GreaterThan{T}}
106+
end
107+
function LessToGreaterBridge{T, F}(model::MOI.ModelLike,
108+
g::MOI.AbstractScalarFunction,
109+
s::MOI.LessThan) where {T, F}
110+
f = MOIU.operate(-, T, g)
111+
flipped_constraint = MOI.add_constraint(model, f, MOI.GreaterThan(-s.upper))
112+
return LessToGreaterBridge{T, F}(flipped_constraint)
113+
end
114+
function concrete_bridge_type(::Type{<:LessToGreaterBridge{T}},
115+
G::Type{<:MOI.AbstractScalarFunction},
116+
::Type{MOI.LessThan{T}}) where T
117+
F = MOIU.promote_operation(-, T, G)
118+
return LessToGreaterBridge{T, F}
119+
end
120+
function MOI.set(model::MOI.ModelLike, attr::MOI.ConstraintSet,
121+
bridge::LessToGreaterBridge, new_set::MOI.LessThan)
122+
MOI.set(model, attr, bridge.flipped_constraint,
123+
MOI.GreaterThan(-new_set.upper))
124+
end
125+
126+
"""
127+
NonnegToNonposBridge{T, F<:MOI.AbstractVectorFunction}
128+
129+
Transforms a `G`-in-`Nonnegatives` constraint into a `F`-in-`Nonpositives`
130+
constraint.
131+
"""
132+
struct NonnegToNonposBridge{T, F<:MOI.AbstractVectorFunction} <:
133+
FlipSignBridge{MOI.Nonnegatives, MOI.Nonpositives, F}
134+
flipped_constraint::CI{F, MOI.Nonpositives}
135+
end
136+
function NonnegToNonposBridge{T, F}(model::MOI.ModelLike,
137+
g::MOI.AbstractVectorFunction,
138+
s::MOI.Nonnegatives) where {T, F}
139+
f = MOIU.operate(-, T, g)
140+
flipped_constraint = MOI.add_constraint(model, f,
141+
MOI.Nonpositives(s.dimension))
142+
return NonnegToNonposBridge{T, F}(flipped_constraint)
143+
end
144+
function concrete_bridge_type(::Type{<:NonnegToNonposBridge{T}},
145+
G::Type{<:MOI.AbstractVectorFunction},
146+
::Type{MOI.Nonnegatives}) where T
147+
F = MOIU.promote_operation(-, T, G)
148+
return NonnegToNonposBridge{T, F}
149+
end
150+
151+
"""
152+
NonposToNonnegBridge{T, F<:MOI.AbstractVectorFunction}
153+
154+
Transforms a `G`-in-`Nonpositives` constraint into a `F`-in-`Nonnegatives`
155+
constraint.
156+
"""
157+
struct NonposToNonnegBridge{T, F<:MOI.AbstractVectorFunction} <:
158+
FlipSignBridge{MOI.Nonpositives, MOI.Nonnegatives, F}
159+
flipped_constraint::CI{F, MOI.Nonnegatives}
160+
end
161+
function NonposToNonnegBridge{T, F}(model::MOI.ModelLike,
162+
g::MOI.AbstractVectorFunction,
163+
s::MOI.Nonpositives) where {T, F}
164+
f = MOIU.operate(-, T, g)
165+
flipped_constraint = MOI.add_constraint(model, f,
166+
MOI.Nonnegatives(s.dimension))
167+
return NonposToNonnegBridge{T, F}(flipped_constraint)
168+
end
169+
function concrete_bridge_type(::Type{<:NonposToNonnegBridge{T}},
170+
G::Type{<:MOI.AbstractVectorFunction},
171+
::Type{MOI.Nonpositives}) where T
172+
F = MOIU.promote_operation(-, T, G)
173+
return NonposToNonnegBridge{T, F}
174+
end

src/Utilities/functions.jl

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -705,11 +705,19 @@ const VectorLike{T} = Union{MOI.VectorOfVariables, MOI.VectorAffineFunction{T},
705705
###################################### +/- #####################################
706706
## promote_operation
707707

708+
function promote_operation(::typeof(-), ::Type{T},
709+
::Type{<:ScalarAffineLike{T}}) where T
710+
return MOI.ScalarAffineFunction{T}
711+
end
708712
function promote_operation(::Union{typeof(+), typeof(-)}, ::Type{T},
709713
::Type{<:ScalarAffineLike{T}},
710714
::Type{<:ScalarAffineLike{T}}) where T
711715
return MOI.ScalarAffineFunction{T}
712716
end
717+
function promote_operation(::typeof(-), ::Type{T},
718+
::Type{<:ScalarQuadraticLike{T}}) where T
719+
return MOI.ScalarQuadraticFunction{T}
720+
end
713721
function promote_operation(::Union{typeof(+), typeof(-)}, ::Type{T},
714722
::Type{<:ScalarQuadraticLike{T}},
715723
::Type{<:ScalarQuadraticLike{T}}) where T
@@ -804,18 +812,22 @@ function operate(op::typeof(-), ::Type{T}, α::T, f::ScalarLike{T}) where T
804812
end
805813

806814
# Scalar Variable +/- ...
815+
function operate(::typeof(-), ::Type{T}, f::MOI.SingleVariable) where T
816+
return MOI.ScalarAffineFunction{T}(
817+
[MOI.ScalarAffineTerm(-one(T), f.variable)], zero(T))
818+
end
807819
function operate(op::Union{typeof(+), typeof(-)}, ::Type{T},
808820
f::MOI.SingleVariable, α::T) where T
809-
return MOI.ScalarAffineFunction{T}([MOI.ScalarAffineTerm(one(T),
810-
f.variable)],
811-
op(α))
821+
return MOI.ScalarAffineFunction{T}(
822+
[MOI.ScalarAffineTerm(one(T), f.variable)], op(α))
812823
end
813824
function operate(op::Union{typeof(+), typeof(-)}, ::Type{T},
814825
f::MOI.SingleVariable,
815826
g::MOI.SingleVariable) where T
816-
return MOI.ScalarAffineFunction{T}([MOI.ScalarAffineTerm(one(T), f.variable),
817-
MOI.ScalarAffineTerm(op(one(T)), g.variable)],
818-
zero(T))
827+
return MOI.ScalarAffineFunction{T}(
828+
[MOI.ScalarAffineTerm(one(T), f.variable),
829+
MOI.ScalarAffineTerm(op(one(T)), g.variable)],
830+
zero(T))
819831
end
820832
function operate(op::typeof(+), ::Type{T},
821833
f::MOI.SingleVariable,
@@ -848,6 +860,13 @@ function operate(op::Union{typeof(+), typeof(-)}, ::Type{T},
848860
op(f.constant, g.constant))
849861
end
850862
# Scalar Quadratic +/- ...
863+
function operate(op::Union{typeof(-)}, ::Type{T},
864+
f::MOI.ScalarQuadraticFunction{T}) where T
865+
return MOI.ScalarQuadraticFunction(
866+
operate_terms(op, f.affine_terms),
867+
operate_terms(op, f.quadratic_terms),
868+
op(f.constant))
869+
end
851870
function operate(op::Union{typeof(+), typeof(-)}, ::Type{T},
852871
f::MOI.ScalarQuadraticFunction{T},
853872
g::ScalarQuadraticLike{T}) where T
@@ -875,10 +894,14 @@ end
875894

876895
# Vector +/-
877896
###############################################################################
878-
# function promote_operation(::Union{typeof(+), typeof(-)}, ::Type{T},
879-
# ::Type{<:VectorAffineLike{T}}) where T
880-
# return MOI.VectorAffineFunction{T}
881-
# end
897+
function promote_operation(::typeof(-), ::Type{T},
898+
::Type{<:VectorAffineLike{T}}) where T
899+
return MOI.VectorAffineFunction{T}
900+
end
901+
function promote_operation(::typeof(-), ::Type{T},
902+
::Type{<:VectorQuadraticLike{T}}) where T
903+
return MOI.VectorQuadraticFunction{T}
904+
end
882905
function promote_operation(::Union{typeof(+), typeof(-)}, ::Type{T},
883906
::Type{<:VectorAffineLike{T}},
884907
::Type{<:VectorAffineLike{T}}) where T
@@ -1346,6 +1369,12 @@ function promote_operation(::typeof(vcat), ::Type{T},
13461369
::Type{<:Union{ScalarAffineLike{T}, VVF, VAF{T}}}...) where T
13471370
return VAF{T}
13481371
end
1372+
function promote_operation(
1373+
::typeof(vcat), ::Type{T},
1374+
::Type{<:Union{ScalarQuadraticLike{T}, VVF, VAF{T}, VQF{T}}}...) where T
1375+
return VQF{T}
1376+
end
1377+
13491378
function operate(::typeof(vcat), ::Type{T},
13501379
funcs::Union{ScalarAffineLike{T}, VVF, VAF{T}}...) where T
13511380
nterms = sum(func -> number_of_affine_terms(T, func), funcs)

0 commit comments

Comments
 (0)