シミュレーテッドアニーリングアルゴリズム(SAアルゴリズム)

シミュレーテッドアニーリングアルゴリズムは確率的アルゴリズムであり、必ずしもグローバルな最適解を見つけるとは限りませんが、問題のおおよその最適解を比較的迅速に見つけることができます。パラメータが適切に設定されている場合、シミュレーテッドアニーリングアルゴリズムの検索効率は徹底的な方法よりも高くなります。

1.トピックに入る前に、物理学における固体アニーリングの原理を簡単に紹介しましょう。

熱力学では、アニーリング(アニーリング)とは、物体が徐々に冷える物理現象を指します。温度が低いほど、物体のエネルギー状態は低くなります。十分に低くなると、液体は凝縮して結晶化し始めます。結晶状態では、システムのエネルギー状態が最も低くなります。自然がゆっくりと冷えると(つまり、アニーリング)、最も低いエネルギー状態である結晶化を「見つける」ことができます。ただし、プロセスが速すぎたり速すぎたりすると、急速な冷却(「急冷」とも呼ばれます)により、最低エネルギー状態ではないアモルファス形態になります。

下の写真に示すように、最初(左の写真)のオブジェクトはアモルファス状態です。固体を十分に高いレベルに加熱し(中央の画像)、ゆっくりと冷却してからアニールします(右の画像)。加熱すると、温度上昇に伴って固体の内部粒子が乱れ、内部エネルギーが増加します。ゆっくりと冷却すると、粒子は徐々に規則正しくなり、各温度で平衡状態になり、最終的には室温で基底状態になります。内部エネルギーが減少します。最小です(この時点でオブジェクトは結晶の形で表示されます)。
ここに写真の説明を書いてください

ゆっくりと冷却して、対象の分子が各温度で安定する場所を見つけるのに十分な時間を確保し、最後に最低のエネルギー状態が得られるまで徐々に、システムが最も安定します。

2.その歴史を簡単に紹介します

シミュレーテッドアニーリング(SA)の最も初期のアイデアは、1953年にN.メトロポリス[1]などによって提案されました。1983年、S。Kirkpatrickらは、組み合わせ最適化の分野にアニーリングのアイデアを導入することに成功しました。これは、モンテカルロ反復解法戦略に基づく確率的最適化アルゴリズムであり、その出発点は、物理学における固体のアニーリングプロセスと一般的な組み合わせ最適化問題との類似性に基づいています。シミュレーテッドアニーリングアルゴリズムは、特定のより高い初期温度から開始し、温度パラメーターの継続的な減少と、突然のジャンプ特性の確率を組み合わせて、解空間内の目的関数のグローバル最適解をランダムに見つけます。ローカル最適解は確率的に飛び出してマージすることができ、最終的にはグローバル最適になる傾向があります。
ほぼ同時に、ヨーロッパの物理学者V.カーニーもほぼ同じ結果を発表しましたが、2つは独立して発見されました。カーニーが「不運」であり、当時誰も彼の傑作に気づかなかっただけでした。おそらくそれは言えるでしょう。その「サイエンス」誌は世界的に販売されており、「露出」度が高く、よく知られています。しかし、カーニーは、発行部数の少ない別の特別学術誌「J.Opt.TheoryAppl。」に結果を発表しました。それは十分な注意を喚起しませんでした。
シミュレーテッドアニーリングアルゴリズムは一般的な最適化アルゴリズムであり、理論的には確率的な大域的最適化性能を備えており、VLSI、生産スケジューリング、制御工学、機械学習、ニューラルネットワーク、信号処理などの工学で広く使用されています。
シミュレーテッドアニーリングアルゴリズムは、検索プロセスに時間変化し、最終的にはゼロの確率ジャンプを与える最適化アルゴリズムです。これにより、極小値、最終的にはグローバル最適シリアル構造に陥ることを効果的に回避できます。

3.焼きなまし法

アニーリングの物理的な意味についてまだ目がくらんでいる場合は、それを理解するためのより簡単な方法があるかどうかは問題ではありません。次の関数があり、関数の(グローバルな)最適解を見つけたいと想像してみてください。
ここに写真の説明を書いてください

1.最初に山登りアルゴリズムを簡単に紹介します(このアルゴリズムには欠陥があります)
シミュレーテッドアニーリングを導入する前に、まず山登りアルゴリズムを紹介します。山登りアルゴリズムは、単純な欲張り探索アルゴリズムであり、局所的な最適解に到達するまで、毎回、現在の解の隣接する解空間から最適解を現在の解として選択します。

