码迷,mamicode.com
首页 > 编程语言 > 详细

[python] 简单遗传算法与粒子群算法

时间:2020-06-30 22:43:24      阅读:68      评论:0      收藏:0      [点我收藏+]

标签:range   point   for   pytho   min   pen   改善   alc   探索   

遺伝的アルゴリズム

問題の説明

遺伝的アルゴリズムを使用し、下記の関数の最大化及び最小化を実現しなさい。
ただし、x1、x2、x3の取り得る値は0~15とし、それぞれの遺伝子型は4ビットのビット列で表現すること。
選択、交叉、突然変異のパラメータは各自の自由とする。
群の個体数は100とし、100世代まで進化させた際の、1~100世代における最良解のy値をグラフで示しなさい。選択、交叉、突然変異のパラメータも記載すること。

このプロジェクトでは、遺伝的アルゴリズムをいくつかの小さな部分に分割し、それらを個別に実装する予定です。
実行シーケンスは、遺伝子の初期化 → ベストバリュー計算 → 100回の繰り返し。
繰り返しは一点交叉 → 突然変異 → 適応度計算 → ベストバリュー計算 → 出力 → 選択で構成されます。

y=2x1^2-3x2^2-4x1+5x2+x3

適応度は上記の式で表されます

グローバル変数を宣言する

num = 100         # 個体数
iteration = 100   # 世代数
Pc = 0.3          # 交叉確率
Pm = 0.05         # 突然変異確率

データ構造

100 * 13リストを作成して、0?11番目は3 * 4ビットの変数を格納し、12番目は適合度を格納します。

[[0,1,0,0,0,1,1,1,0,1,0,0,133] ,
 [0,1,0,0,0,1,1,1,0,1,0,0,123] ,
        … 合計100個 … 
 [0,1,0,0,0,1,1,1,0,1,0,0,223] ,
 [0,1,0,0,0,1,1,1,0,1,0,0,233]]

初期世代の構造関数はランダム関数を呼び出し、ランダムに各ビットの0/1を生成します。次に、適応度計算関数を呼び出し、リストの12番目の場所に入力します。

ci = []
    for i in range(num):  # 初期世代の個体群を構造
        temp = []
        for j in range(12):
            temp.append(rand(0.5))
        temp.append(calculate(temp))
        ci.append(temp)

関数の実装

ランダム関数
import random
def rand(a):
    if random.random() < a:
        return 1
    else:
        return 0
適応度計算関数
def calculate(lb):
    x1 = lb[0]*8 + lb[1]*4 + lb[2]*2 + lb[3]
    x2 = lb[4]*8 + lb[5]*4 + lb[6]*2 + lb[7]
    x3 = lb[8]*8 + lb[9]*4 + lb[10]*2 + lb[11]
    return 2*x1*x1 - 3*x2*x2 - 4*x1 + 5*x2 + x3
出力関数
def show(lb, ni):
    sum_l = 0
    max_l = 0
    min_l = 0
    for i in range(num):
        sum_l = sum_l + lb[i][12]
        if lb[i][12] > lb[max_l][12]:
            max_l = i
        if lb[i][12] < lb[min_l][12]:
            min_l = i
    sum_l = sum_l / num
    print(ni, ":平均値", sum_l, ",最大値", lb[max_l], ",最小値", lb[min_l])
ベストバリュー計算
  • 最大値計算

    def cal_max(lb):
        max_l = 0
        for i in range(num):
            if lb[i][12] > lb[max_l][12]:
                max_l = i
        return lb[max_l][12]
    
  • 最小値計算

    def cal_min(lb):
        min_l = 0
        for i in range(num):
            if lb[i][12] < lb[min_l][12]:
                min_l = i
        return lb[min_l][12]
    

コア関数の実装

一点交叉関数

一点交叉関数は100の遺伝子をランダムに50ペアに一致させ、特定の確率(このプログラムでは0.3に設定)で一点交叉を実行し、クロスポイントはランダムです。

def cross(lb):
    tmp = []  # 個体の利用フラグ
    for i in range(num):
        tmp.append(False)
    for i in range(int(num/2)):
        p1 = random.randint(0, num-1)  # 親p1を決定
        while tmp[p1]:
            p1 = random.randint(0, num-1)
        tmp[p1] = True
        p2 = random.randint(0, num-1)  # 親p2を決定
        while tmp[p2]:
            p2 = random.randint(0, num-1)
        tmp[p2] = True
        point = random.randint(0, 11)  # 交叉点を決定
        if rand(Pc) == 1:
            for j in range(point):
                t = lb[p1][j]
                lb[p1][j] = lb[p2][j]
                lb[p2][j] = t
        return lb
突然変異関数

突然変異関数に奇妙なbugが含まれています。リストで各ヘリターを直接操作した場合、10回を超える反復の後、ある操作がすると、操作された遺伝子はすべての遺伝子に自分自身をコピーします。 bugの原因は見つかりませんでしたが、新しいリストを作成してbugを回避するために戻るだけで済みました。

