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
1 change: 1 addition & 0 deletions docs/src/apireference.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ ResultCount
ObjectiveFunction
ObjectiveFunctionType
ObjectiveValue
DualObjectiveValue
ObjectiveBound
RelativeGap
SolveTime
Expand Down
37 changes: 37 additions & 0 deletions src/Test/contconic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ function _lin1test(model::MOI.ModelLike, config::TestConfig, vecofvars::Bool)
end

@test MOI.get(model, MOI.ObjectiveValue()) ≈ -11 atol=atol rtol=rtol
if config.duals
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ -11 atol=atol rtol=rtol
end

@test MOI.get(model, MOI.VariablePrimal(), v) ≈ [1, 0, 2] atol=atol rtol=rtol

Expand Down Expand Up @@ -155,6 +158,9 @@ function _lin2test(model::MOI.ModelLike, config::TestConfig, vecofvars::Bool)
end

@test MOI.get(model, MOI.ObjectiveValue()) ≈ -82 atol=atol rtol=rtol
if config.duals
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ -82 atol=atol rtol=rtol
end

@test MOI.get(model, MOI.VariablePrimal(), x) ≈ -4 atol=atol rtol=rtol
@test MOI.get(model, MOI.VariablePrimal(), y) ≈ -3 atol=atol rtol=rtol
Expand Down Expand Up @@ -343,6 +349,9 @@ function _soc1test(model::MOI.ModelLike, config::TestConfig, vecofvars::Bool)
end

@test MOI.get(model, MOI.ObjectiveValue()) ≈ √2 atol=atol rtol=rtol
if config.duals
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ √2 atol=atol rtol=rtol
end

@test MOI.get(model, MOI.VariablePrimal(), x) ≈ 1 atol=atol rtol=rtol
@test MOI.get(model, MOI.VariablePrimal(), y) ≈ 1/√2 atol=atol rtol=rtol
Expand Down Expand Up @@ -418,6 +427,9 @@ function _soc2test(model::MOI.ModelLike, config::TestConfig, nonneg::Bool)
end

@test MOI.get(model, MOI.ObjectiveValue()) ≈ -1/√2 atol=atol rtol=rtol
if config.duals
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ -1/√2 atol=atol rtol=rtol
end

@test MOI.get(model, MOI.VariablePrimal(), x) ≈ -1/√2 atol=atol rtol=rtol
@test MOI.get(model, MOI.VariablePrimal(), y) ≈ 1/√2 atol=atol rtol=rtol
Expand Down Expand Up @@ -537,6 +549,9 @@ function soc4test(model::MOI.ModelLike, config::TestConfig)
end

@test MOI.get(model, MOI.ObjectiveValue()) ≈ -√5 atol=atol rtol=rtol
if config.duals
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ -√5 atol=atol rtol=rtol
end

@test MOI.get(model, MOI.VariablePrimal(), x) ≈ [1.0, 2/√5, 1/√5, 2/√5, 1/√5] atol=atol rtol=rtol

