題目:
用遺傳算法求函數f(a,b)=2a x sin(8PI x b) + b x cos(13PI x a)最大值,a:[-3,7],b:[-4:10]
實現步驟:
- 初始化種群
- 計算種群中每個個體的適應值
- 淘汰部分個體(這里是求最大值,f值存在正值,所以淘汰所有負值)
- 輪盤算法對種群進行選擇
- 進行交配、變異,交叉點、變異點隨機
分析:
為了方便,先將自變量范圍調整為[0,10]、[0,14]
有兩個變量,種群中每個個體用一個列表表示,兩個列表項,每項是一個二進制字符串(分別由a、b轉化而來)
種群之間交配時需要確定交叉點,先將個體染色體中的兩個二進制字符串拼接,再確定一個隨機數作為交叉點
為了程序的數據每一步都比較清晰正確,我在select、crossover、mutation之后分別都進行了一次適應值的重新計算
具體代碼:
import math
import random
def sum(list):
total = 0.0
for line in list:
total += line
return total
def rand(a, b):
number = random.uniform(a,b)
return math.floor(number*100)/100
PI = math.pi
def fitness(x1,x2):
return 2*(x1-3)*math.sin(8*PI*x2)+(x2-4)*math.cos(13*PI*x1)
def todecimal(str):
parta = str[0:4]
partb = str[4:]
numerical = int(parta,2)
partb = partb[::-1]
for i in range(len(partb)):
numerical += int(partb[i])*math.pow(0.5,(i+1))
return numerical
def tobinarystring(numerical):
numa = math.floor(numerical)
numb = numerical - numa
bina = bin(numa)
bina = bina[2:]
result = "0"*(4-len(bina))
result += bina
for i in range(7):
numb *= 2
result += str(math.floor(numb))
numb = numb - math.floor(numb)
return result
class Population:
def __init__(self):
self.pop_size = 500 # 設定種群個體數為500
self.population = [[]] # 種群個體的二進制字符串集合,每個個體的字符串由一個列表組成[x1,x2]
self.individual_fitness = [] # 種群個體的適應度集合
self.chrom_length = 22 # 一個染色體22位
self.results = [[]] # 記錄每一代最優個體,是一個三元組(value,x1_str,x2_str)
self.pc = 0.6 # 交配概率
self.pm = 0.01 # 變異概率
self.distribution = [] # 用於種群選擇時的輪盤
def initial(self):
for i in range(self.pop_size):
x1 = rand(0,10)
x2 = rand(0,14)
x1_str = tobinarystring(x1)
x2_str = tobinarystring(x2)
self.population.append([x1_str,x2_str]) # 添加一個個體
fitness_value = fitness(x1,x2)
self.individual_fitness.append(fitness_value) # 記錄該個體的適應度
self.population = self.population[1:]
self.results = self.results[1:]
def eliminate(self):
for i in range(self.pop_size):
if self.individual_fitness[i]<0:
self.individual_fitness[i] = 0.0
def getbest(self):
"取得當前種群中的一個最有個體加入results集合"
index = self.individual_fitness.index(max(self.individual_fitness))
x1_str = self.population[index][0]
x2_str = self.population[index][1]
value = self.individual_fitness[index]
self.results.append((value,x1_str,x2_str,))
def select(self):
"輪盤算法,用隨機數做個體選擇,選擇之后會更新individual_fitness對應的數值"
"第一步先要初始化輪盤"
"選出新種群之后更新individual_fitness"
total = sum(self.individual_fitness)
begin = 0
for i in range(self.pop_size):
temp = self.individual_fitness[i]/total+begin
self.distribution.append(temp)
begin = temp
new_population = []
new_individual_fitness = []
for i in range(self.pop_size):
num = random.random() # 生成一個0~1之間的浮點數
j = 0
for j in range(self.pop_size):
if self.distribution[j]<num:
continue
else:
break
index = j if j!=0 else (self.pop_size-1)
new_population.append(self.population[index])
new_individual_fitness.append(self.individual_fitness[index])
self.population = new_population
self.individual_fitness = new_individual_fitness
def crossover(self):
"選擇好新種群之后要進行交配"
"注意這只是一次種群交配,種群每一次交配過程,會讓每兩個相鄰的染色體進行信息交配"
for i in range(self.pop_size-1):
if random.random()<self.pc:
cross_position = random.randint(1,self.chrom_length-1)
i_x1x2_str = self.population[i][0]+self.population[i][1] # 拼接起第i個染色體的兩個二進制字符串
i1_x1x2_str = self.population[i+1][0]+self.population[i+1][1] # 拼接起第i+1個染色體的兩個二進制字符串
str1_part1 = i_x1x2_str[:cross_position]
str1_part2 = i_x1x2_str[cross_position:]
str2_part1 = i1_x1x2_str[:cross_position]
str2_part2 = i1_x1x2_str[cross_position:]
str1 = str1_part1+str2_part2
str2 = str2_part1+str1_part2
self.population[i] = [str1[:11],str1[11:]]
self.population[i+1] = [str2[:11],str2[11:]]
"然后更新individual_fitness"
for i in range(self.pop_size):
x1_str = self.population[i][0]
x2_str = self.population[i][1]
x1 = todecimal(x1_str)
x2 = todecimal(x2_str)
self.individual_fitness[i] = fitness(x1,x2)
def mutation(self):
"個體基因變異"
for i in range(self.pop_size):
if random.random()<self.pm:
x1x2_str = self.population[i][0]+self.population[i][1]
pos = random.randint(0,self.chrom_length-1)
bit = "1" if x1x2_str[pos]=="0" else "0"
x1x2_str = x1x2_str[:pos]+bit+x1x2_str[pos+1:]
self.population[i][0] = x1x2_str[:11]
self.population[i][1] = x1x2_str[11:]
"然后更新individual_fitness"
for i in range(self.pop_size):
x1_str = self.population[i][0]
x2_str = self.population[i][1]
x1 = todecimal(x1_str)
x2 = todecimal(x2_str)
self.individual_fitness[i] = fitness(x1, x2)
def solving(self,times):
"進行times次數的整個種群交配變異"
"先獲得初代的最優個體"
self.getbest()
for i in range(times):
"每一代的染色體個體和適應值,需要先淘汰,然后選擇,再交配、變異,最后獲取最優個體。然后進入下一代"
self.eliminate()
self.select()
self.crossover()
self.mutation()
self.getbest()
def returnbest(self):
self.results.sort()
return self.results[len(self.results)-1]
if __name__ == '__main__':
demo = Population()
demo.initial()
demo.solving(100)
answer = demo.returnbest()
value = answer[0]
x1 = todecimal(answer[1])
x2 = todecimal(answer[2])
print(x1,x2,value)
參考文章