Python Gurobi问题-使用回调函数添加usercuts

Python Gurobi问题-使用回调函数添加usercuts,python,linear-programming,gurobi,Python,Linear Programming,Gurobi,我目前正在研究一个MILP公式,我想使用Gurobi和分支切割方法来解决这个问题。我的模型是一个经典的带时间窗的提货和交货问题(PDPTW)的变体,定义了几类有效不等式。当分支和边界解算器运行时,如果满足当前节点中的某些条件,我想添加这些不等式(即,我想添加切割)。我的问题如下: model._vars = model.getVars() #---> added this call right before the optimization starts model.optimize(my

我目前正在研究一个MILP公式,我想使用Gurobi和分支切割方法来解决这个问题。我的模型是一个经典的带时间窗的提货和交货问题(PDPTW)的变体,定义了几类有效不等式。当分支和边界解算器运行时,如果满足当前节点中的某些条件,我想添加这些不等式(即,我想添加切割)。我的问题如下:

model._vars = model.getVars() #---> added this call right before the optimization starts
model.optimize(mycallback)
def mycallback(model,where):
    if where == GRB.Callback.MIPNODE:
        status = model.cbGet(GRB.Callback.MIPNODE_STATUS)
        # If current node was solved to optimality, add cuts to strenghten
        # linear relaxation
        if status == GRB.OPTIMAL:
            this_Sol =  model.cbGetNodeRel(model._vars) # Get variables of current solution
            # Adding a cut
            model.cbCut(lhs=this_Sol[123]+this_Sol[125],sense=GRB.LESS_EQUAL,rhs=1) #---> Dummy cut just 
                                                                                    # for illustration 
                                                                                    # purposes
我的变量被定义为字典,这使得在制定约束时很容易使用它们,因为我可以很容易地使用它们的原始索引。下面提供了我如何定义变量的示例

tauOD = {}
# Start- End-Service time of trucks
for i in range(0,Nt):
    tauOD[i,0]=model.addVar(lb=0.0, ub=truckODTime[i][0],
                             vtype=GRB.CONTINUOUS,name='tauOD[%s,%s]'%(i,0))
    tauOD[i,1]=model.addVar(lb=0.0, ub=truckODTime[i][1],
                             vtype=GRB.CONTINUOUS,name='tauOD[%s,%s]'%(i,1))
一旦根据变量、约束和成本函数定义了我的模型,在一个经典的分支定界问题中,我只需使用model.optimize()来开始这个过程。在本例中,我使用命令model.optimize(my_callback),其中my_callback是我定义的用于添加剪切的回调函数。我的问题是,由于某些原因,回调函数不喜欢定义为字典的模型变量。我发现的唯一解决方法如下:

model._vars = model.getVars() #---> added this call right before the optimization starts
model.optimize(mycallback)
def mycallback(model,where):
    if where == GRB.Callback.MIPNODE:
        status = model.cbGet(GRB.Callback.MIPNODE_STATUS)
        # If current node was solved to optimality, add cuts to strenghten
        # linear relaxation
        if status == GRB.OPTIMAL:
            this_Sol =  model.cbGetNodeRel(model._vars) # Get variables of current solution
            # Adding a cut
            model.cbCut(lhs=this_Sol[123]+this_Sol[125],sense=GRB.LESS_EQUAL,rhs=1) #---> Dummy cut just 
                                                                                    # for illustration 
                                                                                    # purposes
然后在回调中,我现在可以使用变量的顺序而不是索引检索变量,如下所示:

model._vars = model.getVars() #---> added this call right before the optimization starts
model.optimize(mycallback)
def mycallback(model,where):
    if where == GRB.Callback.MIPNODE:
        status = model.cbGet(GRB.Callback.MIPNODE_STATUS)
        # If current node was solved to optimality, add cuts to strenghten
        # linear relaxation
        if status == GRB.OPTIMAL:
            this_Sol =  model.cbGetNodeRel(model._vars) # Get variables of current solution
            # Adding a cut
            model.cbCut(lhs=this_Sol[123]+this_Sol[125],sense=GRB.LESS_EQUAL,rhs=1) #---> Dummy cut just 
                                                                                    # for illustration 
                                                                                    # purposes
