【问题标题】:How to apply Gurobi Traveling Salesman Problem Python code to my data如何将 Gurobi Traveling Salesman Problem Python 代码应用于我的数据
【发布时间】:2019-07-07 21:12:54
【问题描述】:

我想将 Gurobi 网站上的旅行推销员问题 Python 代码示例与我的数据文件一起使用。我正在努力解决如何操作数据的 df 以便将其合并到 Gurobi 代码中。我对 Python 还是很陌生,而且我最近才被介绍给 Gurobi。

我从 Gurobi 网站上提取了 TSP 示例代码并让它运行。该示例创建随机点并计算它们之间的距离以说明 TSP 问题。我的电子表格中已经有了点和距离,该电子表格已作为 df 导入。我似乎无法在 Python 中将我的 df 转换为正确的格式以供代码使用。似乎我需要将我的 df 转换为字典,其中包含对的每种可能组合及其距离,但我不知道一种简单的方法。

这是为示例创建虚拟数据的代码部分。我注释掉了我正在使用少量 df 数据来模拟我的文件的部分。

import math
import random
from gurobipy import *

# Euclidean distance between two points 

def distance(points, i, j): 
    dx = points[i][0] - points[j][0] 
    dy = points[i][1] - points[j][1] 
    return math.sqrt(dx*dx + dy*dy)

n=50

# Create n random points 

random.seed(1) 
points = [] 
for i in range(n): 
    points.append((random.randint(0,100),random.randint(0,100))) 

m = Model() 

# Create variables 

vars = {} 
for i in range(n): 
    for j in range(i+1): 
        vars[i,j] = m.addVar(obj=distance(points, i, j), vtype=GRB.BINARY, name='e'+str(i)+'_'+str(j)) 
        vars[j,i] = vars[i,j] 
    m.update()

#Attempting to incorporate my own data
#import pandas as pd
#data = [[0,20,15,8,6],[15,0,18,9,28],[24,23,0,13,13],[15,27,8,0,14],[8,17,24,15,0]]
#df = pd.DataFrame(data, columns=['P1','P2','P3','P4','P5'],index=['P1','P2','P3','P4','P5'])

我希望能够将我的数据的 df 与 Gurobi TSP Python 代码一起使用。提前感谢您的帮助。

【问题讨论】:

  • 被注释掉的data list-of-lists 是成对距离矩阵吗?它应该是对称的吗?
  • 这是一个 5x5 对称矩阵。我想在 Gurobi TSP 代码中使用数据矩阵。
  • 但它甚至不接近对称。有错别字吗?
  • 哎呀,这是一个错字。肯定是不对称的。有了这个数据,从 P1 到 P2 的距离与从 P2 到 P1 的距离不同,依此类推。很抱歉造成混乱。

标签: python pandas dictionary traveling-salesman gurobi


【解决方案1】:

我之前在Gurobi discussion board 上回答过这个问题。为方便起见,我在这里重新发布(并详细说明)答案:

addVars 不直接接受 DataFrame。如果您的数据在 DataFrame df 中,您可以执行以下操作:

n=df.shape[0]
dist = {(i,j) : df.iloc[i][j] for i in range(n) for j in range(n) if i != j}

tsp.py example code 假设距离矩阵是对称的。 例如,您可以从以下几行中看到这一点:

for i,j in vars.keys():
   vars[j,i] = vars[i,j] # edge in opposite direction

您需要删除这些以使其适用于非对称矩阵。

此外,您应该将 2 阶约束替换为确保每个节点都只有一个传入和传出边的约束。即,替换

m.addConstrs(vars.sum(i,'*') == 2 for i in range(n))

通过

m.addConstrs(vars.sum(i,'*') == 1 for i in range(n))
m.addConstrs(vars.sum('*',i) == 1 for i in range(n))

对于惰性约束,您需要确保添加每个边的两个方向。添加惰性约束应该如下所示:

        model.cbLazy(quicksum(model._vars[i,j] + model._vars[j,i]
                              for i,j in itertools.combinations(tour, 2))
                     <= len(tour)-1)

【讨论】:

  • 浏览我的旧帖子并意识到我从未跟进过这个。这个回应非常有帮助。我错误地解释了基本 TSP 代码的某些部分,这让我偏离了轨道。感谢您的帮助!
  • 虽然我喜欢你的回答,但我觉得这里有问题。首先,在惰性约束中的 quicksum 之前,一个小错字是缺少 gp。没有那个 tsp.py 将无法正常运行。此外,被替换的 2 级约束似乎是错误的。我可以想,i != j,否则 vars[i,i] = 1 假设 dist[i,i] = 0。当我实施您的建议时,我得到一个 obj val 为 0,而启发式实施给出了一些有意义的结果。你能重温一下这个公式吗?这对我有很大帮助:)
  • 我猜,添加“m.addConstrs(vars.sum(i,i) == 0 for i in range(n))”可以解决问题。点头表示赞赏!
猜你喜欢
  • 2021-06-29
  • 1970-01-01
  • 1970-01-01
  • 2021-12-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-22
  • 1970-01-01
  • 2014-09-24
相关资源
最近更新 更多