0

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.

mohammad rezza
  • 324
  • 1
  • 3
  • 17
  • For a start, I'd pull np.sin(theta) out of the loop. I'm also wondering if your code is correct since I think your two "for" loops are in reverse order. Or do you have have older value of `m` from before the loop that you're accidentally using in the first `for`. – Frank Yellin May 08 '23 at 15:43
  • thank you @FrankYellin , But I've just used the following link: https://stackoverflow.com/questions/66475717/nested-summation-in-python I think my formula is acceptable. But, If you have another way to implement it, let me know. – mohammad rezza May 08 '23 at 21:25
  • Trust me. Your `for`s are backwards. Your `for i in range(.....[m])` gets executed before the `for m in range(...)` is. The value of `m` is not set from inside the for loop, but from whatever value `m` had beforehand. – Frank Yellin May 09 '23 at 02:29

0 Answers0