Expand Down Expand Up @@ -619,6 +634,9 @@ function _rotatedsoc1test(model::MOI.ModelLike, config::TestConfig, abvars::Bool
end

@test MOI.get(model, MOI.ObjectiveValue()) ≈ √2 atol=atol rtol=rtol
if config.duals
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ √2 atol=atol rtol=rtol
end

if abvars
@test MOI.get(model, MOI.VariablePrimal(), a) ≈ 0.5 atol=atol rtol=rtol
Expand Down Expand Up @@ -787,6 +805,9 @@ function rotatedsoc3test(model::MOI.ModelLike, config::TestConfig; n=2, ub=3.0)
end

@test MOI.get(model, MOI.ObjectiveValue()) ≈ √ub atol=atol rtol=rtol
if config.duals
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ √ub atol=atol rtol=rtol
end

@test MOI.get(model, MOI.VariablePrimal(), x) ≈ [1.0; zeros(n-1)] atol=atol rtol=rtol
@test MOI.get(model, MOI.VariablePrimal(), u) ≈ ub atol=atol rtol=rtol
Expand Down Expand Up @@ -947,6 +968,10 @@ function _exp1test(model::MOI.ModelLike, config::TestConfig, vecofvars::Bool)
end

@test MOI.get(model, MOI.ObjectiveValue()) ≈ 3 + 2exp(1/2) atol=atol rtol=rtol
if config.duals
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ 3 + 2exp(1/2) atol=atol rtol=rtol
end

@test MOI.get(model, MOI.VariablePrimal(), v) ≈ [1., 2., 2exp(1/2)] atol=atol rtol=rtol

@test MOI.get(model, MOI.ConstraintPrimal(), vc) ≈ [1., 2., 2exp(1/2)] atol=atol rtol=rtol
Expand Down Expand Up @@ -1013,6 +1038,9 @@ function exp2test(model::MOI.ModelLike, config::TestConfig)
end

@test MOI.get(model, MOI.ObjectiveValue()) ≈ exp(-0.3) atol=atol rtol=rtol
if config.duals
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ exp(-0.3) atol=atol rtol=rtol
end

@test MOI.get(model, MOI.VariablePrimal(), v) ≈ [0., -0.3, 0., exp(-0.3), exp(-0.3), exp(-0.3), 0., 1.0, 0.] atol=atol rtol=rtol

Expand Down Expand Up @@ -1078,6 +1106,9 @@ function exp3test(model::MOI.ModelLike, config::TestConfig)
end

@test MOI.get(model, MOI.ObjectiveValue()) ≈ log(5) atol=atol rtol=rtol
if config.duals
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ log(5) atol=atol rtol=rtol
end

@test MOI.get(model, MOI.VariablePrimal(), x) ≈ log(5) atol=atol rtol=rtol
@test MOI.get(model, MOI.VariablePrimal(), y) ≈ 5. atol=atol rtol=rtol
Expand Down Expand Up @@ -1157,6 +1188,9 @@ function _psd0test(model::MOI.ModelLike, vecofvars::Bool, psdcone, config::TestC
end

@test MOI.get(model, MOI.ObjectiveValue()) ≈ 2 atol=atol rtol=rtol
if config.duals
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ 2 atol=atol rtol=rtol
end

Xv = square ? ones(4) : ones(3)
@test MOI.get(model, MOI.VariablePrimal(), X) ≈ Xv atol=atol rtol=rtol
Expand Down Expand Up @@ -1302,6 +1336,9 @@ function _psd1test(model::MOI.ModelLike, vecofvars::Bool, psdcone, config::TestC
end

@test MOI.get(model, MOI.ObjectiveValue()) ≈ obj atol=atol rtol=rtol
if config.duals
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ obj atol=atol rtol=rtol
end

Xv = square ? [α^2, α*β, α^2, α*β, β^2, α*β, α^2, α*β, α^2] : [α^2, α*β, β^2, α^2, α*β, α^2]
xv = [√2*x2, x2, x2]
Expand Down
26 changes: 26 additions & 0 deletions src/Test/contlinear.jl
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ function linear1test(model::MOI.ModelLike, config::TestConfig)

if config.duals
@test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ -1 atol=atol rtol=rtol
@test MOI.get(model, MOI.ConstraintDual(), c) ≈ -1 atol=atol rtol=rtol

# reduced costs
Expand Down Expand Up @@ -112,6 +113,7 @@ function linear1test(model::MOI.ModelLike, config::TestConfig)

if config.duals
@test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ 1 atol=atol rtol=rtol
@test MOI.get(model, MOI.ConstraintDual(), c) ≈ -1 atol=atol rtol=rtol

@test MOI.get(model, MOI.ConstraintDual(), vc1) ≈ 0 atol=atol rtol=rtol
Expand Down Expand Up @@ -171,6 +173,7 @@ function linear1test(model::MOI.ModelLike, config::TestConfig)

if config.duals
@test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ 2 atol=atol rtol=rtol
@test MOI.get(model, MOI.ConstraintDual(), c) ≈ -2 atol=atol rtol=rtol

@test MOI.get(model, MOI.ConstraintDual(), vc1) ≈ 1 atol=atol rtol=rtol
Expand Down Expand Up @@ -198,6 +201,11 @@ function linear1test(model::MOI.ModelLike, config::TestConfig)
@test MOI.get(model, MOI.ObjectiveValue()) ≈ 3 atol=atol rtol=rtol

@test MOI.get(model, MOI.VariablePrimal(), v) ≈ [-1, 0, 2] atol=atol rtol=rtol

if config.duals
@test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ 3 atol=atol rtol=rtol
end
end

# put lb of x back to 0 and fix z to zero to get :
Expand Down Expand Up @@ -317,6 +325,7 @@ function linear1test(model::MOI.ModelLike, config::TestConfig)

if config.duals
@test MOI.get(model, MOI.DualStatus(1)) == MOI.FEASIBLE_POINT
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ 3 atol=atol rtol=rtol

@test MOI.get(model, MOI.ConstraintDual(), c) ≈ -1.5 atol=atol rtol=rtol
@test MOI.get(model, MOI.ConstraintDual(), c2) ≈ 0.5 atol=atol rtol=rtol
Expand Down Expand Up @@ -405,6 +414,7 @@ function linear2test(model::MOI.ModelLike, config::TestConfig)

if config.duals
@test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ -1 atol=atol rtol=rtol
@test MOI.get(model, MOI.ConstraintDual(), c) ≈ -1 atol=atol rtol=rtol

# reduced costs
Expand Down Expand Up @@ -1157,6 +1167,7 @@ function linear10test(model::MOI.ModelLike, config::TestConfig)
if config.duals
@test MOI.get(model, MOI.ResultCount()) >= 1
@test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ 10.0 atol=atol rtol=rtol
@test MOI.get(model, MOI.ConstraintDual(), c) ≈ -1 atol=atol rtol=rtol
end

Expand All @@ -1180,6 +1191,7 @@ function linear10test(model::MOI.ModelLike, config::TestConfig)
@test MOI.get(model, MOI.ConstraintPrimal(), c) ≈ 5 atol=atol rtol=rtol

if config.duals
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ 5.0 atol=atol rtol=rtol
@test MOI.get(model, MOI.ResultCount()) >= 1
@test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT
@test MOI.get(model, MOI.ConstraintDual(), c) ≈ 1 atol=atol rtol=rtol
Expand Down Expand Up @@ -1213,6 +1225,13 @@ function linear10test(model::MOI.ModelLike, config::TestConfig)
MOI.get(model, MOI.ConstraintBasisStatus(), vc[2])== MOI.BASIC)
@test MOI.get(model, MOI.ConstraintBasisStatus(), c) == MOI.NONBASIC_AT_LOWER
end

if config.duals
@test MOI.get(model, MOI.ResultCount()) >= 1
@test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ 2.0 atol=atol rtol=rtol
@test MOI.get(model, MOI.ConstraintDual(), c) ≈ 1 atol=atol rtol=rtol
end
end

MOI.set(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 1.0], [x, y]), 0.0))
Expand Down Expand Up @@ -1529,6 +1548,7 @@ function linear14test(model::MOI.ModelLike, config::TestConfig)

