I am trying to implement a genetic algorithm to solve (Diophantine Equation).
For instance, a + 2b + 3c + 4d = 90 where a, b, c, d are positive integers.
After reading some books and following tutorials, I finally wrote this code, but as I am new to programming and GA, I don't know if this is a good implementation.
#include<iostream>
#include <string>
#include <vector>
#include <time.h>
#include <algorithm>
using namespace std;
#define variable 4
#define chromoSize 100000
float total = 0;
struct Equation
{
int eq[variable];
float ev;
float fit;
float p;
};
void init_chrom(vector<Equation> &Original, vector<Equation> &Temp)
{
for(int i=0; i<chromoSize; i++)
{
Equation e;
for(int j=0; j<variable; j++)
{
e.eq[j] = rand() % 30;
e.fit = 0;
}
Original.push_back(e);
}
Temp.resize(chromoSize);
}
void calc_fit(vector<Equation> &orginalCh)
{
for(int i=0; i<chromoSize; i++)
{
int j = 0;
orginalCh[i].ev = abs((orginalCh[i].eq[j] + 2*orginalCh[i].eq[j+1] +
3*orginalCh[i].eq[j+2] + 4*orginalCh[i].eq[j+3]) - 10);
}
}
void select_fit(vector<Equation> &orginalCh)
{
for(int i=0; i<chromoSize; i++)
{
orginalCh[i].fit = 1 /( 1 + orginalCh[i].ev);
total += orginalCh[i].fit;
}
float pro = 0;
for(int i=0; i<chromoSize; i++)
{
pro += orginalCh[i].fit / total;
orginalCh[i].p = pro;
}
}
void _copy(vector<Equation> &p1, vector<Equation> &p2, int s)
{
for(int i=0; i<s; i++)
{
for(int j=0; j<variable; j++)
p2[i].eq[j] = p1[i].eq[j];
p2[i].fit = p1[i].fit;
}
}
void mutate(vector<Equation> &parent2, int i)
{
int size = variable;
int index1 = rand() % size;
int index2 = rand() % size;
int j = rand() % chromoSize;
parent2[i].eq[index1] = parent2[j].eq[index2];
}
void mate(vector<Equation> &parent1, vector<Equation> &parent2)
{
int sub, p1, p2, tSsize = variable;
_copy(parent1, parent2, chromoSize);
for(int i=0; i<chromoSize; i++)
{
p1 = rand() % chromoSize;
p2 = rand() % chromoSize;
sub = rand() % tSsize;
for(int j=sub; j<variable; j++)
parent2[p2].eq[j] = parent1[p1].eq[j];
if(parent2[i].ev > 0.1f)
mutate(parent2, i);
}
}
bool sort_fitness(Equation x, Equation y)
{
return(x.fit > y.fit);
}
void _sort(vector<Equation> &orginalCh)
{
sort(orginalCh.begin(),orginalCh.end(),sort_fitness);
}
void swap(vector<Equation> *&parent1, vector<Equation> *&parent2)
{
vector<Equation> *temp = parent1;
parent1 = parent2;
parent2 = temp;
}
void print(vector<Equation> &originalCh)
{
for(int i=0; i<variable; i++)
{
cout<<originalCh[0].eq[i]<<", ";
}
cout<<" "<<originalCh[0].ev<<" "<<originalCh[0].fit;
cout<<endl;
}
int main()
{
srand(unsigned(time(NULL)));
vector<Equation> chromO, chromT;
vector<Equation> *originalCh, *bufferCh;
init_chrom(chromO, chromT);
originalCh = &chromO;
bufferCh = &chromT;
for(int i=0; i<2000; i++)
{
calc_fit(*originalCh);
select_fit(*originalCh);
_sort(*originalCh);
print(*originalCh);
if((*originalCh)[0].fit == 1) break;
mate(*originalCh,*bufferCh);
swap(*originalCh, *bufferCh);
}
system("pause");
return 0;
}
The code will output something like this:
21, 22, 7, 1, 0 1
The first four numbers are the values of (a,b,c,d) and the fifth number is the evaluation and the last number is the fitness.
UPDATE
After taking @glampert post into consideration and reading more about what he suggested, this is an updated version of the above code.
GeneticAlgorithm.h
#include <vector>
#include <random>
//the variables in the equation, which represnts the (a,b,c,d)
const int VARIABLES = 4;
//the size of chromosoms population
const int CHROMO_SIZE = 10000;
class GA
{
public:
struct Equation
{
int equation[VARIABLES];
float evaluation;
float fit;
float probability;
};
public:
GA();
//initialize the chromosoms
void initChromos(std::vector<Equation> &original, std::vector<Equation> &temp);
//calculate the fitness of chromosoms
void calcFitness(std::vector<Equation> &orginalCh);
//select the fit ones
void selectFitness(std::vector<Equation> &orginalCh);
//copy from parent one to parent two
void copyFromP1toP2(std::vector<Equation> &parent1,
std::vector<Equation> &parent2, int size);
//mutate the chromosoms and select two chromosoms to mate
void mutate(std::vector<Equation> &parent2, int i);
void mate(std::vector<Equation> &parent1, std::vector<Equation> &parent2);
//sort chromosoms by fitness
bool static sortFitness(Equation x, Equation y);
void sortByFitness(std::vector<Equation> &orginalCh);
//swap parent one and parent two for the next generation
void swap(std::vector<Equation> *&parent1, std::vector<Equation> *&parent2);
//print the best fit of every generation
void print(std::vector<Equation> &originalCh);
//generate random number
int randGenerate(int start, int end);
public:
std::default_random_engine dRandom;
private:
float total;
};
Implementation.cpp
#include<iostream>
#include <vector>
#include <algorithm>
#include<random>
#include "GeneticAlgorithm.h"
GA::GA(): total(0),dRandom()
{
}
void GA::initChromos(std::vector<Equation> &original, std::vector<Equation> &temp)
{
for(int i = 0; i < CHROMO_SIZE; i++)
{
GA::Equation e;
for(int j = 0; j < VARIABLES; j++)
{
int randNum = randGenerate(0,40);
e.equation[j]= randNum;
e.fit = 0;
}
original.push_back(e);
}
temp.resize(CHROMO_SIZE);
}
void GA::calcFitness(std::vector<Equation> &orginalCh)
{
for(int i = 0; i < CHROMO_SIZE; i++)
{
int j = 0;
orginalCh[i].evaluation = (float)abs((orginalCh[i].equation[j] + 2 * orginalCh[i].equation[ j + 1 ]
+ 3 * orginalCh[i].equation[ j + 2 ] + 4 * orginalCh[i].equation[ j + 3 ]) - 4 );
}
}
void GA::selectFitness(std::vector<Equation> &orginalCh)
{
for(int i = 0; i < CHROMO_SIZE; i++)
{
orginalCh[i].fit = 1 / ( 1 + orginalCh[i].evaluation);
total += orginalCh[i].fit;
}
float pro = 0;
for(int i = 0; i < CHROMO_SIZE; i++)
{
pro += orginalCh[i].fit / total;
orginalCh[i].probability = pro;
}
}
void GA::copyFromP1toP2(std::vector<Equation> &p1, std::vector<Equation> &p2, int s)
{
for(int i = 0; i < s; i++)
{
for(int j = 0; j < VARIABLES; j++)
{
p2[i].equation[j] = p1[i].equation[j];
}
p2[i].fit = p1[i].fit;
}
}
void GA::mutate(std::vector<Equation> &parent2, int i)
{
int index1 = randGenerate(0, VARIABLES - 1);
int index2 = randGenerate(0, VARIABLES - 1);
int j = randGenerate(0, CHROMO_SIZE - 1);
parent2[i].equation[index1] = parent2[j].equation[index2];
}
void GA::mate(std::vector<Equation> &parent1, std::vector<Equation> &parent2)
{
int sub, p1, p2, p3, tSsize = VARIABLES;
copyFromP1toP2(parent1, parent2, CHROMO_SIZE);
for(int i = 0; i < CHROMO_SIZE; i++)
{
p1 = randGenerate(0, CHROMO_SIZE - 1);
p2 = randGenerate(0, CHROMO_SIZE - 1);;
p3 = randGenerate(0, CHROMO_SIZE - 1);
sub = randGenerate(0, VARIABLES - 1);
for(int j=sub; j<VARIABLES; j++)
{
parent2[p2].equation[j] = abs(parent1[p1].equation[j] - parent1[p3].equation[j]);
}
if(parent2[i].evaluation > 0.5f)
mutate(parent2, i);
}
}
bool GA::sortFitness(Equation x, Equation y)
{
return(x.fit > y.fit);
}
void GA::sortByFitness(std::vector<Equation> &orginalCh)
{
std::sort(orginalCh.begin(),orginalCh.end(),&GA::sortFitness);
}
void GA::swap(std::vector<GA::Equation> *&parent1, std::vector<GA::Equation> *&parent2)
{
std::vector<GA::Equation> *temp = parent1;
parent1 = parent2;
parent2 = temp;
}
void GA::print(std::vector<Equation> &originalCh)
{
for(int i=0; i<VARIABLES; i++)
{
std::cout<< originalCh[0].equation[i] << ", ";
}
std::cout << " fitness = " << originalCh[0].fit;
std::cout<< std::endl;
}
int GA::randGenerate(int start, int end)
{
std::uniform_int_distribution<int> genenNum(start, end - 1);
return genenNum(dRandom);
}
int main()
{
GA ga;
std::vector<GA::Equation> chromO, chromT;
std::vector<GA::Equation> *originalCh, *bufferCh;
ga.initChromos(chromO, chromT);
originalCh = &chromO;
bufferCh = &chromT;
for(int i=0; i<2000; i++)
{
ga.calcFitness(*originalCh);
ga.selectFitness(*originalCh);
ga.sortByFitness(*originalCh);
ga.print(*originalCh);
if((*originalCh)[0].fit == 1) break;
ga.mate(*originalCh,*bufferCh);
ga.swap(*&originalCh, *&bufferCh);
}
std::cin.get();
return 0;
}