def accident(lb):
    temp = []  # 新しいリストを作成
    for i in range(num):
        a = []
        for j in range(0, 12):  # すべての遺伝子のすべてを通過する
            if rand(Pm) == 1:  # 0-1の間の変換は、特定の確率で発生します
                a.append((1 + lb[i][j]) % 2)
            else:
                a.append(lb[i][j])
        a.append(0)
        temp.append(a)
    return temp
選択関数

最初に、各遺伝子の適応度を計算して正規化し、対応する数の遺伝子をリストに入力しました。乱数0 ≤ n < sumである限り、対応するインデックスにアクセスと、対応する遺伝子を取得します。

def select_max(lb):
    min_l = cal_min(lb)  # 最小値計算
    sum_l = 0
    temp_l = []
    ci_l = []
    for i in range(num):  # 正規化
        lb[i][12] = lb[i][12] + abs(min_l)
        sum_l = sum_l + lb[i][12]
        for j in range(lb[i][12]):
            temp_l.append(lb[i])
    if sum_l is 0:
        return lb
    for i in range(num):  # リストを生成する
        a = random.randint(0, sum_l-1)
        ci_l.append(temp_l[a])  # 対応するインデックスにアクセス
    return ci_l

ただし、リストアイテムを大量に追加する必要があるため、このアプローチのリスト生成速度は遅すぎます。 そのため、この状況に合わせて最適化されました。代わりに、100項目のリストを使用して、各遺伝子サブの適応度+以前のすべての遺伝子サブの適応度の合計を記録し、リストを後でたどりました。 乱数より大きい数値が表示された場合、それは選択する必要があるインデックス番号です。

def select_max(lb):
    min_l = cal_min(lb)  # 最小値計算
    sum_l = 0
    temp_l = []
    ci_l = []
    for i in range(num):  # 正規化
        lb[i][12] = lb[i][12] + abs(min_l)
        sum_l = sum_l + lb[i][12]
        temp_l.append(sum_l)
    for i in range(num):  # リストを生成する
        a = random.random() * sum_l
        for j in range(num):
            if a < temp_l[j]:
                ci_l.append(lb[j])  # 対応するインデックスにアクセス
                break
    return ci_l

そのような最適化の後、操作速度は大幅に改善されます

演算結果