if config.duals
@test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ 8 atol=atol rtol=rtol
@test MOI.get(model, MOI.ConstraintDual(), c) ≈ -1 atol=atol rtol=rtol

# reduced costs
Expand Down Expand Up @@ -1565,6 +1585,7 @@ function linear14test(model::MOI.ModelLike, config::TestConfig)

if config.duals
@test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ 6 atol=atol rtol=rtol
@test MOI.get(model, MOI.ConstraintDual(), c) ≈ -1 atol=atol rtol=rtol

# reduced costs
Expand Down Expand Up @@ -1617,6 +1638,11 @@ function linear15test(model::MOI.ModelLike, config::TestConfig)
@test MOI.get(model, MOI.ObjectiveValue()) ≈ 0 atol=atol rtol=rtol

@test MOI.get(model, MOI.VariablePrimal(), x[1]) ≈ 0 atol=atol rtol=rtol

if config.duals
@test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ 0 atol=atol rtol=rtol
end
end
end

Expand Down
38 changes: 26 additions & 12 deletions src/Utilities/mockoptimizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ mutable struct MockOptimizer{MT<:MOI.ModelLike} <: MOI.AbstractOptimizer
# Computes `ObjectiveValue` by evaluating the `ObjectiveFunction` with
# `VariablePrimal`. See `get_fallback`.
eval_objective_value::Bool
objectivevalue::Float64
objectivebound::Float64 # set this using MOI.set(model, MOI.ObjectiveBound(), value)
objective_value::Float64 # set this using MOI.set(model, MOI.ObjectiveValue(), value)
# Computes `DualObjectiveValue` using `get_fallback`
eval_dual_objective_value::Bool
dual_objective_value::Float64 # set this using MOI.set(model, MOI.DualObjectiveValue(), value)
objective_bound::Float64 # set this using MOI.set(model, MOI.ObjectiveBound(), value)
primalstatus::MOI.ResultStatusCode
dualstatus::MOI.ResultStatusCode
varprimal::Dict{MOI.VariableIndex,Float64}
Expand All @@ -54,6 +57,7 @@ xor_variables(f) = mapvariables(xor_index, f)
function MockOptimizer(inner_model::MOI.ModelLike; supports_names=true,
needs_allocate_load=false,
eval_objective_value=true,
eval_dual_objective_value=true,
eval_variable_constraint_dual=true)
return MockOptimizer(inner_model,
0,
Expand All @@ -73,6 +77,8 @@ function MockOptimizer(inner_model::MOI.ModelLike; supports_names=true,
0,
eval_objective_value,
NaN,
eval_dual_objective_value,
NaN,
NaN,
MOI.NO_SOLUTION,
MOI.NO_SOLUTION,
Expand Down Expand Up @@ -141,10 +147,11 @@ function MOI.supports(mock::MockOptimizer,
return MOI.supports(mock.inner_model, attr, IdxT)
end

MOI.supports(mock::MockOptimizer, ::Union{MOI.ResultCount,MOI.TerminationStatus,MOI.ObjectiveValue,MOI.PrimalStatus,MOI.DualStatus,MockModelAttribute}) = true
MOI.supports(mock::MockOptimizer, ::MockModelAttribute) = true
MOI.set(mock::MockOptimizer, ::MOI.ResultCount, value::Integer) = (mock.resultcount = value)
MOI.set(mock::MockOptimizer, ::MOI.TerminationStatus, value::MOI.TerminationStatusCode) = (mock.terminationstatus = value)
MOI.set(mock::MockOptimizer, ::MOI.ObjectiveValue, value::Real) = (mock.objectivevalue = value)
MOI.set(mock::MockOptimizer, ::MOI.ObjectiveValue, value::Real) = (mock.objective_value = value)
MOI.set(mock::MockOptimizer, ::MOI.DualObjectiveValue, value::Real) = (mock.dual_objective_value = value)
MOI.set(mock::MockOptimizer, ::MOI.PrimalStatus, value::MOI.ResultStatusCode) = (mock.primalstatus = value)
MOI.set(mock::MockOptimizer, ::MOI.DualStatus, value::MOI.ResultStatusCode) = (mock.dualstatus = value)
MOI.set(mock::MockOptimizer, ::MockModelAttribute, value::Integer) = (mock.attribute = value)
Expand Down Expand Up @@ -237,7 +244,14 @@ function MOI.get(mock::MockOptimizer, attr::MOI.ObjectiveValue)
if mock.eval_objective_value
return get_fallback(mock, attr)
else
return mock.objectivevalue
return mock.objective_value
end
end
function MOI.get(mock::MockOptimizer, attr::MOI.DualObjectiveValue)
if mock.eval_dual_objective_value
return get_fallback(mock, attr, Float64)
else
return mock.dual_objective_value
end
end
MOI.get(mock::MockOptimizer, ::MOI.PrimalStatus) = mock.primalstatus
Expand Down Expand Up @@ -283,10 +297,9 @@ end
MOI.get(mock::MockOptimizer, ::MockConstraintAttribute, idx::MOI.ConstraintIndex) = mock.conattribute[xor_index(idx)]
MOI.get(mock::MockOptimizer, ::MOI.ConstraintBasisStatus, idx::MOI.ConstraintIndex) = mock.con_basis[xor_index(idx)]

MOI.supports(mock::MockOptimizer, ::MOI.ObjectiveBound) = true
MOI.get(mock::MockOptimizer, ::MOI.ObjectiveBound) = mock.objectivebound
MOI.get(mock::MockOptimizer, ::MOI.ObjectiveBound) = mock.objective_bound
function MOI.set(mock::MockOptimizer, ::MOI.ObjectiveBound, value::Float64)
mock.objectivebound = value
mock.objective_bound = value
end

MOI.get(::MockOptimizer, ::MOI.SolverName) = "Mock"
Expand All @@ -301,8 +314,9 @@ function MOI.empty!(mock::MockOptimizer)
mock.hasdual = false
mock.terminationstatus = MOI.OPTIMIZE_NOT_CALLED
mock.resultcount = 0
mock.objectivevalue = NaN
mock.objectivebound = NaN
mock.objective_value = NaN
mock.dual_objective_value = NaN
mock.objective_bound = NaN
mock.primalstatus = MOI.NO_SOLUTION
mock.dualstatus = MOI.NO_SOLUTION
mock.varprimal = Dict{MOI.VariableIndex,Float64}()
Expand All @@ -318,8 +332,8 @@ function MOI.is_empty(mock::MockOptimizer)
return MOI.is_empty(mock.inner_model) && mock.attribute == 0 &&
!mock.solved && !mock.hasprimal && !mock.hasdual &&
mock.terminationstatus == MOI.OPTIMIZE_NOT_CALLED &&
mock.resultcount == 0 && isnan(mock.objectivevalue) &&
isnan(mock.objectivebound) &&
mock.resultcount == 0 && isnan(mock.objective_value) &&
isnan(mock.dual_objective_value) && isnan(mock.objective_bound) &&
mock.primalstatus == MOI.NO_SOLUTION &&
mock.dualstatus == MOI.NO_SOLUTION &&
isempty(mock.con_basis)
Expand Down
Loading