解决旅行推销员问题(TSP)时,避免穿过物体。

huangapple go评论63阅读模式
英文:

Solve TSP without crossing through the object

问题

我有一个点阵,这些点组成一个立方体。立方体看起来像这样:

解决旅行推销员问题(TSP)时,避免穿过物体。

现在我想创建一条路径,连接所有这些点,所以我使用了以下方法,应用了TSP并使用2-Opt进行路径优化:

def tsp_2opt(points):
    # 当只给定一个点时返回输入
    if len(points) <= 1:
        return points

    # 创建所有点之间的距离矩阵
    dist_matrix = np.sqrt(np.sum((points[:, np.newaxis] - points) ** 2, axis=2))

    # 使用最近邻算法创建初始路径
    n = len(points)
    unvisited = set(range(n))
    curr_point = 0  # 从第一个点开始
    tour = [curr_point]
    unvisited.remove(curr_point)
    while unvisited:
        next_point = min(unvisited, key=lambda x: dist_matrix[curr_point, x])
        if len(unvisited) == 1:
            tour.append(next_point)
            break
        tour.append(next_point)
        unvisited remove(next_point)
        curr_point = next_point

    # 使用2-Opt算法改进路径
    improved = True
    while improved:
        improved = False
        for i in range(n-2):
            for j in range(i+2, n-1):
                if dist_matrix[tour[i], tour[j]] + dist_matrix[tour[i+1], tour[j+1]] < dist_matrix[tour[i], tour[i+1]] + dist_matrix[tour[j], tour[j+1]]:
                    tour[i+1:j+1] = reversed(tour[i+1:j+1])
                    improved = True

    return points[np.array(tour)]

这导致了以下结果:

解决旅行推销员问题(TSP)时,避免穿过物体。

这几乎是我想要的,除了它违反了我的模型应该防止的一个规则。路径不允许穿过物体,因此最后一部分是从中间穿过的,因为没有其他方法到达最后一个点。我尝试将距离矩阵中不同表面上的点的距离设为无穷大,以防止它尝试穿越,但在我的情况下,没有其他选择。

这些是我的数据点:

[[  0. 100. 100.]
 [  0. 100.  50.]
 [  0. 100.   0.]
 ...
 [100.   0.  50.]
 [100.  50.  50.]
 [100. 100.  50.]
 [100.   0. 100.]
 [100.  50. 100.]
 [100. 100. 100.]
 [  0.   0.   0.]
 [  0.  50.   0.]
 [  0. 100.   0.]
 ...
 [100.   0.   0.]]

首先,我创建了一个检查,只允许一次移动一个轴,以防止这些交叉路径发生,但问题是,这个解决方案只适用于立方体。我需要使其适用于其他形状。

英文:

I have a grid of points which are forming a cube. The cube looks like this:

解决旅行推销员问题(TSP)时,避免穿过物体。

Now I want to create a path through all the points, so I had the following method which applies TSP and optimizes the path with 2-Opt:

def tsp_2opt(points):
    # Return input when only one point is given
    if len(points) &lt;= 1:
        return points

    # Create a distance matrix between all points
    dist_matrix = np.sqrt(np.sum((points[:, np.newaxis] - points) ** 2, axis=2))

    # Create an initial tour using the nearest neighbor algorithm
    n = len(points)
    unvisited = set(range(n))
    curr_point = 0  # start with the first point
    tour = [curr_point]
    unvisited.remove(curr_point)
    while unvisited:
        next_point = min(unvisited, key=lambda x: dist_matrix[curr_point, x])
        if len(unvisited) == 1:
            tour.append(next_point)
            break
        tour.append(next_point)
        unvisited.remove(next_point)
        curr_point = next_point

    # Use 2-Opt algorithm to improve the tour
    improved = True
    while improved:
        improved = False
        for i in range(n-2):
            for j in range(i+2, n-1):
                if dist_matrix[tour[i], tour[j]] + dist_matrix[tour[i+1], tour[j+1]] &lt; dist_matrix[tour[i], tour[i+1]] + dist_matrix[tour[j], tour[j+1]]:
                    tour[i+1:j+1] = reversed(tour[i+1:j+1])
                    improved = True

    return points[np.array(tour)]

This resulted in:

解决旅行推销员问题(TSP)时,避免穿过物体。

This is almost what I want, except that this breaks one rule that my model should prevent. The path is not allowed to go through the object, so the last part it crosses from middle to middle, because it has no other option to reach that last point. I tried setting the distance matrix to infinity for points on a different surface, so that it would not try to go there, but in my case it has no other option.
These are my data points:

