BinaryCodedGeneticAlgorithm/main.cpp

221 lines
6.8 KiB
C++
Raw Permalink Normal View History

2022-03-29 16:05:48 +03:00
#include <iostream>
#include <cstdlib>
#define ITERATION 100
#define POPULATIONCOUNT 20
#define CROSSOVERCHANCE .5
#define MUTATIONCHANCE .02
#define CROSSOVERCOUNTPERITERATION 10
#define POPULATIONSIZE 200
#define BITCOUNT 12
const float ValuePeriod = (float)(1 << BITCOUNT);
const unsigned int ValuePeriodMask = (1 << BITCOUNT) - 1;
struct Chromosome
{
unsigned int x1;
unsigned int x2;
};
unsigned int GetRandomValue() { return rand() & ValuePeriodMask; }
float GetRandomPercentage()
{
// RAND_MAX in Windows causes the rand values to be between 0 and 32767
// So to overcome we get two random numbers and bitshift the one of them
int random = rand() << 15 | rand();
return float(random % 1000000) / 1000000.0;
}
float GetX1(unsigned int value) { return -1.5 + value * (4.0 / ValuePeriod); }
float GetX2(unsigned int value) { return value * (5.0 / ValuePeriod); }
float GetFitnessScore(const Chromosome &chromosome)
{
float x1 = GetX1(chromosome.x1);
float x2 = GetX2(chromosome.x2);
float score = 40.0;
score -= 4.5 * x1;
score += 4.0 * x2;
score -= x1 * x1;
score -= 2.0 * x2 * x2;
score += 2.0 * x1 * x2;
score -= x1 * x1 * x1 * x1;
score += 2.0 * x1 * x1 * x2;
return score;
}
void Initialize(Chromosome &chromosome)
{
chromosome.x1 = GetRandomValue();
chromosome.x2 = GetRandomValue();
}
unsigned int InvertBits(unsigned int &value) { return (~value) & ValuePeriodMask; }
unsigned int GetRandomBits(float chance)
{
unsigned int result = 0;
for (size_t i = 0; i < BITCOUNT; i++)
if (GetRandomPercentage() < chance)
result += 1 << i;
return result & ValuePeriodMask;
}
void Mutate(Chromosome &chromosome)
{
unsigned int mutationBitsX1 = GetRandomBits(MUTATIONCHANCE);
unsigned int mutationBitsX2 = GetRandomBits(MUTATIONCHANCE);
chromosome.x1 ^= mutationBitsX1;
chromosome.x2 ^= mutationBitsX2;
}
Chromosome Crossover(Chromosome &chromosomeLeft, Chromosome &chromosomeRight)
{
Chromosome result = Chromosome();
unsigned int crossoverBitsX1 = GetRandomBits(CROSSOVERCHANCE);
unsigned int crossoverBitsX2 = GetRandomBits(CROSSOVERCHANCE);
result.x1 = chromosomeLeft.x1 & crossoverBitsX1;
result.x1 |= chromosomeRight.x1 & InvertBits(crossoverBitsX1);
result.x2 = chromosomeLeft.x2 & crossoverBitsX2;
result.x2 |= chromosomeRight.x2 & InvertBits(crossoverBitsX2);
return result;
}
void UpdateFitnessScores(Chromosome *populationPointer, float *fitnessPointer)
{
for (size_t i = 0; i < POPULATIONSIZE; i++)
*(fitnessPointer++) = GetFitnessScore(*(populationPointer++));
}
Chromosome *GetRandomChromosome(Chromosome *populationPointer) { return populationPointer + rand() % POPULATIONSIZE; }
Chromosome *GetRandomCumulativeChromosome(Chromosome *populationPointer, float *fitnessPointer)
{
float sumOfScores = 0.0;
float cumulativeFloat = 0.0;
float randomPoint = GetRandomPercentage();
size_t i;
for (i = 0; i < POPULATIONSIZE; i++)
sumOfScores += *(fitnessPointer + i);
for (i = 0; i < POPULATIONSIZE; i++)
{
cumulativeFloat += *(fitnessPointer + i) / sumOfScores;
if (randomPoint <= cumulativeFloat)
return populationPointer + i;
}
return populationPointer;
}
Chromosome *GetFittest(Chromosome *populationPointer, float *fitnessPointer)
{
unsigned int fittestIndex = 0;
for (size_t i = 0; i < POPULATIONSIZE; i++)
if (*(fitnessPointer + i) > *(fitnessPointer + fittestIndex))
fittestIndex = i;
return populationPointer + fittestIndex;
}
Chromosome *GetElitistOffSpring(Chromosome *fittest, Chromosome *populationPointer)
{
Chromosome *offspring = nullptr;
do
offspring = GetRandomChromosome(populationPointer);
while (fittest == offspring);
return offspring;
}
void SortScores(float *scores)
{
float temp;
for (size_t i = 0; i < POPULATIONCOUNT; i++)
for (size_t j = i + 1; j < POPULATIONCOUNT; j++)
if (*(scores + i) > *(scores + j))
{
temp = *(scores + i);
*(scores + i) = *(scores + j);
*(scores + j) = temp;
}
}
int main()
{
Chromosome population[POPULATIONSIZE];
float fitnessScores[POPULATIONSIZE];
float fitnessScoreRecord[POPULATIONCOUNT];
Chromosome *offspring = nullptr;
Chromosome *left = nullptr;
Chromosome *right = nullptr;
Chromosome *fittest = nullptr;
int i;
int generation;
int crossoverCounter;
int mutationIndex;
int populationCounter;
srand(0);
for (populationCounter = 0; populationCounter < POPULATIONCOUNT; populationCounter++)
{
for (i = 0; i < POPULATIONSIZE; i++)
Initialize(population[i]);
UpdateFitnessScores(population, fitnessScores);
fittest = GetFittest(population, fitnessScores);
for (generation = 0; generation < ITERATION; generation++)
{
for (crossoverCounter = 0; crossoverCounter < CROSSOVERCOUNTPERITERATION; crossoverCounter++)
{
offspring = GetElitistOffSpring(fittest, population);
left = GetRandomCumulativeChromosome(population, fitnessScores);
right = GetRandomCumulativeChromosome(population, fitnessScores);
(*offspring) = Crossover(*left, *right);
}
// Mutate all except the Fittest
for (mutationIndex = 0; mutationIndex < POPULATIONSIZE; mutationIndex++)
if (population + mutationIndex != fittest)
Mutate(*(population + mutationIndex));
UpdateFitnessScores(population, fitnessScores);
fittest = GetFittest(population, fitnessScores);
// std::cout << "Fittest Score: " << GetFitnessScore(*fittest) << "\n";
// std::cout << "x1: " << GetX1(fittest->x1) << "\n";
// std::cout << "x2: " << GetX2(fittest->x2) << "\n";
// std::cout << "-----End of Generation " << generation << "-----\n";
}
fitnessScoreRecord[populationCounter] = GetFitnessScore(*fittest);
}
SortScores(fitnessScoreRecord);
std::cout << "Population Size: " << POPULATIONSIZE << "\n";
std::cout << "Population Count: " << POPULATIONCOUNT << "\n";
std::cout << "Iteration Count: " << ITERATION << "\n";
std::cout << "Crossover Per Iteration: " << CROSSOVERCOUNTPERITERATION << "\n";
std::cout << "Crossover Ratio: " << CROSSOVERCHANCE << "\n";
std::cout << "Mutation Ratio: " << MUTATIONCHANCE << "\n";
std::cout << "Bits Per Value: " << BITCOUNT << "\n";
std::cout << "-----------------\n";
std::cout << "Best: " << fitnessScoreRecord[POPULATIONCOUNT - 1] << "\n";
std::cout << "Median: " << fitnessScoreRecord[(POPULATIONCOUNT - 1) / 2] << "\n";
std::cout << "Worst: " << fitnessScoreRecord[0] << "\n";
return 0;
}