Skip to content

Commit 946d18d

Browse files
authored
[breaking] Fix setting constant objective function (#581)
1 parent dea1d81 commit 946d18d

File tree

7 files changed

+91
-31
lines changed

7 files changed

+91
-31
lines changed

src/Convex.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,13 +218,13 @@ for (root, _, files) in walkdir(joinpath(@__DIR__, "constraints"))
218218
end
219219
end
220220

221-
include("problems.jl")
222221
include("SparseTape.jl")
223222
include("VectorAffineFunctionAsMatrix.jl")
224223
include("ComplexTape.jl")
225224
include("operate.jl")
226225
include("complex_operate.jl")
227226
include("real_operate.jl")
227+
include("problems.jl")
228228
include("solution.jl")
229229
include("MOI_wrapper.jl")
230230

src/MOI_wrapper.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,12 +225,12 @@ function MOI.supports(
225225
end
226226

227227
function MOI.set(
228-
model::Optimizer,
228+
model::Optimizer{T},
229229
::MOI.ObjectiveFunction{MOI.ScalarNonlinearFunction},
230230
func::MOI.ScalarNonlinearFunction,
231-
)
231+
) where {T}
232232
cfp = conic_form!(model.context, _expr(model, func))
233-
obj = scalar_fn(cfp)
233+
obj = _to_scalar_moi(T, cfp)
234234
MOI.set(model, MOI.ObjectiveFunction{typeof(obj)}(), obj)
235235
return
236236
end

src/problem_depot/problems/lp.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ end
195195
end
196196
handle_problem!(p)
197197
if test
198-
@test p.optval === nothing
198+
@test p.optval === 1.0
199199
@test evaluate(sum(neg(x))) 6 atol = atol rtol = rtol
200200
end
201201
end

src/problem_depot/problems/sdp.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1499,7 +1499,7 @@ function sdp_quantum_relative_entropy_impl(
14991499
atol rtol = rtol
15001500
elseif mode == 5
15011501
# Satisfiability problem
1502-
@test p.optval === nothing
1502+
@test p.optval 0 atol = atol rtol = rtol
15031503
end
15041504
end
15051505
end

src/problems.jl

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,20 @@ function new_conic_form!(context::Context, p::Problem)
143143
return conic_form!(context, p.objective)
144144
end
145145

146+
function _to_scalar_moi(::Type{T}, x) where {T}
147+
return _to_scalar_moi(T, only(MOI.Utilities.scalarize(x)))
148+
end
149+
150+
function _to_scalar_moi(::Type{T}, x::SparseTape) where {T}
151+
return _to_scalar_moi(T, to_vaf(x))
152+
end
153+
154+
function _to_scalar_moi(::Type{T}, x::Number) where {T<:Real}
155+
return MOI.ScalarAffineFunction{T}(MOI.ScalarAffineTerm{T}[], x)
156+
end
157+
158+
_to_scalar_moi(::Type{T}, f::MOI.AbstractScalarFunction) where {T} = f
159+
146160
function Context(p::Problem{T}, optimizer_factory) where {T}
147161
context = Context{T}(optimizer_factory)
148162
cfp = conic_form!(context, p)
@@ -153,7 +167,7 @@ function Context(p::Problem{T}, optimizer_factory) where {T}
153167
if p.head == :satisfy
154168
MOI.set(context.model, MOI.ObjectiveSense(), MOI.FEASIBILITY_SENSE)
155169
else
156-
obj = scalar_fn(cfp)
170+
obj = _to_scalar_moi(T, cfp)
157171
MOI.set(context.model, MOI.ObjectiveFunction{typeof(obj)}(), obj)
158172
MOI.set(
159173
context.model,
@@ -189,16 +203,20 @@ function minimize(
189203
return Problem{numeric_type}(:minimize, objective, constraints)
190204
end
191205

192-
function minimize(::Value, constraints::Constraint...; numeric_type = Float64)
193-
return satisfy(collect(constraints); numeric_type = numeric_type)
206+
function minimize(
207+
objective::Value,
208+
constraints::Constraint...;
209+
numeric_type = Float64,
210+
)
211+
return minimize(objective, collect(constraints); numeric_type)
194212
end
195213

196214
function minimize(
197-
::Value,
215+
objective::Value,
198216
constraints::Array{<:Constraint} = Constraint[];
199217
numeric_type = Float64,
200218
)
201-
return satisfy(constraints; numeric_type = numeric_type)
219+
return minimize(constant(objective), constraints; numeric_type)
202220
end
203221

204222
# Allow users to simply type maximize
@@ -218,16 +236,20 @@ function maximize(
218236
return Problem{numeric_type}(:maximize, objective, constraints)
219237
end
220238

221-
function maximize(::Value, constraints::Constraint...; numeric_type = Float64)
222-
return satisfy(collect(constraints); numeric_type = numeric_type)
239+
function maximize(
240+
objective::Value,
241+
constraints::Constraint...;
242+
numeric_type = Float64,
243+
)
244+
return maximize(objective, collect(constraints); numeric_type)
223245
end
224246

225247
function maximize(
226-
::Value,
248+
objective::Value,
227249
constraints::Array{<:Constraint} = Constraint[];
228250
numeric_type = Float64,
229251
)
230-
return satisfy(constraints; numeric_type = numeric_type)
252+
return maximize(constant(objective), constraints; numeric_type)
231253
end
232254

233255
# Allow users to simply type satisfy (if there is no objective)

src/solution.jl

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,6 @@ function add_variables!(model, var::AbstractVariable)
1010
end
1111
end
1212

13-
scalar_fn(x::Number) = x # for `satisfy` problems? Not sure...
14-
scalar_fn(x) = only(MOI.Utilities.scalarize(x))
15-
scalar_fn(x::SparseTape) = scalar_fn(to_vaf(x))
16-
scalar_fn(v::MOI.AbstractScalarFunction) = v
17-
1813
"""
1914
solve!(problem::Problem, optimizer_factory;
2015
silent_solver = false,

test/test_utilities.jl

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,18 +90,12 @@ function test_complex_objective_function_errors()
9090
return
9191
end
9292

93-
function test_constant_objective()
93+
function test_satisfy_constant_objective()
9494
x = Variable()
95-
for p in [
96-
satisfy(x == 0, x == 1),
97-
satisfy(Constraint[]),
98-
minimize(0, x == 0),
99-
minimize(0, Constraint[]),
100-
maximize(0, x == 0),
101-
maximize(0, Constraint[]),
102-
]
103-
@test isnothing(p.objective)
104-
end
95+
p = satisfy(x == 0, x == 1)
96+
@test isnothing(p.objective)
97+
p = satisfy(Constraint[])
98+
@test isnothing(p.objective)
10599
return
106100
end
107101

@@ -1142,6 +1136,55 @@ function test_tree_interface()
11421136
return
11431137
end
11441138

1139+
function test_scalar_fn_constant_objective()
1140+
x = Variable()
1141+
p = minimize(2.1, [x >= 1])
1142+
solve!(p, SCS.Optimizer; silent_solver = true)
1143+
@test isapprox(p.optval, 2.1; atol = 1e-5)
1144+
p = minimize(2.2, x >= 1)
1145+
solve!(p, SCS.Optimizer; silent_solver = true)
1146+
@test isapprox(p.optval, 2.2; atol = 1e-5)
1147+
p = maximize(2.3, [x >= 1])
1148+
solve!(p, SCS.Optimizer; silent_solver = true)
1149+
@test isapprox(p.optval, 2.3; atol = 1e-5)
1150+
p = maximize(2.4, x >= 1)
1151+
solve!(p, SCS.Optimizer; silent_solver = true)
1152+
@test isapprox(p.optval, 2.4; atol = 1e-5)
1153+
return
1154+
end
1155+
1156+
function test_scalar_fn_objective_number()
1157+
x = Variable()
1158+
p = minimize(constant(2), [x >= 1])
1159+
solve!(p, SCS.Optimizer)
1160+
@test isapprox(p.optval, 2.0; atol = 1e-5)
1161+
return
1162+
end
1163+
1164+
function test_scalar_fn_objective_variable()
1165+
x = Variable()
1166+
p = minimize(x, [x >= 1])
1167+
solve!(p, SCS.Optimizer)
1168+
@test isapprox(p.optval, 1.0; atol = 1e-5)
1169+
return
1170+
end
1171+
1172+
function test_scalar_fn_objective_affine()
1173+
x = Variable()
1174+
p = minimize(x + 1, [x >= 1])
1175+
solve!(p, SCS.Optimizer)
1176+
@test isapprox(p.optval, 2.0; atol = 1e-5)
1177+
return
1178+
end
1179+
1180+
function test_scalar_fn_objective_square()
1181+
x = Variable()
1182+
p = minimize(square(x - 2), [x >= 1])
1183+
solve!(p, SCS.Optimizer)
1184+
@test isapprox(p.optval, 0.0; atol = 1e-3)
1185+
return
1186+
end
1187+
11451188
end # TestUtilities
11461189

11471190
TestUtilities.runtests()

0 commit comments

Comments
 (0)