## 0 コンテストのアイデア
(コンテストの質問が出たらすぐに CSDN で共有します)
https://blog.csdn.net/dc_sinor?type=blog
1 アニーリングアルゴリズムの原理
1.1 物理的背景
熱力学におけるアニーリング現象は、物体が徐々に冷える物理現象を指します。温度が低くなるほど、物体のエネルギー状態は低くなります。温度が十分に低くなると、液体は凝縮して結晶化し始めます。状態では、システムのエネルギー状態が最低になります。自然はゆっくりと冷える(つまりアニールする)と、エネルギーが最も低い状態、つまり結晶化を「見つける」ことができます。ただし、プロセスが速すぎると、急速冷却 (「急冷」とも呼ばれます) により、最低エネルギー状態ではない非晶質状態が生じます。
以下の図に示すように、最初 (左) のオブジェクトはアモルファス状態にあります。固体を十分に高い温度まで加熱し (中央の画像)、ゆっくりと冷却するかアニールします (右の画像)。加熱すると、温度の上昇とともに固体内部の粒子が乱れ内部エネルギーが増加しますが、ゆっくりと冷却すると粒子は徐々に整い、各温度で平衡状態に達し、最終的には室温で基底状態に達します。温度が上昇すると内部エネルギーが減少し、その値が最も小さくなります(この時点で物体は結晶の形で現れます)。
1.2 背後にある数学モデル
アニーリングの物理的意味についてまだ混乱している場合は、それを理解するためのより簡単な方法があるかどうかは問題ではありません。次のような関数があり、その関数の (全体的な) 最適解を見つけたいと考えていると想像してください。貪欲戦略が採用されている場合は、ポイント A からテストを開始し、関数値が減少し続ける場合はテスト プロセスが続行されます。そして、点 B に到達すると、明らかに探索プロセスは終了します (どの方向に頑張っても、結果はますます大きくなるからです)。結局のところ、部分的な最終解 B しか見つかりません。
Metropolis の基準によると、粒子が温度 T でバランスする傾向にある確率は exp(-ΔE/(kT)) です。ここで、E は温度 T での内部エネルギー、ΔE はその変化数、k はボルツマン定数です。大都市基準は、次のように表現されることがよくあります。
Metropolis 基準は、温度が T のとき、エネルギー差 dE による温度低下の確率は P(dE) であり、次のように表されることを示します。 P(dE) = exp( dE/(kT) )。ここで、k は定数、exp は自然指数を表し、dE<0 です。したがって、P と T は正の相関関係にあります。この式は、温度が高いほど、エネルギー差 dE による温度低下の確率が大きくなり、温度が低いほど、温度低下の確率が小さくなるということを意味します。また、dE は常に 0 未満であるため (アニーリング プロセスは徐々に温度を下げるプロセスであるため)、dE/kT < 0 となるため、P(dE) の関数値の範囲は (0,1) になります。温度 T が低下すると、P(dE) は徐々に減少します。
より悪い解への移行を温度上昇プロセスと見なし、そのような移行を確率 P(dE) で受け入れます。つまり、固体アニーリングを使用して組み合わせ最適化問題をシミュレートする場合、内部エネルギー E が目的関数値 f としてシミュレートされ、温度 T が制御パラメータ t、つまり、これを解くためのシミュレーテッド アニーリング アルゴリズムに展開されます。組み合わせ最適化問題は、初期解 i と制御から得られます。 パラメーター t の初期値から開始して、現在の解について「新しい解の生成→目的関数の差の計算→受け入れるか破棄する」の繰り返しを繰り返します。アルゴリズムが終了するときの現在の解は、モンテカルロ反復解法のヒューリスティック ランダム探索手順に基づいて得られた近似最適解です。アニーリングプロセスは、制御パラメータの初期値 t とその減衰係数 Δt、反復回数 L、各 t 値に対する停止条件 S を含む冷却スケジュール (Cooling Schedule) によって制御されます。
2 アニーリングアルゴリズムの実装
2.1 アルゴリズム処理
(1) 初期化: 初期温度 T (十分に大きい)、初期解状態 S (アルゴリズム反復の開始点)、各 T 値の反復回数 L (2) k=1, ..., L の場合、最初の処理を実行します (3)
) ステップ 6 に進みます:
(3) 新しい解 S' を生成します。
(4) 増分 Δt'=C(S')-C(S) を計算します。ここで、C(S) は評価関数です。 (5
) Δt' の場合<0 の場合は S' を新しい現在解として受け入れ、そうでない場合は S' を新しい現在解として確率 exp(-Δt'/T) で受け入れます
(6) 終了条件が満たされている場合は、現在の解を最適解として出力します。そしてプログラムを終了します。
終了条件は通常、いくつかの連続した新しい解が受け入れられない場合にアルゴリズムを終了するように選択されます。
(7) T が徐々に減少し、T->0 になり、2 番目に移ります。
2.2 アルゴリズムの実装
import numpy as np
import matplotlib.pyplot as plt
import random
class SA(object):
def __init__(self, interval, tab='min', T_max=10000, T_min=1, iterMax=1000, rate=0.95):
self.interval = interval # 给定状态空间 - 即待求解空间
self.T_max = T_max # 初始退火温度 - 温度上限
self.T_min = T_min # 截止退火温度 - 温度下限
self.iterMax = iterMax # 定温内部迭代次数
self.rate = rate # 退火降温速度
#############################################################
self.x_seed = random.uniform(interval[0], interval[1]) # 解空间内的种子
self.tab = tab.strip() # 求解最大值还是最小值的标签: 'min' - 最小值;'max' - 最大值
#############################################################
self.solve() # 完成主体的求解过程
self.display() # 数据可视化展示
def solve(self):
temp = 'deal_' + self.tab # 采用反射方法提取对应的函数
if hasattr(self, temp):
deal = getattr(self, temp)
else:
exit('>>>tab标签传参有误:"min"|"max"<<<')
x1 = self.x_seed
T = self.T_max
while T >= self.T_min:
for i in range(self.iterMax):
f1 = self.func(x1)
delta_x = random.random() * 2 - 1
if x1 + delta_x >= self.interval[0] and x1 + delta_x <= self.interval[1]: # 将随机解束缚在给定状态空间内
x2 = x1 + delta_x
else:
x2 = x1 - delta_x
f2 = self.func(x2)
delta_f = f2 - f1
x1 = deal(x1, x2, delta_f, T)
T *= self.rate
self.x_solu = x1 # 提取最终退火解
def func(self, x): # 状态产生函数 - 即待求解函数
value = np.sin(x**2) * (x**2 - 5*x)
return value
def p_min(self, delta, T): # 计算最小值时,容忍解的状态迁移概率
probability = np.exp(-delta/T)
return probability
def p_max(self, delta, T):
probability = np.exp(delta/T) # 计算最大值时,容忍解的状态迁移概率
return probability
def deal_min(self, x1, x2, delta, T):
if delta < 0: # 更优解
return x2
else: # 容忍解
P = self.p_min(delta, T)
if P > random.random(): return x2
else: return x1
def deal_max(self, x1, x2, delta, T):
if delta > 0: # 更优解
return x2
else: # 容忍解
P = self.p_max(delta, T)
if P > random.random(): return x2
else: return x1
def display(self):
print('seed: {}\nsolution: {}'.format(self.x_seed, self.x_solu))
plt.figure(figsize=(6, 4))
x = np.linspace(self.interval[0], self.interval[1], 300)
y = self.func(x)
plt.plot(x, y, 'g-', label='function')
plt.plot(self.x_seed, self.func(self.x_seed), 'bo', label='seed')
plt.plot(self.x_solu, self.func(self.x_solu), 'r*', label='solution')
plt.title('solution = {}'.format(self.x_solu))
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.savefig('SA.png', dpi=500)
plt.show()
plt.close()
if __name__ == '__main__':
SA([-5, 5], 'max')
結果を達成する