How to handle an optimizer which doesn't support an attribute of MathOptInterface?

Dear Julia Discourse’s optimization community,

Because getting Node Count: MOI.get(m, MOI.NodeCount()) is not supported by GLPK.jl, at the end of my optimization model, I tried the following:

    nodecount = -1
    try
        nodecount = MOI.get(m, MOI.NodeCount())
    catch e
        println("Getting Node Count is not supported by the solver you use")
        rethrow(e)
    end

Unfortunately, it fails and target ] test

	@test RSP.rspoptimize(pars, 1; solutionchecker = true, optimizer =
		optimizer_with_attributes(GLPK.Optimizer,
			"msg_lev" => GLPK.GLP_MSG_ALL,
			"tm_lm" => pars.timelimit)
	) == 0

returns an error:

RingStarProblems.jl: Error During Test at /home/julien/Documents/Travail/Julia/RingStarProblems.jl/test/runtests.jl:33
  Test threw exception
  Expression: RSP.rspoptimize(pars, 1; solutionchecker = true, optimizer = optimizer_with_attributes(GLPK.Optimizer, "msg_lev" => GLPK.GLP_MSG_ALL, "tm_lim" => pars.timelimit)) == 0
  MathOptInterface.GetAttributeNotAllowed{MathOptInterface.NodeCount}: Getting attribute MathOptInterface.NodeCount() cannot be performed: GLPK.Optimizer does not support getting the attribute MathOptInterface.NodeCount(). You may want to use a `CachingOptimizer` in `AUTOMATIC` mode or you may need to call `reset_optimizer` before doing this operation if the `CachingOptimizer` is in `MANUAL` mode.
  Stacktrace:
    [1] get_fallback(model::GLPK.Optimizer, attr::MathOptInterface.NodeCount)
      @ MathOptInterface ~/.julia/packages/MathOptInterface/aJZbq/src/attributes.jl:409
    [2] get(::GLPK.Optimizer, ::MathOptInterface.NodeCount)
      @ MathOptInterface ~/.julia/packages/MathOptInterface/aJZbq/src/attributes.jl:390
    [3] get(b::MathOptInterface.Bridges.LazyBridgeOptimizer{GLPK.Optimizer}, attr::MathOptInterface.NodeCount)
      @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/aJZbq/src/Bridges/bridge_optimizer.jl:889
    [4] _get_model_attribute(model::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{GLPK.Optimizer}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}, attr::MathOptInterface.NodeCount)
      @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/aJZbq/src/Utilities/cachingoptimizer.jl:865
    [5] get(model::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{GLPK.Optimizer}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}, attr::MathOptInterface.NodeCount)
      @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/aJZbq/src/Utilities/cachingoptimizer.jl:900
    [6] _moi_get_result(model::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{GLPK.Optimizer}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}, args::MathOptInterface.NodeCount)
      @ JuMP ~/.julia/packages/JuMP/7rBNn/src/optimizer_interface.jl:1053
    [7] get(model::Model, attr::MathOptInterface.NodeCount)
      @ JuMP ~/.julia/packages/JuMP/7rBNn/src/optimizer_interface.jl:1073
    [8] benders_st_optimize_lazy!(m::Model, x::JuMP.Containers.SparseAxisArray{VariableRef, 2, Tuple{Int64, Int64}}, y::JuMP.Containers.DenseAxisArray{VariableRef, 2, Tuple{UnitRange{Int64}, UnitRange{Int64}}, Tuple{JuMP.Containers._AxisLookup{Tuple{Int64, Int64}}, JuMP.Containers._AxisLookup{Tuple{Int64, Int64}}}}, f::RingStarProblems.var"#f#256"{Dict{Tuple{Int64, Int64}, Float64}, Vector{Float64}, UnitRange{Int64}, Int64}, F::Float64, B::VariableRef, inst::RingStarProblems.RRSPInstance, pars::RingStarProblems.SolverParameters, start_time::Float64; optimizer::MathOptInterface.OptimizerWithAttributes)
      @ RingStarProblems ~/Documents/Travail/Julia/RingStarProblems.jl/src/benders_rrsp.jl:661
    [9] rrspcreatebenders_modellazy(filename::String, inst::RingStarProblems.RRSPInstance, pars::RingStarProblems.SolverParameters; optimizer::MathOptInterface.OptimizerWithAttributes)
      @ RingStarProblems ~/Documents/Travail/Julia/RingStarProblems.jl/src/benders_rrsp.jl:176
   [10] rrspcreatebenders_modellazy
      @ ~/Documents/Travail/Julia/RingStarProblems.jl/src/benders_rrsp.jl:48 [inlined]
   [11] main(pars::RingStarProblems.SolverParameters, filename::Vector{String}; solutionchecker::Bool, optimizer::MathOptInterface.OptimizerWithAttributes)
      @ RingStarProblems ~/Documents/Travail/Julia/RingStarProblems.jl/src/main.jl:181
   [12] main
      @ ~/Documents/Travail/Julia/RingStarProblems.jl/src/main.jl:91 [inlined]
   [13] rspoptimize(pars::RingStarProblems.SolverParameters, id_instance::Int64; solutionchecker::Bool, optimizer::MathOptInterface.OptimizerWithAttributes)
      @ RingStarProblems ~/Documents/Travail/Julia/RingStarProblems.jl/src/main.jl:83
   [14] macro expansion
      @ ~/.julia/juliaup/julia-1.10.4+0.x64.linux.gnu/share/julia/stdlib/v1.10/Test/src/Test.jl:669 [inlined]
   [15] macro expansion
      @ ~/Documents/Travail/Julia/RingStarProblems.jl/test/runtests.jl:33 [inlined]
   [16] macro expansion
      @ ~/.julia/juliaup/julia-1.10.4+0.x64.linux.gnu/share/julia/stdlib/v1.10/Test/src/Test.jl:1577 [inlined]
   [17] top-level scope
      @ ~/Documents/Travail/Julia/RingStarProblems.jl/test/runtests.jl:8

