/*This is a test program for PGAPack.  It implements the DeJong test suite.*/

#include "pgapack.h"

double dejong1(PGAContext *ctx, int p, int pop);
double dejong2(PGAContext *ctx, int p, int pop);
double dejong3(PGAContext *ctx, int p, int pop);
double dejong4(PGAContext *ctx, int p, int pop);
double dejong5(PGAContext *ctx, int p, int pop);

int gray_on;
void   printResultInterpretation(PGAContext *, int);
/*******************************************************************
*                   user main program                              *
*******************************************************************/
int main( int argc, char **argv )
{
     int len,             /* bit string length */
     testnum,
     maxiter;
     PGAContext *ctx;
     char useGray;
     double (*f)(PGAContext *, int, int);

     printf("Do you want to use Gray-coding (y/n)? ");
     scanf("%c", &useGray);
     if (useGray == 'y')
     {
	  gray_on = 1;
	  printf("Graycoding in use . . .\n");
     }
     else
     {
	  gray_on = 0;
	  printf("Graycoding not in use . . .\n");
     }
     printf("Which test do you want to run (1 - 5)? ");
     scanf("%d", &testnum);
     switch (testnum)
     {
     case 1:
	  len = 30;
	  f = dejong1;
	  break;
     case 2:
	  len = 24;
	  f = dejong2;
	  break;
     case 3:
	  len = 50;
	  f = dejong3;
	  break;
     case 4:
	  len = 240;
	  f = dejong4;
	  break;
     case 5:
	  len = 34;
	  f = dejong5;
	  break;
     default:
	  printf("Invalid number test number.\n");
	  exit(1);
	  break;
     }
     printf("How many iterations? ");
     scanf("%d", &maxiter);
     ctx = PGACreate(&argc, argv, PGA_DATATYPE_BINARY, len, PGA_MINIMIZE);
     PGASetMaxIter(ctx, maxiter);
     PGASetRandomSeed(ctx, 1);
     PGASetUp(ctx);
     PGARun(ctx, f);
     printResultInterpretation(ctx, testnum);
     PGADestroy(ctx);
     return (0);
}

double dejong1(PGAContext *ctx, int p, int pop)
{
     int i;
     double term, sum = 0;

     if (gray_on)
	  for(i = 0; i < 30; i+=10)
	  {
	       term = PGAGetRealFromGrayCode(ctx, p, pop, i, i + 9, -5.12,
					     5.11);
	       sum += (term * term);
	  }
     else
	  for(i = 0; i < 30; i+=10)
	  {
	       term = PGAGetRealFromBinary(ctx, p, pop, i, i + 9, -5.12,
					   5.11);
	       sum += (term * term);
	  }

     return (sum);
}

double dejong2(PGAContext *ctx, int p, int pop)
{
     double x1, x2, p1, p2;

     if (gray_on)
     {
	  x1 = PGAGetRealFromGrayCode(ctx, p, pop, 0, 11, -2.048, 2.047);
	  x2 = PGAGetRealFromGrayCode(ctx, p, pop, 12, 23, -2.048, 2.047);
     }
     else
     {
	  x1 = PGAGetRealFromBinary(ctx, p, pop, 0, 11, -2.048, 2.047);
	  x2 = PGAGetRealFromBinary(ctx, p, pop, 12, 23, -2.048, 2.047);
     }
     p1 = x1 * x1 - x2;
     p2 = 1 - x1;

     return (100 * p1 * p1 + p2 * p2);
}

double dejong3(PGAContext *ctx, int p, int pop)
{
     int i;
     double sum = 0;

     if (gray_on)
	  for(i = 0; i < 50; i += 10)
	       sum += floor(PGAGetRealFromGrayCode(ctx, p, pop, i, i + 9,
						   -5.12, 5.11));
     else
	  for(i = 0; i < 50; i += 10)
	       sum += floor(PGAGetRealFromBinary(ctx, p, pop, i, i + 9,
						 -5.12, 5.11));

     return (sum);
}

