Environmental modeling and software paper supplementary material

De
Aller à la navigation Aller à la recherche

/*_________________________________________________________

 This is a standard GP implementation on EASEA, 
 aimed for regression.
 For running on CPU, compile with:
 $ make easeaclean ; easena -gp regression.ez ; make
 Then run with:
 $ ./regression --seed 2      // for a nice result :-)
 You can test the parallel version on several cores with:
 $ ./regression --seed 2 --nbCPUThreads 20
 For running on GPU, compile with:	
 $ make easeaclean ; easena -cuda_gp regression.ez ; make

__________________________________________________________*/

\User declarations :

  1. include<stdio.h>
  2. include<string.h>

// these 3 defines are mandatory here. Adjust as you like.

  1. define NO_FITNESS_CASES 18
  2. define VAR_LEN 1 // number of input variables
  3. define GROW_FULL_RATIO 0.5 // cf. Koza's book on Genetic Programming
  1. define NUMTHREAD 1024 // nb of threads in parallel on GPU cards.
  // 1024 is the maximum on Fermi architectures. It is 512 on older cards
  1. define MAX_STACK 15
  1. define PI (3.141592653589793)


float x[NO_FITNESS_CASES] = {0.0833, 0.1667, 0.25, 0.3333, 0.4167, 0.5, 0.5833, 0.6667, 0.75, 0.8333, 0.9167, 1, 1.0833, 1.1667, 1.25, 1.3333, 1.4167, 1.5};

float y[NO_FITNESS_CASES] = { -0.457142857, -0.428571429, -0.285714286, -0.042857143, 0.142857143, 0.328571429, 0.457142857, 0.571428571, 0.742857143, 0.914285714, 1.128571429, 1.271428571, 1.171428571, 0.985714286, 0.714285714, 0.442857143, 0.2, 0.057142857};


\end

\User functions:

int initData(float*** inputs, float** outputs) {

 int i=0;
 (*inputs) = new float*[NO_FITNESS_CASES];
 (*outputs) = new float[NO_FITNESS_CASES];
   
 for( i=0 ; i<NO_FITNESS_CASES ; i++ ){
   (*inputs)[i]=new float[VAR_LEN];
   (*inputs)[i][0] = x[i];
   (*outputs)[i] = y[i];
 }
 return NO_FITNESS_CASES;

}

void free_data(){

 for( int i=0 ; i<NO_FITNESS_CASES ;i++ ) delete[] inputs[i] ;
 delete[] outputs;
 delete[] inputs;

}

\end


\Before everything else function:

 initData(&inputs,&outputs); // inputs, outputs requis par EASEA

\end

\After everything else function:

 std::cout << "y=" << toString(((IndividualImpl*)EA->population->Best)->root) << std::endl;
 free_data();

\end

\At the beginning of each generation function: \end

\At the end of each generation function: \end

\At each generation before reduce function: \end


\User classes :

GenomeClass {

 GPNode* root; // GPNode is a reserved name that must be used for GP

} \end

\GenomeClass::display: \end

\GenomeClass::initialiser :

 Genome.root = ramped_hh(); // Initializer, cf. Koza GP

\end

\GenomeClass::crossover :

 simpleCrossOver(parent1,parent2,child); // cf. Koza GP
 child.valid = false;       // to force the evaluation of the child

\end

\GenomeClass::mutator :

 simple_mutator(&Genome); // cf. Koza GP

\end


\begin operator description : // <symbole>, "<affichage dans l'arbre>", <arité de l'opérateur>, {RESULT=<resultat>} OP_X, "x", 0, {RESULT=INPUT[0];}; OP_ERC, "ERC", 0, {RESULT=ERC;}; // ERC = valeur aléatoire entre 0 et 1 OP_ADD, "+", 2, {RESULT=OP1+OP2;}; OP_SUB, "-", 2, {RESULT=OP1-OP2;}; OP_MUL, "*", 2, {RESULT=OP1*OP2;}; OP_SIN, "sin", 1, {RESULT=sin(OP1);};