最大を見つける
1 : 平均値 -86.14 , 最大値 15 1 13 , 最小値 2 15 4
2 : 平均値 4.4 , 最大値 15 1 13 , 最小値 3 15 10
3 : 平均値 24.49 , 最大値 15 0 6 , 最小値 3 14 9
4 : 平均値 94.56 , 最大値 15 0 11 , 最小値 1 14 2
5 : 平均値 125.34 , 最大値 15 0 14 , 最小値 9 15 0
6 : 平均値 164.72 , 最大値 15 0 10 , 最小値 9 15 9
7 : 平均値 197.09 , 最大値 15 0 14 , 最小値 4 12 10
8 : 平均値 215.71 , 最大値 15 2 15 , 最小値 9 12 8
9 : 平均値 253.02 , 最大値 15 0 13 , 最小値 1 5 9
10 : 平均値 256.97 , 最大値 15 0 13 , 最小値 7 12 13
11 : 平均値 272.89 , 最大値 15 0 15 , 最小値 14 14 11
12 : 平均値 263.58 , 最大値 15 0 15 , 最小値 7 15 3
13 : 平均値 255.41 , 最大値 15 1 15 , 最小値 15 15 11
14 : 平均値 269.75 , 最大値 15 1 15 , 最小値 12 14 11
15 : 平均値 266.94 , 最大値 15 0 15 , 最小値 7 12 12
16 : 平均値 257.24 , 最大値 15 0 15 , 最小値 3 5 13
17 : 平均値 291.26 , 最大値 15 1 13 , 最小値 7 6 14
18 : 平均値 288.23 , 最大値 15 1 13 , 最小値 14 13 1
19 : 平均値 270.99 , 最大値 15 1 13 , 最小値 13 14 11
20 : 平均値 267.73 , 最大値 15 1 13 , 最小値 2 9 11
21 : 平均値 262.81 , 最大値 15 0 13 , 最小値 9 12 0
22 : 平均値 265.99 , 最大値 15 0 13 , 最小値 7 14 11
23 : 平均値 263.43 , 最大値 15 1 14 , 最小値 6 13 1
24 : 平均値 255.39 , 最大値 15 0 12 , 最小値 8 13 5
25 : 平均値 271.49 , 最大値 15 1 14 , 最小値 14 13 8
26 : 平均値 257.18 , 最大値 15 0 12 , 最小値 13 15 0
27 : 平均値 243.53 , 最大値 15 0 12 , 最小値 5 12 8
28 : 平均値 253.7 , 最大値 15 0 13 , 最小値 7 14 14
29 : 平均値 246.05 , 最大値 15 1 6 , 最小値 15 15 0
30 : 平均値 260.21 , 最大値 15 2 14 , 最小値 13 15 11
31 : 平均値 249.38 , 最大値 15 2 14 , 最小値 3 14 12
32 : 平均値 246.18 , 最大値 15 2 14 , 最小値 15 15 2
33 : 平均値 260.36 , 最大値 15 2 14 , 最小値 13 14 11
34 : 平均値 239.45 , 最大値 15 2 13 , 最小値 10 12 4
35 : 平均値 237.81 , 最大値 15 2 13 , 最小値 11 13 7
36 : 平均値 237.08 , 最大値 15 1 12 , 最小値 5 7 4
37 : 平均値 265.21 , 最大値 15 2 15 , 最小値 14 14 5
38 : 平均値 271.42 , 最大値 15 1 11 , 最小値 12 14 10
39 : 平均値 288.8 , 最大値 15 1 13 , 最小値 7 7 14
40 : 平均値 279.2 , 最大値 15 1 14 , 最小値 14 12 1
41 : 平均値 290.35 , 最大値 15 1 14 , 最小値 7 10 9
42 : 平均値 298.95 , 最大値 15 1 14 , 最小値 7 9 9
43 : 平均値 273.21 , 最大値 15 1 15 , 最小値 11 14 12
44 : 平均値 296.45 , 最大値 15 1 15 , 最小値 3 8 8
45 : 平均値 283.2 , 最大値 15 1 15 , 最小値 14 14 7
46 : 平均値 288.22 , 最大値 15 0 15 , 最小値 6 6 7
47 : 平均値 293.06 , 最大値 15 1 15 , 最小値 7 6 15
48 : 平均値 288.76 , 最大値 15 0 15 , 最小値 7 11 11
49 : 平均値 298.55 , 最大値 15 1 14 , 最小値 14 14 5
50 : 平均値 296.83 , 最大値 15 1 14 , 最小値 11 12 11
51 : 平均値 267.88 , 最大値 15 1 13 , 最小値 12 14 6
52 : 平均値 246.19 , 最大値 15 2 15 , 最小値 14 15 13
53 : 平均値 257.11 , 最大値 15 0 14 , 最小値 14 15 10
54 : 平均値 276.37 , 最大値 15 2 15 , 最小値 11 15 14
55 : 平均値 240.25 , 最大値 15 1 14 , 最小値 1 6 1
56 : 平均値 259.25 , 最大値 15 1 14 , 最小値 14 15 10
57 : 平均値 260.02 , 最大値 15 1 14 , 最小値 6 13 1
58 : 平均値 269.05 , 最大値 15 1 12 , 最小値 13 14 5
59 : 平均値 271.16 , 最大値 15 1 12 , 最小値 15 15 8
60 : 平均値 269.82 , 最大値 15 1 14 , 最小値 7 11 0
61 : 平均値 273.94 , 最大値 15 1 14 , 最小値 6 11 12
62 : 平均値 267.44 , 最大値 15 1 14 , 最小値 13 15 13
63 : 平均値 292.45 , 最大値 15 1 14 , 最小値 7 4 2
64 : 平均値 278.96 , 最大値 15 0 14 , 最小値 14 13 2
65 : 平均値 260.95 , 最大値 15 1 12 , 最小値 6 11 3
66 : 平均値 255.04 , 最大値 15 1 14 , 最小値 14 13 10
67 : 平均値 264.48 , 最大値 15 1 14 , 最小値 6 14 3
68 : 平均値 267.67 , 最大値 15 1 14 , 最小値 6 9 10
69 : 平均値 281.47 , 最大値 15 1 14 , 最小値 15 15 12
70 : 平均値 281.71 , 最大値 15 1 14 , 最小値 9 11 8
71 : 平均値 264.98 , 最大値 15 1 12 , 最小値 14 15 6
72 : 平均値 265.07 , 最大値 15 1 13 , 最小値 13 15 4
73 : 平均値 267.13 , 最大値 15 1 12 , 最小値 9 12 13
74 : 平均値 281.34 , 最大値 15 1 14 , 最小値 13 15 4
75 : 平均値 273.73 , 最大値 15 1 14 , 最小値 9 10 9
76 : 平均値 294.49 , 最大値 15 1 14 , 最小値 9 14 9
77 : 平均値 293.32 , 最大値 15 1 14 , 最小値 8 15 8
78 : 平均値 272.92 , 最大値 15 1 14 , 最小値 4 8 5
79 : 平均値 286.8 , 最大値 15 1 14 , 最小値 7 10 0
80 : 平均値 299.35 , 最大値 15 1 14 , 最小値 6 9 12
81 : 平均値 285.55 , 最大値 15 1 14 , 最小値 15 15 3
82 : 平均値 280.27 , 最大値 15 1 14 , 最小値 15 14 0
83 : 平均値 267.84 , 最大値 15 1 15 , 最小値 11 11 15
84 : 平均値 277.02 , 最大値 15 1 15 , 最小値 5 9 7
85 : 平均値 267.05 , 最大値 15 1 15 , 最小値 7 11 11
86 : 平均値 268.56 , 最大値 15 1 15 , 最小値 9 9 6
87 : 平均値 269.93 , 最大値 15 1 15 , 最小値 7 13 14
88 : 平均値 290.83 , 最大値 15 1 15 , 最小値 7 10 12
89 : 平均値 287.12 , 最大値 15 1 15 , 最小値 11 11 6
90 : 平均値 307.94 , 最大値 15 1 15 , 最小値 15 14 9
91 : 平均値 291.02 , 最大値 15 1 15 , 最小値 11 12 8
92 : 平均値 290.77 , 最大値 15 1 15 , 最小値 6 7 13
93 : 平均値 276.55 , 最大値 15 1 15 , 最小値 9 9 15
94 : 平均値 306.53 , 最大値 15 1 15 , 最小値 7 9 9
95 : 平均値 301.99 , 最大値 15 1 15 , 最小値 7 11 4
96 : 平均値 290.15 , 最大値 15 1 15 , 最小値 9 12 12
97 : 平均値 289.04 , 最大値 15 1 15 , 最小値 1 10 12
98 : 平均値 285.86 , 最大値 15 1 15 , 最小値 5 5 6
99 : 平均値 276.47 , 最大値 15 1 15 , 最小値 11 14 1
100 : 平均値 284.85 , 最大値 15 1 15 , 最小値 4 8 6
最大値は: 407 です
最小を見つける
1 : 平均値 -77.74 , 最大値 14 1 8 , 最小値 3 15 6
2 : 平均値 -187.7 , 最大値 11 2 12 , 最小値 1 15 11
3 : 平均値 -257.01 , 最大値 11 4 7 , 最小値 1 15 11
4 : 平均値 -321.24 , 最大値 13 9 15 , 最小値 1 15 3
5 : 平均値 -351.15 , 最大値 8 2 2 , 最小値 2 15 1
6 : 平均値 -389.09 , 最大値 14 6 5 , 最小値 2 15 1
7 : 平均値 -411.3 , 最大値 11 8 9 , 最小値 1 15 1
8 : 平均値 -400.56 , 最大値 6 4 4 , 最小値 2 15 1
9 : 平均値 -391.36 , 最大値 11 5 14 , 最小値 1 15 3
10 : 平均値 -371.05 , 最大値 11 3 11 , 最小値 1 15 1
11 : 平均値 -401.58 , 最大値 15 12 14 , 最小値 1 15 7
12 : 平均値 -425.69 , 最大値 3 7 11 , 最小値 2 15 5
13 : 平均値 -420.51 , 最大値 5 0 1 , 最小値 1 15 6
14 : 平均値 -444.87 , 最大値 7 7 12 , 最小値 2 15 2
15 : 平均値 -428.34 , 最大値 10 7 2 , 最小値 1 15 0
16 : 平均値 -435.0 , 最大値 14 9 2 , 最小値 1 15 1
17 : 平均値 -428.14 , 最大値 8 7 12 , 最小値 1 15 1
18 : 平均値 -480.21 , 最大値 3 6 2 , 最小値 1 15 1
19 : 平均値 -432.8 , 最大値 15 7 6 , 最小値 1 15 1
20 : 平均値 -415.34 , 最大値 15 7 7 , 最小値 1 15 2
21 : 平均値 -441.3 , 最大値 11 7 0 , 最小値 1 15 2
22 : 平均値 -419.79 , 最大値 9 1 10 , 最小値 1 15 2
23 : 平均値 -437.17 , 最大値 10 6 10 , 最小値 1 15 2
24 : 平均値 -462.87 , 最大値 15 11 11 , 最小値 1 15 1
25 : 平均値 -440.88 , 最大値 10 7 9 , 最小値 0 15 0
26 : 平均値 -405.39 , 最大値 14 5 11 , 最小値 1 15 1
27 : 平均値 -434.42 , 最大値 14 7 8 , 最小値 1 15 0
28 : 平均値 -442.73 , 最大値 13 7 11 , 最小値 1 15 0
29 : 平均値 -429.37 , 最大値 6 3 3 , 最小値 1 15 2
30 : 平均値 -423.1 , 最大値 12 6 8 , 最小値 1 15 2
31 : 平均値 -432.83 , 最大値 9 7 15 , 最小値 1 15 0
32 : 平均値 -449.45 , 最大値 5 2 0 , 最小値 1 15 0
33 : 平均値 -438.95 , 最大値 7 6 3 , 最小値 1 15 0
34 : 平均値 -453.62 , 最大値 10 7 14 , 最小値 1 15 0
35 : 平均値 -461.67 , 最大値 12 9 7 , 最小値 1 15 0
36 : 平均値 -456.97 , 最大値 13 7 15 , 最小値 1 15 0
37 : 平均値 -489.36 , 最大値 5 6 2 , 最小値 1 15 0
38 : 平均値 -459.12 , 最大値 1 3 0 , 最小値 1 15 0
39 : 平均値 -491.9 , 最大値 9 7 13 , 最小値 1 15 0
40 : 平均値 -481.82 , 最大値 9 6 8 , 最小値 1 15 0
41 : 平均値 -475.63 , 最大値 13 7 0 , 最小値 1 15 0
42 : 平均値 -479.99 , 最大値 11 5 8 , 最小値 1 15 0
43 : 平均値 -474.5 , 最大値 0 3 2 , 最小値 1 15 0
44 : 平均値 -460.77 , 最大値 13 7 11 , 最小値 1 15 0
45 : 平均値 -476.18 , 最大値 6 6 0 , 最小値 1 15 0
46 : 平均値 -497.66 , 最大値 5 7 11 , 最小値 1 15 0
47 : 平均値 -495.33 , 最大値 1 3 0 , 最小値 1 15 0
48 : 平均値 -493.76 , 最大値 7 3 9 , 最小値 1 15 0
49 : 平均値 -473.62 , 最大値 12 7 0 , 最小値 1 15 0
50 : 平均値 -457.96 , 最大値 2 4 9 , 最小値 1 15 0
51 : 平均値 -475.4 , 最大値 5 6 13 , 最小値 1 15 0
52 : 平均値 -457.61 , 最大値 4 3 7 , 最小値 1 15 0
53 : 平均値 -450.48 , 最大値 9 7 1 , 最小値 1 15 0
54 : 平均値 -463.83 , 最大値 6 5 9 , 最小値 1 15 0
55 : 平均値 -478.52 , 最大値 9 7 1 , 最小値 1 15 0
56 : 平均値 -489.0 , 最大値 6 7 9 , 最小値 1 15 0
57 : 平均値 -471.68 , 最大値 11 7 6 , 最小値 1 15 0
58 : 平均値 -456.63 , 最大値 10 7 5 , 最小値 1 15 0
59 : 平均値 -455.26 , 最大値 10 7 13 , 最小値 1 15 0
60 : 平均値 -466.83 , 最大値 11 6 12 , 最小値 1 15 0
61 : 平均値 -482.53 , 最大値 5 7 7 , 最小値 1 15 0
62 : 平均値 -474.0 , 最大値 9 5 15 , 最小値 1 15 0
63 : 平均値 -478.58 , 最大値 7 6 12 , 最小値 1 15 0
64 : 平均値 -493.78 , 最大値 3 2 8 , 最小値 1 15 2
65 : 平均値 -481.1 , 最大値 9 5 4 , 最小値 1 15 2
66 : 平均値 -463.97 , 最大値 14 11 5 , 最小値 0 15 0
67 : 平均値 -470.84 , 最大値 2 5 14 , 最小値 2 15 3
68 : 平均値 -451.24 , 最大値 12 7 1 , 最小値 1 15 1
69 : 平均値 -489.47 , 最大値 0 1 8 , 最小値 1 15 0
70 : 平均値 -513.98 , 最大値 9 5 15 , 最小値 1 15 0
71 : 平均値 -491.74 , 最大値 2 3 3 , 最小値 1 15 0
72 : 平均値 -475.63 , 最大値 2 3 10 , 最小値 1 15 0
73 : 平均値 -464.65 , 最大値 5 3 0 , 最小値 1 15 0
74 : 平均値 -487.96 , 最大値 10 7 9 , 最小値 1 15 0
75 : 平均値 -484.62 , 最大値 1 6 8 , 最小値 1 15 0
76 : 平均値 -464.15 , 最大値 14 11 12 , 最小値 1 15 0
77 : 平均値 -428.86 , 最大値 15 11 2 , 最小値 1 15 1
78 : 平均値 -478.03 , 最大値 9 4 12 , 最小値 1 15 1
79 : 平均値 -482.3 , 最大値 0 5 14 , 最小値 1 15 1
80 : 平均値 -458.75 , 最大値 9 5 12 , 最小値 1 15 0
81 : 平均値 -445.12 , 最大値 13 4 11 , 最小値 1 15 0
82 : 平均値 -421.97 , 最大値 14 3 14 , 最小値 1 15 0
83 : 平均値 -408.07 , 最大値 9 7 0 , 最小値 1 15 0
84 : 平均値 -445.73 , 最大値 13 10 11 , 最小値 1 15 0
85 : 平均値 -417.5 , 最大値 13 7 12 , 最小値 1 15 0
86 : 平均値 -437.89 , 最大値 14 7 2 , 最小値 1 15 0
87 : 平均値 -412.38 , 最大値 13 5 7 , 最小値 1 15 0
88 : 平均値 -435.58 , 最大値 8 7 1 , 最小値 0 15 0
89 : 平均値 -432.28 , 最大値 11 6 1 , 最小値 2 15 0
90 : 平均値 -445.06 , 最大値 4 3 1 , 最小値 1 15 1
91 : 平均値 -440.91 , 最大値 9 7 0 , 最小値 1 15 1
92 : 平均値 -456.21 , 最大値 1 2 13 , 最小値 1 15 1
93 : 平均値 -446.63 , 最大値 9 7 4 , 最小値 1 15 1
94 : 平均値 -444.54 , 最大値 13 7 8 , 最小値 2 15 2
95 : 平均値 -425.98 , 最大値 4 4 12 , 最小値 0 15 1
96 : 平均値 -450.8 , 最大値 8 7 8 , 最小値 1 15 1
97 : 平均値 -467.01 , 最大値 14 10 12 , 最小値 0 15 2
98 : 平均値 -461.93 , 最大値 6 6 4 , 最小値 2 15 2
99 : 平均値 -465.24 , 最大値 6 2 0 , 最小値 0 15 2
100 : 平均値 -442.72 , 最大値 13 6 9 , 最小値 0 15 2
最小値は: -602 です

