Skip to content

Commit 8b6e9ef

Browse files
authored
[Bridges.Objective] add ToScalarNonlinearBridge (#2834)
1 parent 0e52dcb commit 8b6e9ef

File tree

4 files changed

+192
-3
lines changed

4 files changed

+192
-3
lines changed

src/Bridges/Constraint/bridges/AbstractFunctionConversionBridge.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,8 @@ function conversion_cost(
269269
::Type{
270270
<:Union{
271271
MOI.VariableIndex,
272-
MOI.ScalarAffineFunction,
273-
MOI.ScalarQuadraticFunction,
272+
MOI.ScalarAffineFunction{Float64},
273+
MOI.ScalarQuadraticFunction{Float64},
274274
},
275275
},
276276
)

src/Bridges/Objective/Objective.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ The coefficient type used is `T`.
2828
function add_all_bridges(model, ::Type{T}) where {T}
2929
MOI.Bridges.add_bridge(model, FunctionizeBridge{T})
3030
MOI.Bridges.add_bridge(model, QuadratizeBridge{T})
31+
MOI.Bridges.add_bridge(model, ToScalarNonlinearBridge{T})
3132
MOI.Bridges.add_bridge(model, SlackBridge{T})
3233
MOI.Bridges.add_bridge(model, VectorFunctionizeBridge{T})
3334
MOI.Bridges.add_bridge(model, VectorSlackBridge{T})

src/Bridges/Objective/bridges/FunctionConversionBridge.jl

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
1515
for these pairs of functions:
1616
17-
* [`MOI.ScalarAffineFunction`](@ref)` to [`MOI.ScalarQuadraticFunction`](@ref)
17+
* [`MOI.ScalarAffineFunction`](@ref) to [`MOI.ScalarQuadraticFunction`](@ref)
1818
* [`MOI.ScalarQuadraticFunction`](@ref) to [`MOI.ScalarNonlinearFunction`](@ref)
1919
* [`MOI.VectorAffineFunction`](@ref) to [`MOI.VectorQuadraticFunction`](@ref)
2020
@@ -173,6 +173,34 @@ const QuadratizeBridge{T,G} =
173173
const Quadratize{T,OT<:MOI.ModelLike} =
174174
SingleBridgeOptimizer{QuadratizeBridge{T},OT}
175175

176+
"""
177+
ToScalarNonlinearBridge{T,G} <: FunctionConversionBridge{T,MOI.ScalarNonlinearFunction,G}
178+
179+
`ToScalarNonlinearBridge` implements the following reformulations:
180+
181+
* ``\\min\\{x^\\top \\mathbf{𝑄} x + a^\\top x + b\\}`` into ``\\min\\{f(x)\\}``
182+
* ``\\max\\{x^\\top \\mathbf{𝑄} x + a^\\top x + b\\}`` into ``\\max\\{f(x)\\}``
183+
184+
where `f(x)` is a `MOI.ScalarNonlinearFunction`.
185+
186+
## Source node
187+
188+
`ToScalarNonlinearBridge` supports:
189+
190+
* [`MOI.ObjectiveFunction{G}`](@ref)
191+
192+
## Target nodes
193+
194+
`ToScalarNonlinearBridge` creates:
195+
196+
* One objective node: [`MOI.ObjectiveFunction{MOI.ScalarNonlinearFunction}`](@ref)
197+
"""
198+
const ToScalarNonlinearBridge{T,G} =
199+
FunctionConversionBridge{T,MOI.ScalarNonlinearFunction,G}
200+
201+
const ToScalarNonlinear{T,OT<:MOI.ModelLike} =
202+
SingleBridgeOptimizer{ToScalarNonlinearBridge{T},OT}
203+
176204
"""
177205
VectorFunctionizeBridge{T,G} <: FunctionConversionBridge{T,MOI.VectorAffineFunction{T},G}
178206
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# Copyright (c) 2017: Miles Lubin and contributors
2+
# Copyright (c) 2017: Google Inc.
3+
#
4+
# Use of this source code is governed by an MIT-style license that can be found
5+
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
6+
7+
module TestObjectiveToScalarNonlinear
8+
9+
using Test
10+
11+
import MathOptInterface as MOI
12+
13+
function runtests()
14+
for name in names(@__MODULE__; all = true)
15+
if startswith("$(name)", "test_")
16+
@testset "$(name)" begin
17+
getfield(@__MODULE__, name)()
18+
end
19+
end
20+
end
21+
return
22+
end
23+
24+
include("../utilities.jl")
25+
26+
function test_solve_singlevariable_obj()
27+
mock = MOI.Utilities.MockOptimizer(MOI.Utilities.Model{Float64}())
28+
model = MOI.Bridges.Objective.ToScalarNonlinear{Float64}(mock)
29+
MOI.Utilities.set_mock_optimize!(
30+
mock,
31+
(mock::MOI.Utilities.MockOptimizer) ->
32+
MOI.Utilities.mock_optimize!(mock, [1.0], MOI.FEASIBLE_POINT),
33+
)
34+
MOI.Test.test_objective_ObjectiveFunction_duplicate_terms(
35+
model,
36+
MOI.Test.Config(;
37+
exclude = Any[MOI.DualObjectiveValue, MOI.ConstraintDual],
38+
),
39+
)
40+
@test MOI.get(mock, MOI.ObjectiveFunctionType()) ==
41+
MOI.ScalarNonlinearFunction
42+
@test MOI.get(model, MOI.ObjectiveFunctionType()) ==
43+
MOI.ScalarAffineFunction{Float64}
44+
@test MOI.get(mock, MOI.ObjectiveSense()) == MOI.MIN_SENSE
45+
@test MOI.get(model, MOI.ObjectiveSense()) == MOI.MIN_SENSE
46+
vis = MOI.get(model, MOI.ListOfVariableIndices())
47+
func = 3.0 * vis[1] + 0.0
48+
49+
@test MOI.get(
50+
model,
51+
MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),
52+
) func
53+
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
54+
@test MOI.get(mock, MOI.ObjectiveSense()) == MOI.MAX_SENSE
55+
@test MOI.get(model, MOI.ObjectiveSense()) == MOI.MAX_SENSE
56+
57+
_test_delete_objective(model, 1, tuple())
58+
return
59+
end
60+
61+
function test_solve_result_index()
62+
mock = MOI.Utilities.MockOptimizer(MOI.Utilities.Model{Float64}())
63+
model = MOI.Bridges.Objective.ToScalarNonlinear{Float64}(mock)
64+
MOI.Utilities.set_mock_optimize!(
65+
mock,
66+
(mock::MOI.Utilities.MockOptimizer) -> MOI.Utilities.mock_optimize!(
67+
mock,
68+
MOI.OPTIMAL,
69+
(MOI.FEASIBLE_POINT, [1.0]),
70+
MOI.FEASIBLE_POINT,
71+
(MOI.VariableIndex, MOI.GreaterThan{Float64}) => [1.0],
72+
),
73+
)
74+
MOI.Test.test_solve_result_index(
75+
model,
76+
MOI.Test.Config(;
77+
exclude = Any[MOI.DualObjectiveValue, MOI.ConstraintDual],
78+
),
79+
)
80+
81+
return
82+
end
83+
84+
function test_runtests()
85+
MOI.Bridges.runtests(
86+
MOI.Bridges.Objective.ToScalarNonlinearBridge,
87+
model -> begin
88+
x = MOI.add_variable(model)
89+
aff = MOI.ScalarAffineFunction(
90+
MOI.ScalarAffineTerm.([2.0], [x]),
91+
1.0,
92+
)
93+
MOI.set(
94+
model,
95+
MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),
96+
aff,
97+
)
98+
MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)
99+
end,
100+
model -> begin
101+
x = MOI.add_variable(model)
102+
exp = MOI.ScalarNonlinearFunction(
103+
:+,
104+
[
105+
MOI.ScalarNonlinearFunction(
106+
:*,
107+
[2.0, MOI.VariableIndex(1)],
108+
),
109+
1.0,
110+
],
111+
)
112+
MOI.set(
113+
model,
114+
MOI.ObjectiveFunction{MOI.ScalarNonlinearFunction}(),
115+
exp,
116+
)
117+
MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)
118+
end,
119+
)
120+
MOI.Bridges.runtests(
121+
MOI.Bridges.Objective.ToScalarNonlinearBridge,
122+
model -> begin
123+
x = MOI.add_variable(model)
124+
aff = MOI.ScalarAffineFunction(
125+
MOI.ScalarAffineTerm.([2.0], [x]),
126+
1.0,
127+
)
128+
MOI.set(
129+
model,
130+
MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),
131+
aff,
132+
)
133+
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
134+
end,
135+
model -> begin
136+
x = MOI.add_variable(model)
137+
exp = MOI.ScalarNonlinearFunction(
138+
:+,
139+
[
140+
MOI.ScalarNonlinearFunction(
141+
:*,
142+
[2.0, MOI.VariableIndex(1)],
143+
),
144+
1.0,
145+
],
146+
)
147+
MOI.set(
148+
model,
149+
MOI.ObjectiveFunction{MOI.ScalarNonlinearFunction}(),
150+
exp,
151+
)
152+
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
153+
end,
154+
)
155+
return
156+
end
157+
158+
end # module
159+
160+
TestObjectiveToScalarNonlinear.runtests()

0 commit comments

Comments
 (0)