生成一些随机的高斯坐标,我注意到TSP求解器返回了可怕的解,但是对于相同的输入,它又一次又一次地返回了相同的可怕解。
给出以下代码:
import numpy
import math
from ortools.constraint_solver import pywrapcp
from ortools.constraint_solver import routing_enums_pb2
import matplotlib
%matplotlib inline
from matplotlib import pyplot, pylab
pylab.rcParams['figure.figsize'] = 20, 10
n_points = 200
orders = numpy.random.randn(n_points, 2)
coordinates = orders.tolist()
class Distance:
def __init__(self, coords):
self.coords = coords
def distance(self, x, y):
return math.sqrt((x[0] - y[0]) ** 2 + (x[1] - y[1]) ** 2)
def __call__(self, x, y):
return self.distance(self.coords[x], self.coords[y])
distance = Distance(coordinates)
search_parameters = pywrapcp.RoutingModel.DefaultSearchParameters()
search_parameters.first_solution_strategy = (
routing_enums_pb2.FirstSolutionStrategy.LOCAL_CHEAPEST_ARC)
search_parameters.local_search_metaheuristic = routing_enums_pb2.LocalSearchMetaheuristic.TABU_SEARCH
routing = pywrapcp.RoutingModel(len(coordinates), 1)
routing.SetArcCostEvaluatorOfAllVehicles(distance)
routing.SetDepot(0)
solver = routing.solver()
routing.CloseModel() # the documentation is a bit unclear on whether this is needed
assignment = routing.SolveWithParameters(search_parameters)
nodes = []
index = routing.Start(0)
while not routing.IsEnd(index):
nodes.append(routing.IndexToNode(index))
index = assignment.Value(routing.NextVar(index))
nodes.append(0)
for (a, b) in zip(nodes, nodes[1:]):
a, b = coordinates[a], coordinates[b]
pyplot.plot([a[0], b[0]], [a[1], b[1]], 'r' )
Run Code Online (Sandbox Code Playgroud)
例如,对于10分,我得到一个不错的解决方案:
对于20,更糟糕的是,仍然存在一些明显的优化(其中仅一个就需要交换两点。
200太恐怖了:
我想知道上面的代码实际上是执行某些LNS还是只是返回初始值,特别是因为大多数first_solution_strategy选项都建议进行确定性初始化。
为何即使禁忌搜索和模拟退火等都是随机的,上面的TSP求解器也为相同的数据返回一致的解。而且,为什么200点解决方案如此糟糕?
我在SearchParameters中使用了多个选项,尤其是在中启用了“ use _...”字段local_search_operators。这没有效果,返回了同样非常次优的解决方案。
我认为问题出在距离测量上:)。我记得kScalingFactor在C代码中来自or-tools的样本,该样本用于放大距离,然后将其舍入(通过强制转换)为整数:or-tools期望距离为整数。
或者,当然,标准高斯随机坐标之间的距离通常在0到2之间,因此,大多数点对在映射为整数时具有相同的距离:无用输入,无用输出。
我通过简单地乘以并强制转换为整数来解决它(只是为了确保swig不会将浮点数解释为整数):
# ...
def distance(self, x, y):
return int(10000 * math.sqrt((x[0] - y[0]) ** 2 + (x[1] - y[1]) ** 2))
# ...
Run Code Online (Sandbox Code Playgroud)
那么结果就更有意义了:
10分:
20分:
200分:
| 归档时间: |
|
| 查看次数: |
945 次 |
| 最近记录: |