Simulated Annealing

🔥 Vibe Prompt

"Solve TSP with 20 cities using SA. Compare final tour length vs greedy algorithm."

import math, random

cities = [(random.randint(0,100), random.randint(0,100)) for _ in range(20)]

def dist(a, b): return math.sqrt((a[0]-b[0])**2 + (a[1]-b[1])**2)
def tour_len(tour): return sum(dist(tour[i], tour[i+1]) for i in range(-1, len(tour)-1))

def simulated_annealing(cities, temp_start=1000, temp_end=0.01, cooling=0.995):
    tour = cities[:]
    random.shuffle(tour)
    best = tour[:]
    
    temp = temp_start
    while temp > temp_end:
        i, j = sorted(random.sample(range(len(tour)), 2))
        tour[i:j] = reversed(tour[i:j])
        delta = tour_len(tour) - tour_len(best)
        if delta < 0:
            best = tour[:]
        elif random.random() >= math.exp(-delta / temp):
            tour[i:j] = reversed(tour[i:j])  # Undo
        temp *= cooling
    return best

# Compare
greedy = cities[:]
random.shuffle(greedy)
sa_tour = simulated_annealing(cities)

print(f"Greedy: {tour_len(greedy):.0f}")
print(f"SA:     {tour_len(sa_tour):.0f}")
print(f"Improvement: {(1-tour_len(sa_tour)/tour_len(greedy))*100:.1f}%")

Applications

  • VLSI circuit layout
  • Job shop scheduling
  • Protein folding
  • Airport gate assignment

Key Points

  • Understand the core concepts thoroughly
  • Practice with hands-on code examples
  • Apply knowledge to real-world problems
  • Review and reinforce through exercises

Further Learning

  • Official documentation
  • Open source projects on GitHub
  • Community forums and discussions
  • Related courses and tutorials

模擬退火的靈感來源:金屬冶煉

Simulated Annealing 的名字來自冶金學中的退火 (Annealing) 過程:

  1. 加熱:將金屬加熱到高溫,原子獲得能量後可以自由移動(進入高能量狀態)
  2. 保溫:維持高溫一段時間,讓原子有機會重新排列
  3. 緩慢冷卻:以非常緩慢的速度降溫,原子逐漸固定在能量最低的排列方式

如果降溫太快(淬火 Quenching),原子來不及找到最低能量排列,會卡在一個較高能量的狀態——金屬會變脆。

SA 完全對應了這個過程:

  • 高溫:演算法可以自由跳到更差的解(探索)
  • 緩慢降溫:逐漸減少接受差解的機率
  • 低溫:收斂到局部最佳解

為什麼 SA 在 TSP 上這麼有效?

旅行推銷員問題 (TSP) 的搜尋空間是 (n-1)!/2——20 個城市就有約 6×10¹⁶ 種可能路徑。暴力搜尋不可能,貪婪演算法容易找到很差的路徑。

SA 用一種精巧的方式平衡了探索與利用:

| 溫度階段 | 行為 | 比喻 | |:--------:|------|------| | 高溫 (T=1000) | 幾乎接受任何新解(好壞都收) | 到處亂逛,了解地形 | | 中溫 (T=10) | 只接受稍微差一點的解 | 找到大概方向,開始往下走 | | 低溫 (T=0.1) | 幾乎只接受更好的解 | 精細調整,確保是最低點 | | 極低溫 (T<0.01) | 不接受任何差解 | 鎖定最佳解 |

什麼時候該用 SA?

| 場景 | 適合度 | 原因 | |:----:|:------:|------| | TSP 與路徑規劃 | ✅ 非常適合 | SA 對排列問題的鄰居搜尋很有效率 | | 連續函數最佳化 | ✅ 適合 | 搭配高斯擾動即可,但 PSO 通常更快 | | 晶片佈局設計 | ✅ 業界標準 | 晶片設計從 80 年代就開始用 SA | | 影像處理 | ✅ 可使用 | 影像分割、匹配等 | | 神經網路訓練 | ❌ 不適合 | Adam 等梯度方法快太多了 | | 需要保證最佳解 | ❌ 不適合 | SA 是機率性演算法,不保證最佳 |

下一章預告:從一個解到一群解

模擬退火一次只維護一個解,逐步降溫收斂。下一章的 遺傳演算法 (GA) 則採取完全不同的策略——維護一群解,讓它們透過選擇、交叉、突變來演化。

如果說 SA 是一個登山者摸索下山的路,那 GA 就是同時派出 100 個登山者,彼此分享資訊,最後一起找到山谷。不同的策略,適合不同的問題。

解鎖完整教學內容

本章為付費內容。加入專案即可解鎖超過 5000 字的深度解析,包含 10 個以上神級 Prompt 與真實 Source Code 範例!