From bf12e5d10bb8d5371241b37be213107f1039617f Mon Sep 17 00:00:00 2001 From: odow Date: Wed, 14 Jul 2021 12:35:11 +1200 Subject: [PATCH 01/11] Migreate tests of mockoptimizer.jl --- src/Utilities/mockoptimizer.jl | 446 ++++++++++++++++++++------------ test/Utilities/mockoptimizer.jl | 103 ++------ 2 files changed, 301 insertions(+), 248 deletions(-) diff --git a/src/Utilities/mockoptimizer.jl b/src/Utilities/mockoptimizer.jl index 876bdb7d0e..7e7ca7372d 100644 --- a/src/Utilities/mockoptimizer.jl +++ b/src/Utilities/mockoptimizer.jl @@ -56,11 +56,15 @@ mutable struct MockOptimizer{MT<:MOI.ModelLike} <: MOI.AbstractOptimizer submitted::Dict{MOI.AbstractSubmittable,Vector{Tuple}} end -# All user-facing indices are xor'd with this mask to produce unusual indices. -# This is good at catching bugs. -const internal_xor_mask = Int64(12345678) -xor_index(vi::VI) = VI(xor(vi.value, internal_xor_mask)) -xor_index(ci::CI{F,S}) where {F,S} = CI{F,S}(xor(ci.value, internal_xor_mask)) +""" +All user-facing indices are xor'd with this mask to produce unusual indices. +This is good at catching bugs in solvers which assume indices are ordered 1, 2, +3, ... +""" +const _INTERNAL_XOR_MASK = Int64(12345678) + +xor_index(vi::VI) = VI(xor(vi.value, _INTERNAL_XOR_MASK)) +xor_index(ci::CI{F,S}) where {F,S} = CI{F,S}(xor(ci.value, _INTERNAL_XOR_MASK)) xor_indices(x) = map_indices(xor_index, x) function MockOptimizer( @@ -176,7 +180,8 @@ function MOI.optimize!(mock::MockOptimizer) mock.solved = true mock.hasprimal = true mock.hasdual = true - return mock.optimize!(mock) + mock.optimize!(mock) + return end MOI.compute_conflict!(::MockOptimizer) = nothing @@ -193,12 +198,13 @@ function throw_mock_unsupported_names(attr) end function MOI.supports( - mock::MockOptimizer, + ::MockOptimizer, ::Union{MOI.VariablePrimal,MockVariableAttribute}, ::Type{MOI.VariableIndex}, ) return true end + function MOI.supports( mock::MockOptimizer, attr::MOI.AbstractVariableAttribute, @@ -206,13 +212,15 @@ function MOI.supports( ) return MOI.supports(mock.inner_model, attr, IdxT) end + function MOI.supports( - mock::MockOptimizer, + ::MockOptimizer, ::Union{MOI.ConstraintDual,MockConstraintAttribute}, ::Type{<:MOI.ConstraintIndex}, ) return true end + function MOI.supports( mock::MockOptimizer, attr::MOI.AbstractConstraintAttribute, @@ -222,49 +230,66 @@ function MOI.supports( end MOI.supports(mock::MockOptimizer, ::MockModelAttribute) = true + function MOI.set( mock::MockOptimizer, ::MOI.TerminationStatus, value::MOI.TerminationStatusCode, ) - return (mock.terminationstatus = value) + mock.terminationstatus = value + return end + function MOI.set(mock::MockOptimizer, attr::MOI.ObjectiveValue, value::Real) - return mock.objective_value[attr.result_index] = value + mock.objective_value[attr.result_index] = value + return end + function MOI.set(mock::MockOptimizer, attr::MOI.DualObjectiveValue, value::Real) - return mock.dual_objective_value[attr.result_index] = value + mock.dual_objective_value[attr.result_index] = value + return end + function MOI.set( mock::MockOptimizer, attr::MOI.PrimalStatus, value::MOI.ResultStatusCode, ) - return mock.primal_status[attr.result_index] = value + mock.primal_status[attr.result_index] = value + return end + function MOI.set( mock::MockOptimizer, attr::MOI.DualStatus, value::MOI.ResultStatusCode, ) - return mock.dual_status[attr.result_index] = value + mock.dual_status[attr.result_index] = value + return end + function MOI.set( mock::MockOptimizer, ::MOI.ConflictStatus, value::MOI.ConflictStatusCode, ) - return (mock.conflictstatus = value) + mock.conflictstatus = value + return end + MOI.get(mock::MockOptimizer, ::MOI.ConflictStatus) = mock.conflictstatus + function MOI.set(mock::MockOptimizer, ::MockModelAttribute, value::Integer) - return (mock.attribute = value) + mock.attribute = value + return end + function MOI.supports(mock::MockOptimizer, attr::MOI.AbstractOptimizerAttribute) # `supports` is not defined if `is_set_by_optimize(attr)` so we pass it to # `mock.inner_model`. return MOI.supports(mock.inner_model, attr) end + function MOI.set( mock::MockOptimizer, attr::MOI.AbstractOptimizerAttribute, @@ -275,18 +300,22 @@ function MOI.set( else MOI.set(mock.inner_model, attr, xor_indices(value)) end + return end + function MOI.supports(mock::MockOptimizer, attr::MOI.AbstractModelAttribute) # `supports` is not defined if `is_set_by_optimize(attr)` so we pass it to # `mock.inner_model`. return MOI.supports(mock.inner_model, attr) end + function MOI.set(mock::MockOptimizer, attr::MOI.AbstractModelAttribute, value) if MOI.is_set_by_optimize(attr) mock.model_attributes[attr] = value else MOI.set(mock.inner_model, attr, xor_indices(value)) end + return end function MOI.set( @@ -295,55 +324,68 @@ function MOI.set( idx::MOI.VariableIndex, value, ) - return MOI.set(mock.inner_model, attr, xor_index(idx), xor_indices(value)) + MOI.set(mock.inner_model, attr, xor_index(idx), xor_indices(value)) + return end + function MOI.set( mock::MockOptimizer, attr::MOI.VariablePrimal, idx::MOI.VariableIndex, value, ) - return _safe_set_result(mock.varprimal, attr, idx, value) + _safe_set_result(mock.varprimal, attr, idx, value) + return end + function MOI.set( mock::MockOptimizer, ::MOI.CallbackVariablePrimal, idx::MOI.VariableIndex, value, ) - return mock.callback_variable_primal[xor_index(idx)] = value + mock.callback_variable_primal[xor_index(idx)] = value + return end + function MOI.set( mock::MockOptimizer, ::MockVariableAttribute, idx::MOI.VariableIndex, value, ) - return mock.varattribute[xor_index(idx)] = value + mock.varattribute[xor_index(idx)] = value + return end + function MOI.set( mock::MockOptimizer, attr::MOI.AbstractConstraintAttribute, idx::MOI.ConstraintIndex, value, ) - return MOI.set(mock.inner_model, attr, xor_index(idx), value) + MOI.set(mock.inner_model, attr, xor_index(idx), value) + return end + function MOI.set( mock::MockOptimizer, ::MockConstraintAttribute, idx::MOI.ConstraintIndex, value, ) - return mock.conattribute[xor_index(idx)] = value + mock.conattribute[xor_index(idx)] = value + return end + function MOI.set( mock::MockOptimizer, attr::MOI.ConstraintDual, idx::MOI.ConstraintIndex, value, ) - return _safe_set_result(mock.condual, attr, idx, value) + _safe_set_result(mock.condual, attr, idx, value) + return end function MOI.set( @@ -352,7 +394,8 @@ function MOI.set( idx::MOI.ConstraintIndex, value, ) - return _safe_set_result(mock.con_basis, attr, idx, value) + _safe_set_result(mock.con_basis, attr, idx, value) + return end function MOI.set( @@ -361,7 +404,8 @@ function MOI.set( idx::MOI.VariableIndex, value, ) - return _safe_set_result(mock.var_basis, attr, idx, value) + _safe_set_result(mock.var_basis, attr, idx, value) + return end function MOI.set( @@ -375,6 +419,7 @@ function MOI.set( end MOI.get(mock::MockOptimizer, ::MOI.RawSolver) = mock + function MOI.get(mock::MockOptimizer, attr::MOI.AbstractOptimizerAttribute) if MOI.is_set_by_optimize(attr) return mock.optimizer_attributes[attr] @@ -397,13 +442,15 @@ end function MOI.supports(mock::MockOptimizer, attr::MOI.Name) return mock.supports_names && MOI.supports(mock.inner_model, attr) end + function MOI.set(mock::MockOptimizer, attr::MOI.Name, value) - if mock.supports_names - MOI.set(mock.inner_model, attr, value) - else + if !mock.supports_names throw_mock_unsupported_names(attr) end + MOI.set(mock.inner_model, attr, value) + return end + function MOI.supports( mock::MockOptimizer, attr::MOI.VariableName, @@ -411,18 +458,20 @@ function MOI.supports( ) return mock.supports_names && MOI.supports(mock.inner_model, attr, IdxT) end + function MOI.set( mock::MockOptimizer, attr::MOI.VariableName, index::MOI.VariableIndex, value, ) - if mock.supports_names - MOI.set(mock.inner_model, attr, xor_index(index), value) - else + if !mock.supports_names throw_mock_unsupported_names(attr) end + MOI.set(mock.inner_model, attr, xor_index(index), value) + return end + function MOI.supports( mock::MockOptimizer, attr::MOI.ConstraintName, @@ -430,26 +479,23 @@ function MOI.supports( ) return mock.supports_names && MOI.supports(mock.inner_model, attr, IdxT) end + function MOI.set( mock::MockOptimizer, attr::MOI.ConstraintName, index::MOI.ConstraintIndex, value, ) - if mock.supports_names - MOI.set(mock.inner_model, attr, xor_index(index), value) - else + if !mock.supports_names throw_mock_unsupported_names(attr) end + MOI.set(mock.inner_model, attr, xor_index(index), value) + return end function MOI.get(b::MockOptimizer, IdxT::Type{<:MOI.Index}, name::String) index = MOI.get(b.inner_model, IdxT, name) - if index === nothing - return nothing - else - return xor_index(index) - end + return index === nothing ? nothing : xor_index(index) end ##### @@ -457,39 +503,44 @@ end ##### MOI.get(mock::MockOptimizer, ::MOI.ResultCount) = mock.result_count -MOI.set(mock::MockOptimizer, ::MOI.ResultCount, x) = (mock.result_count = x) + +function MOI.set(mock::MockOptimizer, ::MOI.ResultCount, x) + mock.result_count = x + return +end MOI.get(mock::MockOptimizer, ::MOI.TerminationStatus) = mock.terminationstatus + function MOI.get(mock::MockOptimizer, attr::MOI.ObjectiveValue) MOI.check_result_index_bounds(mock, attr) if mock.eval_objective_value return get_fallback(mock, attr) - else - return get(mock.objective_value, attr.result_index, NaN) end + return get(mock.objective_value, attr.result_index, NaN) end + function MOI.get(mock::MockOptimizer, attr::MOI.DualObjectiveValue) MOI.check_result_index_bounds(mock, attr) if mock.eval_dual_objective_value return get_fallback(mock, attr, Float64) - else - return get(mock.dual_objective_value, attr.result_index, NaN) end + return get(mock.dual_objective_value, attr.result_index, NaN) end + function MOI.get(mock::MockOptimizer, attr::MOI.PrimalStatus) if attr.result_index > mock.result_count return MOI.NO_SOLUTION - else - return get(mock.primal_status, attr.result_index, MOI.NO_SOLUTION) end + return get(mock.primal_status, attr.result_index, MOI.NO_SOLUTION) end + function MOI.get(mock::MockOptimizer, attr::MOI.DualStatus) if attr.result_index > mock.result_count return MOI.NO_SOLUTION - else - return get(mock.dual_status, attr.result_index, MOI.NO_SOLUTION) end + return get(mock.dual_status, attr.result_index, MOI.NO_SOLUTION) end + MOI.get(mock::MockOptimizer, ::MockModelAttribute) = mock.attribute function MOI.get( @@ -499,6 +550,7 @@ function MOI.get( ) return xor_indices(MOI.get(mock.inner_model, attr, xor_index(idx))) end + function MOI.get( mock::MockOptimizer, ::MockVariableAttribute, @@ -519,17 +571,17 @@ end function MOI.get( mock::MockOptimizer, - attr::MOI.CallbackVariablePrimal, + ::MOI.CallbackVariablePrimal, idx::MOI.VariableIndex, ) + if !MOI.is_valid(mock, idx) + throw(MOI.InvalidIndex(idx)) + end primal = get(mock.callback_variable_primal, xor_index(idx), nothing) - if primal !== nothing - return primal - elseif MOI.is_valid(mock, idx) + if primal === nothing error("No mock callback primal is set for variable `", idx, "`.") - else - throw(MOI.InvalidIndex(idx)) end + return primal end function MOI.get( @@ -550,6 +602,7 @@ function MOI.get( MOI.throw_if_not_valid(mock, idx) return MOI.get(mock.inner_model, attr, xor_index(idx)) end + function MOI.get( mock::MockOptimizer, attr::MOI.CanonicalConstraintFunction, @@ -562,6 +615,7 @@ function MOI.get( xor_indices(MOI.get(mock.inner_model, attr, xor_index(idx))), ) end + function MOI.get( mock::MockOptimizer, attr::Union{MOI.CanonicalConstraintFunction,MOI.ConstraintFunction}, @@ -593,6 +647,7 @@ function MOI.get( ) return mock.conattribute[xor_index(idx)] end + function MOI.get( mock::MockOptimizer, attr::MOI.ConstraintBasisStatus, @@ -634,6 +689,7 @@ function _safe_set_result( end return dict[xored][attr.result_index] = value end + function _safe_get_result( dict::Dict, attr::MOI.AnyAttribute, @@ -648,13 +704,8 @@ function _safe_get_result( value = get(result_to_value, attr.result_index, nothing) if value === nothing error( - "No mock $name is set for ", - index_name, - " `", - index, - "` at result index `", - attr.result_index, - "`.", + "No mock $name is set for $(index_name) `$(index)` at result " * + "index `$(attr.result_index)`.", ) end return value @@ -765,7 +816,8 @@ function MOI.modify( if !mock.modify_allowed throw(MOI.ModifyConstraintNotAllowed(c, change)) end - return MOI.modify(mock.inner_model, xor_index(c), xor_indices(change)) + MOI.modify(mock.inner_model, xor_index(c), xor_indices(change)) + return end function MOI.set( @@ -774,20 +826,23 @@ function MOI.set( c::CI{<:MOI.AbstractFunction,S}, set::S, ) where {S<:MOI.AbstractSet} - return MOI.set(mock.inner_model, MOI.ConstraintSet(), xor_index(c), set) + MOI.set(mock.inner_model, MOI.ConstraintSet(), xor_index(c), set) + return end + function MOI.set( mock::MockOptimizer, ::MOI.ConstraintFunction, c::CI{F}, func::F, ) where {F<:MOI.AbstractFunction} - return MOI.set( + MOI.set( mock.inner_model, MOI.ConstraintFunction(), xor_index(c), xor_indices(func), ) + return end function MOI.modify( @@ -798,15 +853,18 @@ function MOI.modify( if !mock.modify_allowed throw(MOI.ModifyObjectiveNotAllowed(change)) end - return MOI.modify(mock.inner_model, obj, xor_indices(change)) + MOI.modify(mock.inner_model, obj, xor_indices(change)) + return end MOI.supports(::MockOptimizer, ::MOI.AbstractSubmittable) = true + function MOI.submit(mock::MockOptimizer, sub::MOI.AbstractSubmittable, args...) if !haskey(mock.submitted, sub) mock.submitted[sub] = Tuple[] end - return push!(mock.submitted[sub], args) + push!(mock.submitted[sub], args) + return end # TODO: transform @@ -818,18 +876,21 @@ function MOI.supports_constraint( ) return MOI.supports_constraint(mock.inner_model, F, S) end + function MOI.supports_add_constrained_variable( mock::MockOptimizer, S::Type{<:MOI.AbstractScalarSet}, ) return MOI.supports_add_constrained_variable(mock.inner_model, S) end + function MOI.supports_add_constrained_variables( mock::MockOptimizer, S::Type{<:MOI.AbstractVectorSet}, ) return MOI.supports_add_constrained_variables(mock.inner_model, S) end + # Add this method to avoid ambiguity function MOI.supports_add_constrained_variables( mock::MockOptimizer, @@ -841,6 +902,7 @@ end function MOI.copy_to(mock::MockOptimizer, src::MOI.ModelLike; kws...) return automatic_copy_to(mock, src; kws...) end + function MOI.supports_incremental_interface( mock::MockOptimizer, copy_names::Bool, @@ -848,6 +910,7 @@ function MOI.supports_incremental_interface( return !mock.needs_allocate_load && MOI.supports_incremental_interface(mock.inner_model, copy_names) end + function final_touch(uf::MockOptimizer, index_map) return final_touch(uf.inner_model, index_map) end @@ -860,9 +923,11 @@ end function allocate_variables(mock::MockOptimizer, nvars) return xor_index.(allocate_variables(mock.inner_model, nvars)) end + function allocate(mock::MockOptimizer, attr::MOI.AnyAttribute, value) return allocate(mock.inner_model, attr, xor_indices(value)) end + function allocate( mock::MockOptimizer, attr::MOI.AnyAttribute, @@ -871,6 +936,7 @@ function allocate( ) return allocate(mock.inner_model, attr, xor_index(idx), xor_indices(value)) end + function allocate_constraint( mock::MockOptimizer, f::MOI.AbstractFunction, @@ -882,9 +948,11 @@ end function load_variables(mock::MockOptimizer, nvars) return load_variables(mock.inner_model, nvars) end + function load(mock::MockOptimizer, attr::MOI.AnyAttribute, value) return load(mock.inner_model, attr, xor_indices(value)) end + function load( mock::MockOptimizer, attr::MOI.AnyAttribute, @@ -893,6 +961,7 @@ function load( ) return load(mock.inner_model, attr, xor_index(idx), xor_indices(value)) end + function load_constraint( mock::MockOptimizer, ci::CI, @@ -905,52 +974,99 @@ end """ set_mock_optimize!(mock::MockOptimizer, opt::Function...) -Sets multiple optimize! function. The first is to be used the first time `MOI.optimize!(mock)` is called, the second function is to be used the second time, ... +Sets multiple optimize! function. The first is to be used the first time +`MOI.optimize!(mock)` is called, the second function is to be used the second +time, ... """ function set_mock_optimize!(mock::MockOptimizer, opts::Function...) - return mock.optimize! = rec_mock_optimize(mock, opts...) + mock.optimize! = _recursive_mock_optimize(opts...) + return end -function rec_mock_optimize( - mock::MockOptimizer, - opt::Function, - opts::Function..., -) - return (mock::MockOptimizer) -> - (opt(mock); mock.optimize! = rec_mock_optimize(mock, opts...)) + +_recursive_mock_optimize(optimize::Function) = optimize + +function _recursive_mock_optimize(optimize::Function, tail::Function...) + return (mock::MockOptimizer) -> begin + optimize(mock) + mock.optimize! = _recursive_mock_optimize(tail...) + return + end end -rec_mock_optimize(mock::MockOptimizer, opt::Function) = opt """ - mock_optimize!(mock::MockOptimizer, termstatus::MOI.TerminationStatusCode, (primstatus::MOI.ResultStatusCode, varprim::Vector), dual_status::MOI.ResultStatusCode, conduals::Pair...) - -Sets the termination status of `mock` to `termstatus` and the primal (resp. dual) status to `primstatus` (resp. `dual_status`). -The primal values of the variables in the order returned by `ListOfVariableIndices` are set to `varprim`. -If `termstatus` is missing, it is assumed to be `MOI.OPTIMAL`. -If `primstatus` is missing, it is assumed to be `MOI.FEASIBLE_POINT`. -If `dual_status` is missing, it is assumed to be `MOI.FEASIBLE_POINT` if there is a primal solution and `primstatus` is not `MOI.INFEASIBLE_POINT`, otherwise it is `MOI.INFEASIBILITY_CERTIFICATE`. -The dual values are set to the values specified by `conduals`. Each pair is of the form `(F,S)=>[...]` where `[...]` is the the vector of dual values for the constraints `F`-in-`S` in the order returned by `ListOfConstraintIndices{F,S}`. - -The bases status are set to the status specified by `con_basis` and `var_basis`. -`con_basis` must be a vector of pairs, each of the form `(F,S)=>[...]`, where -`[...]` is the the vector of basis status for the constraints `F`-in-`S` in the -order returned by `ListOfConstraintIndices{F,S}`. -`var_basis` is a vector of statuses, corresponding the status of the variables -returned by `ListOfVariableIndices`. + mock_optimize!( + mock::MockOptimizer, + termination_status::MOI.TerminationStatusCode, + primal::Union{ + Tuple{MOI.ResultStatusCode,<:Vector}, + MOI.ResultStatusCode, + <:Vector, + } + dual_status::MOI.ResultStatusCode, + constraint_duals::Pair{Tuple{DataTypeDataType},<:Vector}...; + con_basis = Pair{Tuple{DataTypeDataType},<:Vector}[], + var_basis = MOI.BasisStatusCode[], + ) + +Fake the result of a call to `optimize!` in the mock optimizer by storing the +solution. + +## Arguments + + * `termination_status`: defaults to `MOI.OPTIMAL` if not provided. + + * `primal`: pass one of the following: a tuple of `(status, result)` + corresponding to the `MOI.PrimalStatus` and `MOI.VariablePrimal` attributes, + or pass a `status` with no result vector, or pass only the result vector. If + the status is omitted, it is assumed to be `MOI.FEASIBLE_POINT`. The `result` + vector should correspond to the order of the primal values given by + `MOI.ListOfVariableIndices`. + + * `dual_status`: corresponds to the `MOI.DualStatus` attribute. If not + provided, it defaults to `MOI.FEASIBLE_POINT` if there is a primal solution + and the primal status is not `MOI.INFEASIBLE_POINT`, otherwise it defaults to + `MOI.INFEASIBILITY_CERTIFICATE`. + + * `constraint_duals`: the remaining positional arguments are passed as pairs. + Each pair is of the form `(F, S) => result`, where `result` is the the vector + of `MOI.ConstraintDual` values for the constraints `F`-in-`S` in the order + returned by `MOI.ListOfConstraintIndices{F,S}`. + + * `con_basis`: a vector of pairs similar to `constraint_duals`, except this + time for the `MOI.ConstraintBasisStatus` attribute. + + * `var_basis`: a vector of `MOI.BasisStatusCode`, corresponding to the + `MOI.VariableBasisStatus` attribute of the variables in the order returned by + `MOI.ListOfVariableIndices`. """ function mock_optimize!( mock::MockOptimizer, - termstatus::MOI.TerminationStatusCode, - primal, - dual...; + termination_status::MOI.TerminationStatusCode, + primal::Union{ + Tuple{MOI.ResultStatusCode,<:Vector}, + MOI.ResultStatusCode, + <:Vector, + }, + dual_status_constraint_duals...; con_basis = [], - var_basis = [], + var_basis = MOI.BasisStatusCode[], ) - MOI.set(mock, MOI.TerminationStatus(), termstatus) + MOI.set(mock, MOI.TerminationStatus(), termination_status) MOI.set(mock, MOI.ResultCount(), 1) - mock_primal!(mock, primal) - mock_dual!(mock, dual...) + _set_mock_primal(mock, primal) + _set_mock_dual(mock, dual_status_constraint_duals...) for con_basis_pair in con_basis - mock_basis_status!(mock, con_basis_pair) + F, S = con_basis_pair.first + for (i, ci) in enumerate( + MOI.get(mock, MOI.ListOfConstraintIndices{F,S}()) + ) + MOI.set( + mock, + MOI.ConstraintBasisStatus(), + ci, + con_basis_pair.second[i], + ) + end end if length(var_basis) > 0 variables = MOI.get(mock, MOI.ListOfVariableIndices()) @@ -960,85 +1076,87 @@ function mock_optimize!( return end -# Default termination status -function mock_optimize!(mock::MockOptimizer, primdual...; kws...) - return mock_optimize!(mock, MOI.OPTIMAL, primdual...; kws...) -end +# The fallback for default termination_status function mock_optimize!( mock::MockOptimizer, - termstatus::MOI.TerminationStatusCode, + primal::Union{ + Tuple{MOI.ResultStatusCode,<:Vector}, + MOI.ResultStatusCode, + <:Vector, + }, + args...; + kwargs..., ) - MOI.set(mock, MOI.TerminationStatus(), termstatus) - return MOI.set(mock, MOI.ResultCount(), 0) + mock_optimize!(mock, MOI.OPTIMAL, primal, args...; kwargs...) + return end -# Primal -mock_primal!(mock, primal::Tuple) = mock_primal!(mock, primal...) -function mock_primal!( +# The fallback if no primal solution is provided +function mock_optimize!(mock::MockOptimizer, status::MOI.TerminationStatusCode) + MOI.set(mock, MOI.TerminationStatus(), status) + MOI.set(mock, MOI.ResultCount(), 0) + return +end + +# _set_mock_primal + +function _set_mock_primal(mock::MockOptimizer) + mock.hasprimal = false + return +end + +function _set_mock_primal( mock::MockOptimizer, - primstatus::MOI.ResultStatusCode, - varprim::Vector..., + primal::Tuple{MOI.ResultStatusCode,<:Vector}, ) - MOI.set(mock, MOI.PrimalStatus(), primstatus) - return mock_varprimal!(mock, varprim...) -end -# Default primal status -function mock_primal!(mock::MockOptimizer, varprim::Vector) - return mock_primal!(mock, MOI.FEASIBLE_POINT, varprim) -end -function mock_primal!(mock::MockOptimizer) - # No primal solution - return mock.hasprimal = false -end - -# Sets variable primal to varprim -function mock_varprimal!(mock::MockOptimizer) end -function mock_varprimal!(mock::MockOptimizer, varprim::Vector) - return MOI.set( - mock, - MOI.VariablePrimal(), - MOI.get(mock, MOI.ListOfVariableIndices()), - varprim, - ) + MOI.set(mock, MOI.PrimalStatus(), primal[1]) + x = MOI.get(mock, MOI.ListOfVariableIndices()) + MOI.set(mock, MOI.VariablePrimal(), x, primal[2]) + return +end + +function _set_mock_primal(mock::MockOptimizer, primal::MOI.ResultStatusCode) + MOI.set(mock, MOI.PrimalStatus(), MOI.primal) + return +end + +function _set_mock_primal(mock::MockOptimizer, primal::Vector) + MOI.set(mock, MOI.PrimalStatus(), MOI.FEASIBLE_POINT) + x = MOI.get(mock, MOI.ListOfVariableIndices()) + MOI.set(mock, MOI.VariablePrimal(), x, primal) + return +end + +# _set_mock_dual + +function _set_mock_dual(mock::MockOptimizer) + mock.hasdual = false + return end -# Dual -function mock_dual!( +function _set_mock_dual( mock::MockOptimizer, dual_status::MOI.ResultStatusCode, - conduals::Pair..., + constraint_duals::Pair..., ) MOI.set(mock, MOI.DualStatus(), dual_status) - return mock_condual!(mock, conduals...) -end -# Default dual status -function mock_dual!(mock::MockOptimizer, conduals::Pair...) - status = - !mock.hasprimal || - MOI.get(mock, MOI.PrimalStatus()) == MOI.INFEASIBLE_POINT ? - MOI.INFEASIBILITY_CERTIFICATE : MOI.FEASIBLE_POINT - return mock_dual!(mock, status, conduals...) -end -function mock_dual!(mock::MockOptimizer) - # No dual solution - return mock.hasdual = false -end - -# Sets constraint dual to conduals -function mock_condual!(mock::MockOptimizer) end -function mock_condual!(mock::MockOptimizer, condual::Pair, conduals...) - F, S = condual.first - duals = condual.second - for (i, ci) in enumerate(MOI.get(mock, MOI.ListOfConstraintIndices{F,S}())) - MOI.set(mock, MOI.ConstraintDual(), ci, duals[i]) + for ((F, S), result) in constraint_duals + indices = MOI.get(mock, MOI.ListOfConstraintIndices{F,S}()) + for (i, ci) in enumerate(indices) + MOI.set(mock, MOI.ConstraintDual(), ci, result[i]) + end end - return mock_condual!(mock, conduals...) -end -# Set the basis status of the provided constraints. -function mock_basis_status!(mock::MockOptimizer, con_basis::Pair) - F, S = con_basis.first - bases = con_basis.second - for (i, ci) in enumerate(MOI.get(mock, MOI.ListOfConstraintIndices{F,S}())) - MOI.set(mock, MOI.ConstraintBasisStatus(), ci, bases[i]) + return +end + +# fallback for no status +function _set_mock_dual(mock::MockOptimizer, args::Pair...) + if !mock.hasprimal + _set_mock_dual(mock, MOI.INFEASIBLE_POINT, args...) + elseif MOI.get(mock, MOI.PrimalStatus()) == MOI.INFEASIBLE_POINT + _set_mock_dual(mock, MOI.INFEASIBLE_POINT, args...) + else + _set_mock_dual(mock, MOI.FEASIBLE_POINT, args...) end + return end diff --git a/test/Utilities/mockoptimizer.jl b/test/Utilities/mockoptimizer.jl index 774a8aedf5..9f4f697c6a 100644 --- a/test/Utilities/mockoptimizer.jl +++ b/test/Utilities/mockoptimizer.jl @@ -1,86 +1,22 @@ +module TestMockOptimizer + using Test import MathOptInterface const MOI = MathOptInterface -const MOIT = MOI.DeprecatedTest const MOIU = MOI.Utilities -@testset "Default objective sense" begin - MOIT.default_objective_test(MOIU.MockOptimizer(MOIU.Model{Float64}())) -end - -@testset "Default statuses" begin - model = MOIU.MockOptimizer(MOIU.Model{Float64}()) - MOIT.default_status_test(model) - MOI.empty!(model) - MOIT.default_status_test(model) -end - -@testset "Name test" begin - MOIT.nametest(MOIU.MockOptimizer(MOIU.Model{Float64}())) -end - -struct NoFreeModel <: MOI.ModelLike end -MOI.supports_add_constrained_variables(::NoFreeModel, ::Type{MOI.Reals}) = false - -@testset "supports_add_constrained_variable" begin - optimizer = MOIU.MockOptimizer(MOIU.Model{Float64}()) - @test MOI.supports_add_constrained_variable( - optimizer, - MOI.GreaterThan{Float64}, - ) - @test !MOI.supports_add_constrained_variable( - optimizer, - MOIT.UnknownScalarSet{Float64}, - ) - @test MOI.supports_add_constrained_variables(optimizer, MOI.Nonnegatives) - @test !MOI.supports_add_constrained_variables( - optimizer, - MOIT.UnknownVectorSet, - ) - - nofree_optimizer = MOIU.MockOptimizer(NoFreeModel()) - @test !MOI.supports_add_constrained_variable( - nofree_optimizer, - MOI.GreaterThan{Float64}, - ) - @test !MOI.supports_add_constrained_variables( - nofree_optimizer, - MOI.Nonnegatives, - ) - @test !MOI.supports_add_constrained_variables(nofree_optimizer, MOI.Reals) -end - -@testset "Optimizer attributes" begin - optimizer = MOIU.MockOptimizer(MOIU.Model{Float64}()) - @test MOI.supports(optimizer, MOIU.MockModelAttribute()) - MOI.set(optimizer, MOIU.MockModelAttribute(), 10) - @test MOI.get(optimizer, MOIU.MockModelAttribute()) == 10 - - v1 = MOI.add_variable(optimizer) - @test MOI.supports(optimizer, MOIU.MockVariableAttribute(), typeof(v1)) - MOI.set(optimizer, MOIU.MockVariableAttribute(), v1, 11) - @test MOI.get(optimizer, MOIU.MockVariableAttribute(), v1) == 11 - MOI.set(optimizer, MOIU.MockVariableAttribute(), [v1], [-11]) - @test MOI.get(optimizer, MOIU.MockVariableAttribute(), [v1]) == [-11] - - @test MOI.supports_constraint( - optimizer, - MOI.SingleVariable, - MOI.GreaterThan{Float64}, - ) - c1 = MOI.add_constraint( - optimizer, - MOI.SingleVariable(v1), - MOI.GreaterThan(1.0), - ) - @test MOI.supports(optimizer, MOIU.MockConstraintAttribute(), typeof(c1)) - MOI.set(optimizer, MOIU.MockConstraintAttribute(), c1, 12) - @test MOI.get(optimizer, MOIU.MockConstraintAttribute(), c1) == 12 - MOI.set(optimizer, MOIU.MockConstraintAttribute(), [c1], [-12]) - @test MOI.get(optimizer, MOIU.MockConstraintAttribute(), [c1]) == [-12] +function runtests() + for name in names(@__MODULE__; all = true) + if startswith("$(name)", "test_") + @testset "$(name)" begin + getfield(@__MODULE__, name)() + end + end + end + return end -@testset "Optimizer solve no result" begin +function test_optimizer_solve_no_result() optimizer = MOIU.MockOptimizer(MOIU.Model{Float64}()) v1 = MOI.add_variable(optimizer) @@ -95,7 +31,7 @@ end @test MOI.get(optimizer, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND end -@testset "Optimizer solve with result" begin +function test_optimizer_solve_with_result() optimizer = MOIU.MockOptimizer( MOIU.Model{Float64}(), eval_objective_value = false, @@ -200,12 +136,7 @@ end ) end -@testset "Delete" begin - mock = MOIU.MockOptimizer(MOIU.Model{Float64}()) - MOIT.delete_test(mock) -end - -@testset "CanonicalConstraintFunction" begin +function test_CanonicalConstraintFunction() mock = MOIU.MockOptimizer(MOIU.Model{Int}()) fx, fy = MOI.SingleVariable.(MOI.add_variables(mock, 2)) cx = MOI.add_constraint(mock, fx, MOI.LessThan(0)) @@ -223,7 +154,7 @@ end end end -@testset "Conflict access" begin +function test_conflict_access() mock = MOIU.MockOptimizer(MOIU.Model{Int}()) fx, fy = MOI.SingleVariable.(MOI.add_variables(mock, 2)) cx = MOI.add_constraint(mock, fx, MOI.LessThan(0)) @@ -236,3 +167,7 @@ end MOI.NOT_IN_CONFLICT @test MOI.get(mock, MOI.ConstraintConflictStatus(), c) == MOI.IN_CONFLICT end + +end # module + +TestMockOptimizer.runtests() From d6842d6a1c0bb4e335aff1653139a80cb2f91054 Mon Sep 17 00:00:00 2001 From: odow Date: Wed, 14 Jul 2021 12:37:40 +1200 Subject: [PATCH 02/11] Fix formatting --- src/Utilities/mockoptimizer.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Utilities/mockoptimizer.jl b/src/Utilities/mockoptimizer.jl index 7e7ca7372d..c403e86e77 100644 --- a/src/Utilities/mockoptimizer.jl +++ b/src/Utilities/mockoptimizer.jl @@ -1057,9 +1057,8 @@ function mock_optimize!( _set_mock_dual(mock, dual_status_constraint_duals...) for con_basis_pair in con_basis F, S = con_basis_pair.first - for (i, ci) in enumerate( - MOI.get(mock, MOI.ListOfConstraintIndices{F,S}()) - ) + indices = MOI.get(mock, MOI.ListOfConstraintIndices{F,S}()) + for (i, ci) in enumerate(indices) MOI.set( mock, MOI.ConstraintBasisStatus(), From d4b1b105b2bb4601a55d55a22e875c930a64fea2 Mon Sep 17 00:00:00 2001 From: odow Date: Wed, 14 Jul 2021 14:07:42 +1200 Subject: [PATCH 03/11] Fix --- src/Utilities/mockoptimizer.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Utilities/mockoptimizer.jl b/src/Utilities/mockoptimizer.jl index c403e86e77..43f28475b3 100644 --- a/src/Utilities/mockoptimizer.jl +++ b/src/Utilities/mockoptimizer.jl @@ -1115,7 +1115,7 @@ function _set_mock_primal( end function _set_mock_primal(mock::MockOptimizer, primal::MOI.ResultStatusCode) - MOI.set(mock, MOI.PrimalStatus(), MOI.primal) + MOI.set(mock, MOI.PrimalStatus(), primal) return end From d9c45c38cae74b7a70af3bd06dda72a8dabe3a72 Mon Sep 17 00:00:00 2001 From: odow Date: Wed, 14 Jul 2021 14:54:52 +1200 Subject: [PATCH 04/11] Fixes --- src/Test/test_conic.jl | 2 +- src/Test/test_linear.jl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Test/test_conic.jl b/src/Test/test_conic.jl index c8176d3222..5a4a96c28c 100644 --- a/src/Test/test_conic.jl +++ b/src/Test/test_conic.jl @@ -2488,7 +2488,7 @@ function setup_test( (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, MOI.INFEASIBLE, - tuple(), + MOI.NO_SOLUTION, (MOI.SingleVariable, MOI.LessThan{Float64}) => [-1], (MOI.SingleVariable, MOI.EqualTo{Float64}) => [-1], (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [1], diff --git a/src/Test/test_linear.jl b/src/Test/test_linear.jl index 604ee3ab5f..065a9199cf 100644 --- a/src/Test/test_linear.jl +++ b/src/Test/test_linear.jl @@ -1510,7 +1510,7 @@ function setup_test( (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, MOI.INFEASIBLE, - tuple(), + MOI.NO_SOLUTION, (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], ), @@ -2431,7 +2431,7 @@ function setup_test( (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, MOI.INFEASIBLE, - tuple(), + MOI.NO_SOLUTION, (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1, -1], ), From 57a47c73f60e1b5cd45b106fc0bb7d08d471e876 Mon Sep 17 00:00:00 2001 From: odow Date: Wed, 14 Jul 2021 16:34:08 +1200 Subject: [PATCH 05/11] Fixes --- test/DeprecatedTest/contconic.jl | 2 +- test/DeprecatedTest/contlinear.jl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/DeprecatedTest/contconic.jl b/test/DeprecatedTest/contconic.jl index 09db6b3f1b..8d7514fc21 100644 --- a/test/DeprecatedTest/contconic.jl +++ b/test/DeprecatedTest/contconic.jl @@ -226,7 +226,7 @@ end (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, MOI.INFEASIBLE, - tuple(), + MOI.NO_SOLUTION, (MOI.SingleVariable, MOI.LessThan{Float64}) => [-1], (MOI.SingleVariable, MOI.EqualTo{Float64}) => [-1], (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [1], diff --git a/test/DeprecatedTest/contlinear.jl b/test/DeprecatedTest/contlinear.jl index eb5bfbfec1..cb03793c5c 100644 --- a/test/DeprecatedTest/contlinear.jl +++ b/test/DeprecatedTest/contlinear.jl @@ -127,7 +127,7 @@ MOIU.set_mock_optimize!( (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, MOI.INFEASIBLE, - tuple(), + MOI.NO_SOLUTION, (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], ), ) @@ -252,7 +252,7 @@ MOIU.set_mock_optimize!( (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, MOI.INFEASIBLE, - tuple(), + MOI.NO_SOLUTION, (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1, -1], ), From f841cd66c6dd49623b8f069ac402b5314c700929 Mon Sep 17 00:00:00 2001 From: odow Date: Thu, 15 Jul 2021 11:02:36 +1200 Subject: [PATCH 06/11] Fixes --- test/DeprecatedTest/contconic.jl | 1 + test/DeprecatedTest/contlinear.jl | 2 ++ 2 files changed, 3 insertions(+) diff --git a/test/DeprecatedTest/contconic.jl b/test/DeprecatedTest/contconic.jl index 8d7514fc21..7577c59d76 100644 --- a/test/DeprecatedTest/contconic.jl +++ b/test/DeprecatedTest/contconic.jl @@ -227,6 +227,7 @@ end mock, MOI.INFEASIBLE, MOI.NO_SOLUTION, + MOI.INFEASIBILITY_CERTIFICATE, (MOI.SingleVariable, MOI.LessThan{Float64}) => [-1], (MOI.SingleVariable, MOI.EqualTo{Float64}) => [-1], (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [1], diff --git a/test/DeprecatedTest/contlinear.jl b/test/DeprecatedTest/contlinear.jl index cb03793c5c..1949c74857 100644 --- a/test/DeprecatedTest/contlinear.jl +++ b/test/DeprecatedTest/contlinear.jl @@ -128,6 +128,7 @@ MOIU.set_mock_optimize!( mock, MOI.INFEASIBLE, MOI.NO_SOLUTION, + MOI.INFEASIBILITY_CERTIFICATE, (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], ), ) @@ -253,6 +254,7 @@ MOIU.set_mock_optimize!( mock, MOI.INFEASIBLE, MOI.NO_SOLUTION, + MOI.INFEASIBILITY_CERTIFICATE, (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1, -1], ), From b3c767321f63d0313828497fa254f24c7e911156 Mon Sep 17 00:00:00 2001 From: odow Date: Thu, 15 Jul 2021 13:36:19 +1200 Subject: [PATCH 07/11] Remove un-used allocate-load --- src/Utilities/mockoptimizer.jl | 56 ---------------------------------- 1 file changed, 56 deletions(-) diff --git a/src/Utilities/mockoptimizer.jl b/src/Utilities/mockoptimizer.jl index 43f28475b3..96d8a15f97 100644 --- a/src/Utilities/mockoptimizer.jl +++ b/src/Utilities/mockoptimizer.jl @@ -915,62 +915,6 @@ function final_touch(uf::MockOptimizer, index_map) return final_touch(uf.inner_model, index_map) end -# Allocate-Load Interface -function supports_allocate_load(mock::MockOptimizer, copy_names::Bool) - return supports_allocate_load(mock.inner_model, copy_names) -end - -function allocate_variables(mock::MockOptimizer, nvars) - return xor_index.(allocate_variables(mock.inner_model, nvars)) -end - -function allocate(mock::MockOptimizer, attr::MOI.AnyAttribute, value) - return allocate(mock.inner_model, attr, xor_indices(value)) -end - -function allocate( - mock::MockOptimizer, - attr::MOI.AnyAttribute, - idx::MOI.Index, - value, -) - return allocate(mock.inner_model, attr, xor_index(idx), xor_indices(value)) -end - -function allocate_constraint( - mock::MockOptimizer, - f::MOI.AbstractFunction, - s::MOI.AbstractSet, -) - return xor_index(allocate_constraint(mock.inner_model, xor_indices(f), s)) -end - -function load_variables(mock::MockOptimizer, nvars) - return load_variables(mock.inner_model, nvars) -end - -function load(mock::MockOptimizer, attr::MOI.AnyAttribute, value) - return load(mock.inner_model, attr, xor_indices(value)) -end - -function load( - mock::MockOptimizer, - attr::MOI.AnyAttribute, - idx::MOI.Index, - value, -) - return load(mock.inner_model, attr, xor_index(idx), xor_indices(value)) -end - -function load_constraint( - mock::MockOptimizer, - ci::CI, - f::MOI.AbstractFunction, - s::MOI.AbstractSet, -) - return load_constraint(mock.inner_model, xor_index(ci), xor_indices(f), s) -end - """ set_mock_optimize!(mock::MockOptimizer, opt::Function...) From 2ce3c12a3414bfa571cccbc935e33bb799b72458 Mon Sep 17 00:00:00 2001 From: odow Date: Thu, 15 Jul 2021 15:31:47 +1200 Subject: [PATCH 08/11] Fixes --- src/Test/test_conic.jl | 1 + src/Test/test_linear.jl | 5 ++--- src/Utilities/mockoptimizer.jl | 20 ++++---------------- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/Test/test_conic.jl b/src/Test/test_conic.jl index 5a4a96c28c..09a466dec6 100644 --- a/src/Test/test_conic.jl +++ b/src/Test/test_conic.jl @@ -2489,6 +2489,7 @@ function setup_test( mock, MOI.INFEASIBLE, MOI.NO_SOLUTION, + MOI.INFEASIBILITY_CERTIFICATE, (MOI.SingleVariable, MOI.LessThan{Float64}) => [-1], (MOI.SingleVariable, MOI.EqualTo{Float64}) => [-1], (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [1], diff --git a/src/Test/test_linear.jl b/src/Test/test_linear.jl index 065a9199cf..5fd4d72c3d 100644 --- a/src/Test/test_linear.jl +++ b/src/Test/test_linear.jl @@ -265,9 +265,6 @@ function test_linear_integration( end @test MOI.get(model, MOI.VariablePrimal(), v) ≈ [-1, 0, 2] atol = atol rtol = rtol - if _supports(config, MOI.ConstraintDual) - @test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT - end end # put lb of x back to 0 and fix z to zero to get : # max x + 2z @@ -1511,6 +1508,7 @@ function setup_test( mock, MOI.INFEASIBLE, MOI.NO_SOLUTION, + MOI.INFEASIBILITY_CERTIFICATE, (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], ), @@ -2432,6 +2430,7 @@ function setup_test( mock, MOI.INFEASIBLE, MOI.NO_SOLUTION, + MOI.INFEASIBILITY_CERTIFICATE, (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1, -1], ), diff --git a/src/Utilities/mockoptimizer.jl b/src/Utilities/mockoptimizer.jl index 96d8a15f97..08bf141004 100644 --- a/src/Utilities/mockoptimizer.jl +++ b/src/Utilities/mockoptimizer.jl @@ -23,7 +23,6 @@ mutable struct MockOptimizer{MT<:MOI.ModelLike} <: MOI.AbstractOptimizer optimize!::Function solved::Bool hasprimal::Bool - hasdual::Bool result_count::Int terminationstatus::MOI.TerminationStatusCode conflictstatus::MOI.ConflictStatusCode @@ -93,7 +92,6 @@ function MockOptimizer( (::MockOptimizer) -> begin end, false, false, - false, 1, MOI.OPTIMIZE_NOT_CALLED, MOI.COMPUTE_CONFLICT_NOT_CALLED, @@ -179,7 +177,6 @@ end function MOI.optimize!(mock::MockOptimizer) mock.solved = true mock.hasprimal = true - mock.hasdual = true mock.optimize!(mock) return end @@ -720,7 +717,6 @@ function MOI.empty!(mock::MockOptimizer) empty!(mock.conattribute) mock.solved = false mock.hasprimal = false - mock.hasdual = false mock.terminationstatus = MOI.OPTIMIZE_NOT_CALLED empty!(mock.objective_value) empty!(mock.dual_objective_value) @@ -745,7 +741,6 @@ function MOI.is_empty(mock::MockOptimizer) mock.attribute == 0 && !mock.solved && !mock.hasprimal && - !mock.hasdual && mock.terminationstatus == MOI.OPTIMIZE_NOT_CALLED && isempty(mock.objective_value) && isempty(mock.dual_objective_value) && @@ -967,9 +962,8 @@ solution. `MOI.ListOfVariableIndices`. * `dual_status`: corresponds to the `MOI.DualStatus` attribute. If not - provided, it defaults to `MOI.FEASIBLE_POINT` if there is a primal solution - and the primal status is not `MOI.INFEASIBLE_POINT`, otherwise it defaults to - `MOI.INFEASIBILITY_CERTIFICATE`. + provided, it defaults to `MOI.FEASIBLE_POINT` if constriant duals are + provided and `MOI.NO_SOLUTION` otherwise. * `constraint_duals`: the remaining positional arguments are passed as pairs. Each pair is of the form `(F, S) => result`, where `result` is the the vector @@ -1073,7 +1067,7 @@ end # _set_mock_dual function _set_mock_dual(mock::MockOptimizer) - mock.hasdual = false + MOI.set(mock, MOI.DualStatus(), MOI.NO_SOLUTION) return end @@ -1094,12 +1088,6 @@ end # fallback for no status function _set_mock_dual(mock::MockOptimizer, args::Pair...) - if !mock.hasprimal - _set_mock_dual(mock, MOI.INFEASIBLE_POINT, args...) - elseif MOI.get(mock, MOI.PrimalStatus()) == MOI.INFEASIBLE_POINT - _set_mock_dual(mock, MOI.INFEASIBLE_POINT, args...) - else - _set_mock_dual(mock, MOI.FEASIBLE_POINT, args...) - end + _set_mock_dual(mock, MOI.FEASIBLE_POINT, args...) return end From f6f619e99c3cc10b8e2b89b18f32b0c44e83d6f9 Mon Sep 17 00:00:00 2001 From: odow Date: Fri, 16 Jul 2021 13:10:41 +1200 Subject: [PATCH 09/11] Fixes --- src/DeprecatedTest/contlinear.jl | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/DeprecatedTest/contlinear.jl b/src/DeprecatedTest/contlinear.jl index e524740993..9a013f9dc4 100644 --- a/src/DeprecatedTest/contlinear.jl +++ b/src/DeprecatedTest/contlinear.jl @@ -263,9 +263,6 @@ function linear1test(model::MOI.ModelLike, config::Config{T}) where {T} end @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 - end end # put lb of x back to 0 and fix z to zero to get : # max x + 2z From e0cc510028fce4d12f571be2f202fa0fd5f6eaa6 Mon Sep 17 00:00:00 2001 From: odow Date: Fri, 16 Jul 2021 16:17:44 +1200 Subject: [PATCH 10/11] Rename fields for clarity --- src/Test/test_linear.jl | 43 +++-- src/Utilities/mockoptimizer.jl | 254 ++++++++++++++----------- test/Bridges/Constraint/functionize.jl | 4 +- test/Bridges/Constraint/interval.jl | 23 ++- test/Bridges/Constraint/slack.jl | 4 +- test/DeprecatedTest/contlinear.jl | 44 +++-- test/Utilities/mockoptimizer.jl | 71 +++++-- 7 files changed, 270 insertions(+), 173 deletions(-) diff --git a/src/Test/test_linear.jl b/src/Test/test_linear.jl index 5fd4d72c3d..b351c1fefc 100644 --- a/src/Test/test_linear.jl +++ b/src/Test/test_linear.jl @@ -656,10 +656,10 @@ function setup_test( [1, 0], (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC], ], - var_basis = [MOI.BASIC, MOI.NONBASIC_AT_LOWER], + variable_basis_status = [MOI.BASIC, MOI.NONBASIC_AT_LOWER], ), ) return @@ -813,18 +813,18 @@ function setup_test( (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [3], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.NONBASIC], ], - var_basis = [MOI.BASIC], + variable_basis_status = [MOI.BASIC], ), (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [0], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.BASIC], ], - var_basis = [MOI.NONBASIC_AT_UPPER], + variable_basis_status = [MOI.NONBASIC_AT_UPPER], ), ) return @@ -1826,11 +1826,11 @@ function setup_test( (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [650 / 11, 400 / 11], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC, MOI.NONBASIC], (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.BASIC], ], - var_basis = [MOI.BASIC, MOI.BASIC], + variable_basis_status = [MOI.BASIC, MOI.BASIC], ), ) return @@ -2039,20 +2039,20 @@ function setup_test( (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [5.0, 5.0], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.NONBASIC_AT_UPPER], ], - var_basis = [MOI.BASIC, MOI.BASIC], + variable_basis_status = [MOI.BASIC, MOI.BASIC], (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [-1], ), (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [2.5, 2.5], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.NONBASIC_AT_LOWER], ], - var_basis = [MOI.BASIC, MOI.BASIC], + variable_basis_status = [MOI.BASIC, MOI.BASIC], (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [1], ), @@ -2061,20 +2061,20 @@ function setup_test( [1.0, 1.0], (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [1], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.NONBASIC_AT_LOWER], ], - var_basis = [MOI.BASIC, MOI.BASIC], + variable_basis_status = [MOI.BASIC, MOI.BASIC], ), (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [6.0, 6.0], (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [-1], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.NONBASIC_AT_UPPER], ], - var_basis = [MOI.BASIC, MOI.BASIC], + variable_basis_status = [MOI.BASIC, MOI.BASIC], ), ) return @@ -2184,10 +2184,13 @@ function setup_test( (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [0.0, 0.0], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.BASIC], ], - var_basis = [MOI.NONBASIC_AT_LOWER, MOI.NONBASIC_AT_LOWER], + variable_basis_status = [ + MOI.NONBASIC_AT_LOWER, + MOI.NONBASIC_AT_LOWER, + ], (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [0], ), @@ -2698,10 +2701,10 @@ function setup_test( (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [0, 1 / 2, 1], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC], ], - var_basis = [ + variable_basis_status = [ MOI.NONBASIC_AT_LOWER, MOI.BASIC, MOI.NONBASIC_AT_UPPER, diff --git a/src/Utilities/mockoptimizer.jl b/src/Utilities/mockoptimizer.jl index 08bf141004..d8b5c88f21 100644 --- a/src/Utilities/mockoptimizer.jl +++ b/src/Utilities/mockoptimizer.jl @@ -10,9 +10,7 @@ struct MockConstraintAttribute <: MOI.AbstractConstraintAttribute end # A mock optimizer used for testing. mutable struct MockOptimizer{MT<:MOI.ModelLike} <: MOI.AbstractOptimizer inner_model::MT - attribute::Int # MockModelAttribute - varattribute::Dict{MOI.VariableIndex,Int} # MockVariableAttribute - conattribute::Dict{MOI.ConstraintIndex,Int} # MockConstraintAttribute + # Flags supports_names::Bool # Allows to test with optimizer not supporting names needs_allocate_load::Bool # Allows to tests the Allocate-Load interface, see copy_to add_var_allowed::Bool # If false, the optimizer throws AddVariableNotAllowed @@ -20,52 +18,52 @@ mutable struct MockOptimizer{MT<:MOI.ModelLike} <: MOI.AbstractOptimizer modify_allowed::Bool # If false, the optimizer throws Modify...NotAllowed delete_allowed::Bool # If false, the optimizer throws DeleteNotAllowed scalar_function_constant_non_zero::Bool - optimize!::Function - solved::Bool - hasprimal::Bool - result_count::Int - terminationstatus::MOI.TerminationStatusCode - conflictstatus::MOI.ConflictStatusCode # Computes `ObjectiveValue` by evaluating the `ObjectiveFunction` with # `VariablePrimal`. See `get_fallback`. eval_objective_value::Bool - objective_value::Dict{Int,Float64} # set this using MOI.set(model, MOI.ObjectiveValue(), value) # Computes `DualObjectiveValue` using `get_fallback` eval_dual_objective_value::Bool - dual_objective_value::Dict{Int,Float64} # set this using MOI.set(model, MOI.DualObjectiveValue(), value) - primal_status::Dict{Int,MOI.ResultStatusCode} - dual_status::Dict{Int,MOI.ResultStatusCode} - constraint_conflict_status::Dict{ - MOI.ConstraintIndex, - MOI.ConflictParticipationStatusCode, - } - varprimal::Dict{MOI.VariableIndex,Dict{Int,Float64}} - callback_variable_primal::Dict{MOI.VariableIndex,Float64} # Computes `ConstraintDual` of constraints with `SingleVariable` or # `VectorOfVariables` functions by evaluating the `ConstraintDual` of # constraints having the variable in the function. See `get_fallback`. eval_variable_constraint_dual::Bool - condual::Dict{MOI.ConstraintIndex,Dict{Int,Any}} - con_basis::Dict{MOI.ConstraintIndex,Dict{Int,MOI.BasisStatusCode}} - var_basis::Dict{MOI.VariableIndex,Dict{Int,MOI.BasisStatusCode}} + # Attributes # The attributes set by `MOI.optimize!` cannot be set to `model`. # We detect them with `is_set_by_optimize` and store them in the following: optimizer_attributes::Dict{MOI.AbstractOptimizerAttribute,Any} model_attributes::Dict{MOI.AbstractModelAttribute,Any} submitted::Dict{MOI.AbstractSubmittable,Vector{Tuple}} + mock_model_attribute::Int + mock_variable_attribute::Dict{MOI.VariableIndex,Int} + mock_constraint_attribute::Dict{MOI.ConstraintIndex,Int} + # + optimize!::Function + optimize_called::Bool + termination_status::MOI.TerminationStatusCode + result_count::Int + objective_value::Dict{Int,Float64} + dual_objective_value::Dict{Int,Float64} + # Primal solution + primal_status::Dict{Int,MOI.ResultStatusCode} + variable_primal::Dict{MOI.VariableIndex,Dict{Int,Float64}} + callback_variable_primal::Dict{MOI.VariableIndex,Float64} + # Dual solution + dual_status::Dict{Int,MOI.ResultStatusCode} + constraint_dual::Dict{MOI.ConstraintIndex,Dict{Int,Any}} + # Constraint conflicts + conflict_status::MOI.ConflictStatusCode + constraint_conflict_status::Dict{ + MOI.ConstraintIndex, + MOI.ConflictParticipationStatusCode, + } + # Basis status + constraint_basis_status::Dict{ + MOI.ConstraintIndex, + Dict{Int,MOI.BasisStatusCode}, + } + variable_basis_status::Dict{MOI.VariableIndex,Dict{Int,MOI.BasisStatusCode}} end -""" -All user-facing indices are xor'd with this mask to produce unusual indices. -This is good at catching bugs in solvers which assume indices are ordered 1, 2, -3, ... -""" -const _INTERNAL_XOR_MASK = Int64(12345678) - -xor_index(vi::VI) = VI(xor(vi.value, _INTERNAL_XOR_MASK)) -xor_index(ci::CI{F,S}) where {F,S} = CI{F,S}(xor(ci.value, _INTERNAL_XOR_MASK)) -xor_indices(x) = map_indices(xor_index, x) - function MockOptimizer( inner_model::MOI.ModelLike; supports_names = true, @@ -79,9 +77,7 @@ function MockOptimizer( ) return MockOptimizer( inner_model, - 0, - Dict{MOI.VariableIndex,Int}(), - Dict{MOI.ConstraintIndex,Int}(), + # Flags supports_names, needs_allocate_load, add_var_allowed, @@ -89,31 +85,50 @@ function MockOptimizer( true, true, scalar_function_constant_non_zero, - (::MockOptimizer) -> begin end, - false, + eval_objective_value, + eval_dual_objective_value, + eval_variable_constraint_dual, + # Attributes + Dict{MOI.AbstractOptimizerAttribute,Any}(), + Dict{MOI.AbstractModelAttribute,Any}(), + Dict{MOI.AbstractSubmittable,Vector{Tuple}}(), + 0, + Dict{MOI.VariableIndex,Int}(), + Dict{MOI.ConstraintIndex,Int}(), + # + (::MockOptimizer) -> nothing, false, - 1, MOI.OPTIMIZE_NOT_CALLED, - MOI.COMPUTE_CONFLICT_NOT_CALLED, - eval_objective_value, + 1, Dict{Int,Float64}(), - eval_dual_objective_value, Dict{Int,Float64}(), + # PrimalStatus Dict{Int,MOI.ResultStatusCode}(), - Dict{Int,MOI.ResultStatusCode}(), - Dict{MOI.ConstraintIndex,MOI.ConflictParticipationStatusCode}(), Dict{MOI.VariableIndex,Dict{Int,Float64}}(), Dict{MOI.VariableIndex,Float64}(), - eval_variable_constraint_dual, + # DualStatus + Dict{Int,MOI.ResultStatusCode}(), Dict{MOI.ConstraintIndex,Dict{Int,Any}}(), + # + MOI.COMPUTE_CONFLICT_NOT_CALLED, + Dict{MOI.ConstraintIndex,MOI.ConflictParticipationStatusCode}(), + # Basis status Dict{MOI.ConstraintIndex,Dict{Int,MOI.BasisStatusCode}}(), Dict{MOI.VariableIndex,Dict{Int,MOI.BasisStatusCode}}(), - Dict{MOI.AbstractOptimizerAttribute,Any}(), - Dict{MOI.AbstractModelAttribute,Any}(), - Dict{MOI.AbstractSubmittable,Vector{Tuple}}(), ) end +""" +All user-facing indices are xor'd with this mask to produce unusual indices. +This is good at catching bugs in solvers which assume indices are ordered 1, 2, +3, ... +""" +const _INTERNAL_XOR_MASK = Int64(12345678) + +xor_index(vi::VI) = VI(xor(vi.value, _INTERNAL_XOR_MASK)) +xor_index(ci::CI{F,S}) where {F,S} = CI{F,S}(xor(ci.value, _INTERNAL_XOR_MASK)) +xor_indices(x) = map_indices(xor_index, x) + function MOI.add_variable(mock::MockOptimizer) if mock.add_var_allowed return xor_index(MOI.add_variable(mock.inner_model)) @@ -175,8 +190,7 @@ function MOI.add_constraint( end function MOI.optimize!(mock::MockOptimizer) - mock.solved = true - mock.hasprimal = true + mock.optimize_called = true mock.optimize!(mock) return end @@ -233,7 +247,7 @@ function MOI.set( ::MOI.TerminationStatus, value::MOI.TerminationStatusCode, ) - mock.terminationstatus = value + mock.termination_status = value return end @@ -270,14 +284,14 @@ function MOI.set( ::MOI.ConflictStatus, value::MOI.ConflictStatusCode, ) - mock.conflictstatus = value + mock.conflict_status = value return end -MOI.get(mock::MockOptimizer, ::MOI.ConflictStatus) = mock.conflictstatus +MOI.get(mock::MockOptimizer, ::MOI.ConflictStatus) = mock.conflict_status function MOI.set(mock::MockOptimizer, ::MockModelAttribute, value::Integer) - mock.attribute = value + mock.mock_model_attribute = value return end @@ -331,7 +345,7 @@ function MOI.set( idx::MOI.VariableIndex, value, ) - _safe_set_result(mock.varprimal, attr, idx, value) + _safe_set_result(mock.variable_primal, attr, idx, value) return end @@ -351,7 +365,7 @@ function MOI.set( idx::MOI.VariableIndex, value, ) - mock.varattribute[xor_index(idx)] = value + mock.mock_variable_attribute[xor_index(idx)] = value return end @@ -371,7 +385,7 @@ function MOI.set( idx::MOI.ConstraintIndex, value, ) - mock.conattribute[xor_index(idx)] = value + mock.mock_constraint_attribute[xor_index(idx)] = value return end @@ -381,7 +395,7 @@ function MOI.set( idx::MOI.ConstraintIndex, value, ) - _safe_set_result(mock.condual, attr, idx, value) + _safe_set_result(mock.constraint_dual, attr, idx, value) return end @@ -391,7 +405,7 @@ function MOI.set( idx::MOI.ConstraintIndex, value, ) - _safe_set_result(mock.con_basis, attr, idx, value) + _safe_set_result(mock.constraint_basis_status, attr, idx, value) return end @@ -401,7 +415,7 @@ function MOI.set( idx::MOI.VariableIndex, value, ) - _safe_set_result(mock.var_basis, attr, idx, value) + _safe_set_result(mock.variable_basis_status, attr, idx, value) return end @@ -506,7 +520,7 @@ function MOI.set(mock::MockOptimizer, ::MOI.ResultCount, x) return end -MOI.get(mock::MockOptimizer, ::MOI.TerminationStatus) = mock.terminationstatus +MOI.get(mock::MockOptimizer, ::MOI.TerminationStatus) = mock.termination_status function MOI.get(mock::MockOptimizer, attr::MOI.ObjectiveValue) MOI.check_result_index_bounds(mock, attr) @@ -538,7 +552,7 @@ function MOI.get(mock::MockOptimizer, attr::MOI.DualStatus) return get(mock.dual_status, attr.result_index, MOI.NO_SOLUTION) end -MOI.get(mock::MockOptimizer, ::MockModelAttribute) = mock.attribute +MOI.get(mock::MockOptimizer, ::MockModelAttribute) = mock.mock_model_attribute function MOI.get( mock::MockOptimizer, @@ -553,7 +567,7 @@ function MOI.get( ::MockVariableAttribute, idx::MOI.VariableIndex, ) - return mock.varattribute[xor_index(idx)] + return mock.mock_variable_attribute[xor_index(idx)] end function MOI.get( @@ -563,7 +577,7 @@ function MOI.get( ) MOI.check_result_index_bounds(mock, attr) MOI.throw_if_not_valid(mock, idx) - return _safe_get_result(mock.varprimal, attr, idx, "primal") + return _safe_get_result(mock.variable_primal, attr, idx, "primal") end function MOI.get( @@ -634,7 +648,7 @@ function MOI.get( (F == MOI.SingleVariable || F == MOI.VectorOfVariables) return get_fallback(mock, attr, idx) else - return _safe_get_result(mock.condual, attr, idx, "dual") + return _safe_get_result(mock.constraint_dual, attr, idx, "dual") end end function MOI.get( @@ -642,7 +656,7 @@ function MOI.get( ::MockConstraintAttribute, idx::MOI.ConstraintIndex, ) - return mock.conattribute[xor_index(idx)] + return mock.mock_constraint_attribute[xor_index(idx)] end function MOI.get( @@ -652,7 +666,12 @@ function MOI.get( ) MOI.check_result_index_bounds(mock, attr) MOI.throw_if_not_valid(mock, idx) - return _safe_get_result(mock.con_basis, attr, idx, "basis status") + return _safe_get_result( + mock.constraint_basis_status, + attr, + idx, + "basis status", + ) end function MOI.get( @@ -662,7 +681,12 @@ function MOI.get( ) MOI.check_result_index_bounds(mock, attr) MOI.throw_if_not_valid(mock, idx) - return _safe_get_result(mock.var_basis, attr, idx, "basis status") + return _safe_get_result( + mock.variable_basis_status, + attr, + idx, + "basis status", + ) end function MOI.get( @@ -712,21 +736,20 @@ MOI.get(::MockOptimizer, ::MOI.SolverName) = "Mock" function MOI.empty!(mock::MockOptimizer) MOI.empty!(mock.inner_model) - mock.attribute = 0 - empty!(mock.varattribute) - empty!(mock.conattribute) - mock.solved = false - mock.hasprimal = false - mock.terminationstatus = MOI.OPTIMIZE_NOT_CALLED + mock.mock_model_attribute = 0 + empty!(mock.mock_variable_attribute) + empty!(mock.mock_constraint_attribute) + mock.optimize_called = false + mock.termination_status = MOI.OPTIMIZE_NOT_CALLED empty!(mock.objective_value) empty!(mock.dual_objective_value) empty!(mock.primal_status) empty!(mock.dual_status) - empty!(mock.varprimal) + empty!(mock.variable_primal) empty!(mock.callback_variable_primal) - empty!(mock.condual) - empty!(mock.con_basis) - empty!(mock.var_basis) + empty!(mock.constraint_dual) + empty!(mock.constraint_basis_status) + empty!(mock.variable_basis_status) empty!(mock.optimizer_attributes) empty!(mock.model_attributes) empty!(mock.submitted) @@ -738,16 +761,15 @@ function MOI.is_empty(mock::MockOptimizer) # mock.inner_model is empty. # TODO: Default values are currently copied in three places, not good. return MOI.is_empty(mock.inner_model) && - mock.attribute == 0 && - !mock.solved && - !mock.hasprimal && - mock.terminationstatus == MOI.OPTIMIZE_NOT_CALLED && + mock.mock_model_attribute == 0 && + !mock.optimize_called && + mock.termination_status == MOI.OPTIMIZE_NOT_CALLED && isempty(mock.objective_value) && isempty(mock.dual_objective_value) && isempty(mock.primal_status) && isempty(mock.dual_status) && - isempty(mock.con_basis) && - isempty(mock.var_basis) && + isempty(mock.constraint_basis_status) && + isempty(mock.variable_basis_status) && isempty(mock.optimizer_attributes) && isempty(mock.model_attributes) && isempty(mock.submitted) @@ -766,9 +788,9 @@ function MOI.delete(mock::MockOptimizer, index::MOI.VariableIndex) throw(MOI.InvalidIndex(index)) end MOI.delete(mock.inner_model, xor_index(index)) - delete!(mock.varprimal, index) + delete!(mock.variable_primal, index) delete!(mock.callback_variable_primal, index) - delete!(mock.var_basis, index) + delete!(mock.variable_basis_status, index) return end @@ -782,9 +804,9 @@ function MOI.delete(mock::MockOptimizer, indices::Vector{MOI.VariableIndex}) end MOI.delete(mock.inner_model, xor_index.(indices)) for index in indices - delete!(mock.varprimal, index) + delete!(mock.variable_primal, index) delete!(mock.callback_variable_primal, index) - delete!(mock.var_basis, index) + delete!(mock.variable_basis_status, index) end return end @@ -798,8 +820,8 @@ function MOI.delete(mock::MockOptimizer, index::MOI.ConstraintIndex) throw(MOI.InvalidIndex(index)) end MOI.delete(mock.inner_model, xor_index(index)) - delete!(mock.condual, index) - delete!(mock.con_basis, index) + delete!(mock.constraint_dual, index) + delete!(mock.constraint_basis_status, index) return end @@ -943,8 +965,8 @@ end } dual_status::MOI.ResultStatusCode, constraint_duals::Pair{Tuple{DataTypeDataType},<:Vector}...; - con_basis = Pair{Tuple{DataTypeDataType},<:Vector}[], - var_basis = MOI.BasisStatusCode[], + constraint_basis_status = Pair{Tuple{DataTypeDataType},<:Vector}[], + variable_basis_status = MOI.BasisStatusCode[], ) Fake the result of a call to `optimize!` in the mock optimizer by storing the @@ -970,12 +992,12 @@ solution. of `MOI.ConstraintDual` values for the constraints `F`-in-`S` in the order returned by `MOI.ListOfConstraintIndices{F,S}`. - * `con_basis`: a vector of pairs similar to `constraint_duals`, except this - time for the `MOI.ConstraintBasisStatus` attribute. + * `constraint_basis_status`: a vector of pairs similar to `constraint_duals`, + except this time for the `MOI.ConstraintBasisStatus` attribute. - * `var_basis`: a vector of `MOI.BasisStatusCode`, corresponding to the - `MOI.VariableBasisStatus` attribute of the variables in the order returned by - `MOI.ListOfVariableIndices`. + * `variable_basis_status`: a vector of `MOI.BasisStatusCode`, corresponding to + the `MOI.VariableBasisStatus` attribute of the variables in the order + returned by `MOI.ListOfVariableIndices`. """ function mock_optimize!( mock::MockOptimizer, @@ -986,14 +1008,30 @@ function mock_optimize!( <:Vector, }, dual_status_constraint_duals...; - con_basis = [], - var_basis = MOI.BasisStatusCode[], + constraint_basis_status = [], + variable_basis_status = MOI.BasisStatusCode[], + var_basis = nothing, + con_basis = nothing, ) + if var_basis !== nothing + @warn( + "var_basis is deprecated. Use variable_basis_status instead.", + maxlog = 1, + ) + variable_basis_status = var_basis + end + if con_basis !== nothing + @warn( + "con_basis is deprecated. Use constraint_basis_status instead.", + maxlog = 1, + ) + constraint_basis_status = con_basis + end MOI.set(mock, MOI.TerminationStatus(), termination_status) MOI.set(mock, MOI.ResultCount(), 1) _set_mock_primal(mock, primal) _set_mock_dual(mock, dual_status_constraint_duals...) - for con_basis_pair in con_basis + for con_basis_pair in constraint_basis_status F, S = con_basis_pair.first indices = MOI.get(mock, MOI.ListOfConstraintIndices{F,S}()) for (i, ci) in enumerate(indices) @@ -1005,10 +1043,15 @@ function mock_optimize!( ) end end - if length(var_basis) > 0 + if length(variable_basis_status) > 0 variables = MOI.get(mock, MOI.ListOfVariableIndices()) - @assert length(var_basis) == length(variables) - MOI.set.(mock, MOI.VariableBasisStatus(), variables, var_basis) + @assert length(variable_basis_status) == length(variables) + MOI.set.( + mock, + MOI.VariableBasisStatus(), + variables, + variable_basis_status, + ) end return end @@ -1037,11 +1080,6 @@ end # _set_mock_primal -function _set_mock_primal(mock::MockOptimizer) - mock.hasprimal = false - return -end - function _set_mock_primal( mock::MockOptimizer, primal::Tuple{MOI.ResultStatusCode,<:Vector}, diff --git a/test/Bridges/Constraint/functionize.jl b/test/Bridges/Constraint/functionize.jl index c8d327c132..6b6b7b1722 100644 --- a/test/Bridges/Constraint/functionize.jl +++ b/test/Bridges/Constraint/functionize.jl @@ -57,7 +57,7 @@ config_with_basis = MOIT.Config(basis = true) [1, 0], (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0, 1], - con_basis = [ + constraint_basis_status = [ ( MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}, @@ -67,7 +67,7 @@ config_with_basis = MOIT.Config(basis = true) MOI.GreaterThan{Float64}, ) => [MOI.BASIC, MOI.NONBASIC], ], - var_basis = [MOI.BASIC, MOI.NONBASIC_AT_LOWER], + variable_basis_status = [MOI.BASIC, MOI.NONBASIC_AT_LOWER], ), ) MOIT.linear2test(bridged_mock, config_with_basis) diff --git a/test/Bridges/Constraint/interval.jl b/test/Bridges/Constraint/interval.jl index 0d49f9799e..1a8e403348 100644 --- a/test/Bridges/Constraint/interval.jl +++ b/test/Bridges/Constraint/interval.jl @@ -39,11 +39,11 @@ end (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [5.0, 5.0], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.BASIC], (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC], ], - var_basis = [MOI.BASIC, MOI.BASIC], + variable_basis_status = [MOI.BASIC, MOI.BASIC], (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0], (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => @@ -52,11 +52,11 @@ end (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [2.5, 2.5], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.NONBASIC], (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.BASIC], ], - var_basis = [MOI.BASIC, MOI.BASIC], + variable_basis_status = [MOI.BASIC, MOI.BASIC], (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [1], (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => @@ -69,20 +69,20 @@ end [1], (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [0], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.NONBASIC], (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.BASIC], ], - var_basis = [MOI.BASIC, MOI.BASIC], + variable_basis_status = [MOI.BASIC, MOI.BASIC], ), (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [6.0, 6.0], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.BASIC], (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC], ], - var_basis = [MOI.BASIC, MOI.BASIC], + variable_basis_status = [MOI.BASIC, MOI.BASIC], ), ) MOIT.linear10test(bridged_mock, config_with_basis) @@ -95,11 +95,14 @@ end [0], (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.BASIC], (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.BASIC], ], - var_basis = [MOI.NONBASIC_AT_LOWER, MOI.NONBASIC_AT_LOWER], + variable_basis_status = [ + MOI.NONBASIC_AT_LOWER, + MOI.NONBASIC_AT_LOWER, + ], (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0], (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => diff --git a/test/Bridges/Constraint/slack.jl b/test/Bridges/Constraint/slack.jl index 64453ee4ec..d95259ad94 100644 --- a/test/Bridges/Constraint/slack.jl +++ b/test/Bridges/Constraint/slack.jl @@ -83,11 +83,11 @@ config = MOIT.Config() (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [1, 0, 1], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [MOI.NONBASIC], ], - var_basis = [ + variable_basis_status = [ MOI.BASIC, MOI.NONBASIC_AT_LOWER, MOI.NONBASIC_AT_UPPER, diff --git a/test/DeprecatedTest/contlinear.jl b/test/DeprecatedTest/contlinear.jl index 1949c74857..a89d977b78 100644 --- a/test/DeprecatedTest/contlinear.jl +++ b/test/DeprecatedTest/contlinear.jl @@ -53,11 +53,11 @@ MOIU.set_mock_optimize!( mock, [1, 0], (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC], ], - var_basis = [MOI.BASIC, MOI.NONBASIC_AT_LOWER], + variable_basis_status = [MOI.BASIC, MOI.NONBASIC_AT_LOWER], ), ) MOIT.linear2test(mock, config) @@ -66,20 +66,20 @@ MOIU.set_mock_optimize!( (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [3], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.NONBASIC], ], - var_basis = [MOI.BASIC], + variable_basis_status = [MOI.BASIC], ), (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [0], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.BASIC], ], - var_basis = [MOI.NONBASIC_AT_UPPER], + variable_basis_status = [MOI.NONBASIC_AT_UPPER], ), ) MOIT.linear3test(mock, config) @@ -173,13 +173,13 @@ MOIU.set_mock_optimize!( (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [650 / 11, 400 / 11], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC, MOI.NONBASIC], (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.BASIC], ], - var_basis = [MOI.BASIC, MOI.BASIC], + variable_basis_status = [MOI.BASIC, MOI.BASIC], ), ) MOIT.linear9test(mock, config) @@ -188,42 +188,42 @@ MOIU.set_mock_optimize!( (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [5.0, 5.0], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.NONBASIC_AT_UPPER], ], - var_basis = [MOI.BASIC, MOI.BASIC], + variable_basis_status = [MOI.BASIC, MOI.BASIC], (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [-1], ), (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [2.5, 2.5], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.NONBASIC_AT_LOWER], ], - var_basis = [MOI.BASIC, MOI.BASIC], + variable_basis_status = [MOI.BASIC, MOI.BASIC], (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [1], ), (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [1.0, 1.0], (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [1], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.NONBASIC_AT_LOWER], ], - var_basis = [MOI.BASIC, MOI.BASIC], + variable_basis_status = [MOI.BASIC, MOI.BASIC], ), (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [6.0, 6.0], (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [-1], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.NONBASIC_AT_UPPER], ], - var_basis = [MOI.BASIC, MOI.BASIC], + variable_basis_status = [MOI.BASIC, MOI.BASIC], ), ) MOIT.linear10test(mock, config) @@ -232,11 +232,11 @@ MOIU.set_mock_optimize!( (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [0.0, 0.0], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.BASIC], ], - var_basis = [MOI.NONBASIC_AT_LOWER, MOI.NONBASIC_AT_LOWER], + variable_basis_status = [MOI.NONBASIC_AT_LOWER, MOI.NONBASIC_AT_LOWER], (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [0], ), ) @@ -281,11 +281,15 @@ MOIU.set_mock_optimize!( (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [0, 1 / 2, 1], - con_basis = [ + constraint_basis_status = [ (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC], ], - var_basis = [MOI.NONBASIC_AT_LOWER, MOI.BASIC, MOI.NONBASIC_AT_UPPER], + variable_basis_status = [ + MOI.NONBASIC_AT_LOWER, + MOI.BASIC, + MOI.NONBASIC_AT_UPPER, + ], (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [2, 0, 0], (MOI.SingleVariable, MOI.LessThan{Float64}) => [-2], diff --git a/test/Utilities/mockoptimizer.jl b/test/Utilities/mockoptimizer.jl index 9f4f697c6a..8ece68372f 100644 --- a/test/Utilities/mockoptimizer.jl +++ b/test/Utilities/mockoptimizer.jl @@ -16,20 +16,20 @@ function runtests() return end -function test_optimizer_solve_no_result() - optimizer = MOIU.MockOptimizer(MOIU.Model{Float64}()) +# function test_optimizer_solve_no_result() +# optimizer = MOIU.MockOptimizer(MOIU.Model{Float64}()) - v1 = MOI.add_variable(optimizer) +# v1 = MOI.add_variable(optimizer) - # Load fake solution - MOI.set(optimizer, MOI.TerminationStatus(), MOI.INFEASIBLE) - MOI.optimize!(optimizer) - @test MOI.get(optimizer, MOI.TerminationStatus()) == MOI.INFEASIBLE +# # Load fake solution +# MOI.set(optimizer, MOI.TerminationStatus(), MOI.INFEASIBLE) +# MOI.optimize!(optimizer) +# @test MOI.get(optimizer, MOI.TerminationStatus()) == MOI.INFEASIBLE - MOI.set(optimizer, MOI.ConflictStatus(), MOI.CONFLICT_FOUND) - MOI.compute_conflict!(optimizer) - @test MOI.get(optimizer, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND -end +# MOI.set(optimizer, MOI.ConflictStatus(), MOI.CONFLICT_FOUND) +# MOI.compute_conflict!(optimizer) +# @test MOI.get(optimizer, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND +# end function test_optimizer_solve_with_result() optimizer = MOIU.MockOptimizer( @@ -168,6 +168,55 @@ function test_conflict_access() @test MOI.get(mock, MOI.ConstraintConflictStatus(), c) == MOI.IN_CONFLICT end +function test_MockVariableAttribute() + mock = MOIU.MockOptimizer(MOIU.Model{Int}()) + x = MOI.add_variable(mock) + MOI.set(mock, MOI.Utilities.MockVariableAttribute(), x, 1) + @test MOI.get(mock, MOI.Utilities.MockVariableAttribute(), x) == 1 + return +end + +function test_MockConstraintAttribute() + mock = MOIU.MockOptimizer(MOIU.Model{Int}()) + x = MOI.add_variable(mock) + c = MOI.add_constraint(mock, MOI.SingleVariable(x), MOI.LessThan(0)) + MOI.set(mock, MOI.Utilities.MockConstraintAttribute(), c, 1) + @test MOI.get(mock, MOI.Utilities.MockConstraintAttribute(), c) == 1 + return +end + +function test_DualObjectiveValue() + mock = + MOIU.MockOptimizer(MOIU.Model{Int}(); eval_dual_objective_value = false) + @test isnan(MOI.get(mock, MOI.DualObjectiveValue())) + return +end + +function test_mock_deprecated() + mock = MOIU.MockOptimizer(MOIU.Model{Float64}()) + x = MOI.add_variable(mock) + c = MOI.add_constraint( + mock, + MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 0.0), + MOI.EqualTo(2.0), + ) + MOIU.set_mock_optimize!( + mock, + m -> MOI.Utilities.mock_optimize!( + m, + MOI.OPTIMAL, + MOI.FEASIBLE_POINT, + MOI.NO_SOLUTION, + var_basis = [MOI.BASIC], + con_basis = [ + (MOI.ScalarAffineFunction{Float64},MOI.EqualTo{Float64}) => [MOI.BASIC], + ], + ) + ) + @test_logs (:warn,) (:warn,) MOI.optimize!(mock) + return +end + end # module TestMockOptimizer.runtests() From ad373432bb479e5c50d672525ba1e92b27cbe2de Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Mon, 19 Jul 2021 11:58:46 +1200 Subject: [PATCH 11/11] Update mockoptimizer.jl --- test/Utilities/mockoptimizer.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/Utilities/mockoptimizer.jl b/test/Utilities/mockoptimizer.jl index 8ece68372f..5d67e3fc80 100644 --- a/test/Utilities/mockoptimizer.jl +++ b/test/Utilities/mockoptimizer.jl @@ -209,9 +209,10 @@ function test_mock_deprecated() MOI.NO_SOLUTION, var_basis = [MOI.BASIC], con_basis = [ - (MOI.ScalarAffineFunction{Float64},MOI.EqualTo{Float64}) => [MOI.BASIC], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => + [MOI.BASIC], ], - ) + ), ) @test_logs (:warn,) (:warn,) MOI.optimize!(mock) return