/*****************************************************************************
*     FILE: integer.c: This file contains the routines specific to the integer
*                      data structure
*
*     Authors: David M. Levine, Philip L. Hallstrom, David M. Noelle
*****************************************************************************/

#include "pgapack.h"

/*I****************************************************************************
   PGAIntegerCreateString - Allocate memory for a string of type PGAInteger

   Inputs:
      ctx      - context variable
      p        - string index
      pop      - symbolic constant of the population string p is in
      initflag - A true/false flag used in conjunction with ctx->ga.RandomInit
                 to initialize the string either randomly or set to zero
      
   Outputs:
      new      - a pointer set to the address of the allocated memory

   Example:
      Allocates memory and assigns the address of the allocated memory to
      the string field (ind->chrom) of the individual.
      
      PGAContext *ctx;
      PGAIndividual *ind;
      PGAIntegerCreateString( ctx, ind, PGAFALSE );

****************************************************************************I*/
void PGAIntegerCreateString (PGAContext *ctx, int p, int pop, int InitFlag)
{
     int i;
     PGAInteger *c;
     PGAIndividual *new = PGAGetIndividual(ctx, p, pop);

     PGADebugPrint(ctx, PGADEBUG_ENTERED, "PGAIntegerCreateString",
		   "Entered", PGA_VOID, NULL);

     new->chrom = (void *)malloc(ctx->ga.StringLen * sizeof(PGAInteger));
     if (new->chrom == NULL)
	  PGAError(ctx, "PGAIntegerCreateString: No room to allocate "
		   "new->chrom", PGA_FATAL, PGA_VOID, NULL);
     c = (PGAInteger *)new->chrom;
     if (InitFlag)
	  (*ctx->ops.Randomize)(ctx, p, pop);
     else
	  for (i=0; i<ctx->ga.StringLen; i++)
	       c[i] = 0;
}

/*U****************************************************************************
  PGASetIntegerInitPermute - sets each integer-valued gene to a random
  permutation of the values given by an upper and lower bound.  The length
  of the interval must be the same as the string length.  This is the
  default strategy for initializing integer-valued strings. The default
  interval is [0,L-1] where L is the string length.

  Category: Initialization

  Inputs:
     ctx - context variable
     min - the lower bound of numbers used in the permutation
     max - the upper bound of numbers used in the permutation

  Outputs:

  Example:
      This example will set each gene to a random and unique value from
      the interval $[500,599]$.

      PGAContext *ctx;
      :
      PGASetIntegerInitPermute(ctx, 500, 599)}

****************************************************************************U*/
void PGASetIntegerInitPermute ( PGAContext *ctx, int min, int max)
{
     int i, range;

     PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGASetIntegerInitPermute",
		   "Entered", PGA_VOID, NULL );
      
     range = max - min + 1;
     if (max <= min)
	  PGAError(ctx, "PGASetIntegerInitPermute: max does not exceed min:",
		   PGA_FATAL, PGA_INT, (void *) &max);
     else if (range != ctx->ga.StringLen)
	  PGAError(ctx, "PGASetIntegerInitPermute: range does not equal string "
		   "length:", PGA_FATAL, PGA_INT, (void *) &range);
     else
     {
	  ctx->init.IntegerType = PGA_PERMUTE;
	  for (i = 0; i < ctx->ga.StringLen; i++)
	  {
	       ctx->init.IntegerMin[i] = min;
	       ctx->init.IntegerMax[i] = max;
	  }
     }

     PGADebugPrint (ctx, PGADEBUG_EXIT, "PGASetIntegerInitPermute", "Exit",
		    PGA_VOID, NULL);
}

