# -*- coding: UTF-8 -*-
import sys
from math import *
from random import *
from datetime import *
import numpy as np
######################
# クラスSpeciesの定義
######################
class Species :
#########################
# コンストラクタ
# name : ファイル名
#########################
def __init__(self, name) :
# データの入力
inn = open(name, "r")
s = inn.readline().split()
self.allele_u = int(s[1]) # 対立遺伝子上限
self.allele_l = int(s[3]) # 対立遺伝子下限
s = inn.readline().split()
self.max_len = int(s[1]) # 最大遺伝子長
self.min_len = int(s[3]) # 最小遺伝子長(負の時は,最大遺伝子長で固定)
s = inn.readline().split()
self.dup_a = int(s[1]) # 遺伝子の重複
# =0 : 重複を許さない
# =1 : 重複を許す
self.dup_s = int(s[3]) # 個体の重複(同じ染色体の個体)
# =0 : 重複を許さない
# =1 : 重複を許す
s = inn.readline().split()
self.size = int(s[1]) # 個体総数
self.max_ch = int(s[3]) # 子供の数の最大値
# データのチェック
if self.size <= 0 :
print("***error 個体総数≦0 (Constructor)")
if self.max_ch < 0 :
print("***error 子供の数<0 (Constructor)")
if self.max_len <= 0 or self.min_len == 0 :
print("***error 遺伝子長≦0 (Constructor)")
if self.max_len < self.min_len :
print("***error 最大遺伝子長<最小遺伝子長 (Constructor)")
if self.allele_u <= self.allele_l :
print("***error 対立遺伝子上限≦対立遺伝子下限 (Constructor)")
kind = self.allele_u - self.allele_l + 1
if self.dup_a == 0 and self.max_len > kind :
print("***error 遺伝子の重複を防ぐことはできない (Constructor)")
# 領域の確保
num = self.size + self.max_ch
self.ind = np.empty((num, self.max_len), np.int) # 集団(個体の集まり)
self.edge = np.empty((self.max_len, 5), np.int) # エッジ組み替え交叉用ワークエリア
self.pi = np.empty(num, np.float) # 適応度
self.ro = np.empty(num, np.float) # ルーレット板
self.len = np.empty(num, np.int) # 各個体の遺伝子長
self.kou1 = np.empty(self.max_len, np.int) # 交叉・突然変異用作業場所1
self.kou2 = np.empty(self.max_len, np.int) # 交叉・突然変異用作業場所2
self.s_w = np.empty(num, np.int) # 淘汰用指標(選択された回数)
self.pi_w = np.empty(num, np.int) # 適応度計算指標
# =0 : 未使用
# =1 : 適応度計算前(突然変異はこの個体だけに適用)
# =2 : 適応度計算済み(交叉時に親とみなす)
self.max = -inf # 最大適応度
self.mean = 0.0 # 平均適応度
self.max_n = -1 # 最大適応度の個体番号
##################################################
# 場所を探す
# n : >=0 : n番目の親を捜す
# -1 : 空いている場所を探す
# return : 親の場所,または,空いている場所
# (存在しないときは負の値)
##################################################
def Position(self, n) :
k = -1
sw = 0
# 空いている場所を探す
if n < 0 :
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] == 0 :
k = i1
break
if k < 0 :
print("***error 空いている場所がない --Position--")
# n番目の親(pi_w[i]=2)を捜す
else :
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] == 2 :
k += 1
if k == n :
sw = 1
k = i1
break
return k
###################################################################
# 個体の選択
# method : 選択方法
# =-1 : ランダム(default)
# =0 : 適応度をそのまま使用
# =1 : 最小値からの差(ただし,α以下の場合はα)
# =2 : 評価値に順位をつけ,減少率βで線形化
# bias : α,または,method=2の場合は初期値(default=0)
# step : β(default=1)
# return : 個体番号
###################################################################
def Select(self, method, bias, step) :
sum = 0.0
# ルーレット板の用意
# ランダム
if method == -1 :
n = 0
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] > 1 :
n += 1
sum = 1.0 / n
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] > 1 :
self.ro[i1] = sum
# 評価値をそのまま利用
elif method == 0 :
n = 0
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] > 1 :
sum += self.pi[i1]
n += 1
if fabs(sum) > 1.0e-10 :
sum = 1.0 / fabs(sum)
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] > 1 :
self.ro[i1] = self.pi[i1] * sum
else :
sum = 1.0 / n
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] > 1 :
self.ro[i1] = sum
# 最小値からの差
elif method == 1 :
min = -1
n = 0
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] > 1 :
n += 1
if min < 0 or self.pi[i1] < self.pi[min] :
min = i1
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] > 1 :
self.ro[i1] = self.pi[i1] - self.pi[min]
if self.ro[i1] < bias :
self.ro[i1] = bias
sum += self.ro[i1]
if sum > 1.0e-10 :
sum = 1.0 / sum
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] > 1 :
self.ro[i1] *= sum
else :
sum = 1.0 / n
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] > 1 :
self.ro[i1] = sum
# 線形化
elif method == 2 :
n = 0
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] > 1 :
self.ro[i1] = -1.0
n += 1
else :
self.ro[i1] = 1.0
sw = 0
sum = bias
while sw == 0 :
min = -1
for i1 in range(0, self.size+self.max_ch) :
if self.ro[i1] < 0.0 and (min < 0 or self.pi[i1] < self.pi[min]) :
min = i1
if min < 0 :
sw = 1
else :
self.ro[min] = sum
sum += self.step
sum = 1.0 / (0.5 * (2.0 * bias + step * (n - 1)) * n)
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] > 1 :
self.ro[i1] *= sum
sum = 0.0
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] > 1 :
sum += self.ro[i1]
self.ro[i1] = sum
# 選択
x = random()
sw = 0
k = 0
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] > 1 :
if x <= self.ro[i1] :
sw = 1
k = i1
break
return k
###################
# 標準的な初期設定
###################
def Init_std(self) :
# 初期設定
for i1 in range(0, self.size+self.max_ch) :
if i1 < self.size :
self.pi_w[i1] = 1 # 適応度の計算前
else :
self.pi_w[i1] = 0 # 未使用
# 遺伝子の決定
for i1 in range(0, self.size) :
sw1 = 0
length = 0
while sw1 == 0 :
# 遺伝子長の決定
if self.min_len < 0 :
length = self.max_len
else :
length = int(random() * (self.max_len - self.min_len + 1) + self.min_len)
if length > self.max_len :
length = self.max_len
self.len[i1] = length
# 遺伝子の決定
for i2 in range(0, length) :
sw2 = 0
while sw2 == 0 :
lid = int(random() * (self.allele_u - self.allele_l + 1) + self.allele_l)
if lid > self.allele_u :
lid = self.allele_u
self.ind[i1][i2] = lid
# 重複遺伝子のチェック
sw2 = 1
if self.dup_a == 0 :
for i3 in range(0, i2) :
if lid == self.ind[i1][i3] :
sw2 = 0
break
# 重複個体のチェック
sw1 = 1
if self.dup_s == 0 :
for i2 in range(0, i1) :
if self.len[i1] == self.len[i2] :
sw2 = 0
for i3 in range(0, self.len[i1]) :
if self.ind[i1][i3] != self.ind[i2][i3] :
sw2 = 1
break
if sw2 == 0 :
sw1 = 0
break
####################################################
# 標準的な出力
# sw : 出力レベル
# =0 : 最終出力だけ
# n>0 : n世代毎に出力(負はファイル)
# out_m : 出力方法
# =0 : すべての個体を出力
# =1 : 最大適応度の個体だけを出力
# gen : 現在の世代番号
# name : 出力ファイル名
####################################################
def Out_std(self, sw, out_m, gen, name) :
k = 0
pr = -1
if sw >= 0 :
pr = int(input(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "))
if pr != 0 :
# 出力先の決定と評価値の出力
if pr > 0 :
out = sys.stdout
input("")
else :
now = datetime.today().time().isoformat()
out = open(name, "a")
out.write("***世代 " + str(gen) + " 適応度 max " + str(self.max) + " (" + str(self.max_n) + ") mean " + str(self.mean) + " 時間 " + now + "\n")
# 詳細出力
for i1 in range(0, self.size+self.max_ch) :
if (self.pi_w[i1] > 1) and (out_m == 0 or out_m == 1 and i1 == self.max_n) :
out.write(str(i1) + " allele")
for i2 in range(0, self.len[i1]) :
out.write(" " + str(self.ind[i1][i2]))
out.write(" value " + str(self.pi[i1]) + "\n")
if pr > 0 :
k += 1
if k == pr :
input("")
k = 0
if pr < 0 :
out.close()
###################################################################
# 交叉(親のコピー)
# method : =2 : 有性(2つの親から2つの子供)(default)
# =1 : 1つの親から1つの子供
# pair : method=2 の時は親のペア数(default=max_ch/2)
# method=1 の時は親の数(=子供の数)
# k_method : 選択方法
# =-1 : ランダム(default)
# =0 : 適応度をそのまま使用
# =1 : 最小値からの差(ただし,α以下の場合はα)
# =2 : 評価値に順位をつけ,減少率βで線形化
# k_bias : α,または,method=2の場合は初期値(default=0)
# k_step : β(default=1)
###################################################################
def C_copy(self, method = 2, pair = 0, k_method = -1, k_bias = 0.0, k_step = 1.0) :
# 初期設定とデータチェック
if method != 1 :
method = 2
if pair <= 0 :
if method == 2 :
pair = int(self.max_ch / 2)
else :
pair = self.max_ch
else :
if method == 2 and 2*pair > self.max_ch or method == 1 and pair > self.max_ch :
print("***error 子供が多すぎる (C_copy)")
# 実行
for i1 in range(0, pair) :
# 親の選択
p1 = self.Select(k_method, k_bias, k_step)
p2 = p1
sw = 0
while sw == 0 :
p2 = self.Select(k_method, k_bias, k_step)
if p1 != p2 :
sw = 1
# コピー
for i2 in range(0, method) :
p = p2
if i2 == 0 :
p = p1
k = self.Position(-1)
self.len[k] = self.len[p]
self.pi_w[k] = 1
for i3 in range(0, self.len[k]) :
self.ind[k][i3] = self.ind[p][i3]
###################################################################
# 交叉(多点交叉)
# kosa : 交叉確率
# k_point : 交叉点の数(default=1)
# (負の時は,1から-k_point間のランダム)
# k_vr : =0 : 両親とも同じ位置で交叉(default)
# =1 : 両親が異なる位置で交叉(遺伝子長は可変)
# k_method : 選択方法
# =-1 : ランダム(default)
# =0 : 適応度をそのまま使用
# =1 : 最小値からの差(ただし,α以下の場合はα)
# =2 : 評価値に順位をつけ,減少率βで線形化
# k_bias : α,または,method=2の場合は初期値(default=0)
# k_step : β(default=1)
###################################################################
def C_point(self, kosa, k_point = 1, k_vr = 0, k_method = -1, k_bias = 0.0, k_step = 1.0) :
mn = 0
# 初期設定とデータのチェック
pair = int(self.max_ch / 2)
if self.dup_a == 0 :
print("***error 交叉方法が不適当 (C_point)")
abs_p = abs(k_point)
if abs_p == 0 or abs_p > self.max_len-1 or self.min_len > 0 and abs_p > self.min_len-1 :
print("***error 交叉点の数が不適当 (C_point)")
if k_vr > 0 and self.min_len < 0 :
print("***error 遺伝子長は可変でなければならない (C_point)")
# 交叉
num = k_point
for i1 in range(0, pair) :
# 交叉しない場合
if random() > kosa :
self.C_copy(2, 1)
# 交叉する場合
else :
# 親の選択
p1 = self.Select(k_method, k_bias, k_step)
p2 = p1
sw = 0
while sw == 0 :
p2 = self.Select(k_method, k_bias, k_step)
if p1 != p2 :
sw = 1
# 交叉位置の数の決定
if k_point < 0 :
num = int(random() * abs_p + 1)
if num > abs_p :
num = abs_p
# 交叉位置の決定(点の後ろで交叉)
for i2 in range(0, num) :
# 親1の交叉位置
sw = 0
while sw == 0 :
sw = 1
self.kou1[i2] = int(random() * (self.len[p1] - 1))
if self.kou1[i2] > self.len[p1]-2 :
self.kou1[i2] = self.len[p1] - 2
if k_vr == 0 and self.kou1[i2] > self.len[p2]-2 :
self.kou1[i2] = self.len[p2] - 2
for i3 in range(0, i2) :
if self.kou1[i3] == self.kou1[i2] :
sw = 0
break
# 親2の交叉位置
if k_vr > 0 :
sw = 0
while sw == 0 :
sw = 1
self.kou2[i2] = int(random() * (self.len[p2] - 1))
if self.kou2[i2] > self.len[p2]-2 :
self.kou2[i2] = self.len[p2] - 2
for i3 in range(0, i2) :
if self.kou2[i3] == self.kou2[i2] :
sw = 0
break
# 交叉の実行
# 親1のt11からt12を子1のc1へコピー
# 親2のt21からt22を子2のc2へコピー
# 次は,
# 親1のt11からt12を子2のc2へコピー
# 親2のt21からt22を子1のc1へコピー
# ・・・・・
c1 = 0
c2 = 0
t11 = 0
t21 = 0
# 遺伝子長
k1 = self.Position(-1)
self.pi_w[k1] = 1
self.len[k1] = self.len[p1]
k2 = self.Position(-1)
self.pi_w[k2] = 1
self.len[k2] = self.len[p2]
for i2 in range(0, num+1) :
# 次の交叉位置を求める
if i2 == num : # 最後
t12 = self.len[p1]
t22 = self.len[p2]
else :
# 親1
t12 = self.max_len
for i3 in range(0, num) :
if self.kou1[i3] >= 0 and self.kou1[i3] <= t12 :
t12 = self.kou1[i3]
mn = i3
self.kou1[mn] = -1
t12 += 1
# 親2
if k_vr == 0 :
t22 = t12
else :
t22 = self.max_len
for i3 in range(0, num) :
if self.kou2[i3] >= 0 and self.kou2[i3] <= t22 :
t22 = self.kou2[i3]
mn = i3
self.kou2[mn] = -1
t22 += 1
# 指定箇所のコピー
for i3 in range(t11, t12) :
if i2%2 == 0 :
if c1 < self.max_len :
self.ind[k1][c1] = self.ind[p1][i3]
c1 += 1
else :
if c2 < self.max_len :
self.ind[k2][c2] = self.ind[p1][i3]
c2 += 1
for i3 in range(t21, t22) :
if i2%2 == 0 :
if c2 < self.max_len :
self.ind[k2][c2] = self.ind[p2][i3]
c2 += 1
else :
if c1 < self.max_len :
self.ind[k1][c1] = self.ind[p2][i3]
c1 += 1
# 交叉位置の移動
t11 = t12
t21 = t22
###################################################################
# 交叉(一様交叉.[0,1]を等確率で発生させ,1であれば,
# 親1,0であれば親2の遺伝子を子1が受け継ぐ)
# kosa : 交叉確率
# k_method : 選択方法
# =-1 : ランダム(default)
# =0 : 適応度をそのまま使用
# =1 : 最小値からの差(ただし,α以下の場合はα)
# =2 : 評価値に順位をつけ,減少率βで線形化
# k_bias : α,または,method=2の場合は初期値(default=0)
# k_step : β(default=1)
###################################################################
def C_uniform(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) :
# 初期設定とデータのチェック
pair = int(self.max_ch / 2)
if self.dup_a == 0 :
print("***error 交叉方法が不適当 (C_uniform)")
if self.min_len > 0 :
print("***error 遺伝子長は固定長でなければならない (C_uniform)")
# 交叉
for i1 in range(0, pair) :
# 交叉しない場合
if random() > kosa :
self.C_copy(2, 1)
# 交叉する場合
else :
# 親の選択
p1 = self.Select(k_method, k_bias, k_step)
p2 = p1
sw = 0
while sw == 0 :
p2 = self.Select(k_method, k_bias, k_step)
if p1 != p2 :
sw = 1
# 遺伝子長
k1 = self.Position(-1)
self.pi_w[k1] = 1
self.len[k1] = self.len[p1]
k2 = self.Position(-1)
self.pi_w[k2] = 1
self.len[k2] = self.len[p2]
# 交叉
for i2 in range(0, self.len[p1]) :
if random() > 0.5 :
self.ind[k1][i2] = self.ind[p1][i2]
self.ind[k2][i2] = self.ind[p2][i2]
else :
self.ind[k1][i2] = self.ind[p2][i2]
self.ind[k2][i2] = self.ind[p1][i2]
###################################################################
# 交叉(平均化交叉.2つの親の平均値を受け継ぐ)
# kosa : 交叉確率
# k_method : 選択方法
# =-1 : ランダム(default)
# =0 : 適応度をそのまま使用
# =1 : 最小値からの差(ただし,α以下の場合はα)
# =2 : 評価値に順位をつけ,減少率βで線形化
# k_bias : α,または,method=2の場合は初期値(default=0)
# k_step : β(default=1)
###################################################################
def C_mean(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) :
# 初期設定とデータのチェック
if self.min_len > 0 :
print("***error 遺伝子長は固定長でなければならない (C_mean)")
# 交叉
for i1 in range(0, self.max_ch) :
# 交叉しない場合
if random() > kosa :
self.C_copy(1, 1)
# 交叉する場合
else :
# 親の選択
p1 = self.Select(k_method, k_bias, k_step)
p2 = p1
sw = 0
while sw == 0 :
p2 = self.Select(k_method, k_bias, k_step)
if p1 != p2 :
sw = 1
# 遺伝子長
k = self.Position(-1)
self.len[k] = self.len[p1]
self.pi_w[k] = 1
# 交叉
for i2 in range(0, self.len[k]) :
self.ind[k][i2] = int((self.ind[p1][i2] + self.ind[p2][i2]) / 2)
###################################################################
# 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を
# そのまま各子供が選択する.その位置にある親2(1)の遺伝
# 子を,その遺伝子の親1(2)の場所に,子1(2)が受け継
# ぐ(ただし,doubleの場合は,この手続きをのぞく).この手
# 続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り
# 返し,残りの遺伝子については,子1(2)は,親2(1)の
# 遺伝子をその順番通りに受け継ぐ)
# 2 4 1 3 6 5 + + 1 + + 5 3 2 1 4 6 5
# * → →
# 3 2 5 4 1 6 + + 5 + 1 + 2 4 5 3 1 6
# kosa : 交叉確率
# k_method : 選択方法
# =-1 : ランダム(default)
# =0 : 適応度をそのまま使用
# =1 : 最小値からの差(ただし,α以下の場合はα)
# =2 : 評価値に順位をつけ,減少率βで線形化
# k_bias : α,または,method=2の場合は初期値(default=0)
# k_step : β(default=1)
###################################################################
def C_cycle(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) :
# 初期設定とデータのチェック
pair = int(self.max_ch / 2)
if self.dup_a != 0 :
print("***error 交叉方法が不適当 (C_cycle)")
if self.min_len > 0 :
print("***error 遺伝子長は固定長でなければならない (C_cycle)")
# 交叉
for i1 in range(0, pair) :
# 交叉しない場合
if random() > kosa :
self.C_copy(2, 1)
# 交叉する場合
else :
# 親の選択
p1 = self.Select(k_method, k_bias, k_step)
p2 = p1
sw = 0
while sw == 0 :
p2 = self.Select(k_method, k_bias, k_step)
if p1 != p2 :
sw = 1
# 初期設定
for i2 in range(0, self.len[p1]) :
self.kou1[i2] = 0
self.kou2[i2] = 0
# 遺伝子長
k1 = self.Position(-1)
self.pi_w[k1] = 1
self.len[k1] = self.len[p1]
k2 = self.Position(-1)
self.pi_w[k2] = 1
self.len[k2] = self.len[p2]
# 交叉
sw = 0
while sw == 0 :
sw = 1
p = int(random() * self.len[p1])
if p >= self.len[p1] :
p = self.len[p1] - 1
if self.kou1[p] == 0 and self.kou2[p] == 0 :
self.kou1[p] = 1
self.kou2[p] = 1
self.ind[k1][p] = self.ind[p1][p]
self.ind[k2][p] = self.ind[p2][p]
for i2 in range(0, self.len[p1]) :
if self.ind[p2][p] == self.ind[p1][i2] :
self.ind[k1][i2] = self.ind[p1][i2]
self.kou1[i2] = 1
sw = 0
break
sw = 1
for i2 in range(0, self.len[p2]) :
if self.ind[p1][p] == self.ind[p2][i2] :
self.ind[k2][i2] = self.ind[p2][i2]
self.kou2[i2] = 1
sw = 0
break
sw = 0
i2 = 0
i3 = 0
while sw == 0 :
while sw == 0 and i2 < self.len[p1] :
if self.kou1[i2] == 0 :
sw = 1
else :
i2 += 1
sw = 0
while sw == 0 and i3 < self.len[p2] :
if self.kou2[i3] == 0 :
sw = 1
else :
i3 += 1
if i2 < self.len[p1] and i3 < self.len[p2] :
self.ind[k1][i2] = self.ind[p2][i3]
self.ind[k2][i3] = self.ind[p1][i2]
sw = 0
i2 += 1
i3 += 1
else :
sw = 1
###################################################################
# 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と
# 親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ
# の2つの遺伝子の位置を交換する.この操作を,選択した点よ
# り右にあるすべての遺伝子に対して実施する
# 2 4 1 3 6 5 2 4 5 3 6 1
# * → → ・・・・・
# 3 2 5 4 1 6 3 2 1 4 5 6
# kosa : 交叉確率
# k_method : 選択方法
# =-1 : ランダム(default)
# =0 : 適応度をそのまま使用
# =1 : 最小値からの差(ただし,α以下の場合はα)
# =2 : 評価値に順位をつけ,減少率βで線形化
# k_bias : α,または,method=2の場合は初期値(default=0)
# k_step : β(default=1)
#******************************************************************/
def C_part(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) :
# 初期設定とデータのチェック
pair = int(self.max_ch / 2)
if self.dup_a != 0 :
print("***error 交叉方法が不適当 (C_part)")
if self.min_len > 0 :
print("***error 遺伝子長は固定長でなければならない (C_part)")
# 交叉
for i1 in range(0, pair) :
# 交叉しない場合
if random() > kosa :
self.C_copy(2, 1)
# 交叉する場合
else :
# 親の選択
p1 = self.Select(k_method, k_bias, k_step)
p2 = p1
sw = 0
while sw == 0 :
p2 = self.Select(k_method, k_bias, k_step)
if p1 != p2 :
sw = 1
# 遺伝子長
k1 = self.Position(-1)
self.pi_w[k1] = 1
self.len[k1] = self.len[p1]
k2 = self.Position(-1)
self.pi_w[k2] = 1
self.len[k2] = self.len[p2]
# 交叉
p = int(random() * self.len[p1])
if p >= self.len[p1] :
p = self.len[p1] - 1
for i2 in range(0, self.len[p1]) :
self.ind[k1][i2] = self.ind[p1][i2]
self.ind[k2][i2] = self.ind[p2][i2]
for i2 in range(p, self.len[p1]) :
sw = 0
lv = self.ind[k1][i2]
for i3 in range(0, self.len[p1]) :
if self.ind[k2][i2] == self.ind[k1][i3] :
self.ind[k1][i2] = self.ind[k1][i3]
self.ind[k1][i3] = lv
sw = 1
break
sw = 0
for i3 in range(0, self.len[p1]) :
if lv == self.ind[k2][i3] :
self.ind[k2][i3] = self.ind[k2][i2]
self.ind[k2][i2] = lv
sw = 1
break
###################################################################
# 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の
# 左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1
# の遺伝子を親2の遺伝子の出現順序に並べ替える.
# 2 4 1 3 6 5 2 4 1 3 5 6
# * →
# 3 2 5 4 1 6 3 2 5 4 1 6
# kosa : 交叉確率
# k_method : 選択方法
# =-1 : ランダム(default)
# =0 : 適応度をそのまま使用
# =1 : 最小値からの差(ただし,α以下の場合はα)
# =2 : 評価値に順位をつけ,減少率βで線形化
# k_bias : α,または,method=2の場合は初期値(default=0)
# k_step : β(default=1)
###################################################################
def C_seq(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) :
# 初期設定とデータのチェック
pair = int(self.max_ch / 2)
if self.dup_a != 0 :
printf("***error 交叉方法が不適当 (C_seq)\n")
if self.min_len > 0 :
printf("***error 遺伝子長は固定長でなければならない (C_seq)\n")
# 交叉
for i1 in range(0, pair) :
# 交叉しない場合
if random() > kosa :
self.C_copy(2, 1)
# 交叉する場合
else :
# 親の選択
p1 = self.Select(k_method, k_bias, k_step)
p2 = p1
sw = 0
while sw == 0 :
p2 = self.Select(k_method, k_bias, k_step)
if p1 != p2 :
sw = 1
# 遺伝子長
k1 = self.Position(-1)
self.pi_w[k1] = 1
self.len[k1] = self.len[p1]
k2 = self.Position(-1)
self.pi_w[k2] = 1
self.len[k2] = self.len[p2]
# 交叉
p = int(random() * (self.len[p1] - 1))
if p >= self.len[p1]-1 :
p = self.len[p1] - 2
for i2 in range(0, p+1) :
self.ind[k1][i2] = self.ind[p1][i2]
self.ind[k2][i2] = self.ind[p2][i2]
pp = 0
for i2 in range(p+1, self.len[p1]) :
sw = 0
i3 = pp
while i3 < self.len[p2] and sw == 0 :
i4 = p + 1
while i4 < self.len[p1] and sw == 0 :
if self.ind[p2][i3] == self.ind[p1][i4] :
sw = 1
pp = i3 + 1
self.ind[k1][i2] = self.ind[p1][i4]
i4 += 1
i3 += 1
pp = 0
for i2 in range(p+1, self.len[p2]) :
sw = 0
i3 = pp
while i3 < self.len[p1] and sw == 0 :
i4 = p + 1
while i4 < self.len[p2] and sw == 0 :
if self.ind[p1][i3] == self.ind[p2][i4] :
sw = 1
pp = i3 + 1
self.ind[k2][i2] = self.ind[p2][i4]
i4 += 1
i3 += 1
###################################################################
# 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選
# 択された位置における遺伝子の順序に従って,他の親の遺伝子
# を並べ替える
# 2 4 1 3 6 5 2 4 1 3 6 5
# * * →
# 3 2 5 4 1 6 4 2 5 3 1 6
# kosa : 交叉確率
# k_method : 選択方法
# =-1 : ランダム(default)
# =0 : 適応度をそのまま使用
# =1 : 最小値からの差(ただし,α以下の場合はα)
# =2 : 評価値に順位をつけ,減少率βで線形化
# k_bias : α,または,method=2の場合は初期値(default=0)
# k_step : β(default=1)
###################################################################
def C_useq(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) :
# 初期設定とデータのチェック
pair =int(self.max_ch / 2)
if self.dup_a != 0 :
print("***error 交叉方法が不適当 (C_useq)")
if self.min_len > 0 :
print("***error 遺伝子長は固定長でなければならない (C_useq)")
# 交叉
for i1 in range(0, pair) :
# 交叉しない場合
if random() > kosa :
self.C_copy(2, 1)
# 交叉する場合
else :
# 親の選択
p1 = self.Select(k_method, k_bias, k_step)
p2 = p1
sw = 0
while sw == 0 :
p2 = self.Select(k_method, k_bias, k_step)
if p1 != p2 :
sw = 1
# 遺伝子長
k1 = self.Position(-1)
self.pi_w[k1] = 1
self.len[k1] = self.len[p1]
k2 = self.Position(-1)
self.pi_w[k2] = 1
self.len[k2] = self.len[p2]
# 交叉
for i2 in range(0, self.len[p1]) :
self.ind[k1][i2] = self.ind[p1][i2]
self.ind[k2][i2] = self.ind[p2][i2]
if random() < 0.5 :
self.kou1[i2] = 0
else :
self.kou1[i2] = 1
p = 0
for i2 in range(0, self.len[p1]) :
if self.kou1[i2] > 0 :
sw = 0
i3 = p
while i3 < self.len[p2] and sw == 0 :
i4 = 0
while i4 < self.len[p1] and sw == 0 :
if self.ind[p2][i3] == self.ind[p1][i4] and self.kou1[i4] > 0 :
sw = 1
p = i3 + 1
self.ind[k1][i2] = self.ind[p1][i4]
i4 += 1
i3 += 1
p = 0
for i2 in range(0, self.len[p3]) :
if self.kou1[i2] > 0 :
sw = 0
i3 = p
while i3 < self.len[p1] and sw == 0 :
i4 = 0
while i4 < self.len[p2] and sw == 0 :
if self.ind[p1][i3] == self.ind[p2][i4] and self.kou1[i4] > 0 :
sw = 1
p = i3 + 1
self.ind[k2][i2] = self.ind[p2][i4]
i4 += 1
i3 += 1
###################################################################
# 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選
# 択された位置における遺伝子の位置に,他の親の同じ遺伝子を
# 配置する.残りの遺伝子は,親と同じ順序に配置する.
# 2 4 1 3 6 5 + + 5 + 1 + 2 4 5 3 1 6
# * * → →
# 3 2 5 4 1 6 + + 1 + 6 + 3 2 1 5 6 4
# kosa : 交叉確率
# k_method : 選択方法
# =-1 : ランダム(default)
# =0 : 適応度をそのまま使用
# =1 : 最小値からの差(ただし,α以下の場合はα)
# =2 : 評価値に順位をつけ,減少率βで線形化
# k_bias : α,または,method=2の場合は初期値(default=0)
# k_step : β(default=1)
###################################################################
def C_upos(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) :
# 初期設定とデータのチェック
pair = int(self.max_ch / 2)
if self.dup_a != 0 :
print("***error 交叉方法が不適当 (C_upos)")
if self.min_len > 0 :
print("***error 遺伝子長は固定長でなければならない (C_upos)")
# 交叉
for i1 in range(0, pair) :
# 交叉しない場合
if random() > kosa :
self.C_copy(2, 1)
# 交叉する場合
else :
# 親の選択
p1 = self.Select(k_method, k_bias, k_step)
p2 = p1
sw = 0
while sw == 0 :
p2 = self.Select(k_method, k_bias, k_step)
if p1 != p2 :
sw = 1
# 遺伝子長
k1 = self.Position(-1)
self.pi_w[k1] = 1
self.len[k1] = self.len[p1]
k2 = self.Position(-1)
self.pi_w[k2] = 1
self.len[k2] = self.len[p2]
# 交叉
for i2 in range(0, self.len[p1]) :
self.kou1[i2] = 1
if random() < 0.5 :
self.kou1[i2] = 1
if self.kou1[i2] > 0 :
self.ind[k1][i2] = self.ind[p2][i2]
self.ind[k2][i2] = self.ind[p1][i2]
p = 0
for i2 in range(0, self.len[p1]) :
sw = 0
for i3 in range(0, self.len[p1]) :
if self.kou1[i3] > 0 and self.ind[p1][i2] == self.ind[k1][i3] :
sw = 1
break
if sw == 0 :
for i3 in range(p, self.len[p1]) :
if self.kou1[i3] == 0 :
self.ind[k1][i3] = self.ind[p1][i2]
p = i3 + 1
sw = 1
break
p = 0
for i2 in range(0, self.len[p2]) :
sw = 0
for i3 in range(0, self.len[p2]) :
if self.kou1[i3] > 0 and self.ind[p2][i2] == self.ind[k2][i3] :
sw = 1
break
if sw == 0 :
for i3 in range(p, self.len[p2]) :
if self.kou1[i3] == 0 :
self.ind[k2][i3] = self.ind[p2][i2]
p = i3 + 1
sw = 1
break
###################################################################
# 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は
# 0~(max_len-1)である必要がある)
# (0) エッジマップを作成する.エッジマップとは,2つの親
# を見て,ノードがどこに接続されているのかを表すもの
# であり,例えば,2つの親が,
# [A B C D E F]
# [B D C A E F]
# である場合は,
# A : B F C E
# B : A C D F
# C : B D A
# D : C E B
# E : D F A
# F : A E B
# となる.
# (1) 両親の2つの出発点の内1つで初期化する.ランダムま
# たはステップ(4)の基準に従って選ぶ(現在のノード)
# (2) エッジマップから,現在のノードを除く
# (3) 現在のノードが接続先のノードを持っていたら,(4)に
# 進む.さもなければ,(5)に進む
# (4) 現在のノードが持っている接続先ノードの内,最も少な
# い接続先ノードを持ったノードを選択し(同じ条件の場
# 合は,ランダム),それを現在のノードとし,(2)に進む
# (5) 未接続のノードが残っていればランダムに選択し,(2)に
# 戻る.さもなければ,終了する
# kosa : 交叉確率
# k_method : 選択方法
# =-1 : ランダム(default)
# =0 : 適応度をそのまま使用
# =1 : 最小値からの差(ただし,α以下の場合はα)
# =2 : 評価値に順位をつけ,減少率βで線形化
# k_bias : α,または,method=2の場合は初期値(default=0)
# k_step : β(default=1)
###################################################################
def C_edge(self, kosa, k_method = -1, k_bias = 0.0, k_step = 1.0) :
e = np.empty(2, np.int)
k0 = 0
# 初期設定とデータのチェック
pair = self.max_ch
if self.dup_a != 0 :
print("***error 交叉方法が不適当 (C_edge)")
if self.min_len > 0 :
print("***error 遺伝子長は固定長でなければならない (C_edge)")
# 交叉
for i1 in range(0, pair) :
# 交叉しない場合
if random() > kosa :
self.C_copy(1, 1)
# 交叉する場合
else :
# 親の選択
p1 = self.Select(k_method, k_bias, k_step)
p2 = p1
sw = 0
while sw == 0 :
p2 = self.Select(k_method, k_bias, k_step)
if p1 != p2 :
sw = 1
# 遺伝子長
k = self.Position(-1)
self.pi_w[k] = 1
self.len[k] = self.len[p1]
# エッジマップの初期化
for i2 in range(0, self.len[k]) :
self.edge[i2][0] = 0
for i3 in range(1, 5) :
self.edge[i2][i3] = -1
# 交叉
# エッジマップの作成
for i2 in range(0, self.len[k]) :
sw = 0
for i3 in range(0, self.len[k]) :
if i2 == self.ind[p1][i3] :
sw = 1
if i3 == 0 :
e[0] = self.ind[p1][self.len[k]-1]
e[1] = self.ind[p1][1]
else :
if i3 == self.len[k]-1 :
e[0] = self.ind[p1][i3-1]
e[1] = self.ind[p1][0]
else :
e[0] = self.ind[p1][i3-1]
e[1] = self.ind[p1][i3+1]
for i4 in range(0, 2) :
self.edge[i2][0] += 1
self.edge[i2][self.edge[i2][0]] = e[i4]
break
sw = 0
for i3 in range(0, self.len[k]) :
if i2 == self.ind[p2][i3] :
sw = 1
if i3 == 0 :
e[0] = self.ind[p2][self.len[k]-1]
e[1] = self.ind[p2][1]
else :
if i3 == self.len[k]-1 :
e[0] = self.ind[p2][i3-1]
e[1] = self.ind[p2][0]
else :
e[0] = self.ind[p2][i3-1]
e[1] = self.ind[p2][i3+1]
for i4 in range(0, 2) :
sw = 1
for i5 in range(1, self.edge[i2][0]+1) :
if self.edge[i2][i5] == e[i4] :
sw = 2
break
if sw == 1 :
self.edge[i2][0] += 1
self.edge[i2][self.edge[i2][0]] = e[i4]
break
# 交叉の実行
# 出発点の決定
k1 = self.ind[p1][0]
k2 = self.ind[p2][0]
if self.edge[k1][0] == self.edge[k2][0] :
kk = k1
if random() > 0.5 :
kk = k2
else :
kk = k2
if self.edge[k1][0] < self.edge[k2][0] :
kk = k2
self.ind[k][0] = kk
p = 1
while p < self.len[k] :
# ノードの除去
for i2 in range(0, self.len[k]) :
sw = 0
if self.edge[i2][0] > 0 :
for i3 in range(1, 5) :
if self.edge[i2][i3] == kk :
sw = 1
self.edge[i2][i3] = -1
self.edge[i2][0] -= 1
break
# 次の現在ノードの選択
min = 10
num = 0
for i2 in range(1, 5) :
if self.edge[kk][i2] >= 0 :
k1 = self.edge[kk][i2]
if self.edge[k1][0] >= 0 and self.edge[k1][0] < min :
num = 1
min = self.edge[k1][0]
k0 = k1
else :
if self.edge[k1][0] == min :
num += 1
if num > 1 :
k1 = int(random() * num) + 1
if k1 > num :
k1 = num
k2 = 0
k0 = -1
i2 = 1
while i2 <= 4 and k0 < 0 :
if self.edge[kk][i2] >= 0 :
if self.edge[self.edge[kk][i2]][0] == min :
k2 += 1
if k1 == k2 :
k0 = self.edge[kk][i2]
i2 += 1
else :
if num <= 0 :
num = 0
for i2 in range(0, self.len[k]) :
if i2 != kk and self.edge[i2][0] >= 0 :
num += 1
if num <= 0 :
print("***error invalid data (C_edge)")
else :
k1 = int(random() * num) + 1
if k1 > num :
k1 = num
k2 = 0
k0 = -1
i2 = 0
while i2 < self.len[k] and k0 < 0 :
if i2 != kk and self.edge[i2][0] >= 0 :
k2 += 1
if k1 == k2 :
k0 = i2
i2 += 1
self.edge[kk][0] = -1
self.ind[k][p] = k0
kk = k0
p += 1
##############################################################
# 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に
# 同じ遺伝子のグループがない限り実行されない.たとえば
# ***abcd**
# *cdab****
# のような両親の時実行され,以下の4つの子供が生成され
# る)
# ***cdab**
# *abcd****
# ***badc**
# *dcba****
# 最大,4*交叉回数*個体総数*(個体総数-1) 個の子
# 供が生成される可能性があるので,子供の数としてこの値
# 以上のデータを入力しておく必要がある.
# kosa : 交叉確率
# count : 1つのペアーに対する交差回数(default=10)
##############################################################
def C_sub(self, kosa, count = 10) :
t22 = 0
# 初期設定とデータのチェック
if (4*count*self.size*(self.size-1)) > self.max_ch :
print("***error 子供が多すぎる (C_sub)")
# 交叉
for i1 in range(0, self.size-1) :
# 親1
p1 = self.Position(i1)
if p1 >= 0 :
for i2 in range(i1, self.size) :
# 親2
p2 = self.Position(i2)
if p2 >= 0 :
# 交叉しない場合
if random() > kosa :
self.C_copy(2, 1)
# 交叉する場合
else :
# 交叉回数の制御
for i3 in range(0, count) :
# 交叉位置の決定(点の後ろで交叉)
# 親1の交叉位置
t11 = int(random() * self.len[p1])
if t11 > (self.len[p1]-1) :
t11 = self.len[p1] - 1
sw = 0
while sw == 0 :
t12 = int(random() * self.len[p1])
if t12 > (self.len[p1]-1) :
t12 = self.len[p1] - 1
if t12 != t11 :
sw = 1
if t11 > t12 :
k1 = t11
t11 = t12
t12 = k1
# 親2の交叉位置
sw = 0
t21 = -1
i4 = 0
while i4 < self.len[p2] and t21 < 0 :
i5 = t11
while i5 <= t12 and t21 < 0 :
if self.ind[p2][i4] == self.ind[p1][i5] :
t21 = i4
i5 += 1
i4 += 1
if t21 >= 0 :
t22 = t21 + t12 - t11
if t22 < self.len[p2] :
sw = 1
i4 = t21 + 1
while i4 <= t22 and sw > 0 :
sw = 0
i5 = t11
while i5 <= t12 and sw == 0 :
if self.ind[p2][i4] == self.ind[p1][i5] :
sw = 1
i5 += 1
i4 += 1
# 交叉の実行
if sw > 0 :
k1 = self.Position(-1)
self.pi_w[k1] = 1
self.len[k1] = self.len[p1]
k2 = self.Position(-1)
self.pi_w[k2] = 1
self.len[k2] = self.len[p1]
k3 = self.Position(-1)
self.pi_w[k3] = 1
self.len[k3] = self.len[p2]
k4 = self.Position(-1)
self.pi_w[k4] = 1
self.len[k4] = self.len[p2]
for i4 in range(0, t11) :
self.ind[k1][i4] = self.ind[p1][i4]
self.ind[k2][i4] = self.ind[p1][i4]
for i4 in range(t11, t12+1) :
self.ind[k1][i4] = self.ind[p2][t21+i4-t11]
self.ind[k2][i4] = self.ind[p2][t22-i4+t11]
for i4 in range(t12+1, self.len[p1]) :
self.ind[k1][i4] = self.ind[p1][i4]
self.ind[k2][i4] = self.ind[p1][i4]
for i4 in range(0, t21) :
self.ind[k3][i4] = self.ind[p2][i4]
self.ind[k4][i4] = self.ind[p2][i4]
for i4 in range(t21, t22+1) :
self.ind[k3][i4] = self.ind[p1][t11+i4-t21]
self.ind[k4][i4] = self.ind[p1][t12-i4+t21]
for i4 in range(t22+1, self.len[p2]) :
self.ind[k3][i4] = self.ind[p2][i4]
self.ind[k4][i4] = self.ind[p2][i4]
#######################################
# 突然変異(対立遺伝子との置き換え)
# pr : 突然変異率
#######################################
def M_alle(self, pr) :
# データのチェックと初期設定
if self.dup_a == 0 :
print("***error 突然変異方法が不適当 (M_alle)")
# 実行
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] == 1 :
for i2 in range(0, self.len[i1]) :
if random() <= pr :
lid = int(random() * (self.allele_u - self.allele_l + 1) + self.allele_l)
if lid > self.allele_u :
lid = self.allele_u
if lid != self.ind[i1][i2] :
self.ind[i1][i2] = lid
######################################################################
# 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に
# 移動する)
# pr : 突然変異率
######################################################################
def M_move(self, pr) :
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] == 1 and random() <= pr :
# 位置の決定
# p1
p1 = int(random() * self.len[i1])
if p1 >= self.len[i1] :
p1 = self.len[i1] - 1
# p2
p2 = p1
sw = 0
while sw == 0 :
p2 = int(random() * self.len[i1])
if p2 >= self.len[i1] :
p2 = self.len[i1] - 1
if p2 != p1 :
sw = 1
# 実行
if p2 > p1 :
ld = self.ind[i1][p2]
for i2 in range(p2, p1, -1) :
self.ind[i1][i2] = self.ind[i1][i2-1]
self.ind[i1][p1] = ld
else :
ld = self.ind[i1][p2]
for i2 in range(p2, p1-1) :
self.ind[i1][i2] = self.ind[i1][i2+1]
self.ind[i1][p1-1] = ld
########################################################
# 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える)
# pr : 突然変異率
# wd : >0 : 幅を固定
# =0 : 幅をランダム(default)
########################################################
def M_inv(self, pr, wd = 0) :
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] == 1 and random() <= pr :
# 区間の決定
if wd == 0 :
p1 = int(random() * self.len[i1])
if p1 >= self.len[i1] :
p1 = self.len[i1] - 1
sw = 0
p2 = p1
while sw == 0 :
p2 = int(random() * self.len[i1])
if p2 >= self.len[i1] :
p2 = self.len[i1] - 1
if p2 != p1 :
sw = 1
if p1 > p2 :
p = p1
p1 = p2
p2 = p
else :
p1 = self.len[i1]
while p1 > self.len[i1]-2 :
p1 = int(random() * self.len[i1])
p2 = p1 + wd - 1
if p2 >= self.len[i1] :
p2 = self.len[i1] - 1
# 実行
sw = 0
while sw == 0 :
lid = self.ind[i1][p1]
self.ind[i1][p1] = self.ind[i1][p2]
self.ind[i1][p2] = lid
p1 += 1
p2 -= 1
if p1 >= p2 :
sw = 1
######################################################################
# 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える)
# pr : 突然変異率
# wd : >0 : 幅を固定
# =0 : 幅をランダム(default)
######################################################################
def M_scram(self, pr, wd = 0) :
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] == 1 and random() <= pr :
# 区間の決定
if wd == 0 :
p1 = int(random() * self.len[i1])
if p1 >= self.len[i1] :
p1 = self.len[i1] - 1
sw = 0
p2 = p1
while sw == 0 :
p2 = int(random() * self.len[i1])
if p2 >= self.len[i1] :
p2 = self.len[i1] - 1
if p2 != p1 :
sw = 1
if p1 > p2 :
p = p1
p1 = p2
p2 = p
else :
p1 = self.len[i1]
while p1 > self.len[i1]-2 :
p1 = int(random() * self.len[i1])
p2 = p1 + wd - 1
if p2 >= self.len[i1] :
p2 = self.len[i1] - 1
# 実行
for i2 in range(p1, p2+1) :
p = int(random() * (p2 - p1 + 1) + p1)
if p > p2 :
p = p2
ld = self.ind[i1][i2]
self.ind[i1][i2] = self.ind[i1][p]
self.ind[i1][p] = ld
######################################################################
# 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし
# 重複部分はそのままとする)
# pr : 突然変異率
# wd : >0 : 幅を固定
# =0 : 幅をランダム(default)
######################################################################
def M_chg(self, pr, wd = 0) :
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] == 1 and random() <= pr :
# 区間等の決定([p1,p2]と[p3,p4]の入れ替え)
# p1
p1 = int(random() * self.len[i1])
if p1 >= self.len[i1] :
p1 = self.len[i1] - 1
# p3
sw = 0
p3 = p1
while sw == 0 :
p3 = int(random() * self.len[i1])
if p3 >= self.len[i1] :
p3 = self.len[i1] - 1
if p3 != p1 :
sw = 1
# 小さい方をp1,p2にする
if p1 > p3 :
p = p1
p1 = p3
p3 = p
# p4, p2
p4 = p1 + wd - 1
if wd == 0 :
p4 = int(random() * (self.len[i1] - p3)) + p3
if p4 >= self.len[i1] :
p4 = self.len[i1] - 1
p2 = p1 + (p4 - p3)
# 重複部分のチェック
if p2 >= p3 :
p = p3 - 1
p3 = p2 + 1
p2 = p
p4 = p3 + (p2 - p1)
# 実行
p = p3
for i2 in range(p1, p2+1) :
ld = self.ind[i1][i2]
self.ind[i1][i2] = self.ind[i1][p]
self.ind[i1][p] = ld
p += 1
######################################################################
# 突然変異(重複.2点間の遺伝子を他の位置にコピーする
# pr : 突然変異率
# wd : >0 : 幅を固定
# =0 : 幅をランダム(deafult)
######################################################################
def M_dup(self, pr, wd = 0) :
# データのチェック
if self.dup_a == 0 :
print("***error 突然変異方法が不適当 (M_dup)")
# 実行
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] == 1 and random() <= pr :
# 区間の決定([p1,p2]を[p3,p4]にコピー)
# p1
p1 = int(random() * self.len[i1])
if p1 >= self.len[i1] :
p1 = self.len[i1] - 1
# p3
sw = 0
p3 = p1
while sw == 0 :
p3 = int(random() * self.len[i1])
if p3 >= self.len[i1] :
p3 = self.len[i1] - 1
if p3 != p1 :
sw = 1
# 区間を決める
p2 = p1
p4 = p1
if p3 > p1 :
p4 = p3 + wd - 1
if wd == 0 :
p4 = int(random() * (self.len[i1] - p3)) + p3
if p4 >= self.len[i1] :
p4 = self.len[i1] - 1
p2 = p1 + (p4 - p3)
else :
p2 = p1 + wd - 1
if wd == 0 :
p2 = int(random() * (self.len[i1] - p1)) + p1
if p2 >= self.len[i1] :
p2 = self.len[i1] - 1
p4 = p3 + (p2 - p1)
# 実行
p = p4
for i2 in range(p2, p1-1, -1) :
self.ind[i1][p] = self.ind[i1][i2]
p -= 1
######################################################
# 突然変異(摂動.値をある量だけ変化させる)
# pr : 突然変異率
# method : =0 : 正規分布(default)
# =1 : 一様分布
# m : 平均または一様分布の下限(default=0.0)
# s : 標準偏差または一様分布の上限(default=1.0)
######################################################
def M_per(self, pr, method = 0, m = 0.0, s = 1.0) :
wd = 0.0
# データのチェックと初期設定
if self.dup_a == 0 :
print("***error 突然変異方法が不適当 (M_per)")
if method > 0 :
wd = s - m
# 実行
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] == 1 :
for i2 in range(0, self.len[i1]) :
if random() <= pr :
if method == 0 :
w = normalvariate(m, s)
else :
w = random() * wd
if random() < 0.5 :
w = -w
x1 = float(self.ind[i1][i2]) + w
if x1 > self.allele_u :
x1 = self.allele_u
else :
if x1 < self.allele_l :
x1 = self.allele_l
self.ind[i1][i2] = int(x1)
##############################################
# 突然変異(挿入.ある長さの遺伝子を挿入する)
# pr : 突然変異率
# wd : >0 : 幅を固定
# =0 : 幅をランダム(default)
##############################################
def M_ins(self, pr, wd = 0) :
# データのチェック
if self.dup_a == 0 or self.min_len < 0 :
print("***error 突然変異方法が不適当 (M_ins)")
# 実行
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] == 1 and random() <= pr :
# 挿入位置の決定
p = int(random() * (self.len[i1] + 1))
if p > self.len[i1] :
p = self.len[i1]
# 挿入する遺伝子長の決定
l = wd
if wd == 0 :
l = int(random() * (self.max_len - self.len[i1] + 1))
if l > self.max_len-self.len[i1] :
l = self.max_len - self.len[i1]
else :
if l <= 0 :
l = 1
# 実行
# 挿入場所の確保
if p < self.len[i1] :
for i2 in range(self.len[i1]+l-1, p-1, -1) :
self.ind[i1][i2] = self.ind[i1][i2-l]
# 挿入場所の遺伝子の決定
for i2 in range(p, p+l) :
ld = int(random() * (self.allele_u - self.allele_l + 1) + self.allele_l)
if ld > self.allele_u :
ld = self.allele_u
self.ind[i1][i2] = ld
self.len[i1] += l
##############################################
# 突然変異(削除.ある長さの遺伝子を削除する)
# pr : 突然変異率
# wd : >0 : 幅を固定
# =0 : 幅をランダム(default)
##############################################
def M_del(self, pr, wd = 0) :
# データのチェック
if self.dup_a == 0 or self.min_len < 0 :
print("***error 突然変異方法が不適当 (M_del)")
# 実行
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] == 1 and random() <= pr :
# 削除位置の決定
p = int(random() * self.len[i1])
if p >= self.len[i1] :
p = self.len[i1] - 1
# 削除する遺伝子長の決定
max = self.len[i1] - p
if self.len[i1]-self.min_len < self.len[i1]-p :
max = self.len[i1] - self.min_len
l = wd
if wd == 0 :
l = int(random() * max + 1)
if l > max :
l = max
# 実行
for i2 in range(0, self.len[i1]-p-l) :
self.ind[i1][p+i2] = self.ind[i1][p+i2+l]
self.len[i1] -= l
######################################################################
# 淘汰(エリート・ルーレット選択)
# elite : エリートで残す個体数(default=0)
# s_method : ルーレット板の作成方法(default=1)
# =0 : 適応度をそのまま使用
# =1 : 最小値からの差(ただし,α以下の場合はα)
# =2 : 評価値に順位をつけ,減少率βで線形化
# s_bias : α,または,method=2の場合は初期値(default=0)
# s_step : β(default=1)
######################################################################
def S_roul(self, elite = 0, s_method = 1, s_bias = 0.0, s_step = 1.0) :
count = 0
k = 0
n = 0
# 値のチェックと初期設定
if s_method != 0 and s_method != 2 :
s_method = 1
if elite > self.size :
print("***error エリートで残す数が多すぎる (S_roul)")
if s_method == 2 and s_step <= 0.0 :
s_step = 1.0
for i1 in range(0, self.size+self.max_ch) :
self.s_w[i1] = 0
# 重複個体を削除
if self.dup_s == 0 :
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] > 0 :
for i2 in range(i1+1, self.size+self.max_ch) :
if self.pi_w[i2] > 0 and self.len[i1] == self.len[i2] :
sw = 0
for i3 in range(0, self.len[i1]) :
if self.ind[i1][i3] != self.ind[i2][i3] :
sw = 1
break
if sw == 0 :
self.pi_w[i2] = 0
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] > 1 :
n += 1
if n < 0 or self.dup_s == 0 and n < self.size :
print("***error 残す個体がない (S_roul)")
# 淘汰して残す個体を選ぶ
# エリートの選択
sw = 0
while k < elite and k < n and sw == 0 :
max = -1
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] > 1 and self.s_w[i1] == 0 :
if max < 0 or self.pi[i1] > self.pi[max] :
max = i1
if max < 0 :
sw = 1
else :
self.s_w[max] = 1
k += 1
# ルーレット選択
while count < self.size+self.max_ch and k < self.size :
p = self.Select(s_method, s_bias, s_step)
if self.dup_s == 0 and self.s_w[p] > 0 :
count += 1
else :
count = 0
self.s_w[p] += 1
k += 1
# 選択に失敗した場合の処理
if self.dup_s == 0 and k < self.size :
i1 = 0
while i1 < self.size+self.max_ch and k < self.size :
if self.pi_w[i1] > 1 and self.s_w[i1] == 0 :
self.s_w[i1] = 1
k += 1
i1 += 1
# 複数回選択されたものの処理
for i1 in range(0, self.size+self.max_ch) :
if self.s_w[i1] == 0 :
self.pi_w[i1] = 0
for i1 in range(0, self.size+self.max_ch) :
if self.s_w[i1] > 0 :
if self.s_w[i1] > 1 :
for i2 in range(2, self.s_w[i1]+1) :
k = self.Position(-1)
self.len[k] = self.len[i1]
self.pi_w[k] = 2
self.pi[k] = self.pi[i1]
for i3 in range(0, self.len[i1]) :
self.ind[k][i3] = self.ind[i1][i3]
#######################
# クラスFunctionの定義
#######################
class Function ( Species ) :
######################################
# コンストラクタ
# name1 : Species定義ファイル名
# name2 : Function定義ファイル名
######################################
def __init__(self, name1, name2) :
Species.__init__(self, name1) # 親のコンストラクタ
# 基本データの入力
inn = open(name2, "r")
s = inn.readline().split()
self.out_lvl = int(s[1]) # 出力レベル
# =0 : 最終出力だけ
# n>0 : n世代毎に出力(負の時はファイル)
self.out_m = int(s[3]) # 出力方法
# =0 : すべてを出力
# =1 : 最大適応度の個体だけを出力
s = inn.readline().split()
self.o_file = s[1] # 出力ファイル名
self.out_d = int(s[3]) # 表示間隔
s = inn.readline().split()
self.kosa_m = int(s[1]) # 交叉方法
# =-1 : 交叉を使用しない
# =0 : 親のコピー
# =1 : 多点交叉
# =2 : 一様交叉
# =3 : 平均化交叉
self.kosa = float(s[3]) # 交叉確率
self.k_point = int(s[5]) # 交差点の数(負の時は,1から-k_point間のランダム)
self.k_vr = int(s[7]) # =0 : 両親とも同じ位置で交叉
# =1 : 両親が異なる位置で交叉(遺伝子長は可変)
self.k_method = int(s[9]) # 交叉の時の親の選択方法
# =-1 : ランダム
# =0 : 適応度をそのまま使用
# =1 : 最小値からの差(ただし,α以下の場合はα)
# =2 : 評価値に順位をつけ,減少率βで線形化
self.k_bias = float(s[11]) # α,または,method=2の場合は初期値
self.k_step = float(s[13]) # β
s = inn.readline().split()
self.mute_m = int(s[1]) # 突然変異方法
# =-1 : 突然変異を使用しない
# =0 : 対立遺伝子への置換
# =1 : 移動
# =2 : 逆位
# =3 : スクランブル
# =4 : 転座
# =5 : 重複
# =6 : 摂動
self.mute = float(s[3]) # 突然変異率
self.wd = int(s[5]) # 突然変異に使用する部分遺伝子長
self.m_mean = float(s[7]) # 摂動の平均値
self.m_std = float(s[9]) # 摂動の標準偏差
s = inn.readline().split()
self.elite = int(s[1]) # エリート選択で残す数
self.s_method = int(s[3]) # ルーレット板の作成方法
# =0 : 適応度をそのまま使用
# =1 : 最小値からの差(ただし,α以下の場合はα)
# =2 : 評価値に順位をつけ,減少率βで線形化
self.s_bias = float(s[5]) # α,または,s_method=2の場合は初期値
self.s_step = float(s[7]) # β
s = inn.readline().split()
self.max_gen = int(s[1]) # 最大世代交代数
self.cv = 1.0 / (pow(2.0, float(self.max_len)) - 1.0) # 2進数を10進数の変換する係数
inn.close()
###############
# 全体の制御
###############
def Control(self) :
gen = 1
# 初期集団の発生
self.Init_std()
# 評価
self.Adap()
# 出力
print("***世代 " + str(gen) + " 適応度 max " + str(self.max) + " (" + str(self.max_n) + ") mean " + str(self.mean))
if abs(self.out_lvl) > 0 :
self.Output(gen)
# 世代交代
for gen in range(2, self.max_gen+1) :
# 交叉
if self.kosa_m == 0 :
C_copy() # 親のコピー
elif self.kosa_m == 1 :
self.C_point(self.kosa, self.k_point) # 多点交叉
elif self.kosa_m == 2 :
self.C_uniform(self.kosa) # 一様交叉
elif self.kosa_m == 3 :
self.C_mean(self.kosa) # 平均化交叉
# 突然変異
if self.mute_m == 0 :
self.M_alle(self.mute) # 対立遺伝子への置換
elif self.mute_m == 1 :
self.M_move(self.mute) # 移動
elif self.mute_m == 2 :
self.M_inv(self.mute, self.wd) # 逆位
elif self.mute_m == 3 :
self.M_scram(self.mute, self.wd) # スクランブル
elif self.mute_m == 4 :
self.M_chg(self.mute, self.wd) # 転座
elif self.mute_m == 5 :
self.M_dup(self.mute, self.wd) # 重複
elif self.mute_m == 6 :
self.M_per(self.mute, self.wd, self.m_mean, self.m_std) # 摂動
# 適応度
self.Adap()
# 淘汰
self.S_roul(self.elite)
# 出力
if gen%self.out_d == 0 :
print("***世代 " + str(gen) + " 適応度 max " + str(self.max) + " (" + str(self.max_n) + ") mean " + str(self.mean))
if abs(self.out_lvl) > 0 :
if gen%abs(self.out_lvl) == 0 :
self.Output(gen)
gen -= 1
k1 = self.out_m
self.out_m = 0
print("***世代 " + str(gen) + " 適応度 max " + str(self.max) + " (" + str(self.max_n) + ") mean " + str(self.mean))
self.Output(gen)
self.out_m = k1
################
# 適応度の計算
################
def Adap(self) :
n = 0
self.max = 0.0
self.max_n = -1
self.mean = 0.0
for i1 in range(0, self.size+self.max_ch) :
if self.pi_w[i1] == 1 :
x = 0.0
y = 0.0
for i2 in range(self.len[i1]-1, -1, -1) :
if self.ind[i1][i2] > 0 :
x += pow(2.0, y)
y += 1.0
x *= self.cv
self.pi[i1] = sin(3.0*x) + 0.5 * sin(9.0*x) + sin(15.0*x+50.0)
self.pi_w[i1] = 2
if self.pi_w[i1] > 0 :
self.mean += self.pi[i1]
n += 1
if self.max_n < 0 or self.pi[i1] > self.max :
self.max = self.pi[i1]
self.max_n = i1
self.mean /= n
#############################
# 結果の出力
# gen : 現在の世代番号
#############################
def Output(self, gen) :
k = 0
pr = -1
if self.out_lvl >= 0 :
pr = int(input(" 出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? "))
if pr != 0 :
# 出力先の決定と評価値の出力
if pr > 0 :
out = sys.stdout
input("")
else :
now = datetime.today().time().isoformat()
out = open(self.o_file, "a")
out.write("***世代 " + str(gen) + " 適応度 max " + str(self.max) + " (" + str(self.max_n) + ") mean " + str(self.mean) + " 時間 " + now + "\n")
# 詳細出力
for i1 in range(0, self.size+self.max_ch) :
if (self.pi_w[i1] > 1) and (self.out_m == 0 or self.out_m == 1 and i1 == self.max_n) :
out.write(str(i1) + " allele")
for i2 in range(0, self.len[i1]) :
out.write(" " + str(self.ind[i1][i2]))
x = 0.0
y = 0.0
for i2 in range(self.len[i1]-1, -1, -1) :
if self.ind[i1][i2] > 0 :
x += pow(2.0, y)
y += 1.0
x *= self.cv
out.write(" x " + str(x) + " y " + str(self.pi[i1]) + "\n")
if pr > 0 :
k += 1
if k == pr :
input("")
k = 0
if pr < 0 :
out.close()
----------------------------------
# -*- coding: UTF-8 -*-
import numpy as np
import sys
from math import *
from random import *
from function import Species, Function
###################################################################
# f(x) = sin(3.0*x) + 0.5 * sin(9.0*x) + sin(15.0*x + 50) の最大値
# coded by Y.Suganuma
###################################################################
# 入力ミス
if len(sys.argv) <= 1 :
print("***error ファイル名を入力して下さい")
# 入力OK
else :
# データの数と入力データファイル名の入力
inn = open(sys.argv[1], "r")
ss = inn.readline()
n = int(ss) # データの数
i_file1 = []
i_file2 = []
for i1 in range(0, n) :
s = inn.readline().split()
i_file1.append(s[0])
i_file2.append(s[1])
inn.close()
# 実行(乱数の初期値を変える)
for i1 in range(0, n) :
print("\n+++++ケース " + str(i1+1) + "+++++")
fn = Function(i_file1[i1], i_file2[i1])
fn.Control()
------------------ケーススタディデータ(data1.txt)------
3
data2.txt data3.txt
data2.txt data3.txt
data2.txt data3.txt
------------------Species記述データ(data2.txt)---------
対立遺伝子上限 1 対立遺伝子下限 0
最大遺伝子長 15 最小遺伝子長(負の時は,最大遺伝子長で固定) -1
遺伝子の重複 1 個体の重複(同じ染色体の個体) 0
集団サイズ 20 子供 20
------------------Function記述データ(data3.txt)--------
出力レベル(負はファイル) 20 出力方法(0:すべて,1:最大) 0
出力ファイル名 out1.txt 表示間隔 1
交叉方法 1 交叉確率 1.0 点 2 位置 0 方法 1 バイアス 0 ステップ 1
突然変異方法 0 突然変異率 0.05 幅 1 平均 0.0 標準偏差 1.0
エリート 2 方法 1 バイアス 0 ステップ 1
最大世代交代数 200