Process finished with exit code 0

粒子群最適化

問題の説明

上記の最適化問題を、粒子群最適化法を用いて解きなさい。
各パラメータは各自の自由とする。
粒子の数は100とし、100回目まで更新させた際の、1~100世代における最良解の値をグラフで示しなさい。

このプロジェクトでは、最大値または最小値を探索するための機能を含む、全ての粒子のためのPSOクラスを作成します。
主な機能には、我々は、粒子群として100個の粒子を作成し、各移動後の最善の解決策を見つけると、全ての粒子の運動機能を呼び出す必要があります。

y=2x1^2-3x2^2-4x1+5x2+x3

適応度は上記の式で表されます

クラス構造

初期化中にすべてのプライベート変数を宣言する

def __init__(self, c1=2, c2=2, w=1):
    self.w = w  # 慣性定数
    self.v0 = 0  # 探索個体の初速度
    self.v1 = 0
    self.v2 = 0
    self.x0 = random.randint(0, 15)  # 探索個体の位置
    self.x1 = random.randint(0, 15)
    self.x2 = random.randint(0, 15)
    self.y = calculate(self.x0, self.x1, self.x2)
    self.c1 = c1  # 学習係数
    self.c2 = c2
    self.p = [self.x0, self.x1, self.x2, self.y]  # 探索個体の最良位置

