遺伝子アルゴリズム(アニメーション) | python3Xのブログ

python3Xのブログ

ここでは40代、50代の方が日々の生活で役に立つ情報や私の趣味であるプログラム、Excelや科学に関する内容で投稿する予定です。

まだ完成形ではないようですが、面白いと思って紹介させていただきます。

URL:http://mosirobo.blogspot.com/2014/12/blog-post.html

# -+- coding: utf-8 -*-
import random #ランダムモジュール
import math
import copy
import numpy as np
import pylab
import matplotlib.pyplot as plt
import matplotlib.animation as animation
 
def city_init():
    #都市座標(30個)
    citylist_x = [2,10,7,32,35,9,28,3,8,5,13,45,63,11,17,34,55,38,41,15,6,53,46,18,23,16,19,27,42,12]
    citylist_y = [36,22,47,41,32,24,15,2,25,28,48,5,11,16,27,8,46,35,58,14,26,21,49,34,1,7,19,43,29,39]
 
    return [citylist_x,citylist_y]
 
##評価関数
def eval_func(gean):
    x,y =city_init()
    x_cp = list(x)
    y_cp = list(y)
##    print x
    #a,b,c,d,e,f,のうち行った都市は消していく
    #c,e,a,f,d,bの順で回る場合は
    #[2,3,0,2,1,0]となる
    ##gean = [2, 3, 1, 1, 0]
    ##gean = [2,4,1,3,0]

    gean_decode = []
    geannum = 0
    while geannum<=len(gean)-1:
        num = x.index(x_cp[gean[geannum]])
        gean_decode.append(num)
        del x_cp[gean[geannum]]
        geannum +=1
    #評価の基準は距離が短いことである。
    dist_stok = []
    geannum = 0
    while geannum<=len(gean)-2:
        dist = (x[gean_decode[geannum+1]]-x[gean_decode[geannum]])**2 + (y[gean_decode[geannum+1]]-y[gean_decode[geannum]])**2
        dist_stok.append(dist)
        geannum +=1
    alldistance = sum(dist_stok)
 
    last_dist = (x[gean_decode[len(gean)-1]]-x[gean_decode[0]])**2 + (y[gean_decode[len(gean)-1]]-y[gean_decode[0]])**2
    alldistance = alldistance + last_dist
##    print(alldistance)
    return alldistance
 
 
def geneticoptimize(maxiter = 100,maximize = False,popsize = 50,popnum = 30,elite = 0.99,mutprob =0.2):  
    """
    maxiter = 1, 繰り返し数
    maximize = False,    スコアを最小化する
    popsize = 50,   個体数
    popnum = 30,    遺伝子数(長さ)都市の数
    elite = 0.2,    生き残る遺伝子の割合
    mutprob =0.2    突然変異のおこる確立
    """
    # 突然変異

    def mutate(vec):
        i = random.SystemRandom().randint(0,popnum-1)
        after_mut = random.randint(0,popnum-i-1)
        return vec[:i] + [after_mut]+vec[i+1:]
 
     # 1点交叉 非推奨
    def one_point_crossover(r1,r2):
        i = random.SystemRandom().randint(1,popnum-2)
 
        return random.SystemRandom().choice((r1[0:i] + r2[i:], r2[0:i] + r1[i:]))
 
    # 2点交叉
    def two_point_crossover(r1,r2):
        i, j = sorted(random.SystemRandom().sample(range(popnum),2))
        return random.SystemRandom().choice((r1[0:i] + r2[i:j] + r1[j:] , r2[0:i] + r1[i:j] + r2[j:]))
 
    # 一様交叉
    def uniform_crossover(r1, r2):
        q1 = copy.copy(r1)
        q2 = copy.copy(r2)
        for i in range(len(r1)):
            if random.SystemRandom().random() < 0.5:
                q1[i], q2[i] = q2[i], q1[i]
 
        return random.SystemRandom().choice([q1,q2])
    def anime_flam(gean):
        copy_x = list(citylist_x)
        copy_y = list(citylist_y)
        ordercity_x =[]
        ordercity_y =[]
        for i in gean[0][1]:
            ordercity_x.append(copy_x[i])
            ordercity_y.append(copy_y[i])
            del copy_x[i],copy_y[i]
        return ordercity_x,ordercity_y
    #遺伝子の初期化
    pop = []
    vec = []
    for i in range(popsize):
        selected_city = 1
        while selected_city <= popnum:
            vec_vec = random.SystemRandom().randint(0,popnum-selected_city)
            vec.append(vec_vec)
            selected_city +=1
        pop.append(list(vec))   #listはコピーを渡さないと変更元まで変更される
        del vec[:]
 
    # 交叉アルゴリズムの選択(2点交差を選択)
    crossover = two_point_crossover
    #crossover = uniform_crossover
 
    #メインループ
    topelite = int(elite * popsize)
    score_stoc = []
    citylist_x,citylist_y = city_init()
    fig = plt.figure(figsize=(8, 5))
    ax1=fig.add_subplot(1,2,1)
    ax2=fig.add_subplot(1,2,2)
    ims = []
    im2_pointset =[]
    for i in range(maxiter):
        scores=[(eval_func(v),v) for v in pop]
        scores.sort()
        if maximize:
            scores.reverse()
        ranked = [v for (s,v) in scores]
        # 弱い遺伝子は淘汰される
