Похоже, алгоритм Geneti c не оптимизирует - PullRequest
0 голосов
/ 06 февраля 2020

У меня есть простая проблема, чтобы проверить мой 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

Пара графиков для ясности:

enter image description here enter image description here

edit: Забыл поставить легенду, на каждом графике оранжевая линия представляет среднюю пригодность населения, а синяя линия представляет пригодность для лучшего члена за каждое поколение.

1 Ответ

0 голосов
/ 07 февраля 2020

В этом примере лучше использовать точное решение, т. Е. Просто проверить все возможные значения x и вернуть ваше решение.

Geneti c алгоритмы предназначены для задач большого размера. Цель использования алгоритмов geneti c состоит в том, чтобы уменьшить количество решений, которые вы оцениваете в тех больших проблемах, где оценка всех возможных решений нереальна c.

...