//roulette selection
int roulette_select(double* arr,int num)
{
//srand((unsigned)time(NULL));
int i;
double* stage=new double[num];
stage[0]=arr[0];
for (i=1;i<num;i++){
stage[i]=stage[i-1]+arr[i];
}
double d=(double)rand()/RAND_MAX*stage[num-1];
i=0;
while(d>stage[i]){
i++;
}
delete[] stage;
assert(i<num||i>=0);
return i;
}
//generate a integer sequence from 0 to n-1 at random
void rand_int_order(vector<int>& randorder,const int n)
{
assert(n>1);
randorder.clear();
randorder.resize(n);
vector<int> recoder;
for (int i=0;i<n;i++){
recoder.push_back(i);
}
for(int i=0;i<n;i++){
int sel=rand()%recoder.size();
randorder[i]=recoder[sel];
recoder.erase(recoder.begin()+sel);
}
//assertion
assert(randorder.size()==n);
}
//sequence based sequence_encode
void sequence_encode(vector<int>& chromosome)
{
vector<int>standard;
for (int i=0;i<chromosome.size();i++){
standard.push_back(i);
}
vector<int>::iterator ite;
for (int i=0;i<chromosome.size();i++){
ite=find(standard.begin(),standard.end(),chromosome[i]);
assert(ite!=standard.end());
chromosome[i]=ite-standard.begin();
standard.erase(ite);
}
}
//sequence_decode
void sequence_decode(vector<int>& chromosome)
{
vector<int>standard;
for (int i=0;i<chromosome.size();i++){
standard.push_back(i);
}
for (int i=0;i<chromosome.size();i++){
int t=chromosome[i];
chromosome[i]=standard[t];
standard.erase(standard.begin()+t);
}
}
/*
//function test
int main()
{
//srand((unsigned)time(NULL));
//double a[10];
//int result[10];
//for (int i=0;i<10;i++){
// a[i]=10;
// result[i]=0;
//}
//
//for (int i=0;i<100;i++){
// int d=roulette_select((double*)a,10);
// cout<<d<<" ";
// result[d]++;
// //cout<<rand()%10<<endl;
//}
//cout<<endl;
//for(int i=0;i<10;i++){
// cout<<result[i]<<endl;
//}
/*vector<int> v;
rand_int_order(v,5);
for (int i=0;i<5;i++){
cout<<v[i]<<" ";
}
cout<<endl;
sequence_encode(v);
for (int i=0;i<5;i++){
cout<<v[i]<<" ";
}
cout<<endl;
sequence_decode(v);
for (int i=0;i<5;i++){
cout<<v[i]<<" ";
}
cout<<endl;
}
*/
int main()
{
srand((unsigned)time(NULL));
//read data from file
fstream filein("data/berlin52.tsp.processed",ios::in);
fstream fileout("data/result.txt",ios::out);
if (filein==NULL){
cout<<"cannot open data file"<<endl;
return 1;
}
if (fileout==NULL){
cout<<"cannot open a file to write data"<<endl;
return 1;
}
//number of cities
unsigned int cityNum;
//standard path
int* standardPath;
//distance between cities
double** distance;
//read data from filein
filein>>cityNum;
cout<<cityNum<<endl;
standardPath=new int[cityNum];
for (int i=0;i<cityNum;i++){
filein>>standardPath[i];
}
distance=new double* [cityNum];
for (int i=0;i<cityNum;i++){
distance[i]=new double[cityNum];
for (int j=0;j<cityNum;j++){
filein>>distance[i][j];
}
}
//////////////////////////////////////////////////////////////////////////
//parameters
//number of generations
unsigned int generation = 1000;
//size of the population,i.e. number of chromosomes
unsigned int populationSize = 70;
//number of genes in a individual,i.e. length of chromosome
unsigned int chromLen = cityNum;
//mutate rate ,generally it is between 0.05 and 0.3
double mutationRate = 0.7;
//crossover rate ,generally it is about 0.7
double crossoverRate = 0.9;
// define the population
vector<vector<int> > population;
//initialize population at random
for (int i=0;i<populationSize;i++){
vector<int> chromo;
rand_int_order(chromo,chromLen);
population.push_back(chromo);
}
//length of best path found
double best_path_len=1<<(8*sizeof(int)-2);
//index of best individual
int bestIndex=0;
//evolution
for (int g=0;g<generation;g++){
//fitness value,i.e. length of the path
double* fitness=new double[populationSize];
//calculate fitness of every individual
for(int i=0;i<populationSize;i++){
fitness[i]=0;
}
//update population
vector<vector<int> > parentGeneration=population;
population.clear();
for (int s=0;s<populationSize;s++){
for (int l=0;l<chromLen-1;l++){
fitness[s]+=distance[parentGeneration[s][l]][parentGeneration[s][l+1]];
}
fitness[s]+=distance[parentGeneration[s][chromLen-1]][parentGeneration[s][0]];
if (fitness[s]<best_path_len){
best_path_len=fitness[s];
bestIndex=s;
}
}
//epoch
while(population.size()<populationSize){
//roulette selection
//children
vector<int> baby1,baby2;
int rs=roulette_select(fitness,populationSize);
baby1=parentGeneration[rs];
rs=roulette_select(fitness,populationSize);
baby2=parentGeneration[rs];
//crossover
if(baby1!=baby2){
if (rand()/RAND_MAX<crossoverRate){
//sequence based sequence_encode
sequence_encode(baby1);
sequence_encode(baby2);
//single point crossover
int index=rand()%chromLen;
int tmp=baby1[index];
baby1[index]=baby2[index];
baby2[index]=tmp;
//sequence_decode
sequence_decode(baby1);
sequence_decode(baby2);
}
}
//reverse mutate
int point1=rand()%chromLen;
int point2=point1;
while(point1==point2){
point2=rand()%chromLen;
}
if (point1>point2){
int tmp=point1;
point1=point2;
point2=tmp;
}
//reverse
reverse(baby1.begin()+point1,baby1.begin()+point2);
reverse(baby2.begin()+point1,baby2.begin()+point2);
//update population
population.push_back(baby1);
population.push_back(baby2);
}
//if populationSize is odd,after the epoch,size of population will be populationSize+1
if (population.size()>populationSize){
population.pop_back();
}
fileout<<"generation :"<<g<<endl
<<"best distance found for the moment: "
<<best_path_len<<endl
<<"best distance found in this epoch: "
<<fitness[bestIndex]<<endl
<<"best path found for the moment:"<<endl;
for (int i=0;i<cityNum;i++){
fileout<<population[bestIndex][i]<<" ";
}
fileout<<endl;
//to console
cout<<"generation :"<<g<<endl
<<"best distance found for the moment: "
<<best_path_len<<endl
<<"best distance found in this epoch: "
<<fitness[bestIndex]<<endl
<<"best path found for the moment:"<<endl;
for (int i=0;i<cityNum;i++){
cout<<population[bestIndex][i]<<" ";
}
cout<<endl;
delete[] fitness;
}
//show standard path and distance
fileout<<"standard path:"<<endl;
double standardbestlen=0;
for (int i=0;i<cityNum;i++){
fileout<<standardPath[i]<<" ";
}
for (int i=0;i<cityNum-1;i++){
standardbestlen+=distance[standardPath[i]][standardPath[i+1]];
}
standardbestlen+=distance[standardPath[cityNum-1]][standardPath[0]];
fileout<<endl<<"length of standard path: "<<endl<<" "<<standardbestlen<<endl;
//append the best result found in this test to a file named "best.txt"
fstream bestout("data/best.txt",ios::app);
if (bestout==NULL){
cout<<"cannot open a file to write data"<<endl;
return 1;
}
bestout<<best_path_len<<endl;
for (int i=0;i<cityNum;i++){
bestout<<population[bestIndex][i]<<" ";
}
bestout<<endl;
//free memory/////////////////////////////////////////////////////////////
filein.close();
fileout.close();
bestout.close();
delete[] standardPath;
for (int i=0;i<cityNum;i++){
delete[] distance[i];
}
delete[] distance;
return 0;
}