0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

GAによる巡回セールスマン問題の最適化

Last updated at Posted at 2023-06-04

GA(遺伝的アルゴリズム)は最適化手法の一つで、選択、交叉、突然変異を繰り返すことによる最適化を行うアルゴリズムです。

リポジトリはこちら
https://github.com/hinahina-chips/GA-TSP/tree/main

まずは総距離の短い順にソートしておきます。

以下の操作に従って実装します。

  • 選択:エリート選択。上位半分を選択。
void select_gene1(){
	long i, j;
    for(i = 0; i < NUM_GENE; i++){
        for(j = 0; j < NUM_CITY; j++) Gene[i][j] = Gene[i % (NUM_GENE / 2)][j]; //上位半分をコピー
    }
}
  • 交叉:適当に交叉させると同じ都市(City)が同じ経路(Gene)に含まれるということが起こるため、マスク交叉を行う。
void kousa_gene_pair(long p1[], long p2[]){
    long mask[NUM_CITY];
	long num_mask;
    long i, j, n = 0;
	num_mask = 0;
	mask[0] = 300;//nになり得ない適当な値を初期値として格納
    for(i = 0;; i++){
        n = num_where(p1, p2[n]); //P2[n]の都市がp1のどの要素番号か返す関数num_where
        if(mask[0] == n) break; //既出の要素番号が出たら終了
        mask[num_mask] = n; //mask配列に格納
        num_mask++;//mask配列の要素をインクリメント
    }
    ex_kousa(p1, p2, mask, num_mask);//交叉用の交換関数
}
  • 突然変異:一定確率でランダムに入れ替える
void mutate_gene_each(long i, long j){
	long n, m, k;
	n = Gene[i][j];
	for(;;){
		m = rand() % NUM_CITY;
		if (m != n) break;
	}

	Gene[i][j] = m;
	
	for(k = 0; k < NUM_CITY; k++){
		if(Gene[i][k] == m) break;
	}
	Gene[i][k] = n;
}

とはいってもGAのみでは10都市くらいの小規模な巡回セールスマン問題しか解けませんでした。そこで以下の処理を追加しました。

  • 前世代の最適経路と総距離を保存し、現世代の最適経路と比較して良い方を残す

  • ローカルサーチを実装して交差している経路を無くす(元論文があるんですけど前すぎて見つからんかった...)

void local_gene(){
    long i,j;
    long p[NUM_CITY];
    long p_bef[NUM_CITY];

    for(i = 0; i < NUM_GENE; i++){
        for(j = 0; j < NUM_CITY; j++){
            p[j] = Gene[i][j];	//遺伝子情報を1次元配列pに一時的に格納
            p_bef[j] = Gene[i][j];
        }

        local_each(p);

        for(j = 0; j < NUM_CITY; j++){
        	Gene[i][j] = p[j];//一次元配列pをGeneに戻す
        }
    if (F_local == 1){
   	    fprintf(Fp_deb, "before local_sort in local_each\n"); 
   	    for (j = 0; j < NUM_CITY; j++) fprintf(Fp_deb, "%ld", p_bef[j]);
   	    fprintf(Fp_deb, "\n");
   	    
		fprintf(Fp_deb, "after local_sort in local_each\n"); 
		output_gene(i);
		
	}
	
	
	}
	
}

void local_each(long p[]){
    long i, j, g, k;
    double vii, v_ij, vij, vjj;
	

    
	for(i = 0; i < NUM_CITY-2; i++){
        for(j = i+2; j < NUM_CITY; j++){
            
            vij = kyori(p[i], p[j]);
            v_ij =kyori(p[i + 1], p[(j + 1) % NUM_CITY]);
            vii = kyori(p[i], p[i + 1]);
            vjj = kyori(p[j], p[(j + 1) % NUM_CITY]);
            
            if((vij + v_ij) < (vii + vjj)) {
            	F_local = 1;
				local_sort( i+1, j, p);//localサーチの条件	
		    }
				
		}
	}		
}
  • 後半は突然変異の処理確率を減らす

結果

image.png

image.png

ローカルサーチを入れたおかげでどちらも交差点はなくなっていますね。最適化も進んでいるのでGAは有効であるということが分かります。面白い...

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?