/*U****************************************************************************
  PGASetIntegerInitLU - sets each integer-valued gene to a value chosen
  randomly from the interval given by an upper and lower bound.

  Category: Initialization

  Inputs:
     ctx - context variable
     min - array of lower bounds that define the interval the gene is
           initialized from 
     max - array of upper bounds that define the interval the gene is
           initialized from 

  Outputs:

  Example:
      This example will select a value for gene i uniformly randomly from the
      interval [0,i]

      PGAContext *ctx;
      int *low, *high, stringlen, i;
      :
      stringlen = PGAGetStringLen(ctx);
      low  = (int *) malloc(stringlen*sizeof(int));
      high = (int *) malloc(stringlen*sizeof(int));
      for(i=0;i<stringlen;i++) {
          low[i]  = 0;
          high[i] = i
      }
      PGASetIntegerInitLU(ctx, low, high);
      
****************************************************************************U*/
void PGASetIntegerInitLU (PGAContext *ctx, int *min, int *max)
{
     int i;
     PGADebugPrint(ctx, PGADEBUG_ENTERED, "PGASetIntegerInitLU", "Entered",
		   PGA_VOID, NULL);

     for (i = 0; i < ctx->ga.StringLen; i++)
     {
	  if (max[i] < min[i])
	       PGAError(ctx, "PGASetIntegerInitLU: Lower bound exceeds upper "
			"bound for allele #", PGA_FATAL, PGA_INT, (void *) &i);
	  else
	  {
	       ctx->init.IntegerMin[i] = min[i];
	       ctx->init.IntegerMax[i] = max[i];
	  }
     }
     ctx->init.IntegerType = PGA_RANGE;

     PGADebugPrint(ctx, PGADEBUG_EXIT, "PGASetIntegerInitLU", "Entered",
		   PGA_VOID, NULL);
}
/*I****************************************************************************
   PGAIntegerRandomize - randomly initialize a string of type PGAInteger

   Inputs:
      ctx   - context variable
      p   - index of string to randomly initialize
      pop - symbolic constant of the population string p is in
      
   Outputs:

   Example:
      PGAContext *ctx;
      PGAInteger *s;
      PGAIntegerRandomize ( ctx, s );
   
****************************************************************************I*/
void PGAIntegerRandomize(PGAContext *ctx, int p, int pop)
{
     int *list;
     int len, i, j;
     PGAInteger *c = (PGAInteger *)PGAGetIndividual(ctx, p, pop)->chrom;

     PGADebugPrint(ctx, PGADEBUG_ENTERED, "PGAIntegerRandomize", "Entered", 
                   PGA_VOID, NULL );

     len = ctx->ga.StringLen;
    
     switch (ctx->init.IntegerType)
     {
     case PGA_PERMUTE:
	  list = (int *)malloc(sizeof(int) * len);
	  if (list == NULL)
	       PGAError(ctx, "PGAIntegerRandomize: No room to allocate list",
			PGA_FATAL, PGA_VOID, NULL);
	  j = ctx->init.IntegerMin[0];
	  for (i = 0; i < len; i++)
	       list[i] = j++;
	  for (i = 0; i < len; i++)
	  {
	       j = PGARandomInterval ( ctx, 0, len - i - 1 );
	       c[i] = list[j];
	       list[j] = list[len - i - 1];
	  }
	  free(list);
	  break;
     case PGA_RANGE:
	  for (i = 0; i < len; i++)
	       c[i] = PGARandomInterval(ctx, ctx->init.IntegerMin[i],
					ctx->init.IntegerMax[i]);
	  break;
     }
     PGADebugPrint(ctx, PGADEBUG_EXIT, "PGAIntegerRandomize", "Exit", PGA_VOID,
		   NULL);
}

/*U****************************************************************************
   PGAGetIntegerAllele: returns the value of allele i in population member p.
   Assumes the data type is "Integer"

   Category: Allele

   Inputs:
      ctx - context variable
      p   - string index
      pop - symbolic constant of the population the string is in
      i   - allele index
      
   Outputs:

   Example:
      Returns the value of the ith integer allele of string p
      in population PGA_NEWPOP
      
      PGAContext *ctx;
      int p, i, k;
      k =  PGAGetIntegerAllele ( ctx, p, PGA_NEWPOP, i )

****************************************************************************U*/
int PGAGetIntegerAllele (PGAContext *ctx, int p, int pop, int i)
{
    PGAIndividual *ind;
    PGAInteger     *chrom;

    PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGAGetIntegerAllele", "Entered", 
                   PGA_VOID, NULL );

    ind = PGAGetIndividual ( ctx, p, pop );
    chrom = (PGAInteger *)ind->chrom;
    return( (int) chrom[i] );
}

