Skip to content

Conversation

odow
Copy link
Member

@odow odow commented Oct 29, 2021

While thinking about jump-dev/JuMP.jl#2770. The current behavior is:

julia> using JuMP, Gurobi

julia> model = Model(Gurobi.Optimizer)
Academic license - for non-commercial use only - expires 2021-11-06
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: EMPTY_OPTIMIZER
Solver name: Gurobi

julia> MOI.get(model, Gurobi.ModelAttribute("IsMIP"))
ERROR: KeyError: key Gurobi.ModelAttribute("IsMIP") not found
Stacktrace:
 [1] getindex
   @ ./dict.jl:482 [inlined]
 [2] _get
   @ ~/.julia/packages/MathOptInterface/D0LUL/src/Utilities/universalfallback.jl:264 [inlined]
 [3] get
   @ ~/.julia/packages/MathOptInterface/D0LUL/src/Utilities/universalfallback.jl:309 [inlined]
 [4] get(model::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{Gurobi.Optimizer}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}, attr::Gurobi.ModelAttribute)
   @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/D0LUL/src/Utilities/cachingoptimizer.jl:808
 [5] get(model::Model, attr::Gurobi.ModelAttribute)
   @ JuMP ~/.julia/dev/JuMP/src/JuMP.jl:1217
 [6] top-level scope
   @ REPL[3]:1

This. is clearly unhelpful.

We return nothing variables and constraints, so it seems sensible to do the same with other attributes:

function _get(uf::UniversalFallback, attr::MOI.AbstractOptimizerAttribute)
return uf.optattr[attr]
end
_get(uf::UniversalFallback, attr::MOI.AbstractModelAttribute) = uf.modattr[attr]
function _get(
uf::UniversalFallback,
attr::MOI.AbstractVariableAttribute,
vi::MOI.VariableIndex,
)
attribute_dict = get(uf.varattr, attr, nothing)
if attribute_dict === nothing
# It means the attribute is not set to any variable so in particular, it
# is not set for `vi`
return
end
return get(attribute_dict, vi, nothing)
end
function _get(
uf::UniversalFallback,
attr::MOI.AbstractConstraintAttribute,
ci::MOI.ConstraintIndex,
)
attribute_dict = get(uf.conattr, attr, nothing)
if attribute_dict === nothing
# It means the attribute is not set to any constraint so in particular,
# it is not set for `ci`
return
end
return get(attribute_dict, ci, nothing)
end

But that'd mean that MOI.get(model, Gurobi.ModelAttribute("IsMIP")) returned nothing, which is also unhelpful. We should instead return a meaningful error message.

Thoughts?

@blegat
Copy link
Member

blegat commented Oct 31, 2021

But that'd mean that MOI.get(model, Gurobi.ModelAttribute("IsMIP")) returned nothing, which is also unhelpful. We should instead return a meaningful error message.

Gurobi should probably implement is_set_by_optimize and return true. It's not really set by the optimization but is_set_by_optimize is only ever used by the CachingOptimizer to decide whether to dispatch to the cache or the optimizer and by JuMP to know whether it should check the termination status. Is the use case of being able to attach but not optimize and get the attribute important?

If it is, we should probably do what you suggest in jump-dev/JuMP.jl#2587 (comment)

@odow
Copy link
Member Author

odow commented Oct 31, 2021

So for the Gurobi case, making the attributes is_set_by_optimize is probably okay.

Regardless, there's still a bug here: getting KeyError is unhelpful for users.

@odow
Copy link
Member Author

odow commented Oct 31, 2021

For example, we used to have to try-catch our NLPBlock checks, but now if the block is missing it returns nothing. That seems better.

@blegat
Copy link
Member

blegat commented Nov 1, 2021

Yes, the new behavior with this PR seems better.

@odow odow merged commit 93895e1 into master Nov 1, 2021
@odow odow deleted the od/uf branch November 1, 2021 19:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants