模拟退火不会返回(a)最优解

时间:2016-01-07 07:19:53

标签: python constraints heuristics simulated-annealing

我决定学习模拟退火作为攻击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))

2 个答案:

答案 0 :(得分:1)

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

  • 在主迭代循环外部的顶部附近添加一行到 计算你的t0状态的成本(即你的开始 配置);
  • 在主循环内部,插入一个单独的print语句 计算当前迭代成本的行 - 写入 到文件,由cost函数返回的值 迭代;在下面添加一行,每隔20次打印一次该值 迭代或类似的东西(例如,大约每秒一次 我们可以理解滚动数据的速度一样快

    如果n%10 == 0:print(what_cost_fn_returned_this_iteration)

  • 不要调用acceptance_probability ;没有自然的趋同 组合优化问题的准则;通常的做法 当任何这些发生时,是打破主循环:

    已达到最大迭代次数

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

    在迭代期间达到最小值后,现在成本 随着迭代次数不断增加

其他一些观察

  • 使用诊断程序(见上文),您将能够 确定:(i)从一些初始成本来看,我的求解者在做什么?即 它是在一个或多或少的直接路径中移动到更低和更低的值? 它在摆动吗?它在增加吗? (如果是后者,修复是 通常你有倒退的标志)

  • 一个6 x 6矩阵非常小 - 这不会留下很多东西 成本函数与

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

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

答案 1 :(得分:0)

new_grid = grid[:]制作浅层副本。深度复制或修改网格并恢复到原始网格可以解决问题。