/*U****************************************************************************
   PGASetIntegerAllele - sets the value of a (integer) allele

   Category: Allele

   Inputs:
      ctx - context variable
      p   - string index
      pop - symbolic constant of the population the string is in
      i   - allele index
      val - integer value to set the allele to
      
   Outputs:

   Example:
      Sets the value of the ith gene of string p
      in population PGA_NEWPOP to 64
      
      PGAContext *ctx;
      int p, i;
      PGASetIntegerAllele ( ctx, p, PGA_NEWPOP, i, 64 )

****************************************************************************U*/
void PGASetIntegerAllele (PGAContext *ctx, int p, int pop, int i, int value)
{
    PGAIndividual *ind;
    PGAInteger     *chrom;

    PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGASetIntegerAllele", "Entered", 
                   PGA_VOID, NULL );

    ind = PGAGetIndividual ( ctx, p, pop );
    chrom = (PGAInteger *)ind->chrom;
    chrom[i] = value;
}

/*I****************************************************************************
   PGAIntegerWriteString - writes an integer-valued string to a file.  This
   routine casts the void string pointer it is passed as the second argument.
   
   Inputs:
      ctx - context variable
      fp  - file pointer to file to write the string to
      p   - index of the string to write out
      pop - symbolic constant of the population string p is in
      
   Outputs:

   Example:
      Write string s to stdout.
      
      PGAContext *ctx;
      void *s; 
      PGAIntegerWriteString( ctx, stdout, s );

****************************************************************************I*/
void PGAIntegerWriteString ( PGAContext *ctx, FILE *fp, int p, int pop)
{
    PGAInteger *c = (PGAInteger *)PGAGetIndividual(ctx, p, pop)->chrom;
    int i;

    PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGAIntegerWriteString",
                   "Entered", PGA_VOID, NULL );

    for(i = 0; i < ctx->ga.StringLen; i++)
    {
	switch ( i % 6 )
	{
	case 0:
	    fprintf ( fp, "#%5d: [%8ld]",i,c[i]);
	    break;
	case 1:
	case 2:
	case 3:
	case 4:
	    fprintf ( fp, ", [%8ld]",c[i]);
	    break;
	case 5:
            fprintf ( fp, ", [%8ld]",c[i]);
	    if (i+1 < ctx->ga.StringLen)
		fprintf ( fp, "\n");
	    break;
	}
    }
    fprintf ( fp, "\n" );
}

/*I****************************************************************************
   PGAIntegerCopyString - Copy one integer-valued string to another
   
   Inputs:
      ctx - context variable
      p1   - string to copy
      pop1 - symbolic constant of population containing string p1
      p2   - string to copy p1 to
      pop2 - symbolic constant of population containing string p2
      
   Outputs:

   Example:
      Copy integer string x to y (both are implicitly assumed to be of length
      WL)
      
      void *x, *y;
      int WL;
      PGAIntegerCopyString ( ctx, x, y );

****************************************************************************I*/
void PGAIntegerCopyString (PGAContext *ctx, int p1, int pop1, int p2, int pop2)
{
    PGAInteger *source = (PGAInteger *)PGAGetIndividual(ctx, p1, pop1)->chrom;
    PGAInteger *dest   = (PGAInteger *)PGAGetIndividual(ctx, p2, pop2)->chrom;
    int i;
    
    PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGAIntegerCopyString","Entered", 
                   PGA_VOID, NULL );

    for (i = 0; i < ctx->ga.StringLen; i++)
	dest[i] = source[i];

    return;
}