double dejong4(PGAContext *ctx, int p, int pop)
{
     int i;
     double term, sum = 0;

     if (gray_on)
	  for(i = 0; i < 30; i++)
	  {
	       term = PGAGetRealFromGrayCode(ctx, p, pop, i * 8, i * 8 + 7,
					     -1.28, 1.27);
	       sum += ((i + 1) * term * term * term * term);
	  }
     else
	  for(i = 0; i < 30; i++)
	  {
	       term = PGAGetRealFromBinary(ctx, p, pop, i * 8, i * 8 + 7,
					     -1.28, 1.27);
	       sum += ((i + 1) * term * term * term * term);
	  }

     return (sum + PGARandomGaussian(ctx, 0, 1));
}

double dejong5(PGAContext *ctx, int p, int pop)
{
     static int a[2][25] =
     {
          {
	       -32, -16, 0, 16, 32,
	       -32, -16, 0, 16, 32,
	       -32, -16, 0, 16, 32,
	       -32, -16, 0, 16, 32,
	       -32, -16, 0, 16, 32 
	  },
	  {
	       -32, -32, -32, -32, -32,
	       -16, -16, -16, -16, -16,
	         0,   0,   0,   0,   0,
	        16,  16,  16,  16,  16,
	        32,  32,  32,  32,  32
	  }
     };

     int i, j;
     double sum_over_i = 0, sum_over_j = 0;

     if (gray_on)
	  for (j = 0; j < 25; j++)
	  {
	       sum_over_i = 0;
	       for (i = 0; i < 2; i++)
		    sum_over_i += pow(PGAGetRealFromGrayCode(ctx, p, pop,
							     i * 17,
							     i * 17 + 16,
							     -65.536, 65.535)
				      - a[i][j], 6);
	       sum_over_j += (1.0 / (j + sum_over_i));
	  }
	  for (j = 0; j < 25; j++)
	  {
	       sum_over_i = 0;
	       for (i = 0; i < 2; i++)
		    sum_over_i += pow(PGAGetRealFromBinary(ctx, p, pop,
							     i * 17,
							     i * 17 + 16,
							     -65.536, 65.535)
				      - a[i][j], 6);
	       sum_over_j += (1.0 / (j + sum_over_i));
	  }

     return (1.0 / (0.002 + sum_over_j));
}

void printResultInterpretation(PGAContext *ctx, int testnum)
{
     int best, numcoord, bin_length, i;
     double string[30], lower, upper;

     best = PGAGetBest(ctx, PGA_OLDPOP);
     switch (testnum)
     {
     case 1:
	  numcoord = 3, bin_length = 10;
	  lower = -5.12, upper = 5.11;
	  break;
     case 2:
	  numcoord = 2, bin_length = 12;
	  lower = -2.048, upper = 2.047;
	  break;
     case 3:
	  numcoord = 5, bin_length = 10;
	  lower = -5.12, upper = 5.11;
	  break;
     case 4:
	  numcoord = 30, bin_length = 8;
	  lower = -1.28, upper = 1.27;
	  break;
     case 5:
	  numcoord = 2, bin_length = 17;
	  lower = -65.536, upper = 65.535;
	  break;
     default:
	  fprintf(stderr, "Problem in printResultInterpretation\n");
	  exit(1);
	  break;
     }
     printf("The real interpretation:\n");
     for (i = 0; i < numcoord; i++)
     {
	  if (gray_on)
	       string[i] = PGAGetRealFromGrayCode(ctx, best, PGA_OLDPOP,
						  i * bin_length,
						  bin_length * (i + 1) - 1,
						  lower, upper);
	  else
	       string[i] = PGAGetRealFromBinary(ctx, best, PGA_OLDPOP,
						i * bin_length,
						bin_length * (i + 1) - 1,
						lower, upper);
	  switch ( i % 5 )
	  {
	  case 0:
	       printf ("#%4d: [%11.7g]",i,string[i]);
	       break;
	  case 1:
	  case 2:
	  case 3:
	       printf (", [%11.7g]",string[i]);
	       break;
	  case 4:
	       printf (", [%11.7g]",string[i]);
	       if (i+1 < numcoord)
		    printf ("\n");
	       break;
	  }
     }
     printf("\n");
}