[[  0. 100. 100.]
 [  0. 100.  50.]
 [  0. 100.   0.]
 [ 50. 100. 100.]
 [ 50. 100.  50.]
 [ 50. 100.   0.]
 [100. 100. 100.]
 [100. 100.  50.]
 [100. 100.   0.]
 [100.   0.   0.]
 [100.  50.   0.]
 [100. 100.   0.]
 [100.   0.  50.]
 [100.  50.  50.]
 [100. 100.  50.]
 [100.   0. 100.]
 [100.  50. 100.]
 [100. 100. 100.]
 [  0.   0.   0.]
 [  0.  50.   0.]
 [  0. 100.   0.]
 [  0.   0.  50.]
 [  0.  50.  50.]
 [  0. 100.  50.]
 [  0.   0. 100.]
 [  0.  50. 100.]
 [  0. 100. 100.]
 [  0.   0. 100.]
 [  0.  50. 100.]
 [  0. 100. 100.]
 [ 50.   0. 100.]
 [ 50.  50. 100.]
 [ 50. 100. 100.]
 [100.   0. 100.]
 [100.  50. 100.]
 [100. 100. 100.]
 [  0.   0.   0.]
 [  0.  50.   0.]
 [  0. 100.   0.]
 [ 50.   0.   0.]
 [ 50.  50.   0.]
 [ 50. 100.   0.]
 [100.   0.   0.]
 [100.  50.   0.]
 [100. 100.   0.]
 [  0.   0. 100.]
 [  0.   0.  50.]
 [  0.   0.   0.]
 [ 50.   0. 100.]
 [ 50.   0.  50.]
 [ 50.   0.   0.]
 [100.   0. 100.]
 [100.   0.  50.]
 [100.   0.   0.]]

First I created a check that it is only allowed to move one axis at the time, so that these cross paths would not occur, but the problem is that that solution only works for cubes. I need to make this work for other shapes as well.

答案1

得分: 0

因为你没有限制当前点到第三个点的距离。你应该使用3D搜索,但你使用了2D,所以缺少了一个约束。

从第一个点到第二个点的约束是距离等于50,从第一个点到第三个点的约束是距离大于50且小于100。

英文:

Because you do not constrain the distance from the current point to the third point. You should have used 3D search, but you used 2D, so there is a constraint missing.

The constraint from the first point to the second point is that the distance is equal to 50, and the constraint from the first point to the third point is that the distance is greater than 50 and less than 100.

答案2

得分: 0

以下是您要翻译的内容:

观察一点:按照当前编码的方式,您的算法(包括构建初始路径的第一部分和尝试优化该路径的第二部分)在生成路径时完全可以通过对象“穿过”边缘。

您的目标似乎是要得到一个位于形状表面上的“最终路径”。实现这一目标的一种方法可能是仅处理已经位于表面上的路径(包括初始路径和优化)。

(请注意,此约束可能会阻止探索最后一部分的某些可能的优化,我还没有深入研究)。

例如:

  • 可以添加第二个“connected”矩阵,或为每个节点添加邻接列表,或将“dist”设置为“-1”或“None”以表示禁止路径,
  • 除了检查节点之间的距离外,还要检查是否允许移动到“那个”相邻节点(例如:创建初始路径的条件将比单行代码“min(unvisited, key=lambda x: dist_matrix[curr_point, x])”复杂一些,优化循环的“if”条件将检查更多内容)。

为了生成初始路径,您还需要更改算法:

贪婪地选择当前节点的一个相邻节点可能会导致陷入死胡同(例如:当前节点位于面的中央,周围的所有节点都已探索,但对面仍有未访问的节点)。

您可以尝试:

  • 回溯
  • 尝试通过在本地扩展路径来包括未访问的节点(例如:将段“...a--b...”替换为路径“...a--e--f--b...”)
英文:

One observation: as currently coded, your algorithm (both the first part where you build the initial path and the second part where you try to optimize that path) are perfectly fine with producing paths with edges going "through" the object.

Your goal seems to be to have a final path that lies on the surface of your shape. One way to achieve that could be to only deal with paths already lying on the surface (both initial path and optimization).

(note that this constraint may prevent exploring some possible optimizations at the end, I haven't looked into that).

for example:

  • either add a second connected matrix, or an adjacency list for each node, or set dist to "-1" or to "None" for non forbidden paths,
  • on top of checking the distance between nodes, check that going to that neighbor is allowed (e.g: your condition to create the initial path will be a little bit more complex than the one-liner min(unvisited, key=lambda x: dist_matrix[curr_point, x]), and the if condition of your optimizing loop will check a few more things)

In order to generate the initial path, you will also need to change your algorithm :

greedily selecting one neighbor to your current node may lead you to dead ends (e.g: current in the middle of a face, with all surrounding nodes explored, but some other nodes still unvisited on the opposite face)

You may try :

  • backtracking
  • try to include unvisited nodes by expanding a path locally (e.g: replace a sgement ...a--b... with a path ...a--e--f--b...)

huangapple
  • 本文由 发表于 2023年3月21日 00:07:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/75792660.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定