@@ -31,20 +31,20 @@ mutable struct MockOptimizer{MT<:MOI.ModelLike} <: MOI.AbstractOptimizer
3131 # Computes `ObjectiveValue` by evaluating the `ObjectiveFunction` with
3232 # `VariablePrimal`. See `get_fallback`.
3333 eval_objective_value:: Bool
34- objective_value:: Float64 # set this using MOI.set(model, MOI.ObjectiveValue(), value)
34+ objective_value:: Dict{Int, Float64} # set this using MOI.set(model, MOI.ObjectiveValue(), value)
3535 # Computes `DualObjectiveValue` using `get_fallback`
3636 eval_dual_objective_value:: Bool
37- dual_objective_value:: Float64 # set this using MOI.set(model, MOI.DualObjectiveValue(), value)
38- primalstatus :: MOI.ResultStatusCode
39- dualstatus :: MOI.ResultStatusCode
40- varprimal:: Dict{MOI.VariableIndex,Float64}
37+ dual_objective_value:: Dict{Int, Float64} # set this using MOI.set(model, MOI.DualObjectiveValue(), value)
38+ primal_status :: Dict{Int, MOI.ResultStatusCode}
39+ dual_status :: Dict{Int, MOI.ResultStatusCode}
40+ varprimal:: Dict{MOI.VariableIndex,Dict{Int, Float64} }
4141 callback_variable_primal:: Dict{MOI.VariableIndex, Float64}
4242 # Computes `ConstraintDual` of constraints with `SingleVariable` or
4343 # `VectorOfVariables` functions by evaluating the `ConstraintDual` of
4444 # constraints having the variable in the function. See `get_fallback`.
4545 eval_variable_constraint_dual:: Bool
46- condual:: Dict{MOI.ConstraintIndex,Any}
47- con_basis:: Dict{MOI.ConstraintIndex,MOI.BasisStatusCode}
46+ condual:: Dict{MOI.ConstraintIndex,Dict{Int, Any} }
47+ con_basis:: Dict{MOI.ConstraintIndex,Dict{Int, MOI.BasisStatusCode} }
4848 # The attributes set by `MOI.optimize!` cannot be set to `model`.
4949 # We detect them with `is_set_by_optimize` and store them in the following:
5050 optimizer_attributes:: Dict{MOI.AbstractOptimizerAttribute, Any}
@@ -83,16 +83,16 @@ function MockOptimizer(inner_model::MOI.ModelLike; supports_names=true,
8383 1 ,
8484 MOI. OPTIMIZE_NOT_CALLED,
8585 eval_objective_value,
86- NaN ,
86+ Dict {Int,Float64} () ,
8787 eval_dual_objective_value,
88- NaN ,
89- MOI. NO_SOLUTION ,
90- MOI. NO_SOLUTION ,
91- Dict {MOI.VariableIndex,Float64} (),
88+ Dict {Int,Float64} () ,
89+ Dict {Int, MOI.ResultStatusCode} () ,
90+ Dict {Int, MOI.ResultStatusCode} () ,
91+ Dict {MOI.VariableIndex,Dict{Int, Float64} } (),
9292 Dict {MOI.VariableIndex,Float64} (),
9393 eval_variable_constraint_dual,
94- Dict {MOI.ConstraintIndex,Any} (),
95- Dict {MOI.ConstraintIndex,MOI.BasisStatusCode} (),
94+ Dict {MOI.ConstraintIndex,Dict{Int, Any} } (),
95+ Dict {MOI.ConstraintIndex,Dict{Int, MOI.BasisStatusCode} } (),
9696 Dict {MOI.AbstractOptimizerAttribute, Any} (),
9797 Dict {MOI.AbstractModelAttribute, Any} (),
9898 Dict {MOI.AbstractSubmittable, Vector{Tuple}} ())
@@ -153,10 +153,18 @@ end
153153
154154MOI. supports (mock:: MockOptimizer , :: MockModelAttribute ) = true
155155MOI. set (mock:: MockOptimizer , :: MOI.TerminationStatus , value:: MOI.TerminationStatusCode ) = (mock. terminationstatus = value)
156- MOI. set (mock:: MockOptimizer , :: MOI.ObjectiveValue , value:: Real ) = (mock. objective_value = value)
157- MOI. set (mock:: MockOptimizer , :: MOI.DualObjectiveValue , value:: Real ) = (mock. dual_objective_value = value)
158- MOI. set (mock:: MockOptimizer , :: MOI.PrimalStatus , value:: MOI.ResultStatusCode ) = (mock. primalstatus = value)
159- MOI. set (mock:: MockOptimizer , :: MOI.DualStatus , value:: MOI.ResultStatusCode ) = (mock. dualstatus = value)
156+ function MOI. set (mock:: MockOptimizer , attr:: MOI.ObjectiveValue , value:: Real )
157+ mock. objective_value[attr. result_index] = value
158+ end
159+ function MOI. set (mock:: MockOptimizer , attr:: MOI.DualObjectiveValue , value:: Real )
160+ mock. dual_objective_value[attr. result_index] = value
161+ end
162+ function MOI. set (mock:: MockOptimizer , attr:: MOI.PrimalStatus , value:: MOI.ResultStatusCode )
163+ mock. primal_status[attr. N] = value
164+ end
165+ function MOI. set (mock:: MockOptimizer , attr:: MOI.DualStatus , value:: MOI.ResultStatusCode )
166+ mock. dual_status[attr. N] = value
167+ end
160168MOI. set (mock:: MockOptimizer , :: MockModelAttribute , value:: Integer ) = (mock. attribute = value)
161169function MOI. supports (mock:: MockOptimizer , attr:: MOI.AbstractOptimizerAttribute )
162170 # `supports` is not defined if `is_set_by_optimize(attr)` so we pass it to
@@ -188,9 +196,9 @@ function MOI.set(mock::MockOptimizer, attr::MOI.AbstractVariableAttribute,
188196 idx:: MOI.VariableIndex , value)
189197 MOI. set (mock. inner_model, attr, xor_index (idx), xor_indices (value))
190198end
191- function MOI. set (mock:: MockOptimizer , :: MOI.VariablePrimal ,
199+ function MOI. set (mock:: MockOptimizer , attr :: MOI.VariablePrimal ,
192200 idx:: MOI.VariableIndex , value)
193- mock. varprimal[ xor_index (idx)] = value
201+ _safe_set_result ( mock. varprimal, attr, idx, value)
194202end
195203function MOI. set (mock:: MockOptimizer , :: MOI.CallbackVariablePrimal ,
196204 idx:: MOI.VariableIndex , value)
@@ -208,13 +216,13 @@ function MOI.set(mock::MockOptimizer, ::MockConstraintAttribute,
208216 idx:: MOI.ConstraintIndex , value)
209217 mock. conattribute[xor_index (idx)] = value
210218end
211- function MOI. set (mock:: MockOptimizer , :: MOI.ConstraintDual ,
219+ function MOI. set (mock:: MockOptimizer , attr :: MOI.ConstraintDual ,
212220 idx:: MOI.ConstraintIndex , value)
213- mock. condual[ xor_index (idx)] = value
221+ _safe_set_result ( mock. condual, attr, idx, value)
214222end
215- function MOI. set (mock:: MockOptimizer , :: MOI.ConstraintBasisStatus ,
223+ function MOI. set (mock:: MockOptimizer , attr :: MOI.ConstraintBasisStatus ,
216224 idx:: MOI.ConstraintIndex , value)
217- mock. con_basis[ xor_index (idx)] = value
225+ _safe_set_result ( mock. con_basis, attr, idx, value)
218226end
219227
220228MOI. get (mock:: MockOptimizer , :: MOI.RawSolver ) = mock
@@ -295,29 +303,29 @@ function MOI.get(mock::MockOptimizer, attr::MOI.ObjectiveValue)
295303 if mock. eval_objective_value
296304 return get_fallback (mock, attr)
297305 else
298- return mock. objective_value
306+ return get ( mock. objective_value, attr . result_index, NaN )
299307 end
300308end
301309function MOI. get (mock:: MockOptimizer , attr:: MOI.DualObjectiveValue )
302310 MOI. check_result_index_bounds (mock, attr)
303311 if mock. eval_dual_objective_value
304312 return get_fallback (mock, attr, Float64)
305313 else
306- return mock. dual_objective_value
314+ return get ( mock. dual_objective_value, attr . result_index, NaN )
307315 end
308316end
309317function MOI. get (mock:: MockOptimizer , attr:: MOI.PrimalStatus )
310318 if attr. N > mock. result_count
311319 return MOI. NO_SOLUTION
312320 else
313- return mock. primalstatus
321+ return get ( mock. primal_status, attr . N, MOI . NO_SOLUTION)
314322 end
315323end
316324function MOI. get (mock:: MockOptimizer , attr:: MOI.DualStatus )
317325 if attr. N > mock. result_count
318326 return MOI. NO_SOLUTION
319327 else
320- return mock. dualstatus
328+ return get ( mock. dual_status, attr . N, MOI . NO_SOLUTION)
321329 end
322330end
323331MOI. get (mock:: MockOptimizer , :: MockModelAttribute ) = mock. attribute
@@ -332,14 +340,8 @@ function MOI.get(
332340 mock:: MockOptimizer , attr:: MOI.VariablePrimal , idx:: MOI.VariableIndex
333341)
334342 MOI. check_result_index_bounds (mock, attr)
335- primal = get (mock. varprimal, xor_index (idx), nothing )
336- if primal != = nothing
337- return primal
338- elseif MOI. is_valid (mock, idx)
339- error (" No mock primal is set for variable `" , idx, " `." )
340- else
341- throw (MOI. InvalidIndex (idx))
342- end
343+ MOI. throw_if_not_valid (mock, idx)
344+ return _safe_get_result (mock. varprimal, attr, idx, " primal" )
343345end
344346
345347function MOI. get (
@@ -379,23 +381,42 @@ function MOI.get(
379381 mock:: MockOptimizer , attr:: MOI.ConstraintDual , idx:: MOI.ConstraintIndex{F}
380382) where {F}
381383 MOI. check_result_index_bounds (mock, attr)
384+ MOI. throw_if_not_valid (mock, idx)
382385 if mock. eval_variable_constraint_dual &&
383386 (F == MOI. SingleVariable || F == MOI. VectorOfVariables)
384387 return get_fallback (mock, attr, idx)
385388 else
386- dual = get (mock. condual, xor_index (idx), nothing )
387- if dual === nothing
388- if MOI. is_valid (mock, idx)
389- error (" No mock dual is set for constraint `" , idx, " `." )
390- else
391- throw (MOI. InvalidIndex (idx))
392- end
393- end
394- return dual
389+ return _safe_get_result (mock. condual, attr, idx, " dual" )
395390 end
396391end
397392MOI. get (mock:: MockOptimizer , :: MockConstraintAttribute , idx:: MOI.ConstraintIndex ) = mock. conattribute[xor_index (idx)]
398- MOI. get (mock:: MockOptimizer , :: MOI.ConstraintBasisStatus , idx:: MOI.ConstraintIndex ) = mock. con_basis[xor_index (idx)]
393+ function MOI. get (mock:: MockOptimizer , attr:: MOI.ConstraintBasisStatus , idx:: MOI.ConstraintIndex )
394+ MOI. check_result_index_bounds (mock, attr)
395+ MOI. throw_if_not_valid (mock, idx)
396+ return _safe_get_result (mock. con_basis, attr, idx, " basis status" )
397+ end
398+
399+ function _safe_set_result (dict:: Dict{K,V} , attr:: MOI.AnyAttribute , index:: K ,
400+ value) where {K, V}
401+ xored = xor_index (index)
402+ if ! haskey (dict, xored)
403+ dict[xored] = V ()
404+ end
405+ dict[xored][MOI. _result_index_field (attr)] = value
406+ end
407+ function _safe_get_result (dict:: Dict , attr:: MOI.AnyAttribute , index:: MOI.Index ,
408+ name:: String )
409+ index_name = index isa MOI. VariableIndex ? " variable" : " constraint"
410+ result_to_value = get (dict, xor_index (index), nothing )
411+ if result_to_value === nothing
412+ error (" No mock $name is set for " , index_name, " `" , index, " `." )
413+ end
414+ value = get (result_to_value, MOI. _result_index_field (attr), nothing )
415+ if value === nothing
416+ error (" No mock $name is set for " , index_name, " `" , index, " ` at result index `" , MOI. _result_index_field (attr), " `." )
417+ end
418+ return value
419+ end
399420
400421MOI. get (:: MockOptimizer , :: MOI.SolverName ) = " Mock"
401422
@@ -408,10 +429,10 @@ function MOI.empty!(mock::MockOptimizer)
408429 mock. hasprimal = false
409430 mock. hasdual = false
410431 mock. terminationstatus = MOI. OPTIMIZE_NOT_CALLED
411- mock. objective_value = NaN
412- mock. dual_objective_value = NaN
413- mock. primalstatus = MOI . NO_SOLUTION
414- mock. dualstatus = MOI . NO_SOLUTION
432+ empty! ( mock. objective_value)
433+ empty! ( mock. dual_objective_value)
434+ empty! ( mock. primal_status)
435+ empty! ( mock. dual_status)
415436 empty! (mock. varprimal)
416437 empty! (mock. callback_variable_primal)
417438 empty! (mock. condual)
@@ -429,10 +450,10 @@ function MOI.is_empty(mock::MockOptimizer)
429450 return MOI. is_empty (mock. inner_model) && mock. attribute == 0 &&
430451 ! mock. solved && ! mock. hasprimal && ! mock. hasdual &&
431452 mock. terminationstatus == MOI. OPTIMIZE_NOT_CALLED &&
432- isnan (mock. objective_value) &&
433- isnan (mock. dual_objective_value) &&
434- mock. primalstatus == MOI . NO_SOLUTION &&
435- mock. dualstatus == MOI . NO_SOLUTION &&
453+ isempty (mock. objective_value) &&
454+ isempty (mock. dual_objective_value) &&
455+ isempty ( mock. primal_status) &&
456+ isempty ( mock. dual_status) &&
436457 isempty (mock. con_basis) && isempty (mock. optimizer_attributes) &&
437458 isempty (mock. model_attributes) && isempty (mock. submitted)
438459end
@@ -552,13 +573,13 @@ end
552573rec_mock_optimize (mock:: MockOptimizer , opt:: Function ) = opt
553574
554575"""
555- mock_optimize!(mock::MockOptimizer, termstatus::MOI.TerminationStatusCode, (primstatus::MOI.ResultStatusCode, varprim::Vector), dualstatus ::MOI.ResultStatusCode, conduals::Pair...)
576+ mock_optimize!(mock::MockOptimizer, termstatus::MOI.TerminationStatusCode, (primstatus::MOI.ResultStatusCode, varprim::Vector), dual_status ::MOI.ResultStatusCode, conduals::Pair...)
556577
557- Sets the termination status of `mock` to `termstatus` and the primal (resp. dual) status to `primstatus` (resp. `dualstatus `).
578+ Sets the termination status of `mock` to `termstatus` and the primal (resp. dual) status to `primstatus` (resp. `dual_status `).
558579The primal values of the variables in the order returned by `ListOfVariableIndices` are set to `varprim`.
559580If `termstatus` is missing, it is assumed to be `MOI.OPTIMAL`.
560581If `primstatus` is missing, it is assumed to be `MOI.FEASIBLE_POINT`.
561- If `dualstatus ` 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`.
582+ 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`.
562583The 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}`.
563584The bases status are set to the status specified by `con_basis`. 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}`.
564585"""
@@ -598,8 +619,8 @@ function mock_varprimal!(mock::MockOptimizer, varprim::Vector)
598619end
599620
600621# Dual
601- function mock_dual! (mock:: MockOptimizer , dualstatus :: MOI.ResultStatusCode , conduals:: Pair... )
602- MOI. set (mock, MOI. DualStatus (), dualstatus )
622+ function mock_dual! (mock:: MockOptimizer , dual_status :: MOI.ResultStatusCode , conduals:: Pair... )
623+ MOI. set (mock, MOI. DualStatus (), dual_status )
603624 mock_condual! (mock, conduals... )
604625end
605626# Default dual status
0 commit comments