山登りアルゴリズムは実装が非常に簡単であり、その主な欠点は、ローカルの最適解に分類されることであり、必ずしもグローバルな最適解を検索できるとは限りません。開始点がA(山登りアルゴリズム)であると仮定すると、点Bに到達すると、プロセスは終了します。Bも左もそれより低い点に移動できないため、現時点ではグローバルな最適解を見つけることができません。

2.シミュレーテッドアニーリングアルゴリズム
欲張り戦略が採用されている場合は、ポイントAから試行を開始し、関数値が減少し続ける場合は、試行プロセスが続行されます。そして、ポイントBに到達すると、明らかに探索プロセスは終了します(どちらの方向に取り組んでも、結果はどんどん大きくなるだけです)。結局、部分的な最終解Bしか見つけることができません。(上記の山登りアルゴリズムと同じ)

シミュレーテッドアニーリングは実際には欲張りアルゴリズムですが、その検索プロセスではランダムな要素が導入されます。シミュレーテッドアニーリングアルゴリズムは、特定の確率で現在の解よりも悪い解を受け入れるため、この局所的な最適解から飛び出して、グローバルな最適解に到達する可能性があります。上の図を例にとると、シミュレーテッドアニーリングアルゴリズムが局所最適解Bを検索した後、一定の確率で右に移動し続けます。おそらく、局所的に最適ではないそのようないくつかの動きの後、BとCの間のピーク点に到達し、局所的な最小値Bが飛び出します。

メトロポリス基準によれば、粒子が温度Tで平衡になる確率は、exp(-ΔE/(kT))です。ここで、Eは温度Tでの内部エネルギー、ΔEは変化の数、kはボルツマン定数です。メトロポリス基準は、
ここに写真の説明を書いてください
メトロポリス基準として表されることがよくあります。これは、温度が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とその減衰係数Δt、tの各値での反復回数L、および停止条件Sを含む冷却スケジュールによって制御されます。

要約すれば:

(1)f(Y(i + 1))<= f(Y(i))の場合(つまり、移動後により良い解が得られる場合)、移動は常に受け入れられます。
(2)f(Y(Y( i + 1)))> f(Y(i))(つまり、移動後の解が現在の解よりも悪い)、一定の確率で移動が受け入れられ、この確率は時間の経過とともに徐々に減少します(徐々に)安定するために減少します)、これは上記と同等です。図では、BからBC間の小さなピークに移動すると、右にシフトする(つまり、より悪い値を受け入れる)確率が徐々に減少します。このスロープが特に長い場合、最終的にこのスロープを登らない可能性が非常に高くなります。長すぎない場合は、減衰量tの設定によっては転倒する可能性があります。

通常の欲張りアルゴリズムとシミュレーテッドアニーリングに関して、興味深い類似点があります。

(1)通常の欲張りアルゴリズム:ウサギは現在よりも低い場所に向かってジャンプします。それは遠くないところに最も低い谷を見つけました。しかし、この谷は必ずしも最低ではありません。これは通常の欲張りアルゴリズムであり、ローカル最適値がグローバル最適値であることを保証することはできません。
(2)シミュレーテッドアニーリング:ウサギは酔っています。長い間ランダムにジャンプしました。この期間中、それは低くなるか、平らな地面に足を踏み入れるかもしれません。しかし、次第に地味になり、最低方向にジャンプしました。これはシミュレーテッドアニーリングです。

3.シミュレーテッドアニーリングアルゴリズムのモデル

