【问题标题】:Simulated annealing doesn't return (an) optimal solution模拟退火不会返回(一个)最优解
【发布时间】:2016-01-07 07:19:52
【问题描述】:

我决定学习模拟退火作为攻击this problem 的新方法。它本质上询问如何用 -1、0 或 1 填充网格,以便每一行和每一列的总和都是唯一的。作为一个测试用例,我使用了一个 6x6 的网格,Neil 给出的肯定有一个最优解:

1  1  1  1  1  1  6
1  1  1  1  1 -1  4
1  1  1  1 -1 -1  2
1  1  0 -1 -1 -1 -1
1  0 -1 -1 -1 -1 -3
0 -1 -1 -1 -1 -1 -5
5  3  1  0 -2 -4

我的代码在大多数运行时通常不会达到最佳情况,甚至返回错误的网格成本(old_cost 应该匹配 count_conflict(grid))。是我的参数设置不正确,是我执行不正确,还是模拟退火在这里不是一种可行的方法?

import random
from math import exp

G_SIZE = 6
grid = [[1]*G_SIZE for i in range(G_SIZE)]

def count_conflict(grid):
    cnt = [0]*(2*G_SIZE+1)
    conflicts = 0
    for row in grid:
        cnt[sum(row)] += 1
    for col in zip(*grid):
        cnt[sum(col)] += 1

    #print(cnt)
    for c in cnt:
        if c == 0: conflicts += 1
        if c > 1: conflicts += c-1
    return conflicts

def neighbor(grid):
    new_grid = grid[:]

    i = random.choice(range(G_SIZE))
    j = random.choice(range(G_SIZE))
    new_cells = [-1, 0, 1]
    new_cells.remove(new_grid[i][j])
    new_grid[i][j] = random.choice(new_cells)

    return new_grid

def acceptance_probability(old_cost, new_cost, T):
    if new_cost < old_cost: return 1.0
    return exp(-(new_cost - old_cost) / T)


# Initial guess
for i in range(1, G_SIZE):
    for j in range(0, i):
        grid[i][j] = -1

#print(grid)

old_cost = count_conflict(grid)
T = 10.0
T_min = 0.1
alpha = 0.99
while T > T_min:
    for i in range(1000):
        new_sol = neighbor(grid)
        new_cost = count_conflict(new_sol)
        ap = acceptance_probability(old_cost, new_cost, T)
        print(old_cost, new_cost, ap, T)
        if ap > random.random():
            grid = new_sol
            old_cost = new_cost

    T *= alpha

for row in grid:
    print(row)

print(count_conflict(grid))

【问题讨论】:

  • 不知何故,我认为基本问题应该张贴在数学问题板上,因为您似乎可以将此问题转换为一组具有多个变量的链接方程,从而转换为矩阵计算。
  • 我很确定 SA 不提供任何找到全局最小值的保证。你掷骰子的次数越多,在某些情况下,你就越有可能找到它。使用您的冷却配置文件。这是你必须半手动完成的事情,至少一开始是这样。您能否将您的例程与已知事物进行比较 - 为什么不与 scipy.optimize.anneal 并行运行并比较行为。
  • @uhoh 我已经修改了一些参数,但程序通常在未达到预期目标时停止。由于模拟退火适用于 N 皇后问题,我希望它可以在这里工作。
  • 小心你所说的“作品”。您必须仔细查看它的运行方式、起始案例的数量、温度等。SA 可以工作不工作,具体取决于细节。如果您改用 3D NumPy 数组,您也可以尝试并行运行 100 个案例。只是。
  • 一般来说,不存在可以保证找到全局最优值的算法。

标签: python constraints heuristics simulated-annealing


【解决方案1】:

首先要做一些事情,这可能会很快引导您找到可行的解决方案,而无需执行任何其他操作(例如,交换启发式):

  • 在主迭代循环的顶部附近添加一行,以 计算你的 t0 状态的成本(即你的起始 配置);
  • 在主循环中,在 计算当前迭代成本的行——写 到文件,成本函数返回的值 迭代;在其下方添加一行,每 20 次打印一次该值 迭代或类似的东西(例如,大约每秒一次 与我们理解滚动数据一样快)

    如果 n % 10 == 0:打印(what_cost_fn_returned_this_iteration)

  • 不要调用acceptance_probability;没有自然收敛 组合优化问题的准则;通常的做法 是在发生这些情况时跳出主循环:

    已达到最大迭代次数

    成本函数的当前最小值 过去 __ 次迭代的变化小于 __%;例如 如果在过去 100 次迭代中,成本(通过比较 min 和 max 使用移动窗口)变化小于 1%

    在迭代过程中达到最小值后,现在的成本是 随着迭代次数不断增加


其他一些观察

  • 有了诊断程序(见上文),您将能够 确定:(i)从一些初始成本,我的求解器在做什么? IE, 它是否正朝着越来越低的价值或多或少的直接路径移动? 是不是在震荡?是在增加吗? (如果是后者,解决方法是 通常你有一个向后的标志)

  • 一个 6 x 6 的矩阵非常非常小——不会留下太多的
    使用的成本函数

  • 重新编写成本函数,以便“完美”的解决方案返回一个
    零成本,其他都有更高的价值

  • 1000 次迭代并不多;尝试将其增加到 50,000

【讨论】:

  • 第一点不是用old_cost = count_conflict(grid)完成了吗?
  • 没有acceptance_probability,温度还能用吗?
【解决方案2】:

new_grid = grid[:] 进行浅拷贝。深层复制或修改网格并恢复为原始网格可以解决问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多