Click here to Skip to main content
15,885,914 members
Please Sign up or sign in to vote.
1.00/5 (3 votes)
See more:
import numpy as np
import copy
import time


class Function(object):
    f = None
    a = None
    b = None

    @staticmethod
    def set_func(func):
        Function.f = func
        Function.a, Function.b = {
            Function.sphere: (-5.12, 5.12),
            Function.rastrigin: (-5.12, 5.12),
            Function.rosenbrock: (-2.048, 2.048),
            Function.ackley: (-32, 32),
            Function.sn: (-1.02, 1.02),
            Function.sn2: (-1.05, 1.05),
            Function.sn3: (-0.3, 0.3)
        }.get(func, None)

    @staticmethod
    def sphere(arg_vec):
        return np.sum([x ** 2 for x in arg_vec])

    @staticmethod
    def rosenbrock(arg_vec):
        return sum([(100 * (xj - xi ** 2) ** 2 + (xi - 1) ** 2) for xi, xj in zip(arg_vec[:-1], arg_vec[1:])])

    @staticmethod
    def rastrigin(arg_vec):
        return 10 * len(arg_vec) + np.sum([x ** 2 - 10 * np.cos(2 * np.pi * x) for x in arg_vec])

    @staticmethod
    def ackley(arg_vec):
        s1 = -0.2 * np.sqrt(np.sum([x ** 2 for x in arg_vec]) / len(arg_vec))
        s2 = np.sum([np.cos(2 * np.pi * x) for x in arg_vec]) / len(arg_vec)
        return 20 + np.e - 20 * np.exp(s1) - np.exp(s2)

    @staticmethod
    def sn(arg_vec):
        s1 = (sum(arg_vec) - sum(x*x for x in arg_vec)) * sum(np.cos(x) for x in arg_vec)
        s2 = 4 / (np.sqrt(np.abs(np.tan(sum(arg_vec))))) + int(sum(x*x for x in arg_vec))
        return s1 / s2

    @staticmethod
    def sn2(arg_vec):
        s1 =  arg_vec[0] * np.cos(arg_vec[1])
        s2 = (arg_vec[0] ** 2 - arg_vec[1] + 1) - (1 - arg_vec[1] ** 2)
        return s1 / s2

    @staticmethod
    def sn3(arg_vec):
        s1 =  arg_vec[0] * np.cos(arg_vec[1])
        s2 = arg_vec[1] * (1 - arg_vec[0]) ** 2 + 2 * (1 + arg_vec[1])
        return s1 / s2


class MA(object):
    def __init__(self,
                 population_size,
                 fitness_vector_size,
                 bits_per_param,
                 generations,
                 prob_crossover,
                 prob_mutation,
                 prob_local,
                 max_local_gens):
        self.population_size = population_size
        self.fitness_vector_size = fitness_vector_size
        self.bits_per_param = bits_per_param
        self.generations = generations
        self.prob_crossover = prob_crossover
        self.prob_mutation = prob_mutation
        self.prob_local = prob_local
        self.max_local_gens = max_local_gens
        self.population = None
        self.best = None

    def float_rand(self, a, b, size=None):
        return a + ((b - a) * np.random.random(size))

    def generate_population(self):
        self.population = [Individual(self.random_bitstring()) for _ in range(self.population_size)]
        self.best = sorted(self.population, key=lambda x: x.fitness)[0]

    def random_bitstring(self):
        return ''.join(np.random.choice(['0', '1'], self.fitness_vector_size * self.bits_per_param))

    def binary_tournament(self):
        pair_size = 2
        new_popul = [np.random.choice(self.population, pair_size, replace=False) for _ in range(self.population_size)]
        return np.array([min(y, key=lambda x: x.fitness) for y in new_popul])

    def point_mutation(self, bitstring):
        bitstring = list(bitstring)
        for i in range(len(bitstring)):
            if np.random.random() < self.prob_mutation:
                bitstring[i] = '1' if bitstring[i] == '0' else '0'
        return ''.join(bitstring)

    def crossover(self, parent1, parent2):
        if np.random.random() >= self.prob_crossover:
            return parent1.bitstring
        return ''.join([a if np.random.random() < self.prob_crossover
                        else b for a, b in zip(parent1.bitstring, parent2.bitstring)])

    def reproduce(self, selected):
        children = []
        for a, b in zip(selected[::2], selected[1::2]):
            children.append(Individual(self.point_mutation(self.crossover(a, b))))
            children.append(Individual(self.point_mutation(self.crossover(b, a))))
        return children

    def bitclimber(self, child):
        current = copy.copy(child)
        for _ in range(self.max_local_gens):
            candidate = Individual(self.point_mutation(current.bitstring))
            current = candidate if candidate.fitness <= current.fitness else current
        return current

    def run(self):
        self.generate_population()
        for gen in range(self.generations):
            selected = self.binary_tournament()
            children = self.reproduce(selected)
            del self.population[:]
            for child in children:
                if np.random.random() < self.prob_local:
                    child = self.bitclimber(child)
                self.population.append(child)
            self.population = sorted(self.population, key=lambda x: x.fitness)
            self.best = self.population[0] if self.population[0].fitness <= self.best.fitness else self.best
            # if gen % 50 == 0:
            #     print('{0}/{1} Current population:'.format(gen, self.generations))
            #     print(self.best)