1.シミュレーテッドアニーリングアルゴリズムは解空間目的関数初期解の3つの部分に分解できます
2.シミュレーテッドアニーリングの基本的な考え方:
(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 'を新しい現在の解として受け入れます。それ以外の場合、確率exp(-ΔT/ T)でS'を新しい現在の解決として受け入れます。
(6)終了条件が満たされた場合、現在の解を最適解として出力し、プログラムを終了します。
終了条件は通常、いくつかの連続する新しいソリューションが受け入れられない場合のアルゴリズムの終了と見なされます。
(7)Tが徐々に減少し、T-> 0になったら、手順2に進みます。シミュレーテッドアニーリングアルゴリズムの
3つのステップ
シミュレーテッドアニーリングアルゴリズムの新しいソリューションの生成と受け入れは、次の4つのステップに分けることができます。

最初のステップは、母関数によって現在の解から解空間に新しい解を生成することです。その後の計算と受け入れを容易にし、アルゴリズムの時間消費を減らすために、現在の解から新しい解を生成する方法通常、単純な変換による新しい解が選択されます。たとえば、新しい解を構成する要素の全部または一部の置換と交換など。新しい解を生成する変換方法によって、現在の新しい解の近傍構造が決定されることに注意してください。冷却スケジュールの選択に一定の影響があります。

2番目のステップは、新しい解に対応する目的関数の差を計算することです。目的関数の差は変換部分によってのみ生成されるため、目的関数の差の計算は増分で計算するのが最適です。事実は、ほとんどのアプリケーションで、これが目的関数の差を計算するための最速の方法であることを示しています。

3番目のステップは、新しいソリューションが受け入れられるかどうかを判断することです。判断の基礎は受け入れ基準です。最も一般的に使用される受け入れ基準はメトロポリス基準です。ΔT<0の場合、S 'を新しい現在のソリューションSとして受け入れます。それ以外の場合は、確率exp(-ΔT/ T)S 'を新しい現在の解Sとして受け入れます。

4番目のステップは、新しいソリューションが受け入れられると判断されたときに、現在のソリューションを新しいソリューションに置き換えることです。これは、新しいソリューションが生成されるときに対応する現在のソリューションの変換部分を実現するだけで、同時に目的関数の値を変更します。この時点で、現在のソリューションは1回の反復を達成しています。これに基づいて、次の試行を開始できます。新しいソリューションが破棄されたと判断された場合、次のラウンドの試行は元の現在のソリューションに基づいて続行されます。
シミュレーテッドアニーリングアルゴリズムは初期値とは関係がなく、アルゴリズムによって得られた解は初期解状態S(アルゴリズム反復の開始点)とは関係ありません。シミュレーテッドアニーリングアルゴリズムは漸近収束を持ちます。これは、確率を伴う一種の収束であることが理論的に証明されています。lグローバル最適解のグローバル最適化アルゴリズム。シミュレーテッドアニーリングアルゴリズムは並列です。
ここに写真の説明を書いてください
4.シミュレーテッドアニーリングアルゴリズムの擬似コード

/*
* J(y):在状态y时的评价函数值
* Y(i):表示当前状态
* Y(i+1):表示新的状态
* r: 用于控制降温的快慢
* T: 系统的温度,系统初始应该要处于一个高温的状态
* T_min :温度的下限,若温度T达到T_min,则停止搜索
*/
while( T > T_min )
{
  dE = J( Y(i+1) ) - J( Y(i) ) ; 

  if ( dE >=0 ) //表达移动后得到更优解,则总是接受移动
Y(i+1) = Y(i) ; //接受从Y(i)到Y(i+1)的移动
  else
  {
// 函数exp( dE/T )的取值范围是(0,1) ,dE/T越大,则exp( dE/T )也越大
if ( exp( dE/T ) > random( 0 , 1 ) )
Y(i+1) = Y(i) ; //接受从Y(i)到Y(i+1)的移动
  }
  T = r * T ; //降温退火 ,0<r<1 ,r一般被设置为0.98或0.99等等。r越大,降温越慢;r越小,降温越快
  /*
  * 若r过大,则搜索到全局最优解的可能会较高,但搜索的过程也就较长。若r过小,则搜索的过程会很快,但最终可能会达到一个局部最优值
  */
  i ++ ;
}

4. TSP(巡回セールスマン問題)を解決するためのシミュレーテッドアニーリングアルゴリズム

巡回セールスマン問題(TSP、巡回セールスマン問題):Nの都市があり、問題の1つから開始し、すべての都市を横断するだけで、出発都市に戻って最短ルートを見つける必要があります。(ハミルトン回路)

  巡回セールスマン問題は、いわゆるNP完全問題です。TSPは、すべてのパスの組み合わせを徹底的に列挙することによってのみ正確に解決でき、その時間計算量はO(N!)です。

  シミュレーテッドアニーリングアルゴリズムを使用して、TSPのおおよその最適パスを比較的迅速に見つけることができます。(遺伝的アルゴリズムを使用することも可能です)
  TSPを解決するためのシミュレーテッドアニーリングのアイデア:

  1. 新しいトラバーサルパスP(i + 1)を生成し、パスP(i + 1)の長さL(P(i + 1))を計算します。

  2. L(P(i + 1))<L(P(i))の場合は、新しいパスとしてP(i + 1)を受け入れます。それ以外の場合は、シミュレーテッドアニーリングの確率でP(i + 1)を受け入れてから、冷却します。ダウン

  3. 終了条件が満たされるまで、手順1と2を繰り返します。

      新しいトラバーサルパスを生成する方法はたくさんありますが、そのうちの3つを以下に示します。

  4. 2つのノードをランダムに選択し、パス内のこれら2つのノードの順序を交換します。

  5. 2つのノードをランダムに選択し、パス内のこれら2つのノード間のノードの順序を逆にします。

  6. 3つのノードm、n、kをランダムに選択し、ノードmとnの間のノードをノードkの後ろにシフトします。

#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <stdio.h>
#include <time.h>
#include <math.h>

#define N     30      //城市数量
#define T     3000    //初始温度
#define EPS   1e-8    //终止温度
#define DELTA 0.98    //温度衰减率

#define LIMIT 1000   //概率选择上限
#define OLOOP 20    //外循环次数
#define ILOOP 100   //内循环次数

using namespace std;

//定义路线结构体
struct Path
{
    int citys[N];
    double len;
};

//定义城市点坐标
struct Point
{
    double x, y;
};

Path bestPath;        //记录最优路径
Point p[N];       //每个城市的坐标
double w[N][N];   //两两城市之间路径长度
int nCase;        //测试次数

double dist(Point A, Point B)
{
    return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));
}

