threshold_accepting_tsp#
- threshold_accepting_tsp(G, init_cycle, weight='weight', source=None, threshold=1, move='1-1', max_iterations=10, N_inner=100, alpha=0.1, seed=None)[source]#
返回旅行商问题的近似解。
该函数使用阈值接受方法来近似通过节点的最小成本循环。从次优解开始,阈值接受方法扰动该解,接受任何使解不比增加阈值量更差的改变。接受成本的改进,但也接受导致成本小幅增加的改变。这允许解离开解空间中的次优局部最小值。随着迭代进行,阈值缓慢降低,有助于确保最优解。总之,该函数返回一个从
source
开始的循环,其总成本最小化。- Parameters:
- G图
G
应该是一个完全加权图。 所有节点对之间的距离应包含在内。- init_cycle列表或 “greedy”
初始解(通过所有节点返回起点的循环)。 此参数没有默认值,以确保您考虑它。 如果为 “greedy”,则使用
greedy_tsp(G, weight)
。 其他常见的起始循环是list(G) + [next(iter(G))]
或执行threshold_accepting_tsp
时的simulated_annealing_tsp
的最终结果。- weight字符串, 可选 (默认=”weight”)
对应于边权重的边数据键。 如果任何边没有此属性,则权重设置为1。
- source节点, 可选 (默认: 列表(G)中的第一个节点)
起始节点。如果为 None,则默认为
next(iter(G))
- threshold整数, 可选 (默认=1)
算法的阈值参数。表示初始阈值的值
- move“1-1” 或 “1-0” 或 函数, 可选 (默认=”1-1”)
指示在寻找新试验解时使用哪种移动的标志。 字符串表示两种特殊的内置移动:
“1-1”: 1-1 交换,交换当前解中两个元素的位置。 调用的函数是
swap_two_nodes()
。 例如,如果在解A = [3, 2, 1, 4, 3]
中应用 1-1 交换, 我们可以通过交换 1 和 4 元素得到:A' = [3, 2, 4, 1, 3]
“1-0”: 1-0 交换,将解中的一个节点移动到新位置。 调用的函数是
move_one_node()
。 例如,如果在解A = [3, 2, 1, 4, 3]
中应用 1-0 交换, 我们可以将第四个元素转移到第二个位置:A' = [3, 4, 2, 1, 3]
您可以提供自己的函数来从一个解移动到邻近解。该函数必须以解作为输入,并带有控制随机数生成的
seed
输入(参见这里的seed
输入)。您的函数应保持解为一个循环,首尾节点相同,其他节点出现一次。您的函数应返回新解。- max_iterations整数, 可选 (默认=10)
当外循环连续迭代次数达到此数值且最佳成本解没有任何变化时,声明完成。
- N_inner整数, 可选 (默认=100)
内循环的迭代次数。
- alpha介于 (0, 1) 之间的浮点数, 可选 (默认=0.1)
当至少接受一个邻近解时,阈值减少的百分比。 如果没有内循环移动被接受,阈值保持不变。
- seed整数, random_state, 或 None (默认)
随机数生成状态的指示符。 参见 Randomness 。
- Returns:
- cycle节点列表
返回旅行商可以遵循的循环(节点列表),以最小化行程的总权重。
- Raises:
- NetworkXError
如果
G
不是完全图,算法会引发异常。
See also
Notes
阈值接受是一种元启发式局部搜索算法。该算法的主要特点是它接受甚至导致成本增加的解,以逃离低质量的局部最优解。
该算法需要一个初始解。该解可以通过一个简单的贪心算法构造。在每次迭代中,它会仔细选择一个邻近解。 考虑当前解的成本 \(c(x)\) 和邻近解的成本 \(c(x')\)。 如果 \(c(x') - c(x) <= threshold\),则邻近解成为下一次迭代的当前解,其中阈值称为阈值。
与模拟退火算法相比,阈值接受算法不接受非常低质量的解(由于存在阈值值)。在模拟退火的情况下,即使是非常低质量的解也可以以概率 \(p\) 被接受。
时间复杂度: 它的运行时间为 \(O(m * n * |V|)\),其中 \(m\) 和 \(n\) 分别是外循环和内循环运行的次数。
有关算法的更多信息和灵感来源,请参见: https://doi.org/10.1016/0021-9991(90)90201-B
Examples
>>> from networkx.algorithms import approximation as approx >>> G = nx.DiGraph() >>> G.add_weighted_edges_from( ... { ... ("A", "B", 3), ... ("A", "C", 17), ... ("A", "D", 14), ... ("B", "A", 3), ... ("B", "C", 12), ... ("B", "D", 16), ... ("C", "A", 13), ... ("C", "B", 12), ... ("C", "D", 4), ... ("D", "A", 14), ... ("D", "B", 15), ... ("D", "C", 2), ... } ... ) >>> cycle = approx.threshold_accepting_tsp(G, "greedy", source="D") >>> cost = sum(G[n][nbr]["weight"] for n, nbr in nx.utils.pairwise(cycle)) >>> cycle ['D', 'C', 'B', 'A', 'D'] >>> cost 31 >>> incycle = ["D", "B", "A", "C", "D"] >>> cycle = approx.threshold_accepting_tsp(G, incycle, source="D") >>> cost = sum(G[n][nbr]["weight"] for n, nbr in nx.utils.pairwise(cycle)) >>> cycle ['D', 'C', 'B', 'A', 'D'] >>> cost 31