I'm trying to use Cplex with the automatic benders decomposition. There are multiple ways to do that. I want to force the decomposition to be according to my annotations - Cplex calls this Benders strategy 1.
However, I can't get it done in pyomo. I don't know how to annotate the variables so that Cplex recognises the annotation.
In Cplex using docplex I simply do
from docplex.mp.model import Model
model = Model()
...
Variable1 = model.binary_var_dict(E, name="ind_purchase")
for var in Variable1 .values():
var.benders_annotation = 0 # Master problem (1-N for subproblem 1-N)
...
and then I set the benders strategy and solve
model.parameters.benders.strategy = 1
model.solve(log_output=True)
In pyomo I tried different things. Using the fully automatic benders decomposition (strategy=3) actually works using
from pyomo.environ import *
from pyomo.core import *
# create model...
opt = SolverFactory('cplex_direct')
opt.options['benders_strategy'] = 3
solution = opt.solve(model, tee=True)
Yet, using strategy=1 I need to set annotations - and these annotations do not work. I tried it (among others) like this
model.benders_annotation = Suffix(direction=Suffix.EXPORT)
# annotate variables
model.benders_annotation[Variable1] = 0
but it is simply not recognized:
CPLEX Error 2000: No Benders decomposition available.
If it were recognized but faulty, cplex would throw the error:
CPLEX Error 2002: Invalid Benders decomposition.
Any help greatly appreciated!
In pyomo you can write the model into an mps file
model.write("/tmp/model.mps")
and then within docplex python API you can do
m = read_model(“c:/tmp/model.mps”, model_name=”model”, ignore_names=False)
and that way you can use docplex API for the Benders annotation
Full example with my zoo example
import pyomo.environ as pyo
from pyomo.opt import SolverFactory
opt = pyo.SolverFactory("cplex")
opt.options['mip limits solutions'] = 1
model = pyo.ConcreteModel()
model.nbBus = pyo.Var([40,30], domain=pyo.PositiveIntegers)
model.OBJ = pyo.Objective(expr = 500*model.nbBus[40] + 400*model.nbBus[30])
model.Constraint1 = pyo.Constraint(expr = 40*model.nbBus[40] + 30*model.nbBus[30] >= 300)
#opt.solve(model)
model.write("c:/temp/model.mps",io_options = {"symbolic_solver_labels":True})
from docplex.mp.model import Model
from docplex.mp.model_reader import ModelReader
mdl = Model(name='buses')
mdl = ModelReader.read('c:/temp/model.mps', ignore_names=False)
mdl.solve(log_output=True,)
for v in mdl.iter_integer_vars():
print(v," = ",v.solution_value)
https://github.com/AlexFleischerParis/zoodocplex/blob/master/zoopyomogenerateanddocplexsolve.py
which gives
nbBus(30) = 2.0
nbBus(40) = 6.0