Because the error suggests I should use a CachingOptimizer:

GLPK.Optimizer does not support getting the attribute MathOptInterface.NodeCount(). You may want to use a `CachingOptimizer` in `AUTOMATIC` mode or you may need to call `reset_optimizer` before doing this operation if the `CachingOptimizer` is in `MANUAL` mode.`

I tried:

@test RSP.rspoptimize(pars, 1; solutionchecker = true, optimizer =
		() -> MOI.Utilities.CachingOptimizer(
            MOI.Utilities.Model{Float64}(),MOI.OptimizerWithAttributes(GLPK.Optimizer,
			"msg_lev" => GLPK.GLP_MSG_ALL,
			"tm_lim" => pars.timelimit))
	) == 0```

But now the error is:

    RingStarProblems.jl: Error During Test at /home/julien/Documents/Travail/Julia/RingStarProblems.jl/test/runtests.jl:34
      Test threw exception
      Expression: RSP.rspoptimize(pars, 1; solutionchecker = true, optimizer = (()->begin
                        #= /home/julien/Documents/Travail/Julia/RingStarProblems.jl/test/runtests.jl:35 =#
                        MOI.Utilities.CachingOptimizer(MOI.Utilities.Model{Float64}(), MOI.OptimizerWithAttributes(GLPK.Optimizer, "msg_lev" => GLPK.GLP_MSG_ALL, "tm_lim" => pars.timelimit))
                    end)) == 0
      MethodError: no method matching MathOptInterface.Utilities.CachingOptimizer(::MathOptInterface.Utilities.Model{Float64}, ::MathOptInterface.OptimizerWithAttributes)
      
      Closest candidates are:
        MathOptInterface.Utilities.CachingOptimizer(::MathOptInterface.ModelLike, ::MathOptInterface.Utilities.CachingOptimizerMode)
         @ MathOptInterface ~/.julia/packages/MathOptInterface/aJZbq/src/Utilities/cachingoptimizer.jl:88
        MathOptInterface.Utilities.CachingOptimizer(::MathOptInterface.ModelLike, ::MathOptInterface.ModelLike)

And now, I have no idea how to persue :sweat_smile:
Does someone know?

Ok, seems like the problem came from rethrow(e) which I just removed to make everything work :smiley:

1 Like

Ok, seems like the problem came from rethrow(e)

Yes, see

help?> rethrow
search: rethrow

  rethrow()

  Rethrow the current exception from within a catch block. The rethrown exception will continue
  propagation as if it had not been caught.

  │ Note
  │
  │  The alternative form rethrow(e) allows you to associate an alternative exception object
  │  e with the current backtrace. However this misrepresents the program state at the time
  │  of the error so you're encouraged to instead throw a new exception using throw(e). In
  │  Julia 1.1 and above, using throw(e) will preserve the root cause exception on the
  │  stack, as described in current_exceptions.
1 Like