void GetDist(Point p[], int n)
{
    for(int i = 0; i < n; i++)
        for(int j = i + 1; j < n; j++)
            w[i][j] = w[j][i] = dist(p[i], p[j]);
}

void Input(Point p[], int &n)
{
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
        scanf("%lf %lf", &p[i].x, &p[i].y);
}

void Init(int n)
{
    nCase = 0;
    bestPath.len = 0;
    for(int i = 0; i < n; i++)
    {
        bestPath.citys[i] = i;
        if(i != n - 1)
        {
            printf("%d--->", i);
            bestPath.len += w[i][i + 1];
        }
        else
            printf("%d\n", i);
    }
    printf("\nInit path length is : %.3lf\n", bestPath.len);
    printf("-----------------------------------\n\n");
}

void Print(Path t, int n)
{
    printf("Path is : ");
    for(int i = 0; i < n; i++)
    {
        if(i != n - 1)
            printf("%d-->", t.citys[i]);
        else
            printf("%d\n", t.citys[i]);
    }
    printf("\nThe path length is : %.3lf\n", t.len);
    printf("-----------------------------------\n\n");
}

Path GetNext(Path p, int n)
{
    Path ans = p;
    int x = (int)(n * (rand() / (RAND_MAX + 1.0)));
    int y = (int)(n * (rand() / (RAND_MAX + 1.0)));
    while(x == y)
    {
        x = (int)(n * (rand() / (RAND_MAX + 1.0)));
        y = (int)(n * (rand() / (RAND_MAX + 1.0)));
    }
    swap(ans.citys[x], ans.citys[y]);
    ans.len = 0;
    for(int i = 0; i < n - 1; i++)
        ans.len += w[ans.citys[i]][ans.citys[i + 1]];
    cout << "nCase = " << nCase << endl;
    Print(ans, n);
    nCase++;
    return ans;
}

void SA(int n)
{
    double t = T;
    srand((unsigned)(time(NULL)));
    Path curPath = bestPath;
    Path newPath = bestPath;
    int P_L = 0;
    int P_F = 0;
    while(1)       //外循环,主要更新参数t,模拟退火过程
    {
        for(int i = 0; i < ILOOP; i++)    //内循环,寻找在一定温度下的最优值
        {
            newPath = GetNext(curPath, n);
            double dE = newPath.len - curPath.len;
            if(dE < 0)   //如果找到更优值,直接更新
            {
                curPath = newPath;
                P_L = 0;
                P_F = 0;
            }
            else
            {
                double rd = rand() / (RAND_MAX + 1.0);
                //如果找到比当前更差的解,以一定概率接受该解,并且这个概率会越来越小
                if(exp(dE / t) > rd && exp(dE / t) < 1)
                    curPath = newPath;
                P_L++;
            }
            if(P_L > LIMIT)
            {
                P_F++;
                break;
            }
        }
        if(curPath.len < bestPath.len)
            bestPath = curPath;
        if(P_F > OLOOP || t < EPS)
            break;
        t *= DELTA;
    }
}

int main(int argc, const char * argv[]) {

    freopen("TSP.data", "r", stdin);
    int n;
    Input(p, n);
    GetDist(p, n);
    Init(n);
    SA(n);
    Print(bestPath, n);
    printf("Total test times is : %d\n", nCase);
    return 0;
}

5.コンテンツの一般的なソース、参照:

1. http://blog.csdn.net/sci_m3/article/details/51539003
2. https://www.cnblogs.com/ranjiewen/p/6084052.html
3. https://baike.baidu.com/ item /%E6%A8%A1%E6%8B%9F%E9%80%80%E7%81%AB%E7%AE%97%E6%B3%95/355508?fr = aladdin

おすすめ

転載: blog.csdn.net/Puppet__/article/details/79382113