// you can add other operators if you wish \end

\GenomeClass::evaluator header: \end

\GenomeClass::evaluator for each fc : // How to compute error for one point float expected_value = OUTPUT; error = pow((expected_value-EVOLVED_VALUE),2); error/=(float)NO_FITNESS_CASES; error=sqrtf(error); \end

\GenomeClass::evaluator accumulator : // here, error is the sum of errors for each point

return error; \end


\User Makefile options: CXXFLAGS+=-I/usr/local/cuda/common/inc/ -I/usr/local/cuda/include/ LDFLAGS+= \end

\Default run parameters :

 Number of generations : 500   	          // NB_GEN
 Time limit: 0 			                    // In seconds, 0 to deactivate
 Population size : 50000			            // POP_SIZE
 Offspring size : 50000                   // can be a percentage such as 40% 
 Mutation probability : 0.1              // Probability to call the mutation function
 Crossover probability : 1               // Probability to call the crossover function
 Evaluator goal : minimise               // or Maximise
 Selection operator: Tournament 10        // to select parents
 Surviving parents: 100%                 // to select breeders
 Surviving offspring: 100%               // to select among offspring for next generation
 Reduce parents operator: Tournament 2   // how to select the breeders
 Reduce offspring operator: Tournament 2 // how to select the offspring that will compete to access the next generation
 Final reduce operator: Tournament 2     // to select the individuals composing the next generation
 Elitism: Strong			                    // Strong = from parents pop, Weak = from parents + children
 Elite: 1
 Print stats: true
 Generate csv stats file:false			
 Generate gnuplot script:false
 Generate R script:false
 Plot stats:true	
 Remote island model: false
 IP file: ip.txt 			//File containing all the remote island's IP
 Server port : 2929
 Migration probability: 0.33
 Save population: false
 Start from file: false
 // nouveaux paramètres
 max init tree depth : 4 
 min init tree depth : 2
 max tree depth : 6
 size of prog buffer : 200000000

\end



/*_________________________________________________________ GA implementation __________________________________________________________*/

\User declarations :

  1. define PI 3.141592654
  2. define NB_SIN 1
  3. define NB_SAMPLES 18


  1. define MIN_A -2.0
  2. define MAX_A 5.0
  3. define MIN_B -2.0
  4. define MAX_B 2.0
  5. define MIN_C 0.1
  6. define MAX_C 5.0
  7. define MIN_D 0.1
  8. define MAX_D 2.0

int nSample[NB_SAMPLES][2]; // what is read from the file float sample[NB_SAMPLES][2]; // straightened samples float usedSample[NB_SAMPLES][2]; // samples that are used

int xSample[NB_SAMPLES];


__device__ float gpuSample[NB_SAMPLES][2]; \end

\User functions: __device__ __host__ inline float fScoreOnGPU(float genome[NB_SIN*4], int nNbSamples, int nNbSin){

float y,fScore=0.0;

  1. ifndef __CUDA_ARCH__
 for (int i=0;i<nNbSamples;i++){
   y=0;
   for(int j=0;j<nNbSin;j++)
       y+=genome[4*j+0]+usedSample[i][0]*genome[4*j+1]+genome[4*j+2]*sin(usedSample[i][0]*usedSample[i][0]*genome[4*j+3]);
   fScore+=pow((usedSample[i][1]-y),2); // square of the difference
 }
  1. else

for (int i=0;i<nNbSamples;i++){

   y=0;
   for(int j=0;j<nNbSin;j++)
    y+=genome[4*j+0]+gpuSample[i][0]*genome[4*j+1]+genome[4*j+2]*sin(gpuSample[i][0]*gpuSample[i][0]*genome[4*j+3]);      
   fScore+=pow((gpuSample[i][1]-y),2); // square of the difference
 }
  1. endif
 fScore/=(float)nNbSamples; // divided by the number of samples
 fScore=powf(fScore,.5);     // of which I take the cubic root for a more "powerful" MSE
 return fScore*100;  // for a better looking curve

}