前面提到的剪切只是一个虚拟示例,它表明我可以使用顺序变量来添加剪切,而不是使用它们的索引。例如,我希望能够在回调中编写一个约束,如下所示


x[0,3,0]+x[0,5,0]你应该用变量的dict复制变量

要获取变量索引,还必须复制一份os索引列表

试试这个:

model.\u I=model.I
模型。_J=模型.J
模型。_K=模型.K
型号。\u x=型号.x
您需要这些索引列表,以便可以循环每个目标变量x以验证某些条件。就像为模型编写法线约束一样

然后在回调中,您可以进行索引迭代:

def mycallback(型号,其中):
如果其中==GRB.Callback.MIPNODE:
x=model.cbGetSolution(model.\u x)
对于模型中的i。\u i:
如果sum([x[i,j,k]表示模型中的j.\u j表示模型中的k.\u k])>1:
添加__切口()

您应该通过DICT复制变量

要获取变量索引,还必须复制一份os索引列表

试试这个:

model.\u I=model.I
模型。_J=模型.J
模型。_K=模型.K
型号。\u x=型号.x
您需要这些索引列表,以便可以循环每个目标变量x以验证某些条件。就像为模型编写法线约束一样

然后在回调中,您可以进行索引迭代:

def mycallback(型号,其中):
如果其中==GRB.Callback.MIPNODE:
x=model.cbGetSolution(model.\u x)
对于模型中的i。\u i:
如果sum([x[i,j,k]表示模型中的j.\u j表示模型中的k.\u k])>1:
添加__切口()

谢谢@Seimetz的回答。不幸的是,我错过了一些东西。我知道我没有遵循程序,但我用我的后续问题回答了我自己的问题(见上文)。我试着用一系列的评论来回答我的后续问题,但这种方法变得容易多了。非常感谢任何额外的帮助。谢谢谢谢你@Seimetz,但我还是有点困惑。如果我理解正确,命令
model.\u x=model.x
检索我的模型的
x
类型的所有变量的列表(我认为这是比
vars=model.getVars()
更具体的东西,它检索所有变量而不使用原始符号)。然后,在回调内部,命令
x=model.cbGetSolution(model.\ux)
获取我的所有x变量的值。我仍然不明白为什么对于I,j,k,这些仅仅是索引,我需要遵循相同的过程(请参阅下面的注释,因为我在这里没有空间了),命令
model发生了什么事情。_I=model.I
?我不是一个可变字典集,所以我想知道窗帘后面发生了什么。为什么我不能简单地将范围(0,10)中的I写成
:如果sum([x[I,j,k]表示范围(0,10)中的j表示范围(0,10)中的k表示范围(0,10))>1:
?换句话说,我确实理解(或者至少我认为我理解)
model中发生了什么。x=model.x
,当相同的命令应用于索引I、j、k时,我不知道发生了什么。同时,非常感谢您迄今为止的帮助!
I
是一个包含I个索引的列表,就像我用作示例的范围(0,10)。假设您使用
addvars创建了
x
([i in i],[j in j],[k in k])
。您可以使用
范围(0,10)
。我只是假设大小可能会改变。谢谢@Seimetz的回答。不幸的是,我遗漏了一些东西。我知道我没有遵循过程,但我回答了我自己的问题(见上文)关于我的后续问题。我尝试使用一系列注释来回答我的后续问题,但这种方法变得简单多了。非常感谢任何其他帮助。谢谢!谢谢@Seimetz,但我仍然有点困惑。如果我理解正确,命令
model.\u x=model.x
将检索所有变量的列表类型为我的模型的
x
(我认为这是比
vars=model.getVars()
更为特殊的东西,它检索所有的模型而不使用原始的符号)。然后,在回调函数中,命令
x=model.cbGetSolution(model.\u x)
获取我所有x变量的值。我仍然不明白为什么对于I、j、k,它们只是索引,我需要遵循相同的过程(请参阅下面的注释,因为我的空间不足)命令
model.\u I=model.I
?我不是一个变量字典集,所以我想知道窗帘后面发生了什么。为什么不能