我正在尝试应用遗传算法的概念来解决Python中的非线性优化问题,并将结果与其他方法进行比较。我正在尝试求解受以下约束的最小x1.x4(x1 + x2 + x3)+ x3:x1.x2.x3.x4> = 25,x1 ^ 2 + x2 ^ 2 + x3 ^ 2 + x4 ^ 2 == 40,并且x1到x4中的每一个小于或等于5且大于或等于1。此外,初始解为x0 =(1,5,5,1)。 我已经使用scipy和gekko解决了该问题,并得到以下结果:x1 = 1,x2 = 4.743,x3 = 3.8321,x4 = 1.379。
当我运行我的GA代码时,x1,x2,x3始终为1,5,5,并且x4有时为负数或小于1。此外,有时我的目标函数是增加而不是减少(趋势并且每次我运行代码时值都不一致。
下面是我的Python GA代码:
import numpy
# Number of the weights we are looking to optimize.
num_weights = 4 # x1,x2,x3, x4 (4 numbers): no of genes
sol_per_pop = 8 #no. of chromosones; can be changed
num_parents_mating = 4
fitness=numpy.zeros(sol_per_pop)
def cal_pop_fitness(pop):
# Calculating the fitness value of each solution in the current population.
for i in range(sol_per_pop):#(0 till sol_per_pop -1)
#objective function: x4*x1^2 + x1*x2*x4 + x1*x3*x4+ x3
#the fitness value is the objective function
fitness[i]= ((new_population[i][3])*(new_population[i][0]**2))+ \
((new_population[i][0])*(new_population[i][1])*(new_population[i][3]))+\
((new_population[i][0])*(new_population[i][2])*(new_population[i][3]))+(new_population[i][2])
return fitness
def select_mating_pool(pop, fitness, num_parents):
# Selecting the best individuals in the current generation as parents for producing the offspring of the next generation.
parents = numpy.empty((num_parents, pop.shape[1]))#initialize an empty parent array of size equal to 4 rows(num_parents_mating)
#and columns equal to the number of genes(4) which is pop.shape[1]
#add constraints
#initialize functions to be filled by the 6 constraints
# specifiying the dtype to int64 is to avoid the following warning/error: RuntimeWarning: overflow encountered in long scalars
a=numpy.zeros(sol_per_pop,dtype='int64') #for 1st cons.
b=numpy.zeros(sol_per_pop,dtype='int64') #for 2nd cons.
c=numpy.zeros(sol_per_pop,dtype='int64') #for 3rd cons.
d=numpy.zeros(sol_per_pop,dtype='int64') #for 4th cons.
e=numpy.zeros(sol_per_pop,dtype='int64') #for 5th cons.
f=numpy.zeros(sol_per_pop,dtype='int64') #for 6th cons.
for i in range(sol_per_pop):#(0 till sol_per_pop -1)
#filling the 6 functions
a[i]=(new_population[i][0])*(new_population[i][1])*(new_population[i][2])*(new_population[i][3])
b[i]=(new_population[i][0]**2)+(new_population[i][1]**2)+(new_population[i][2]**2)+(new_population[i][3]**2)
c[i]=new_population[i][0]
d[i]=new_population[i][1]
e[i]=new_population[i][2]
f[i]=new_population[i][3]
for parent_num in range(num_parents):
#check if all constraints are met
for i in range(sol_per_pop):
min_fitness_idx = numpy.where(fitness == numpy.min(fitness))#get index where fitness is minimum (obj function)
min_fitness_idx = min_fitness_idx[0][0]#takes only the number
if a[min_fitness_idx]>=25 and b[min_fitness_idx]==40 and c[min_fitness_idx]>=1 and c[min_fitness_idx]<=5 and d[min_fitness_idx]>=1 and d[min_fitness_idx]<=5 and e[min_fitness_idx]>=1 and e[min_fitness_idx]<=5 and f[min_fitness_idx]>=1 and f[min_fitness_idx]<=5:
parents[parent_num, :] = pop[min_fitness_idx, :]
fitness[min_fitness_idx] = +99999999999
break
else:
#remove the fitness value that violates the constraints
fitness[min_fitness_idx]= 100000
pass
return parents
def crossover(parents,offspring_size):
offspring = numpy.empty(offspring_size) #initialze an empty offspring array of number of rows
#equal to number of choromosones - number of rows of parent array ; columns equal to number of genes (4)
# The point at which crossover takes place between two parents. Usually it is at the center.
crossover_point = numpy.uint8(offspring_size[1]/2)# specifies the point where crossover will take place
#unit8 is the type of the number :uint8 is Unsigned integer (0 to 255) ;offspring_size[1] is the number of columns(no of genes)
for k in range(offspring_size[0]): #k : 0 -->3
# Index of the first parent to mate.
parent1_idx = k%parents.shape[0] #returns the remainder of k divided by the number of rows of the parent array
# Index of the second parent to mate.
parent2_idx = (k+1)%parents.shape[0] #returns the remainder of k+1 divided by the number of rows of the parent array
# The new offspring will have its first half of its genes taken from the first parent.
offspring[k, 0:crossover_point] = parents[parent1_idx, 0:crossover_point]
# The new offspring will have its second half of its genes taken from the second parent.
offspring[k, crossover_point:] = parents[parent2_idx, crossover_point:]
return offspring
def mutation(offspring_crossover):
# Mutation changes a single gene in each offspring randomly.
for idx in range(offspring_crossover.shape[0]):
# The random value to be added to the gene.
random_value = numpy.random.uniform(-1.0, 1.0, 1)#random number from -1 to 1
offspring_crossover[idx, 3] = offspring_crossover[idx, 3] + random_value #changes the value of the last gene only
return offspring_crossover
# Defining the population size.
pop_size = (sol_per_pop,num_weights) # The population will have sol_per_pop chromosome where each chromosome has num_weights genes.
#Creating the initial population.
#might need to be changed ( keep only 1st row and other rows put random nos.)
new_population = numpy.zeros(shape=(sol_per_pop,num_weights))
for i in range(num_weights):#columns
for j in range(sol_per_pop): #rows
if i==0:
new_population[j][i]=1
if i==1:
new_population[j][i]=5
if i==2:
new_population[j][i]=5
if i==3:
new_population[j][i]=1
print("the initial population is: \n" , new_population)
num_generations = 5
for generation in range(num_generations):
print("Generation : ", generation)
# Measing the fitness of each chromosome in the population.
fitness = cal_pop_fitness(new_population)
# Selecting the best parents in the population for mating.
parents = select_mating_pool(new_population, fitness, num_parents_mating)
# Generating next generation using crossover.
offspring_crossover = crossover(parents, offspring_size=(pop_size[0]-parents.shape[0], num_weights))
# Adding some variations to the offsrping using mutation.
offspring_mutation = mutation(offspring_crossover)
# Creating the new population based on the parents and offspring.
new_population[0:parents.shape[0], :] = parents
new_population[parents.shape[0]:, :] = offspring_mutation
# The best result in the current iteration.
af=((new_population[generation][3])*(new_population[generation][0]**2))+ \
((new_population[generation][0])*(new_population[generation][1])*(new_population[generation][3]))+\
((new_population[generation][0])*(new_population[generation][2])*(new_population[generation][3]))+(new_population[generation][2])
print("Best result : ", numpy.min(af))
# Getting the best solution after iterating finishing all generations.
#At first, the fitness is calculated for each solution in the final generation.
fitness = cal_pop_fitness(new_population)
# Then return the index of that solution corresponding to the best fitness.
best_match_idx = numpy.where(fitness == numpy.min(fitness))
print("Best solution : ", new_population[best_match_idx, :])
print("Best solution fitness : ", fitness[best_match_idx])
谢谢!