関数宣言、gは最適解の位置です

go(self, g)
go_max(self, g)
go_min(self, g)

関数の実装

適応度計算
def calculate(x0, x1, x2):  # 適応度
    return 2 * x0 * x0 - 3 * x1 * x1 - 4 * x0 + 5 * x1 + x2
探索関数
  1. 計算速度

    v = wv + c1r1(Gbest - x) + c2r2(Pbest - x)

  2. 計算場所

    x = x + v

def go(self, g):  # 探索関数
    # 計算速度
    self.v0 = self.w * self.v0 + self.c1 * random.random() * (g[0] - self.x0) + self.c2 * random.random() * (
                self.p[0] - self.x0)
    self.v1 = self.w * self.v1 + self.c1 * random.random() * (g[1] - self.x1) + self.c2 * random.random() * (
                self.p[1] - self.x1)
    self.v2 = self.w * self.v2 + self.c1 * random.random() * (g[2] - self.x2) + self.c2 * random.random() * (
                self.p[2] - self.x2)
    # 計算場所
    self.x0 = self.x0 + self.v0  # 限られた値の範囲
    if self.x0 > 15:
        self.x0 = 15
    elif self.x0 < 0:
        self.x0 = 0
    self.x1 = self.x1 + self.v1
    if self.x1 > 15:
        self.x1 = 15
    elif self.x1 < 0:
        self.x1 = 0
    self.x2 = self.x2 + self.v2
    if self.x2 > 15:
        self.x2 = 15
    elif self.x2 < 0:
        self.x2 = 0
    self.y = calculate(self.x0, self.x1, self.x2)  # 計算適応度
