JuMP SCIP error

I get the error below when I try to solve a model in JuMP using SCIP. There is no error if I instead use HiGHS.

$ julia Oscar.jl
ERROR: LoadError: MathOptInterface.DeleteNotAllowed{MathOptInterface.VariableIndex}: Deleting the index MathOptInterface.VariableIndex(368) cannot be performed: Can not delete variable while model contains constraints! 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] delete(o::SCIP.Optimizer, vi::MathOptInterface.VariableIndex)
    @ SCIP ~/.julia/packages/SCIP/BUSgq/src/MOI_wrapper/variable.jl:45
  [2] delete(b::MathOptInterface.Bridges.LazyBridgeOptimizer{SCIP.Optimizer}, vi::MathOptInterface.VariableIndex)
    @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/57fsF/src/Bridges/bridge_optimizer.jl:601
  [3] delete(model::MathOptInterface.Bridges.LazyBridgeOptimizer{SCIP.Optimizer}, bridge::MathOptInterface.Bridges.Constraint.CountBelongsToMILPBridge{Float64, MathOptInterface.VectorOfVariables})
    @ MathOptInterface.Bridges.Constraint ~/.julia/packages/MathOptInterface/57fsF/src/Bridges/Constraint/bridges/count_belongs.jl:139
  [4] final_touch(bridge::MathOptInterface.Bridges.Constraint.CountBelongsToMILPBridge{Float64, MathOptInterface.VectorOfVariables}, model::MathOptInterface.Bridges.LazyBridgeOptimizer{SCIP.Optimizer})
    @ MathOptInterface.Bridges.Constraint ~/.julia/packages/MathOptInterface/57fsF/src/Bridges/Constraint/bridges/count_belongs.jl:280
  [5] _final_touch(bridges::OrderedCollections.OrderedSet{MathOptInterface.Bridges.Constraint.CountBelongsToMILPBridge{Float64, MathOptInterface.VectorOfVariables}}, model::MathOptInterface.Bridges.LazyBridgeOptimizer{SCIP.Optimizer})
    @ MathOptInterface.Bridges.Constraint ~/.julia/packages/MathOptInterface/57fsF/src/Bridges/Constraint/map.jl:324
  [6] final_touch(map::MathOptInterface.Bridges.Constraint.Map, model::MathOptInterface.Bridges.LazyBridgeOptimizer{SCIP.Optimizer})
    @ MathOptInterface.Bridges.Constraint ~/.julia/packages/MathOptInterface/57fsF/src/Bridges/Constraint/map.jl:331
  [7] final_touch
    @ ~/.julia/packages/MathOptInterface/57fsF/src/Bridges/bridge_optimizer.jl:459 [inlined]
  [8] optimize!
    @ ~/.julia/packages/MathOptInterface/57fsF/src/Bridges/bridge_optimizer.jl:375 [inlined]
  [9] optimize!
    @ ~/.julia/packages/MathOptInterface/57fsF/src/MathOptInterface.jl:83 [inlined]
 [10] optimize!(m::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{SCIP.Optimizer}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}})
    @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/57fsF/src/Utilities/cachingoptimizer.jl:316
 [11] optimize!(model::Model; ignore_optimize_hook::Bool, _differentiation_backend::MathOptInterface.Nonlinear.SparseReverseMode, kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ JuMP ~/.julia/packages/JuMP/vuP7I/src/optimizer_interface.jl:185
 [12] optimize!
    @ ~/.julia/packages/JuMP/vuP7I/src/optimizer_interface.jl:163 [inlined]
 [13] top-level scope
    @ ./timing.jl:220

Do you have a reproducible example? I cannot reproduce:

julia> using JuMP

julia> import SCIP

julia> model = Model(SCIP.Optimizer);

julia> @variable(model, 0 <= x[i = 1:4] <= i, Int)
4-element Vector{VariableRef}:
 x[1]
 x[2]
 x[3]
 x[4]

julia> @variable(model, n, Int)
n

julia> @objective(model, Max, sum(x))
x[1] + x[2] + x[3] + x[4]

julia> @constraint(model, [n; x] in MOI.CountBelongs(1 + length(x), Set([2, 3])))
[n, x[1], x[2], x[3], x[4]] ∈ MathOptInterface.CountBelongs(5, Set([2, 3]))

julia> optimize!(model)
presolving:
(round 1, fast)       6 del vars, 3 del conss, 0 add conss, 2 chg bounds, 0 chg sides, 0 chg coeffs, 0 upgd conss, 3 impls, 8 clqs
(round 2, fast)       7 del vars, 3 del conss, 0 add conss, 2 chg bounds, 4 chg sides, 1 chg coeffs, 0 upgd conss, 3 impls, 8 clqs
   (0.0s) running MILP presolver
   (0.0s) MILP presolver (2 rounds): 1 aggregations, 2 fixings, 0 bound changes
(round 3, medium)     10 del vars, 9 del conss, 4 add conss, 2 chg bounds, 4 chg sides, 1 chg coeffs, 0 upgd conss, 3 impls, 6 clqs
(round 4, exhaustive) 10 del vars, 9 del conss, 4 add conss, 2 chg bounds, 4 chg sides, 1 chg coeffs, 4 upgd conss, 3 impls, 6 clqs
(round 5, fast)       10 del vars, 9 del conss, 4 add conss, 2 chg bounds, 4 chg sides, 3 chg coeffs, 4 upgd conss, 3 impls, 6 clqs
(round 6, medium)     12 del vars, 11 del conss, 6 add conss, 2 chg bounds, 7 chg sides, 9 chg coeffs, 4 upgd conss, 3 impls, 6 clqs
(round 7, fast)       12 del vars, 13 del conss, 6 add conss, 2 chg bounds, 7 chg sides, 9 chg coeffs, 4 upgd conss, 3 impls, 6 clqs
presolving (8 rounds: 8 fast, 4 medium, 2 exhaustive):
 19 deleted vars, 15 deleted constraints, 6 added constraints, 2 tightened bounds, 0 added holes, 7 changed sides, 9 changed coefficients
 3 implications, 0 cliques
transformed 1/1 original solutions to the transformed problem space
Presolving Time: 0.00

SCIP Status        : problem is solved [optimal solution found]
Solving Time (sec) : 0.00
Solving Nodes      : 0
Primal Bound       : +1.00000000000000e+01 (1 solutions)
Dual Bound         : +1.00000000000000e+01
Gap                : 0.00 %

Reproducible example is:

using JuMP
import SCIP
model = Model(SCIP.Optimizer)
@variable(model, 0 <= s <= 1, Bin)
@variable(model, n)
@constraint(model, [n, s] in MOI.CountBelongs(2, Set([1])))
@constraint(model, [n, s] in MOI.CountBelongs(2, Set([1])))
optimize!(model)

I’ll take a look.

This seems like a bug somewhere in MOI: Bridges and final_touch · Issue #2088 · jump-dev/MathOptInterface.jl · GitHub

A work-around for the meantime is to use:

model = Model() do
    return MOI.Utilities.CachingOptimizer(
        MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()),
        SCIP.Optimizer(),    
    )
end

In your example, instead of repeating the same constraint, did you instead mean the following?
@constraint(model, [n, s] in MOI.CountBelongs(2, Set([0])))
@constraint(model, [n, s] in MOI.CountBelongs(2, Set([1])))

Is there a work-around if we set SCIP as the JuMP solver as follows?

using JuMP, SCIP, HiGHS
use_SCIP = true
model = Model()
if(use_SCIP)
opt = SCIP.Optimizer
else
opt = HiGHS.Optimizer
end
set_optimizer(model, opt)

In your example, instead of repeating the same constraint, did you instead mean the following?

No. I meant what I typed, but it’s somewhat arbitrary. It just needs to be another constraint of any type.

Is there a work-around if we set SCIP as the JuMP solver as follows?

opt = () -> MOI.Utilities.CachingOptimizer(
      MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()),
      SCIP.Optimizer(),    
  )
set_optimizer(model, opt)

Was this SCIP error fixed? If so, what packages must be updated to capture the fix.

This is mostly fixed in the latest MathOptInterface v1.12.0.

But you can still trigger it in some situations, for example, if you try to delete a variable.