##        pop = ranked[0:topelite]

        eliminate_cycle = 0
 
        while eliminate_cycle < popsize:
            if eliminate_cycle == 0:
                pop = ranked[:1]
            else:
                if random.SystemRandom().random() < elite**eliminate_cycle:
                    pop.append(ranked[eliminate_cycle])
            eliminate_cycle +=1
        topelite = len(pop)
        # 生き残った遺伝子同士で交叉したり突然変異したり
        while len(pop) < popsize:
            if random.SystemRandom().random() < mutprob:
                # 突然変異
                c = random.SystemRandom().randint(0,topelite)
                pop.append(mutate(ranked[c]))
                if random.SystemRandom().random() < mutprob:
                    selected_city = 1
                    while selected_city <= popnum:
                        vec_vec = random.SystemRandom().randint(0,popnum-selected_city)
                        vec.append(vec_vec)
                        selected_city +=1
                    pop.append(list(vec))
                    del vec[:]
            else:
                # 交叉
                c1 = random.SystemRandom().randint(0,topelite)
                c2 = random.SystemRandom().randint(0,topelite)
                pop.append(crossover(ranked[c1],ranked[c2]))
        # 暫定の値を出力
        
        score_stoc.append(scores[0][0])
        #scores[0]はスコアと遺伝子(トップの)
        #scores[0][0]はスコア
        #scores[0][1]は遺伝子

        x,y = anime_flam(scores)
        #ordercityは暫定での訪問順
 
        im, = ax1.plot(x,y,'o-m')
        im2, = ax2.plot(score_stoc[0:i],'o-c')
 
        #plotの場合は変数にカンマを付ける
        ims.append([im,im2])
    ani = animation.ArtistAnimation(fig, ims, interval=1,blit=True, repeat_delay=0)
    plt.show()
    return scores[0]

 
def main():
    x,y =city_init()
    ans = geneticoptimize()
    ans_x = []
    ans_y = []
    print("Ans:",ans)
    for i in ans[1]:
        ans_x.append(x[i])
        ans_y.append(y[i])
        del x[i],y[i]
 
 
if __name__ == '__main__':
    main()

================================================================================

途中で中断してしまったのですが

Ans: (17960, [20, 17, 12, 14, 0, 9, 10, 10, 21, 7, 19, 2, 12, 12, 11, 7, 4, 10, 5, 10, 1, 5, 4, 1, 3, 0, 0, 2, 1, 0])