探索個体の最良位置
def go_max(self, g):
    self.go(g)
    if self.y > self.p[3]:
        self.p = [self.x0, self.x1, self.x2, self.y]  # 自分の最適な位置を更新する

def go_min(self, g):
    self.go(g)
    if self.y < self.p[3]:
        self.p = [self.x0, self.x1, self.x2, self.y]  # 自分の最適な位置を更新する
出力

より良い解決策がない場合、それは出力されません

for j in range(100):
    show = False
    for i in range(100):
        a[i].go_min(best)
        if a[i].y < best[3]:
            best = a[i].p
            show = True
    if show:
        print(best)

演算結果

c1 = 2
c2 = 2
w = 1

最大を見つける
[15, 0.374963944391387, 15, 406.4530258431763]
[15, 0.8919276768891968, 15, 407.07303344204314]
[15, 0.8348837178082772, 15, 407.0833261222573]
[15, 0.8321133497489408, 15, 407.0833288682535]
[15, 0.8330926190723068, 15, 407.08333315950324]
[15, 0.8335237214448654, 15, 407.08333322459043]
[15, 0.8334223377156362, 15, 407.083333309568]
最大値は: 407.083333309568 です
最小を見つける
[0.8964719926138809, 15, 0, -601.9785639033732]
[1.0132336239397892, 15, 0, -601.9996497423948]
[0.9902767087255728, 15, 0, -601.9998109152135]
[0.9925054520072736, 15, 0, -601.9998876635008]
[1.0010034789381652, 15, 0.0, -601.9999979860601]
[0.9996368213014294, 15, 0, -601.9999997362025]
[0.9996987995938881, 15, 0, -601.9999998185566]
最小値は: -601.9999998185566 です