\end

\User CUDA: cudaMemcpyToSymbol(gpuSample, usedSample, NB_SAMPLES*2*sizeof(int)); \end

\Before everything else function:

sample[0][0]=0.0833; sample[1][0]=0.1667; sample[2][0]=0.25; sample[3][0]=0.3333; sample[4][0]=0.4167; sample[5][0]=0.5; sample[6][0]=0.5833; sample[7][0]=0.6667; sample[8][0]=0.75; sample[9][0]=0.8333; sample[10][0]=0.9167; sample[11][0]=1; sample[12][0]=1.0833; sample[13][0]=1.1667; sample[14][0]=1.25; sample[15][0]=1.3333; sample[16][0]=1.4167; sample[17][0]=1.5;


sample[0][1]=-0.12; sample[1][1]=0; sample[2][1]=0.22; sample[3][1]=0.48; sample[4][1]=0.64; sample[5][1]=0.82; sample[6][1]=0.88; sample[7][1]=0.94; sample[8][1]=1.16; sample[9][1]=1.4; sample[10][1]=1.68; sample[11][1]=1.86; sample[12][1]=1.8; sample[13][1]=1.56; sample[14][1]=1.22; sample[15][1]=0.92; sample[16][1]=0.6; sample[17][1]=0.34;


  for (int i=0;i<NB_SAMPLES;i++){
//    int nIndex=random(X_MIN,X_MAX); // for random sampling
int  nIndex=i;                   // for exact sampling starting at X_MIN
    usedSample[i][0]=sample[nIndex][0];
    usedSample[i][1]=sample[nIndex][1];
  }


// cudaMalloc((void**)&gpuSample,NB_SAMPLES*2*sizeof(int)); \end

\After everything else function: float gen[NB_SIN*6]; printf("\n\nAfter Everything Else: NB_SIN = %d, nNB_SIN = %d\n",NB_SIN,NB_SIN); for (int i=0;i<NB_SIN*6;i++) gen[i]=bBest->Sin[i];


printf("Obtained functions : \ny="); int i=0; for (i=0;i<NB_SIN-1;i++)

 printf("%f+%f*x+%f*sin(%f*x*x)+",bBest->Sin[i*4+0],bBest->Sin[i*4+1],bBest->Sin[i*4+2],bBest->Sin[i*4+3]);

printf("%f+%f*x+%f*sin(%f*x*x)\n\n",bBest->Sin[i*4+0],bBest->Sin[i*4+1],bBest->Sin[i*4+2],bBest->Sin[i*4+3]);

printf("Fitness=%f\n",bBest->fitness);

printf("%d sines on %d NUS\n",NB_SIN,NB_SAMPLES); printf("Amplitude Angular_velocity Phase\n"); for (int i=0;i<NB_SIN;i++) printf("%.9f\t%.9f\t%.9f\t%.9f\n",gen[i*4+0],gen[i*4+1],gen[i*4+2],gen[i*4+3]);

\end

\At the beginning of each generation function: \end

\At the end of each generation function:

 //cout << "At the end of each generation function called" << endl;

\end

\At each generation before reduce function:

 //cout << "At each generation before replacement function called" << endl;

\end

\User classes : GenomeClass {

 float Sin[NB_SIN*4];  
                        
                         

} \end

\GenomeClass::display: \end

\GenomeClass::initialiser : // "initializer" is also accepted for(int i=0; i<NB_SIN; i++){

Genome.Sin[i*4+0]=-0.5298154;

// Genome.Sin[i*4+0]=random(MIN_A, MAX_A);

// Genome.Sin[i*4+1]= 0.7270191;

