Problem description
f(x)=x*sin(x)+1, x belongs to [0,2 π]. Taking solving the maximum and minimum value of f(x) as an example, a genetic algorithm program for f(x) is designed, and then run to solve it
(1) Determine the basic functions: this experiment is to solve the maximum and minimum values of f (x).
(2) Encoding f(x): a chromosome is represented by a binary vector, and the chromosome represents the real value of variable x.
(3) Design fitness function: since the maximum value of F (x) is required, the fitness function is f (x).
(4) Design and implement genetic algorithm program for f(x): genetic operation mainly includes replication, crossover and mutation. Replication is to directly pass on the parent generation to the offspring, that is, whether it is eliminated or inherited in the next generation is determined according to the quality measured by the fitness function value of the individual. Crossover selects two individuals who can enter the next generation and exchanges part of their code values. Mutation is to select an individual according to the mutation probability and change its bit code randomly.
(5) Design initial population: the default setting is 50 randomly generated 23 bit chromosomes. The population size can be set through input.
(6) Debug crossover and mutation probability: within the commonly used crossover and mutation probability range, the results change with the change of crossover and mutation probability, and the difference between them is relatively less obvious
Population initialization
The process of population initialization is to randomly generate random binary coded individuals with population size and quantity
Reference code
def get_chromosome(size, length): """ generate size Length of length Chromosome list :param size: Population size :param length: Chromosome length :return: 2D list """ population_temp = [] for i in range(size): population_temp.append([random.randint(0, 1) for _ in range(length)]) # Generate a random binary list with length and store it in population_temp list return population_temp
Calculate search accuracy
Here, according to the accuracy calculation formula:
δ
=
U
x
−
L
x
2
l
−
1
\delta = \frac{U_{x} - L_{x}}{2 ^{l} - 1}
δ=2l−1Ux−Lx
Reference code
def get_accuracy(min_, max_, length): """ Calculate search accuracy :param min_: Minimum value of gene :param max_: Maximum value of gene :param length: Chromosome length :return: accuracy """ return (max_ - min_) / (2 ** length - 1) # Accuracy calculation formula
Chromosome decoding
Here, according to the decoding formula:
x
=
L
x
+
δ
∑
i
=
1
l
A
i
2
i
−
1
x = L_{x} + \delta \sum_{i=1}^l A_{i} 2^{i-1}
x=Lx+δi=1∑lAi2i−1
Reference code
def chromosome_decode(chromosome_list, min_, accuracy_): """ Chromosome decoding :param chromosome_list: Binary chromosome list :param min_: Minimum value of gene :param accuracy_: accuracy :return: Decoding results """ decimal = int(''.join([str(i) for i in chromosome_list]), 2) # Convert binary list to decimal integer return min_ + accuracy_ * decimal # Decoding formula
Selection operator
There are many ways to realize the selection operator in genetic algorithm. The more effective ones are roulette algorithm and League selection algorithm. Roulette algorithm is used here
The essence of roulette algorithm is that it can make random selection according to individual fitness. The greater the fitness, the greater the probability of individual selection. When the population scale is large, this algorithm can truly simulate the situation in the natural state
Reference code
def select(chromosome_list, fitness_list): """ choice(roulette algorithm ) :param chromosome_list: Population of two-dimensional list :param fitness_list: Fitness list :return: Population list after selection """ population_fitness = np.array(fitness_list).sum() # Population fitness fit_ratio = [i / population_fitness for i in fitness_list] # Proportion of each individual in population fitness fit_ratio_add = [0] # Individual cumulative probability for i in fit_ratio: fit_ratio_add.append(fit_ratio_add[len(fit_ratio_add) - 1] + i) # Calculate the cumulative probability of each individual and store it in fit_ ratio_ In add fit_ratio_add = fit_ratio_add[1:] # Remove the first 0 rand_list = [random.uniform(0, 1) for _ in chromosome_list] # Generate a list of random values equal to the population size for roulette selection rand_list.sort() fit_index = 0 new_index = 0 new_population = chromosome_list.copy() '''Individual selection start''' while new_index < len(chromosome_list): if rand_list[new_index] < fit_ratio_add[fit_index]: new_population[new_index] = chromosome_list[fit_index] new_index = new_index + 1 else: fit_index = fit_index + 1 '''Individual selection end''' return new_population
Crossover operator
The crossover operator is used to simulate the mating process in the natural state. In order to simplify this process, some chromosomes of two individuals are exchanged directly
Reference code
def exchange(chromosome_list, pc): """ overlapping :param chromosome_list: Population of two-dimensional list :param pc: Crossover probability """ for i in range(0, len(chromosome_list) - 1, 2): if random.uniform(0, 1) < pc: c_point = random.randint(0, len(chromosome_list[0])) # Randomly generated intersection '''On the first i Bit sum i+1 Bit crossover start''' exchanged_list1 = [] exchanged_list2 = [] exchanged_list1.extend(chromosome_list[i][0:c_point]) exchanged_list1.extend(chromosome_list[i + 1][c_point:len(chromosome_list[i])]) exchanged_list2.extend(chromosome_list[i + 1][0:c_point]) exchanged_list2.extend(chromosome_list[i][c_point:len(chromosome_list[i])]) '''On the first i Bit sum i+1 Bit crossover end''' '''Replace the original chromosome with the newly crossed chromosome start''' chromosome_list[i] = exchanged_list1 chromosome_list[i + 1] = exchanged_list2 '''Replace the original chromosome with the newly crossed chromosome end'''
Mutation operator
The mutation process simulates the gene mutation in the natural state
Reference code
def mutation(chromosome_list, pm): """ variation :param chromosome_list: Population of two-dimensional list :param pm: Variation probability """ for i in range(len(chromosome_list)): if random.uniform(0, 1) < pm: m_point = random.randint(0, len(chromosome_list[0]) - 1) # Randomly generated variation points chromosome_list[i][m_point] = chromosome_list[i][m_point] ^ 1 # XOR the value of this bit with 1 (that is, set 0 to 1 and 1 to 0)
optimization
In fact, only by realizing the above functions, a complete genetic algorithm process can be realized, but in practice, we can optimize the algorithm process to make the results more in line with our expectations
- Using the elite retention strategy, the optimal individual is directly retained to the next generation without the selection process
- Directly eliminate some individuals who do not meet expectations in each generation, such as individuals with negative fitness
Complete code
# coding=utf-8 # @Author: GongDeFeng import random import numpy as np import matplotlib.pyplot as plt population_size = 50 # Initial population size generation_count = 50 # Genetic algebra gene_length = 23 # Chromosome length exchange_ratio = 0.8 # Crossover probability variation_ratio = 0.01 # Variation probability solve_max = True # True to solve the maximum value and False to solve the minimum value function = lambda x: x * np.sin(x) + 1 # Mathematical function to be solved x_min = 0 # The minimum value of gene, that is, the minimum value that variable x can take x_max = 2 * np.pi # The maximum value of gene, that is, the maximum value that variable x can take plt.rcParams['font.sans-serif'] = ['FangSong'] # Set Chinese font plt.rcParams['axes.unicode_minus'] = False # Show negative sign support def get_chromosome(size, length): """ generate size Length of length Chromosome list :param size: Population size :param length: Chromosome length :return: 2D list """ population_temp = [] for i in range(size): population_temp.append([random.randint(0, 1) for _ in range(length)]) # Generate a random binary list with length and store it in population_temp list return population_temp def get_accuracy(min_, max_, length): """ Calculate search accuracy :param min_: Minimum value of gene :param max_: Maximum value of gene :param length: Chromosome length :return: accuracy """ return (max_ - min_) / (2 ** length - 1) # Accuracy calculation formula def chromosome_decode(chromosome_list, min_, accuracy_): """ Chromosome decoding :param chromosome_list: Binary chromosome list :param min_: Minimum value of gene :param accuracy_: accuracy :return: Decoding results """ decimal = int(''.join([str(i) for i in chromosome_list]), 2) # Convert binary list to decimal integer return min_ + accuracy_ * decimal # Decoding formula def get_fitness(x, solve_flag): """ Calculate fitness :param x: Chromosome decoding results :param solve_flag: The maximum value is True,The minimum value is False :return: Fitness results """ if solve_flag: return function(x) return -(function(x)) def select(chromosome_list, fitness_list): """ choice(roulette algorithm ) :param chromosome_list: Population of two-dimensional list :param fitness_list: Fitness list :return: Population list after selection """ population_fitness = np.array(fitness_list).sum() # Population fitness fit_ratio = [i / population_fitness for i in fitness_list] # Proportion of each individual in population fitness fit_ratio_add = [0] # Individual cumulative probability for i in fit_ratio: fit_ratio_add.append(fit_ratio_add[len(fit_ratio_add) - 1] + i) # Calculate the cumulative probability of each individual and store it in fit_ ratio_ In add fit_ratio_add = fit_ratio_add[1:] # Remove the first 0 rand_list = [random.uniform(0, 1) for _ in chromosome_list] # Generate a list of random values equal to the population size for roulette selection rand_list.sort() fit_index = 0 new_index = 0 new_population = chromosome_list.copy() '''Individual selection start''' while new_index < len(chromosome_list): if rand_list[new_index] < fit_ratio_add[fit_index]: new_population[new_index] = chromosome_list[fit_index] new_index = new_index + 1 else: fit_index = fit_index + 1 '''Individual selection end''' return new_population def exchange(chromosome_list, pc): """ overlapping :param chromosome_list: Population of two-dimensional list :param pc: Crossover probability """ for i in range(0, len(chromosome_list) - 1, 2): if random.uniform(0, 1) < pc: c_point = random.randint(0, len(chromosome_list[0])) # Randomly generated intersection '''On the first i Bit sum i+1 Bit crossover start''' exchanged_list1 = [] exchanged_list2 = [] exchanged_list1.extend(chromosome_list[i][0:c_point]) exchanged_list1.extend(chromosome_list[i + 1][c_point:len(chromosome_list[i])]) exchanged_list2.extend(chromosome_list[i + 1][0:c_point]) exchanged_list2.extend(chromosome_list[i][c_point:len(chromosome_list[i])]) '''On the first i Bit sum i+1 Bit crossover end''' '''Replace the original chromosome with the newly crossed chromosome start''' chromosome_list[i] = exchanged_list1 chromosome_list[i + 1] = exchanged_list2 '''Replace the original chromosome with the newly crossed chromosome end''' def mutation(chromosome_list, pm): """ variation :param chromosome_list: Population of two-dimensional list :param pm: Variation probability """ for i in range(len(chromosome_list)): if random.uniform(0, 1) < pm: m_point = random.randint(0, len(chromosome_list[0]) - 1) # Randomly generated variation points chromosome_list[i][m_point] = chromosome_list[i][m_point] ^ 1 # XOR the value of this bit with 1 (that is, set 0 to 1 and 1 to 0) def get_best(fitness_list): """ Calculate the best individual in this generation :param fitness_list: Fitness list :return: Subscript of optimal individual """ return fitness_list.index(max(fitness_list)) def eliminate(fitness_list): """ eliminate(Remove negative values) :param fitness_list: Fitness list :return: Obsolete list """ fit_value = [] for i in range(len(fitness_list)): fit_value.append(fitness_list[i] if fitness_list[i] >= 0 else 0.0) # Set fitness less than 0 to 0 return fit_value if __name__ == '__main__': results = [] # Store the optimal solution of each generation, two-dimensional list all_fitness = [] # Store the highest fitness and population fitness in each generation population = get_chromosome(population_size, gene_length) # Population initialization for _ in range(generation_count): accuracy = get_accuracy(x_min, x_max, gene_length) # Calculate search accuracy decode_list = [chromosome_decode(individual, x_min, accuracy) for individual in population] # Decoded list fit_list = [get_fitness(decode_i, solve_max) for decode_i in decode_list] # Calculate the fitness of each individual fit_list = eliminate(fit_list) # Eliminate a part and remove the negative value results.append([decode_list[get_best(fit_list)], fit_list[get_best(fit_list)] if solve_max else -fit_list[get_best(fit_list)]]) # Save the optimal solution of each generation, that is, the individual with the highest fitness all_fitness.append(np.array(fit_list).sum() if solve_max else -np.array(fit_list).sum()) # Preserve the highest fitness and population fitness in each generation population = select(population.copy(), fit_list) exchange(population, exchange_ratio) mutation(population, variation_ratio) if solve_max: results.sort(key=lambda x: x[1]) else: results.sort(key=lambda x: x[1], reverse=True) print('most{}Value point x={},y={}'.format('large' if solve_max else 'Small', results[-1][0], results[-1][1])) '''Draw extreme value trend chart and population fitness trend chart start''' X = [generation_i for generation_i in range(generation_count)] Y1 = [results[generation_i][1] for generation_i in range(generation_count)] Y2 = [all_fitness[generation_i] for generation_i in range(generation_count)] fig1 = plt.figure('figure', figsize=(13, 5)).add_subplot(121) fig1.plot(X, Y1) fig2 = plt.figure('figure', figsize=(13, 5)).add_subplot(122) fig2.plot(X, Y2) fig1.set_title('Extreme point trend chart') fig1.set_xlabel("Genetic algebra") fig1.set_ylabel("extremum") fig2.set_title('Overall fitness trend of population') fig2.set_xlabel("Genetic algebra") fig2.set_ylabel("Population fitness") plt.show() '''Draw extreme value trend chart and population fitness trend chart end'''