Process finished with exit code 0

c1 = 2
c2 = 2
w = 2

最大を見つける
[15, 0.8623157788455933, 15, 407.08081338688976]
[15.0, 0.8618974100967376, 15, 407.08088561388934]
[15, 0.8459074975515879, 15, 407.082859004516]
最大値は: 407.082859004516 です
最小を見つける
[0.8479086047155134, 15, 0, -601.9537364149609]
[1.0394032279942933, 15, 0, -601.9968947712472]
最小値は: -601.9968947712472 です

遺伝的アルゴリズム.py

import random

num = 100         # 個体数
iteration = 100   # 世代数
Pc = 0.3          # 交叉確率
Pm = 0.05         # 突然変異確率


def rand(a):
    if random.random() < a:
        return 1
    else:
        return 0


def calculate(lb):
    x1 = lb[0]*8 + lb[1]*4 + lb[2]*2 + lb[3]
    x2 = lb[4]*8 + lb[5]*4 + lb[6]*2 + lb[7]
    x3 = lb[8]*8 + lb[9]*4 + lb[10]*2 + lb[11]
    return 2*x1*x1 - 3*x2*x2 - 4*x1 + 5*x2 + x3


def show(lb, ni):
    sum_l = 0  # 和
    max_l = 0  # 最大値
    min_l = 0  # 最小値
    for i in range(num):
        sum_l = sum_l + lb[i][12]
        if lb[i][12] > lb[max_l][12]:
            max_l = i
        if lb[i][12] < lb[min_l][12]:
            min_l = i
    sum_l = sum_l / num
    max_x1 = lb[max_l][0]*8 + lb[max_l][1]*4 + lb[max_l][2]*2 + lb[max_l][3]
    max_x2 = lb[max_l][4]*8 + lb[max_l][5]*4 + lb[max_l][6]*2 + lb[max_l][7]
    max_x3 = lb[max_l][8]*8 + lb[max_l][9]*4 + lb[max_l][10]*2 + lb[max_l][11]
    min_x1 = lb[min_l][0]*8 + lb[min_l][1]*4 + lb[min_l][2]*2 + lb[min_l][3]
    min_x2 = lb[min_l][4]*8 + lb[min_l][5]*4 + lb[min_l][6]*2 + lb[min_l][7]
    min_x3 = lb[min_l][8]*8 + lb[min_l][9]*4 + lb[min_l][10]*2 + lb[min_l][11]
    print(ni, ": 平均値", sum_l, ", 最大値", max_x1, max_x2, max_x3, ", 最小値", min_x1, min_x2, min_x3)


def cal_max(lb):
    max_l = 0
    for i in range(num):
        if lb[i][12] > lb[max_l][12]:
            max_l = i
    return lb[max_l][12]


def cal_min(lb):
    min_l = 0
    for i in range(num):
        if lb[i][12] < lb[min_l][12]:
            min_l = i
    return lb[min_l][12]


def cross(lb):
    tmp = []  # 個体の利用フラグ
    for i in range(num):
        tmp.append(False)
    for i in range(int(num/2)):
        p1 = random.randint(0, num-1)  # 親p1を決定
        while tmp[p1]:
            p1 = random.randint(0, num-1)
        tmp[p1] = True
        p2 = random.randint(0, num-1)  # 親p2を決定
        while tmp[p2]:
            p2 = random.randint(0, num-1)
        tmp[p2] = True
        point = random.randint(0, 11)  # 交叉点を決定
        if rand(Pc) == 1:
            for j in range(point):
                t = lb[p1][j]
                lb[p1][j] = lb[p2][j]
                lb[p2][j] = t
        return lb


def accident(lb):
    temp = []  # 新しいリストを作成
    for i in range(num):
        a = []
        for j in range(0, 12):  # すべての遺伝子のすべてを通過する
            if rand(Pm) == 1:  # 0-1の間の変換は、特定の確率で発生します
                a.append((1 + lb[i][j]) % 2)
            else:
                a.append(lb[i][j])
        a.append(0)
        temp.append(a)
    return temp


def select_max(lb):
    min_l = cal_min(lb)  # 最小値計算
    sum_l = 0
    temp_l = []
    ci_l = []
    for i in range(num):  # 正規化
        lb[i][12] = lb[i][12] + abs(min_l)
        sum_l = sum_l + lb[i][12]
        temp_l.append(sum_l)
    for i in range(num):  # リストを生成する
        a = random.random() * sum_l
        for j in range(num):
            if a < temp_l[j]:
                ci_l.append(lb[j])  # 対応するインデックスにアクセス
                break
    return ci_l


