对于旅行商问题(TSP),我想在Python中生成一个随机游览(其中来自一组n的每个节点只被访问一次)来自状态转移矩阵M(nxn),对于这个矩阵M [i,j]包含最短全局路径将节点i连接到节点j的概率。
任何人都知道如何在Python中这样做?我在这里询问有关这方面的一般方法或模块。
示例:假设对于j =(i + 1)%n,M [i,j] = 1,其他地方为0。将生成的所有路径(始终从0开始)是:(0,1,2,...,n)。如果稍微更改此矩阵,将1.0替换为0.9并将0.1替换为M [i,i + 2],则可能的路径为:(0,2,3,..,n,1)。在一些概率为0的特定示例中,我知道最后一次移动是不可能的(从节点n到节点1),因此您可以假设概率总是大于0。
答案 0 :(得分:2)
(如果您提供了一些代码,这将是一个更好的问题;特别是因为问题的目标是一个步骤,其中包含许多步骤)
这里有一些方法应该只是作为一些想法,因为设置可能有点烦人(cvxpy和一些MIP解算器,这是不错的;我在这里使用CBC,请参阅cvxpy的文档替代或设置 - 文档)。它也没有经过实际测试。这个想法在某种程度上基于概率图形模型中的MAP计算,但转移可能在数学上是错误的(无保证)。由于我们案例中的选择问题受限于约束,因此也更难了!
制定一个优化问题,最大化所使用的先验概率=解决方案路径的一部分(并将这个=更大的偏差更严重地惩罚),同时生成有效的解决方案(有效路径)。
虽然问题可能是非凸的(我不确定),因此无法以全局最优的方式求解),我们正在使用一些经过充分分析的启发式算法来解释凸面编程的差异。
备注:这种方法是设计搜索全局最优的(不完全正确,因为我们使用非凸优化算法)。这意味着,在这种方法中,使用不同解决方案的多次采样并不是很自然(但调用具有不同起点的DCCP例程将导致具有高概率的不同解决方案)。
备注2:对于非小型实例(使用非商业解算器),性能非常糟糕,这使其成为一种更理论化的方法。
这是使用Python 3,numpy,scipy(最短路径),cvxpy(选择问题公式)和dccp(cvxpy的凸函数优化扩展的差异)的一些实现
import numpy as np
from scipy.sparse.csgraph import csgraph_from_dense, shortest_path
from scipy.spatial import distance
from cvxpy import *
import dccp
np.random.seed(1)
""" Create random problem """
N = 10
distances = np.random.rand(N, N) # assymetric
""" Calculate shortest paths """
csparse_distances = csgraph_from_dense(distances)
shortest = shortest_path(csparse_distances) # directed
""" Calculate a-prori probabilities based on global shortest paths """
shortest_global = np.copy(shortest)
for row in range(shortest_global.shape[0]):
# normalize sum to 1
row_sum = np.sum(shortest_global[row, :])
shortest_global[row, :] /= row_sum
""" Formulate MIQP problem """
# Based on: https://en.wikipedia.org/wiki/Travelling_salesman_problem
# and my example here: https://github.com/cvxgrp/cvxpy/blob/master/examples/tsp_mip.py#L16
# Variables
x = Bool(N, N) # edge x,y in PATH
u = Int(N) # aux-var
# Constraints
constraints = []
for j in range(N): # ingoing: exactly 1
indices = list(range(0, j)) + list(range(j + 1, N))
constraints.append(sum_entries(x[indices, j]) == 1)
for i in range(N):
indices = list(range(0, i)) + list(range(i + 1, N)) # outgoing: exactly 1
constraints.append(sum_entries(x[i, indices]) == 1)
for i in range(1, N): # subtour-elimination
for j in range(1, N):
if i != j:
constraints.append(u[i] - u[j] + N*x[i, j] <= N-1)
# Objective
obj = Maximize(sum_entries(square(mul_elemwise(shortest_global, x))))
# Solve
prob = Problem(obj, constraints)
print("problem is DCP: ", prob.is_dcp())
prob.solve(method='dccp', solver=CBC, ccp_times=10) # do not use default solver!
# Remark: formulation above not accepted by CVX-ruleset
# -> need "difference of convex function"-extension
# -> heuristic (which is well-known for good behaviour)!
""" Print solution """
print('Solution path matrix')
print(np.round(x.value).astype('int'))
print('A-priori probability matrix')
print(np.round(shortest_global, 2))
...
...
iteration= 1 cost value = 0.34508891154470694 tau = 0.005
iteration= 2 cost value = 0.5092119781611304 tau = 0.006
iteration= 3 cost value = 0.5092119781611304 tau = 0.0072
Solution path matrix
[[0 0 0 0 0 0 0 0 1 0]
[1 0 0 0 0 0 0 0 0 0]
[0 0 0 1 0 0 0 0 0 0]
[0 0 0 0 1 0 0 0 0 0]
[0 0 0 0 0 1 0 0 0 0]
[0 0 0 0 0 0 0 0 0 1]
[0 0 1 0 0 0 0 0 0 0]
[0 0 0 0 0 0 1 0 0 0]
[0 0 0 0 0 0 0 1 0 0]
[0 1 0 0 0 0 0 0 0 0]]
A-priori probability matrix
[[ 0. 0.14 0. 0.24 0.11 0.07 0.07 0.03 0.13 0.21]
[ 0.12 0. 0.09 0.22 0.01 0.17 0.13 0.11 0.06 0.07]
[ 0.11 0.1 0. 0.27 0.08 0.12 0.05 0.02 0.1 0.15]
[ 0.06 0.17 0.06 0. 0.15 0.12 0.11 0.09 0.01 0.23]
[ 0.09 0.16 0.09 0.18 0. 0.13 0.13 0.11 0.05 0.05]
[ 0.01 0.15 0.02 0.21 0.12 0. 0.08 0.05 0.15 0.22]
[ 0.06 0.17 0.06 0.25 0.03 0.12 0. 0.09 0.11 0.11]
[ 0.09 0.07 0.07 0.21 0.08 0.08 0.11 0. 0.14 0.15]
[ 0.11 0.16 0.11 0.09 0.07 0.14 0.11 0.12 0. 0.1 ]
[ 0.07 0.17 0.07 0.21 0.15 0.12 0.12 0.09 0. 0. ]]
修改强>