Genome.Sin[i*4+1]=random(MIN_B, MAX_B); // Genome.Sin[i*4+2]=1.0;

 Genome.Sin[i*4+2]=random(MIN_C, MAX_C);

//Genome.Sin[i*4+3]=1.71968; Genome.Sin[i*4+3]=random(MIN_D, MAX_D); } \end

\GenomeClass::crossover : int nLocus=random(0,NB_SIN); for (int i=nLocus;i<NB_SIN;i++){

 child.Sin[i*4+0]=parent2.Sin[i*4+0];
 child.Sin[i*4+1]=parent2.Sin[i*4+1];
 child.Sin[i*4+2]=parent2.Sin[i*4+2];
 child.Sin[i*4+3]=parent2.Sin[i*4+3];

} \end

\GenomeClass::mutator: // Must return the number of mutations float ampTemp, freqTemp, phaseTemp, DTemp; for (int i=0;i<NB_SIN;i++)

 if (tossCoin(2/((float)NB_SIN))){
 if (tossCoin(.6)) Genome.Sin[i*4+0]+=0.01-random(0.0,0.02);
 if (tossCoin(.6)) Genome.Sin[i*4+1]+=0.01-random(0.0,0.02);
 if (tossCoin(.6)) Genome.Sin[i*4+2]+=0.01-random(0.0,0.02);
 if (tossCoin(.6)) Genome.Sin[i*4+3]+=0.001-random(0.0,0.002);
  
 }

// Here, we "sort" the sines by frequency. This is the first loop only of a // bubble sort. The subsequent loops will be done through the multiple generations /* for (int i=0;i<NB_SIN-1;i++){

 if (Genome.Sin[i*4+1]>Genome.Sin[(i+1)*4+1]){
   ampTemp=Genome.Sin[i*4+0];freqTemp=Genome.Sin[i*4+1];phaseTemp=Genome.Sin[i*4+2];DTemp=Genome.Sin[i*4+3];
   Genome.Sin[i*4+0]=Genome.Sin[(i+1)*4+0]; Genome.Sin[i*4+1]=Genome.Sin[(i+1)*4+1]; Genome.Sin[i*4+2]=Genome.Sin[(i+1)*4+2];Genome.Sin[i*4+3]=Genome.Sin[(i+1)*4+3];
   Genome.Sin[(i+1)*4+0]=ampTemp; Genome.Sin[(i+1)*4+1]=freqTemp; Genome.Sin[(i+1)*4+2]=phaseTemp; Genome.Sin[(i+1)*4+3]=DTemp;
 }

}

  • /

//return ;//1.1; \end

\GenomeClass::evaluator: // Returns the score

 return (double) fScoreOnGPU(Genome.Sin,NB_SAMPLES,NB_SIN); 

\end

\User Makefile options: \end

\Default run parameters : // Please let the parameters appear in this order

 Number of generations : 1000    	// NB_GEN
 Time limit: 0 			// In seconds, 0 to deactivate
 Population size : 50000  
 Offspring size : 100%  
 Mutation probability : 0.2       // MUT_PROB
 Crossover probability : 1      // XOVER_PROB
 Evaluator goal : minimise      // Maximise
 Selection operator: Tournament 10
 Surviving parents: 100% //percentage or absolute  
 Surviving offspring: 100%
 Reduce parents operator: Tournament 2
 Reduce offspring operator: Tournament 2
 Final reduce operator: Tournament 2
 Elitism: Weak			//Weak or Strong
 Elite: 1
 Print stats: true				//Default: 1
 Generate csv stats file:false			
 Generate gnuplot script:false
 Generate R script:false
 Plot stats:false				//Default: 0
 Remote island model: false
 IP file: ip.txt 			//File containing all the remote island's IP
 Server port : 2929
 Migration probability: 0.1 // 0.15 or 0.5
 Save population: true
 Start from file: false

\end