def select_min(lb):
    max_l = cal_max(lb)  # 最大値計算
    sum_l = 0
    temp_l = []
    ci_l = []
    for i in range(num):  # 正規化
        lb[i][12] = abs(lb[i][12] - abs(max_l))
        sum_l = sum_l + lb[i][12]
        temp_l.append(sum_l)
    for i in range(num):  # リストを生成する
        a = random.random() * sum_l
        for j in range(num):
            if a < temp_l[j]:
                ci_l.append(lb[j])  # 対応するインデックスにアクセス
                break
    return ci_l


def go_max():
    ci = []
    for i in range(num):  # 初期世代の個体群を構造
        temp = []
        for j in range(12):
            temp.append(rand(0.5))
        temp.append(calculate(temp))
        ci.append(temp)
    max_g = cal_max(ci)
    # 迭代100次
    g = 0
    while g < iteration:
        ci = cross(ci)
        ci = accident(ci)
        for j in range(num):  # 重新计算
            ci[j][12] = calculate(ci[j])
        now = cal_max(ci)
        if max_g < now:
            max_g = now
        g = g + 1
        show(ci, g)
        ci = select_max(ci)
    print("最大値は:", max_g, "です")


def go_min():
    ci = []
    for i in range(num):   # 初期世代の個体群を構造
        temp = []
        for j in range(12):
            temp.append(rand(0.5))
        temp.append(calculate(temp))
        ci.append(temp)
    min_g = cal_min(ci)
    # 迭代100次
    g = 0
    while g < iteration:
        ci = cross(ci)
        ci = accident(ci)
        for j in range(num):  # 重新计算
            ci[j][12] = calculate(ci[j])
        now = cal_min(ci)
        if min_g > now:
            min_g = now
        g = g + 1
        show(ci, g)
        ci = select_min(ci)
    print("最小値は:", min_g, "です")


print("最大を見つける")
go_max()
print("最小を見つける")
go_min()

粒子群最適化.py

import random


def calculate(x0, x1, x2):  # 適応度
    return 2 * x0 * x0 - 3 * x1 * x1 - 4 * x0 + 5 * x1 + x2


class PSO:
    def __init__(self, c1=2, c2=2, w=2):
        self.w = w  # 慣性定数
        self.v0 = 0  # 探索個体の初速度
        self.v1 = 0
        self.v2 = 0
        self.x0 = random.randint(0, 15)  # 探索個体の位置
        self.x1 = random.randint(0, 15)
        self.x2 = random.randint(0, 15)
        self.y = calculate(self.x0, self.x1, self.x2)
        self.c1 = c1  # 学習係数
        self.c2 = c2
        self.p = [self.x0, self.x1, self.x2, self.y]  # 探索個体の最良位置

    def go(self, g):  # 探索関数
        # 計算速度
        self.v0 = self.w * self.v0 + self.c1 * random.random() * (g[0] - self.x0) + self.c2 * random.random() * (
                    self.p[0] - self.x0)
        self.v1 = self.w * self.v1 + self.c1 * random.random() * (g[1] - self.x1) + self.c2 * random.random() * (
                    self.p[1] - self.x1)
        self.v2 = self.w * self.v2 + self.c1 * random.random() * (g[2] - self.x2) + self.c2 * random.random() * (
                    self.p[2] - self.x2)
        # 計算場所
        self.x0 = self.x0 + self.v0  # 限られた値の範囲
        if self.x0 > 15:
            self.x0 = 15
        elif self.x0 < 0:
            self.x0 = 0
        self.x1 = self.x1 + self.v1
        if self.x1 > 15:
            self.x1 = 15
        elif self.x1 < 0:
            self.x1 = 0
        self.x2 = self.x2 + self.v2
        if self.x2 > 15:
            self.x2 = 15
        elif self.x2 < 0:
            self.x2 = 0
        self.y = calculate(self.x0, self.x1, self.x2)  # 計算適応度

    def go_max(self, g):
        self.go(g)
        if self.y > self.p[3]:
            self.p = [self.x0, self.x1, self.x2, self.y]  # 自分の最適な位置を更新する

    def go_min(self, g):
        self.go(g)
        if self.y < self.p[3]:
            self.p = [self.x0, self.x1, self.x2, self.y]  # 自分の最適な位置を更新する


print("最大を見つける")
a = []
k = 0
best = []

for i in range(100):  # 初期粒子群を構造
    a.append(PSO())
    if a[k].y < a[i].y:
        k = i
best = a[k].p  # 最良解の値
for j in range(100):
    show = False
    for i in range(100):
        a[i].go_max(best)
        if a[i].y > best[3]:
            best = a[i].p
            show = True
    if show:
        print(best)
print("最大値は:", best[3], "です")

a = []
k = 0
best = []

print("最小を見つける")
for i in range(100):
    a.append(PSO())
    if a[k].y > a[i].y:
        k = i
best = a[k].p
for j in range(100):
    show = False
    for i in range(100):
        a[i].go_min(best)
        if a[i].y < best[3]:
            best = a[i].p
            show = True
    if show:
        print(best)
print("最小値は:", best[3], "です")

[python] 简单遗传算法与粒子群算法

标签:range   point   for   pytho   min   pen   改善   alc   探索   

原文地址:https://www.cnblogs.com/winng/p/inherit.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!