Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/Bridges/Objective/bridges/FunctionConversionBridge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ function supports_objective_function(
::Type{<:FunctionConversionBridge{T,F}},
::Type{G},
) where {T,F,G<:MOI.AbstractFunction}
return isfinite(MOI.Bridges.Constraint.conversion_cost(F, G))
return MOI.Utilities.is_coefficient_type(G, T) &&
isfinite(MOI.Bridges.Constraint.conversion_cost(F, G))
end

function MOI.Bridges.bridging_cost(
Expand Down
14 changes: 14 additions & 0 deletions test/Bridges/Constraint/ScalarFunctionizeBridge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,20 @@ function test_approx_convert(T = Float64)
return
end

function test_supports_ScalarNonlinearFunction()
for T in (Int, Float64)
model = MOI.instantiate(MOI.Utilities.Model{T}; with_bridge_type = T)
for (F, flag) in [
MOI.ScalarNonlinearFunction => true,
MOI.ScalarAffineFunction{Float64} => (T == Float64),
MOI.ScalarAffineFunction{Int} => (T == Int),
]
@test MOI.supports_constraint(model, F, MOI.EqualTo{T}) == flag
end
end
return
end

end # module

TestConstraintFunctionize.runtests()
7 changes: 7 additions & 0 deletions test/Bridges/Objective/FunctionConversionBridge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ struct VariableDifference <: MOI.AbstractScalarFunction
y::MOI.VariableIndex
end

function MOI.Utilities.is_coefficient_type(
::Type{VariableDifference},
::Type{T},
) where {T}
return true
end

function MOI.Bridges.Constraint.conversion_cost(
::Type{<:MOI.ScalarAffineFunction},
::Type{VariableDifference},
Expand Down
165 changes: 41 additions & 124 deletions test/Bridges/Objective/ToScalarNonlinearBridge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,140 +21,57 @@ function runtests()
return
end

include("../utilities.jl")

function test_solve_singlevariable_obj()
mock = MOI.Utilities.MockOptimizer(MOI.Utilities.Model{Float64}())
model = MOI.Bridges.Objective.ToScalarNonlinear{Float64}(mock)
MOI.Utilities.set_mock_optimize!(
mock,
(mock::MOI.Utilities.MockOptimizer) ->
MOI.Utilities.mock_optimize!(mock, [1.0], MOI.FEASIBLE_POINT),
)
MOI.Test.test_objective_ObjectiveFunction_duplicate_terms(
model,
MOI.Test.Config(;
exclude = Any[MOI.DualObjectiveValue, MOI.ConstraintDual],
),
)
@test MOI.get(mock, MOI.ObjectiveFunctionType()) ==
MOI.ScalarNonlinearFunction
@test MOI.get(model, MOI.ObjectiveFunctionType()) ==
MOI.ScalarAffineFunction{Float64}
@test MOI.get(mock, MOI.ObjectiveSense()) == MOI.MIN_SENSE
@test MOI.get(model, MOI.ObjectiveSense()) == MOI.MIN_SENSE
vis = MOI.get(model, MOI.ListOfVariableIndices())
func = 3.0 * vis[1] + 0.0

@test MOI.get(
model,
MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),
) ≈ func
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
@test MOI.get(mock, MOI.ObjectiveSense()) == MOI.MAX_SENSE
@test MOI.get(model, MOI.ObjectiveSense()) == MOI.MAX_SENSE

_test_delete_objective(model, 1, tuple())
return
end

function test_solve_result_index()
mock = MOI.Utilities.MockOptimizer(MOI.Utilities.Model{Float64}())
model = MOI.Bridges.Objective.ToScalarNonlinear{Float64}(mock)
MOI.Utilities.set_mock_optimize!(
mock,
(mock::MOI.Utilities.MockOptimizer) -> MOI.Utilities.mock_optimize!(
mock,
MOI.OPTIMAL,
(MOI.FEASIBLE_POINT, [1.0]),
MOI.FEASIBLE_POINT,
(MOI.VariableIndex, MOI.GreaterThan{Float64}) => [1.0],
),
)
MOI.Test.test_solve_result_index(
model,
MOI.Test.Config(;
exclude = Any[MOI.DualObjectiveValue, MOI.ConstraintDual],
),
)

return
end

function test_runtests()
MOI.Bridges.runtests(
MOI.Bridges.Objective.ToScalarNonlinearBridge,
model -> begin
x = MOI.add_variable(model)
aff = MOI.ScalarAffineFunction(
MOI.ScalarAffineTerm.([2.0], [x]),
1.0,
)
MOI.set(
model,
MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),
aff,
)
MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)
end,
model -> begin
x = MOI.add_variable(model)
exp = MOI.ScalarNonlinearFunction(
:+,
[
MOI.ScalarNonlinearFunction(
:*,
[2.0, MOI.VariableIndex(1)],
),
1.0,
],
)
MOI.set(
model,
MOI.ObjectiveFunction{MOI.ScalarNonlinearFunction}(),
exp,
)
MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)
end,
"""
variables: x
minobjective: 2.0 * x + 1.0
""",
"""
variables: x
minobjective: ScalarNonlinearFunction(2.0 * x + 1.0)
""",
)
MOI.Bridges.runtests(
MOI.Bridges.Objective.ToScalarNonlinearBridge,
"""
variables: x
maxobjective: 2.0 * x + 1.0
""",
"""
variables: x
maxobjective: ScalarNonlinearFunction(2.0 * x + 1.0)
""",
)
MOI.Bridges.runtests(
MOI.Bridges.Objective.ToScalarNonlinearBridge,
model -> begin
x = MOI.add_variable(model)
aff = MOI.ScalarAffineFunction(
MOI.ScalarAffineTerm.([2.0], [x]),
1.0,
)
MOI.set(
model,
MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),
aff,
)
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
end,
model -> begin
x = MOI.add_variable(model)
exp = MOI.ScalarNonlinearFunction(
:+,
[
MOI.ScalarNonlinearFunction(
:*,
[2.0, MOI.VariableIndex(1)],
),
1.0,
],
)
MOI.set(
model,
MOI.ObjectiveFunction{MOI.ScalarNonlinearFunction}(),
exp,
)
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
end,
"""
variables: x, y
minobjective: 1.0 * x * x + 2.0 * x * y + 3.0 * y + 4.0
""",
"""
variables: x, y
minobjective: ScalarNonlinearFunction(1.0 * x * x + 2.0 * x * y + 3.0 * y + 4.0)
""",
)
return
end

function test_supports()
for T in (Int, Float64)
model = MOI.instantiate(MOI.Utilities.Model{T}; with_bridge_type = T)
for (F, flag) in [
MOI.ScalarNonlinearFunction => true,
MOI.ScalarAffineFunction{Float64} => (T == Float64),
MOI.ScalarAffineFunction{Int} => (T == Int),
]
@test MOI.supports(model, MOI.ObjectiveFunction{F}()) == flag
end
end
return
end

end # module

TestObjectiveToScalarNonlinear.runtests()
Loading