У меня есть простая проблема, чтобы проверить мой GA, но он, кажется, не сходится или сходится к, казалось бы, случайному значению. Я видел другие посты с похожими проблемами и исправлял проблемы, которые присутствуют в тех, которые я видел (если они актуальны), но они все еще не сходятся. Я не уверен, нужно ли просто играть с такими переменными, как частота мутаций и т. Д. c. или я сделал что-то не так. Задача, которую он пытается оптимизировать, довольно проста: найти максимум функции f (x) = xsin (10πx) +1 в диапазоне -1
Код:
#####################################################################################################
################################# Genetic Algorithm Class (Attempt) #################################
#####################################################################################################
#####################################################################################################
########################################## Relevant Imports ##########################################
#####################################################################################################
import numpy as np
import matplotlib.pyplot as plt
import random
from qutip import *
class GA:
#####################################################################################################
################################## Fitness and Selection Function ###################################
############# Detects how well the pulse sequence works and selects the top x sequences #############
#####################################################################################################
def fitness(self, population):
n = np.linspace(0,len(population)-1,len(population)) # creates list for indices for loop
f = np.zeros(int(len(n))) # defines empty array for fitness values
# runs a loop to obtain the fitness values of all members in the population and add each
# fitness for each population to array f
for i in n:
f[int(i)] = population[int(i)]*np.sin(10*np.pi*population[int(i)])+1
# finds the total fitness to obtain percentage values to allow for biased selection
total_f = sum(f)
percentage_f = [x + abs(min(f)) for x in f]
percentage_f = [x/sum(percentage_f) for x in percentage_f]
return [f, percentage_f]
#####################################################################################################
############################################ Cross Over #############################################
################## "Breeds" two ideal solutions to try and obtain a better solution #################
#####################################################################################################
def crossover(self,a,b):
new_a = (a+b)/2
return new_a
#####################################################################################################
############################################### Mutate ###############################################
########################################## Mutates a member ##########################################
#####################################################################################################
def mutate(self,a, mutationrate):
check = np.random.choice(['mutate','dont mutate'], 1, p = [mutationrate,1-mutationrate])
if check == 'mutate':
new_a = 0
while new_a < -1 or new_a > 2:
new_a = a + random.uniform(-1,1)
return new_a
else:
return a
return
#####################################################################################################
######################################### Create New Member #########################################
################################ Creates a new random pulse sequence ################################
#####################################################################################################
def create_new_member(self,min_val = -1, max_val = 2):
member = random.uniform(min_val,max_val)
return member
#####################################################################################################
##################################### Create Initial Population #####################################
################################ Creates an initial array of members ################################
#####################################################################################################
def create_initial_population(self,size):
population = [] # define empty population array
#loops over desired size to append each member into the population array
for i in range(0,size):
population.append(self.create_new_member())
return population
#####################################################################################################
###################################### Create Next Generation #######################################
####################### Runs a loop to create a number of new pulse sequences #######################
#####################################################################################################
def create_next_generation(self, population, percentage_f, size):
#################################### Biased selection ####################################
# selects a number of members (defined by input size) in the population, taking
# into consideration the probability distribution percentage_f where each index of
# the probability distribution corresponds to the same indexed member in the population
# The key word replace defines whether, once a member is chosen, it is removed or kept
# in for the next choice
new_population = np.random.choice(population, size, p=percentage_f, replace = True)
return new_population
#####################################################################################################
############################################### Main ################################################
##################################### Main body of the program ######################################
#####################################################################################################
def main(self, number_of_itterations, size, mutations, crossovers):
bestf = []
avgf = []
# creates the initial population
population = self.create_initial_population(size)
# creates interger list to loop over for the number of desired itterations
generations = np.linspace(1, number_of_itterations, number_of_itterations)
################################ Start of optimisation loop ################################
for i in generations:
p = np.linspace(1, crossovers, crossovers)
index_p = np.linspace(0,len(population)-1,len(population)) # redefines index array to
# to include all members again
for k in p:
# Selects 2 random index values for the population to crossover and removes them
# from the index array
r1 = random.choice(index_p)
np.delete(index_p,int(r1))
r2 = random.choice(index_p)
np.delete(index_p,int(r1))
children = self.crossover(population[int(r1)], population[int(r2)]) # creates the children
# members
population = np.hstack((population,children)) # extends the child members into the population array
######### Mutates a random member for the number of times defined by mutations ########
m = np.linspace(1, len(population), len(population)) # itterations for number of mutations
index_p = np.linspace(0,len(population)-1,len(population)) # index values of population
mutationrate = 1/len(population)
for j in m:
r1 = random.choice(index_p) # chooses random index in population to mutate
population[int(r1)] = self.mutate(population[int(r1)],mutationrate) # mutates member in population at
# index r1
np.delete(index_p,int(r1)) # removes index r1 from index array to prevent the same member
# being mutated twice
[f, percentage_f] = self.fitness(population) # evaluates the fitness of each member in
# the population
bestf.append(max(f))
avgf.append(np.mean(f))
# Overwrites the population array by creating the next generation
population = self.create_next_generation(population, percentage_f, size)
plt.plot(generations,bestf)
plt.plot(generations,avgf)
plt.title('Final Plot')
plt.xlabel('Generation')
plt.ylabel('Y-value (fitness)')
plt.savefig('Final plot.png')
plt.show()
return
Пара графиков для ясности:
edit: Забыл поставить легенду, на каждом графике оранжевая линия представляет среднюю пригодность населения, а синяя линия представляет пригодность для лучшего члена за каждое поколение.