/*I****************************************************************************
   PGAIntegerMutation - randomly mutates an integer-valued gene with a
   specified probability. This routine is called from PGAMutation and must
   cast the void string pointer it is passed as the second argument.

   Inputs:
      ctx - context variable
      p        - string index
      pop      - symbolic constant of the population string p is in
      mr  - probability of mutating an integer-valued gene
      
   Outputs:
      Returns the number of mutations

   Example:

****************************************************************************I*/
int PGAIntegerMutation( PGAContext *ctx, int p, int pop, double mr )
{
     PGAInteger *c;
     int i;
     int count = 0;

     PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGAIntegerMutation", "Entered", 
                   PGA_VOID, NULL );

     c = (PGAInteger *)PGAGetIndividual(ctx, p, pop)->chrom;
     for(i=0; i<ctx->ga.StringLen; i++)
	  if ( PGARandomFlip(ctx, mr) )	      /* randomly choose an allele   */
	  {
	       if ( PGARandomFlip(ctx, .5) )  /* add or subtract from allele */
		    c[i] += ctx->ga.MutateIntegerVal;
	       else
		    c[i] -= ctx->ga.MutateIntegerVal;
	       count++;
	  }

     return(count);
}

/*I****************************************************************************
   PGAIntegerOneptCrossover - performs one-point crossover on two parent
   strings producing two children via side-effect
   
   Inputs:
      ctx  - context variable
      p1   - the first parent string
      p2   - the second parent string
      pop1 - symbolic constant of the population containing string p1 and p2
      pop2 - symbolic constant of the population to contain string c1 and c2
      
   Outputs:
      c1   - the first child string
      c2   - the second child string

   Example:
      Performs crossover  on the two parent strings m and d, producing
      children s and b.
      
      PGAContext *ctx;
      void *m,*d,*s,*b;
      PGAIntegerOneptCrossover( ctx, m, d, s, b );

****************************************************************************I*/
void PGAIntegerOneptCrossover(PGAContext *ctx, int p1, int p2, int pop1,
			      int c1, int c2, int pop2)
{
     PGAInteger *parent1 = (PGAInteger *)PGAGetIndividual(ctx, p1,
							  pop1)->chrom;
     PGAInteger *parent2 = (PGAInteger *)PGAGetIndividual(ctx, p2,
							  pop1)->chrom;
     PGAInteger *child1  = (PGAInteger *)PGAGetIndividual(ctx, c1,
							  pop2)->chrom;
     PGAInteger *child2  = (PGAInteger *)PGAGetIndividual(ctx, c2,
							  pop2)->chrom;
     int i, xsite;    

     PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGAIntegerOneptCrossover",
                   "Entered", PGA_VOID, NULL );

    xsite = PGARandomInterval(ctx, 1,ctx->ga.StringLen-1);

    for(i=0;i<xsite;i++) {
        child1[i] = parent1[i];
        child2[i] = parent2[i];
    }

    for(i=xsite;i<ctx->ga.StringLen;i++) {
        child1[i] = parent2[i];
        child2[i] = parent1[i];
    }

    return;
}


/*I****************************************************************************
   PGAIntegerTwoptCrossover - performs two-point crossover on two parent
   strings producing two children via side-effect
   
   Inputs:
      ctx  - context variable
      p1   - the first parent string
      p2   - the second parent string
      pop1 - symbolic constant of the population containing string p1 and p2
      pop2 - symbolic constant of the population to contain string c1 and c2
      
   Outputs:
      c1   - the first child string
      c2   - the second child string

   Example:
      Performs crossover on the two parent strings m and d, producing
      children s and b.
      
      PGAContext *ctx;
      void *m,*d,*s,*b;
      PGAIntegerTwoptCrossover( ctx, m, d, s, b );

****************************************************************************I*/
void PGAIntegerTwoptCrossover( PGAContext *ctx, int p1, int p2, int pop1,
			      int c1, int c2, int pop2)
{
     PGAInteger *parent1 = (PGAInteger *)PGAGetIndividual(ctx, p1,
							  pop1)->chrom;
     PGAInteger *parent2 = (PGAInteger *)PGAGetIndividual(ctx, p2,
							  pop1)->chrom;
     PGAInteger *child1  = (PGAInteger *)PGAGetIndividual(ctx, c1,
							  pop2)->chrom;
     PGAInteger *child2  = (PGAInteger *)PGAGetIndividual(ctx, c2,
							  pop2)->chrom;
     int i, temp, xsite1, xsite2;
     PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGAIntegerTwoptCrossover",
                   "Entered", PGA_VOID, NULL );

    /* pick two cross sites such that xsite2 > xsite1 */
    xsite1 = PGARandomInterval(ctx, 1,ctx->ga.StringLen-1);
    xsite2 = xsite1;
    while ( xsite2 == xsite1 )
        xsite2 = PGARandomInterval(ctx, 1,ctx->ga.StringLen-1);
    if ( xsite1 > xsite2 ) {
        temp   = xsite1;
        xsite1 = xsite2;
        xsite2 = temp;
    }

    for(i=0;i<xsite1;i++) {
        child1[i] = parent1[i];
        child2[i] = parent2[i];
    }

    for(i=xsite1;i<xsite2;i++) {
        child1[i] = parent2[i];
        child2[i] = parent1[i];
    }

    for(i=xsite2;i<ctx->ga.StringLen;i++) {
        child1[i] = parent1[i];
        child2[i] = parent2[i];
    }

    return;
}


