How can I speed up this part of my code in python?

Here is part of my code in python:

import numpy as np
from numpy.random import randint
from numpy import ones
from numpy import cos
from numpy import sin
from numpy import exp
from numpy import pi
from numpy import abs
from numpy import sum

SOLUTION_SEQUENCE = np.array([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 * pi / WAVELENGTH
PHI = 0
RING_ELEMENT_NUM = np.array([6, 12, 18, 25, 31, 37, 43, 50, 56])
RING_NUM = 9
CHROMOSOME_LENGTH = int(sum(RING_ELEMENT_NUM))
THETA_range_mul10 = np.array(list(range(-900, 901)))


def AF(self, cur, theta):
        AF_out = 1
        self.cur = np.array(cur)
        AF_out = 1 + sum(sum(self.cur[i] * exp(1j * K * (m * WAVELENGTH / 2) *
                                               sin(theta) * cos(PHI - 2 * pi * (i - 1) / RING_ELEMENT_NUM[m]))
                             for i in range(RING_ELEMENT_NUM[m], int(sum(RING_ELEMENT_NUM[0:m])))) for m in
                         np.array(list(range(int(RING_NUM)))))
        return AF_out

I have used numpy library as much as I could. But, my simulation time is too time-consuming. If I implement my code in MATLAB, I have any improvement in implementation time?

Hi M,
Good Start.
After looking over your function, I do not know your intention.
It may do exactly what you want. Without hearing from you I don’t know if IT is right or wrong.

Could you please add a docstring to your function.

Also, as it stands you have not run the function AF (in the code you showed) and in my notebook it looks ok.
:sunglasses:

Hello @mccurcio ,
No, my function does not have any problem. I just want to implement my code with more speed. you may suggest an alternative method, or recommend aforementioned code some minor modification so as to spped up my code.

now I place the original function which uses the above code:

from random import uniform

import numpy as np
from numpy.random import randint
from numpy import ones
from numpy import cos
from numpy import sin
from numpy import exp
from numpy import pi
from numpy import abs
from numpy import sum

SOLUTION_SEQUENCE = np.array([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 * pi / WAVELENGTH
PHI = 0
RING_ELEMENT_NUM = np.array([6, 12, 18, 25, 31, 37, 43, 50, 56])
RING_NUM = 9
CHROMOSOME_LENGTH = int(sum(RING_ELEMENT_NUM))
THETA_range_mul10 = np.array(list(range(-900, 901)))


class Individual:

    def __init__(self):
        self.cur = None
        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 * abs(fn_com[1] + fn_com[2]) / abs(self.AF(Ipop, 0))
        + WF2 * abs(fn_com[0] - fn_uni)

        return CF

    def fn_uniform(self):

        AF_uni = self.AF_uniform()

        null1 = 0
        null2 = 0

        i = 0
        while i <= 898:
            if AF_uni[int(i + 901) + 1] > AF_uni[int(i + 901)]:
                null1 = i / 10
                break
            i += 1

        i = 0
        while i <= 898:
            if AF_uni[int(-i + 901) - 1] > AF_uni[int(i + 901)]:
                null2 = i / 10
                break
            i += 1

        fn = abs(null2 - null1)

        return [fn]

    def fn_com(self, I_pop):

        msl1 = 0
        msl2 = 0
        AF_com = list(range(-900, 901))
        theta = -900
        while theta <= 900:
            AF_com[theta + 900] = self.AF(I_pop, theta / 10)
            theta += 1

        null1 = 0
        null2 = 0

        i = 0
        while i <= 898:
            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
            i += 1

        i = 0
        while i <= 898:
            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
            i += 1

        fn = abs(null2 - null1)

        return [fn, msl1, msl2]

    def AF_uniform(self):
        AF_uni = list(range(-900, 901))
        cur = ones(CHROMOSOME_LENGTH)
        theta = -900
        while theta < 900:
            theta += 1
            AF_uni[int(theta + 900)] = self.AF(cur, theta / 10)

        return AF_uni

    def AF(self, cur, theta):
        AF_out = 1
        self.cur = np.array(cur)
        AF_out = 1 + sum(sum(self.cur[i] * exp(1j * K * (m * WAVELENGTH / 2) *
                                               sin(theta) * cos(PHI - 2 * pi * (i - 1) / RING_ELEMENT_NUM[m]))
                             for i in range(RING_ELEMENT_NUM[m], int(sum(RING_ELEMENT_NUM[0:m])))) for m in
                         np.array(list(range(int(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)]
        self.new = 0

    def get_fittest(self):

        fittest = self.individuals[0]

        for individual in self.individuals[1:]:
            self.new += 1
            print(self.new)
            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
        self.fittest = 0
        self.fittest_value = 0

    def run(self):

        pop = Population(self.population_size)
        generation_counter = 0

        while generation_counter < 1000:
            generation_counter += 1
            self.fittest = pop.get_fittest()
            self.fittest_value = self.fittest.get_fitness()

            print('Generation #%s - fittest is: %s with fitness value %s' % (
                generation_counter, self.fittest, self.fittest_value))
            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()

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.