
1.关于benders decompostion的解释,请参考bender1,这里只简诉
原问题

限制性主问题(主)

子问题(子)

对偶子问题(sub-dual)

算法流程图

2. python代码
算列解释-参考bender decompostion1
class bender:
def __init__(self):
self.y_num=5
self.x_num=5
self.fix_cost=[7 for i in range(self.y_num)]
self.cost=[1,1,1,1,1]
self.M = [[1,0,0,1,1],[0,1,0,0,1],[0,0,1,1,0]]
self.b=[8,3,5]
self.one_Matrix=list(np.identity(5))
self.y_rhs=[8,3,5,5,3]
#########关于master problem的参数#######
self.q_LB=np.inf
self.iter=0
self.dual_Matrix=[[1,0,0,1,0,0,0,0],[0,1,0,0,1,0,0,0],[0,0,1,0,0,1,0,0],[1,0,1,0,0,0,1,0],[1,1,0,0,0,0,0,1]]
整体流程:
##########################initialization############
mp=master_pro()
mp.optimize()
mp.display()
print('_++++++++++++++++++++++++_')
y_bar,q_bar=update_y_q(mp)
print('_++++++++++++++++++++++++_')
u,q_star,status=sub_dual(y_bar)
mp._sp_status = status
mp._q_star = q_star
mp._q_bar = q_bar
mp=bender_cut(mp,u)
mp.optimize()
mp.display()
y_bar,q_bar=update_y_q(mp)
# # #############start to loop################
while mp._iter<10:
u,q_star,status=sub_dual(y_bar)
print('***********sub_prob_q ',q_star)
print('subdual_{}_\n_{}'.format(u,q_star))
mp._sp_status = status
mp._q_star = q_star
mp._q_bar = q_bar # q_LB
if mp._q_star != mp._q_bar:
new_mp = bender_cut(mp,u)
new_mp.optimize()
new_mp.display()
y_bar,q_bar = update_y_q(new_mp)
mp=new_mp
else:
break
主问题
###############master model,但未添加cut
def master_pro():
data = bender()
# construct master problem
mp = gp.Model('Master')
mp._iter=0
y = {}
for i in range(data.y_num):
y[i] = mp.addVar(lb=0,ub=1,vtype=GRB.BINARY, name="y" + str(i+1))
q = mp.addVar(lb=0,ub=GRB.INFINITY,vtype=GRB.CONTINUOUS, name='q') # q based on different value
# set objective function
obj = LinExpr(0)
for i in range(data.y_num):
obj.addTerms(data.fix_cost[i], y[i])
obj+=q
mp.setObjective(obj, GRB.MINIMIZE)
#constraint
# mp.addConstr(q>=0)
mp.setParam('LazyConstraints', 1)
mp._q=q
mp._y=y
mp.setParam('OutputFlag', 0)
return mp
更新y_bar和q_bar
#get y_bar
def update_y_q(model):
y_bar = []
q_bar=None
for v in model.getVars():
if 'y' in v.varName:
y_bar.append(v.x)
else:
q_bar = v.x
print('q_bar', q_bar)
print('y_bar', y_bar)
# print('jjjjjjjjjjjjjjjjj',y_bar)
return y_bar,q_bar
创建sub-dual问题,并找到对偶值u
extreme ray:当sub-dual unbounded时,用unbdRay,参数看代码块
extreme point:当sub-dual optimal时, 直接拿变量值
def sub_dual(y_bar):
data=bender()
sp=Model('Sub')
a={}
for i in range(3):
a[i]=sp.addVar(vtype=GRB.CONTINUOUS,name='a'+str(i+1))
beta={}
for j in range(5):
beta[j]=sp.addVar(lb= -1*GRB.INFINITY,ub=0,vtype=GRB.CONTINUOUS,name='beta'+str(j+1))
#constraint:
for i in range(5):
sum=0
for j in range(3):
sum+=data.dual_Matrix[i][j]*a[j]
for k in range(5):
sum+=data.dual_Matrix[i][3+k]*beta[k]
sp.addConstr(sum<=1)
sum=0
#objective
OBJ=LinExpr(0)
for i in range(3):
OBJ.addTerms(data.b[i],a[i])
for j in range(5):
sum_obj=data.y_rhs[j]*y_bar[j]
OBJ.addTerms(sum_obj,beta[j])
sp.setObjective(OBJ,GRB.MAXIMIZE)
sp.setParam('InfUnbdInfo' , 1)
sp.setParam('OutputFlag', 0)
sp.optimize()
q_star=sp.objval
sp.display()
if sp.status==GRB.UNBOUNDED:
u={}
count=0
for v in sp.getVars():
u[count]=v.unbdRay
count+=1
print(u)
elif sp.status==GRB.OPTIMAL:
u={}
count=0
for v in sp.getVars():
u[count]=v.x
count += 1
print(u)
return u,q_star,sp.status
添加cut
#callback
def bender_cut(model,u):
print('______________')
# if model._iter==0:
# print('iteration:', model._iter)
# model.addConstr(model._q>=0)
# model._iter+=1
# return model
if model._iter >=0:
data=bender()
if model._sp_status==GRB.OPTIMAL:
if abs(model._q_star-model._q_bar ) > 1e-6:
print('~~~~~~~~~~~optimal~~~~~~~~~~~~~~~~~~')
print('iteration:', model._iter)
print('model._q_star',model._q_star)
print('model._q_bar',model._q_bar)
#add feasibility cut:
lazy=LinExpr(0)
sum=0
for j in range(len(u)):
if j<3:
sum+=u[j]*data.b[j]
else:
coef=u[j]*data.y_rhs[j-3]
lazy.addTerms(coef,model._y[j-3])
model.addConstr(lazy+sum<=model._q)###not sure q how to iter
model._iter += 1
else:
model.terminate()
elif model._sp_status == GRB.UNBOUNDED:
print('~~~~~~~~~~~infeasible~~~~~~~~~~~~~~~~~~')
print('iteration:', model._iter)
lazy = LinExpr(0)
sum = 0
for j in range(len(u)):
if j < 3:
sum +=np.dot(u[j],data.b[j])
else:
coef = u[j] * data.y_rhs[j - 3]
lazy.addTerms(coef, model._y[j - 3])
model.addConstr(lazy + sum <= 0) ###not sure q how to iter
model._iter += 1
else:
model.terminate()
return model
整体代码
import numpy as np
from gurobipy import *
import gurobipy as gp
class bender:
def __init__(self):
self.y_num=5
self.x_num=5
self.fix_cost=[7 for i in range(self.y_num)]
self.cost=[1,1,1,1,1]
self.M = [[1,0,0,1,1],[0,1,0,0,1],[0,0,1,1,0]]
self.b=[8,3,5]
self.one_Matrix=list(np.identity(5))
self.y_rhs=[8,3,5,5,3]
#########关于master problem的参数#######
self.q_LB=np.inf
self.iter=0
self.dual_Matrix=[[1,0,0,1,0,0,0,0],[0,1,0,0,1,0,0,0],[0,0,1,0,0,1,0,0],[1,0,1,0,0,0,1,0],[1,1,0,0,0,0,0,1]]
###############master model,但未添加cut
def master_pro():
data = bender()
# construct master problem
mp = gp.Model('Master')
mp._iter=0
y = {}
for i in range(data.y_num):
y[i] = mp.addVar(lb=0,ub=1,vtype=GRB.BINARY, name="y" + str(i+1))
q = mp.addVar(lb=0,ub=GRB.INFINITY,vtype=GRB.CONTINUOUS, name='q') # q based on different value
# set objective function
obj = LinExpr(0)
for i in range(data.y_num):
obj.addTerms(data.fix_cost[i], y[i])
obj+=q
mp.setObjective(obj, GRB.MINIMIZE)
#constraint
# mp.addConstr(q>=0)
mp.setParam('LazyConstraints', 1)
mp._q=q
mp._y=y
mp.setParam('OutputFlag', 0)
return mp
#callback
def bender_cut(model,u):
print('______________')
# if model._iter==0:
# print('iteration:', model._iter)
# model.addConstr(model._q>=0)
# model._iter+=1
# return model
if model._iter >=0:
data=bender()
if model._sp_status==GRB.OPTIMAL:
if abs(model._q_star-model._q_bar ) > 1e-6:
print('~~~~~~~~~~~optimal~~~~~~~~~~~~~~~~~~')
print('iteration:', model._iter)
print('model._q_star',model._q_star)
print('model._q_bar',model._q_bar)
#add feasibility cut:
lazy=LinExpr(0)
sum=0
for j in range(len(u)):
if j<3:
sum+=u[j]*data.b[j]
else:
coef=u[j]*data.y_rhs[j-3]
lazy.addTerms(coef,model._y[j-3])
model.addConstr(lazy+sum<=model._q)###not sure q how to iter
model._iter += 1
else:
model.terminate()
elif model._sp_status == GRB.UNBOUNDED:
print('~~~~~~~~~~~infeasible~~~~~~~~~~~~~~~~~~')
print('iteration:', model._iter)
lazy = LinExpr(0)
sum = 0
for j in range(len(u)):
if j < 3:
sum +=np.dot(u[j],data.b[j])
else:
coef = u[j] * data.y_rhs[j - 3]
lazy.addTerms(coef, model._y[j - 3])
model.addConstr(lazy + sum <= 0) ###not sure q how to iter
model._iter += 1
else:
model.terminate()
return model
#get y_bar
def update_y_q(model):
y_bar = []
q_bar=None
for v in model.getVars():
if 'y' in v.varName:
y_bar.append(v.x)
else:
q_bar = v.x
print('q_bar', q_bar)
print('y_bar', y_bar)
# print('jjjjjjjjjjjjjjjjj',y_bar)
return y_bar,q_bar
def sub_dual(y_bar):
data=bender()
sp=Model('Sub')
a={}
for i in range(3):
a[i]=sp.addVar(vtype=GRB.CONTINUOUS,name='a'+str(i+1))
beta={}
for j in range(5):
beta[j]=sp.addVar(lb= -1*GRB.INFINITY,ub=0,vtype=GRB.CONTINUOUS,name='beta'+str(j+1))
#constraint:
for i in range(5):
sum=0
for j in range(3):
sum+=data.dual_Matrix[i][j]*a[j]
for k in range(5):
sum+=data.dual_Matrix[i][3+k]*beta[k]
sp.addConstr(sum<=1)
sum=0
#objective
OBJ=LinExpr(0)
for i in range(3):
OBJ.addTerms(data.b[i],a[i])
for j in range(5):
sum_obj=data.y_rhs[j]*y_bar[j]
OBJ.addTerms(sum_obj,beta[j])
sp.setObjective(OBJ,GRB.MAXIMIZE)
sp.setParam('InfUnbdInfo' , 1)
sp.setParam('OutputFlag', 0)
sp.optimize()
q_star=sp.objval
sp.display()
if sp.status==GRB.UNBOUNDED:
u={}
count=0
for v in sp.getVars():
u[count]=v.unbdRay
count+=1
print(u)
elif sp.status==GRB.OPTIMAL:
u={}
count=0
for v in sp.getVars():
u[count]=v.x
count += 1
print(u)
return u,q_star,sp.status
def dual_varible(model):
if model.status==GRB.INFEASIBLE:
u={}
count=0
for v in model.getVals():
u[count]=v.unbdRay
print(u)
elif model.status==GRB.OPTIMAL:
u={}
count=0
for v in model.getVars():
u[count]=v.pi
return u
##########################initialization############
mp=master_pro()
mp.optimize()
mp.display()
print('_++++++++++++++++++++++++_')
y_bar,q_bar=update_y_q(mp)
print('_++++++++++++++++++++++++_')
u,q_star,status=sub_dual(y_bar)
# u,q_star,status=sub(y_bar)
mp._sp_status = status
mp._q_star = q_star
mp._q_bar = q_bar
mp=bender_cut(mp,u)
# mp=bender_cut_dual(mp,u)
mp.optimize()
mp.display()
y_bar,q_bar=update_y_q(mp)
# # #############start to loop################
while mp._iter<10:
u,q_star,status=sub_dual(y_bar)
print('***********sub_prob_q ',q_star)
print('subdual_{}_\n_{}'.format(u,q_star))
mp._sp_status = status
mp._q_star = q_star
mp._q_bar = q_bar # q_LB
if mp._q_star != mp._q_bar:
new_mp = bender_cut(mp,u)
# new_mp = bender_cut_dual(mp, u)
new_mp.optimize()
new_mp.display()
y_bar,q_bar = update_y_q(new_mp)
mp=new_mp
else:
break
最后结果展示
主函数

子函数