class Individual(object):
    def __init__(self, bitstring):
        self.bitstring = bitstring  # phenotype
        nums = [int(bitstring[i:i + bits_per_param], 2) for i in range(0, len(bitstring), bits_per_param)]
        self.vector = [Function.a + ((Function.b - Function.a) / ((2.0 ** bits_per_param) - 1.0)) * x for x in nums]
        self.fitness = Function.f(self.vector)  # value of the fitness function

    def __str__(self):
        return '{0} = {1}'.format(self.vector, self.fitness)

# dim = 2
bits_per_param = 32
# max_gens = 500
# pop_size = 200
p_cross = 0.98
p_local = 0.5
# p_mut = 1.0 / (dim * bits_per_param)
max_local_gens = 30

Function.set_func(Function.ackley)


def main():
    for pop_size in [10, 100, 200, 300, 500]:
        for max_gens, dim in zip([100, 200, 300, 500], [2, 3, 5, 10]):
            p_mut = 1.0 / (dim * bits_per_param)
            start_time = time.clock()
            mem = MA(pop_size,
                     dim,
                     bits_per_param,
                     max_gens,
                     p_cross,
                     p_mut,
                     p_local,
                     max_local_gens)
            mem.run()
            fin_time = time.clock()
            print('{0};{1};{2};{3};{4}'.format(dim, pop_size, max_gens, mem.best.fitness, fin_time - start_time))


if __name__ == '__main__':
    main()


What I have tried:

I have tried to understand the code but could not get right . i would be thankful if anyone can convert this code to c++ or even c would be helpful
Posted
Updated 25-May-21 0:00am

This is not a code conversion service: we are not here to translate code for you.
Even if we did, what you would end up with would not be "good code" in the target language – they are based on very different frameworks, and what makes something work in one language does not always "translate" directly into another.
So what you end up with is very poor code, that is difficult if not impossible to maintain, that can’t be upgraded nicely, and that will cause you immense headaches if the original is changed. And it’ll be a nightmare to debug if it doesn’t work "straight out of the box".
Instead, use the source code as a specification for a new app written in and for the target language / framework and write it from scratch using the original as a "template". You will get a much, much better result that will save you a lot of time in the long run.
 
Share this answer
 
Skimming over the code it looks like a genetic algorithm engine fed with a specific problem. If you look for C++ code on Genetic Algorithms, it shouldn't be too hard to find a working program, quite possibly even on this site. Then all that remains to do is identfiy the encoding/decoding of the candidates/chromosomes and the fitness function(s), as well as the data fed into the engine.

That said, it looks like there's a bit more to it with regard to how new populations are generated. But then the questions why you want this program converted, and which of the features you might not care about.

The main components of a GA are
- how to encode the configuration describing your solution into an individual of your population, and decode an individual back into a configuration
- how to generate an initial population of "valid" individuals (and what "valid" means in the context of your problem)
- how to process the "fitness" of an individual, i. e. how well it serves as a solution to the problem
- how to generate a valid new individual from an existing one by "mutation"
- how to recombine a new valid individual by recombining two existing ones (usually called "crossover")
- how to produce a new generation for your population by applying mutation and crossover
- whether the previous generation should be discarded, or how to decide which individuals should be kept

The key is to understand what each part is used for, and adapt it to the given problem in a meaningful way.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900