如何解决在 Gurobi Python 中正确制定约束
我正在使用带有 gurobi 的 Python IDE 来建模和解决作业问题。这个问题虽然没有说明,但似乎是一个 OVRP(开放式车辆路由问题)(有一些额外的限制)。我现在的代码是:
from itertools import combinations
import gurobipy as gp
from gurobipy import GRB
def find_length(list):
length = 0
for i in range(len(list)):
length += distances[list[i][0]][list[i][1]]
return length
def find_tours(list):
tours = []
for start in list:
this_tour = []
begin = start[0]
end = start[1]
if begin == 0:
this_tour.append(start)
current = start
while next_route_exists(current,list):
current = find_next_route(current,list)
this_tour.append(current)
tours.append(this_tour)
return tours
def find_next_route(current_route,list):
end = current_route[1]
for tuple in list:
if tuple[0] == end:
list.remove(tuple)
return tuple
def next_route_exists(current_route,list):
end = current_route[1]
for tuple in list:
if tuple[0] == end:
return True
return False
def subtourelim(model,where):
if where == GRB.Callback.MIPSOL:
# make a list of edges selected in the solution
vals = model.cbGetSolution(model._vars)
selected = gp.tuplelist((i,j) for i,j in model._vars.keys() if vals[i,j] > 0.5)
tours = find_tours(selected)
for tour in tours:
if find_length(tour) > 400:
# add subtour elimination constr. for every pair of cities in tour
model.cblazy(gp.quicksum(distances[i][j] for i,j in tour) <= 400)
# distances between cities
distances = [[0,180,240,85,285,205,235,255,155,120,230,340,220,160,240],# Α
[0,150,125,100,175,25,65,95,210,55,135,215],# Β1
[0,105,45,245,195,225,310,115,50],# Β2
[0,215,170,130,110,260,200,75,150],# Β3
[0,90,190,50,185],# Β4
[0,70,40,120],# Β5
[0,55],# Β6
[0,250,165,290,20],# Β7
[0,# Β8
[0,145,265,230],# Β9
[0,# Β10
[0,185,175],# Β11
[0,270],# Β12
[0,90],# Β13
[0,0]] # B14
n = 15
for i in range(n):
for j in range(n):
if j > i:
distances[j][i] = distances[i][j]
dist = {(i,j): distances[i][j] for i in range(n) for j in range(n)}
m = gp.Model()
vars = m.addVars(dist.keys(),obj=dist,vtype=GRB.BINARY,name='route')
m.addConstrs(vars.sum(i,'*') <= 1 for i in range(1,n)) # a city might be the departure
m.addConstrs(vars.sum('*',i) == 1 for i in range(1,n)) # every city must be the destination
m.addConstr(vars.sum(0,'*') >= 1,"start") # Could have more than 1 vehicles
m.addConstr(vars.sum('*',0) == 0) # can't go back to start
m.addConstr(vars.sum(0,'*') <= 8,"start") # can't have more than 8 vehicle
m.addConstrs(vars[i,i] == 0 for i in range(1,n)) # can't go to current city from current city
m.addConstrs(vars[i,j] + vars[j,i] <= 1 for i in range(1,n) for j in range(1,n) if j != i) # eliminate double edges between cities
route_km = vars.prod(dist)
m.addConstr(route_km <= 400 * vars.sum(0,'*')) # total km driven
# total vehicles used
total_vehicles = vars.sum(0,'*')
m.setobjective(total_vehicles,GRB.MINIMIZE)
# optimize model
m._vars = vars
m.Params.lazyConstraints = 1
m.optimize(subtourelim)
#m.optimize()
# get edges
vals = m.getAttr('x',vars)
selected = gp.tuplelist((i,j in vals.keys() if vals[i,j] > 0.5)
print('')
tours = find_tours(selected)
i = 0
total=0
for tour in tours:
i += 1
print('Tour No ' + str(i) + ':')
print(tour)
print('is ' + str(find_length(tour)) + ' km long')
print('')
total+=find_length(tour)
print('Total : ' + str(total) + ' km')
我现在遇到的问题是,由于我是 gurobi 的新手,我无法表达我想正确添加的约束,这会导致出现错误的解决方案。问题在于这个约束:
route_km = vars.prod(dist)
m.addConstr(route_km <= 400 * vars.sum(0,'*')) # total km driven
这是错误的。我想添加一个约束,每辆卡车最多可以行驶 400 公里。如果选择了另一个“城市”,则一旦行驶或无法行驶该距离,就必须部署一辆新卡车(卡车总数为 8,如约束中所述)。如果制定了这个约束,我相信我也可以消除这个懒惰的约束:
tours = find_tours(selected)
for tour in tours:
if find_length(tour) > 400:
# add subtour elimination constr. for every pair of cities in tour
model.cblazy(gp.quicksum(distances[i][j] for i,j in tour) <= 400)
在此先感谢您的帮助,
乔治
解决方法
延迟约束最适合具有相对大量约束的模型。例如,在旅行商问题的传统 MIP 模型中,存在指数数量的 subtour 消除约束,因此将这些添加为惰性约束是有意义的。
您似乎希望根据行驶总距离对卡车进行容量限制。在 HP Williams 的书 Model Building in Mathematical Programming 中,丢失行李的例子非常相似; here is a link to a Jupiter notebook for this example on the Gurobi website。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。