Benders decompostion2 解释+pythoncode(通过subdual求解)

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

  • 最后结果展示

  • 主函数

  • 子函数

要使用Gurobi求解Benders分解模型,首先需要在Python中安装Gurobi Optimizer,并使用Gurobi Python API编写代码。 以下是一个示例代码,展示了如何使用Gurobi Python API求解Benders分解模型: ```python import gurobipy as gp # 定义主问题 master = gp.Model("master") x = master.addVars(2, obj=[2, 3], vtype=gp.GRB.CONTINUOUS, name="x") master.addConstr(x[0] + x[1] <= 4, "c0") master.addConstr(x[0] - x[1] <= 1, "c1") # 定义子问题 subproblem = gp.Model("subproblem") y = subproblem.addVars(2, obj=[1, -1], vtype=gp.GRB.CONTINUOUS, name="y") subproblem.addConstr(y[0] + y[1] <= 2, "d0") # 定义Benders分解模型 benders = gp.Model("benders") benders.setParam('OutputFlag', 0) # 将主问题添加到Benders分解模型中 benders.setObjective(master.getObjective(), gp.GRB.MINIMIZE) benders.addVars(master.getVars(), lb=master.getVars(), ub=master.getVars(), obj=master.getVars()) # 添加子问题约束到Benders分解模型中 benders.addConstrs((y[i] == benders.getVarByName("x[" + str(i) + "]") for i in range(2)), "subproblem_constrs") # 解决Benders分解模型 benders.optimize() # 输出结果 print("Objective value: ", benders.ObjVal) print("x[0]: ", benders.getVarByName("x[0]").X) print("x[1]: ", benders.getVarByName("x[1]").X) ``` 在这个示例代码中,我们首先定义了一个主问题和一个子问题。主问题和子问题都是线性规划问题。然后,我们将主问题添加到Benders分解模型中,并将子问题约束添加到Benders分解模型中。最后,我们使用Benders分解模型求解问题,并输出结果。 需要注意的是,这只是一个简单的示例代码,实际的Benders分解模型可能更加复杂。因此,在实际应用中,需要根据具体问题编写代码。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值