/*I****************************************************************************
   PGAIntegerUniformCrossover - performs uniform crossover on two parent
   strings producing two children via side-effect
   
   Inputs:
      ctx  - context variable
      p1   - the first parent string
      p2   - the second parent string
      pop1 - symbolic constant of the population containing string p1 and p2
      pop2 - symbolic constant of the population to contain string c1 and c2
      
   Outputs:
      c1   - the first child string
      c2   - the second child string

   Example:
      Performs crossover on the two parent strings m and d, producing
      children s and b.
      
      PGAContext *ctx;
      void *m,*d,*s,*b;
      PGAIntegerUniformCrossover( ctx, m, d, s, b );

****************************************************************************I*/
void PGAIntegerUniformCrossover(PGAContext *ctx, int p1, int p2, int pop1,
				int c1, int c2, int pop2)
{
     PGAInteger *parent1 = (PGAInteger *)PGAGetIndividual(ctx, p1,
							  pop1)->chrom;
     PGAInteger *parent2 = (PGAInteger *)PGAGetIndividual(ctx, p2,
							  pop1)->chrom;
     PGAInteger *child1  = (PGAInteger *)PGAGetIndividual(ctx, c1,
							  pop2)->chrom;
     PGAInteger *child2  = (PGAInteger *)PGAGetIndividual(ctx, c2,
							  pop2)->chrom;
     int i;

     PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGAIntegerUniformCrossover",
                   "Entered", PGA_VOID, NULL );

    for(i=0;i<ctx->ga.StringLen;i++) {
        if ( parent1[i] == parent2[i] ) {
            child1[i] = parent1[i];
            child2[i] = parent2[i];
        }
        else {
            if(PGARandomFlip(ctx, ctx->ga.UniformCrossProb)) {
                child1[i] = parent1[i];
                child2[i] = parent2[i];
            }
            else {
                child1[i] = parent2[i];
                child2[i] = parent1[i];
            }
        }
    }

    return;
}

/*I****************************************************************************
   PGAIntegerDuplicate - Returns true if string a is a duplicate of
   string b, else returns false.
   
   Inputs:
      ctx - context variable
      p1   - string index of the first string to compare
      pop1 - symbolic constant of the population string p1 is in
      p2   - string index of the second string to compare
      pop2 - symbolic constant of the population string p2 is in
      
   Outputs:
      Returns true/false if strings are duplicates

   Example:
      Compare string x with y to see if they are duplicates
      
      void *x, *y;
      if ( PGAIntegerDuplicate( ctx, x, y ) )
          printf("strings are duplicates\n");

****************************************************************************I*/
int PGAIntegerDuplicate( PGAContext *ctx, int p1, int pop1, int p2, int pop2)
{
     PGAInteger *a = (PGAInteger *)PGAGetIndividual(ctx, p1, pop1)->chrom;
     PGAInteger *b = (PGAInteger *)PGAGetIndividual(ctx, p2, pop2)->chrom;
     int i;
     
     PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGAIntegerDuplicate", "Entered", 
                   PGA_VOID, NULL );

     for(i=0; i<ctx->ga.StringLen; i++)
	  if (a[i] != b[i])
	       return(PGAFALSE);
    
     return(PGATRUE);
}
