I have implemented a complex problem in python. In fact, My code does not have any error. Here is my code (if it seems too long, you can skip it. in last part of question, I have mentioned a short part in my code that I think it makes the simulation time-consuming):
from random import uniform
import numpy as np
from numpy.random import randint
SOLUTION_SEQUENCE = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
TOURNAMENT_SIZE = 20
MAX_FITNESS = 10
FREQUENCY = 28e9
LIGHT_SPEED = 3e8
WAVELENGTH = LIGHT_SPEED / FREQUENCY
K = 2 * np.pi / WAVELENGTH
PHI = 0
RING_ELEMENT_NUM = [6, 12, 18, 25, 31, 37, 43, 50, 56]
RING_NUM = 9
CHROMOSOME_LENGTH = sum(RING_ELEMENT_NUM)
THETA_range_mul10 = range(-900, 901)
class Individual:
def __init__(self):
self.genes = [randint(0, 1) for _ in range(CHROMOSOME_LENGTH)]
def get_fitness(self):
fitness = self.fitness_function(self.genes, self.fn_uniform(), self.fn_com(self.genes))
return fitness
def fitness_function(self, Ipop, fn_uni, fn_com):
WF1 = 0.8
WF2 = 0.2
CF = WF1 * np.abs(fn_com[1] + fn_com[2]) / np.abs(self.AF(Ipop, 0))
+ WF2 * np.abs(fn_com[0] - fn_uni)
return CF
def fn_uniform(self):
AF_uni = self.AF_uniform()
null1 = 0
null2 = 0
for i in range(899):
if AF_uni[int(i + 901) + 1] > AF_uni[int(i + 901)]:
null1 = i / 10
break
for i in range(899):
if AF_uni[int(-i + 901) - 1] > AF_uni[int(i + 901)]:
null2 = i / 10
break
fn = np.abs(null2 - null1)
return [fn]
def fn_com(self, I_pop):
msl1 = 0
msl2 = 0
AF_com = list(range(-900, 901))
for theta in range(-900, 901):
AF_com[theta + 900] = self.AF(I_pop, theta / 10)
null1 = 0
null2 = 0
for i in range(899):
if AF_com[int(i + 901) + 1] > AF_com[int(i + 901)]:
index_msl1 = AF_com.index(max(AF_com[i:]))
msl1 = max(AF_com[i:])
null1 = i / 10
break
for i in range(899):
if AF_com[int(-i + 901) - 1] > AF_com[int(i + 901)]:
index_msl2 = AF_com.index(max(AF_com[0:i]))
msl2 = max(AF_com[i:])
null2 = i / 10
break
fn = np.abs(null2 - null1)
return [fn, msl1, msl2]
def AF_uniform(self):
AF_uni = list(range(-900, 901))
cur = np.ones(CHROMOSOME_LENGTH)
for theta in list(range(-900, 901)):
AF_uni[theta + 900] = self.AF(cur, theta / 10)
return AF_uni
def AF(self, cur, theta):
AF_out = 1
AF_out = 1 + sum(sum(cur[i] * np.exp(1j * K * (m * WAVELENGTH / 2) *
np.sin(theta) * np.cos(PHI - 2 * np.pi * (i - 1) / RING_ELEMENT_NUM[m]))
for i in range(RING_ELEMENT_NUM[m])) for m in range(RING_NUM))
return AF_out
def set_gene(self, index, value):
self.genes[index] = value
def __repr__(self):
return ''.join(str(e) for e in self.genes)
class Population:
def __init__(self, population_size):
self.population_size = population_size
self.individuals = [Individual() for _ in range(population_size)]
def get_fittest(self):
fittest = self.individuals[0]
for individual in self.individuals[1:]:
if individual.get_fitness() > fittest.get_fitness():
fittest = individual
return fittest
def get_fittest_elitism(self, n):
self.individuals.sort(key=lambda ind: ind.get_fitness(), reverse=True)
print(self.individuals)
print(self.individuals[:n])
return self.individuals[:n]
def get_size(self):
return self.population_size
def get_individual(self, index):
return self.individuals[index]
def save_individual(self, index, individual):
self.individuals[index] = individual
class GeneticAlgorithm:
def __init__(self, population_size=100, crossover_rate=0.65, mutation_rate=0.1, elitism_param=5):
self.population_size = population_size
self.crossover_rate = crossover_rate
self.mutation_rate = mutation_rate
self.elitism_param = elitism_param
def run(self):
pop = Population(self.population_size)
generation_counter = 0
while pop.get_fittest().get_fitness() != MAX_FITNESS:
generation_counter += 1
print('Generation #%s - fittest is: %s with fitness value %s' % (
generation_counter, pop.get_fittest(), pop.get_fittest().get_fitness()))
pop = algorithm.evolve_population(pop)
print('Solution found...')
print(pop.get_fittest())
def evolve_population(self, population):
next_population = Population(self.population_size)
# elitism: the top fittest individuals from previous population survive
# so we copy the top 5 individuals to the next iteration (next population)
# in this case the population fitness can not decrease during the iterations
next_population.individuals.extend(population.get_fittest_elitism(self.elitism_param))
# crossover
for index in range(self.elitism_param, next_population.get_size()):
first = self.random_selection(population)
second = self.random_selection(population)
next_population.save_individual(index, self.crossover(first, second))
# mutation
for individual in next_population.individuals:
self.mutate(individual)
print(next_population)
return next_population
def crossover(self, offspring1, offspring2):
cross_individual = Individual()
start = randint(CHROMOSOME_LENGTH)
end = randint(CHROMOSOME_LENGTH)
if start > end:
start, end = end, start
cross_individual.genes = offspring1.genes[:start] + offspring2.genes[start:end] + offspring1.genes[end:]
return cross_individual
def mutate(self, individual):
for index in range(CHROMOSOME_LENGTH):
if uniform(0, 1) <= self.mutation_rate:
individual.genes[index] = randint(CHROMOSOME_LENGTH)
# this is called tournament selection
def random_selection(self, actual_population):
new_population = Population(TOURNAMENT_SIZE)
for i in range(new_population.get_size()):
random_index = randint(new_population.get_size())
new_population.save_individual(i, actual_population.get_individual(random_index))
return new_population.get_fittest()
if __name__ == '__main__':
algorithm = GeneticAlgorithm(100, 0.8, 0.015)
algorithm.run()
Here is part of my code likely causing the problem and making the simulation time-consuming:
def AF(self, cur, theta):
AF_out = 1
AF_out = 1 + sum(sum(cur[i] * np.exp(1j * K * (m * WAVELENGTH / 2) *
np.sin(theta) * np.cos(PHI - 2 * np.pi * (i - 1) / RING_ELEMENT_NUM[m]))
for i in range(RING_ELEMENT_NUM[m])) for m in range(RING_NUM))
return AF_out
If you ask me, how I anticipated this part takes a lot of time, I would say that every time I clicked on start simulation option and then clicked on stop simulation option, it stopped at this line.