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

#include "pgapack.h"

/*I****************************************************************************
   PGARealCreateString - Allocate memory for a string of type PGAReal

   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 real string field (ind->chrom) of the individual.
      
      PGAContext *ctx;
      PGAIndividual *ind;
      PGARealCreateString( ctx, ind, PGAFALSE );

****************************************************************************I*/
void PGARealCreateString (PGAContext *ctx, int p, int pop, int initflag)
{
     PGAIndividual *new = PGAGetIndividual(ctx, p, pop);
     int i;
     PGAReal *c;

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

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

/*U****************************************************************************
  PGASetRealInitPercent - sets the upper and lower bounds for randomly
  initializing real-valued genes.  For each gene these bounds define an
  interval from which the initial allele value is selected uniformly randomly.
  With this routine the user specifies a median value and a percent offset
  for each allele.

  Category: Initialization

  Inputs:
     ctx     - context variable
     median  - an array containing the mean value of the interval
     percent - an array containing the percent offset to add and subtract to
               the median to define the interval
      
  Outputs:
     initializes the population via side effect
      
  Example:
     This example will select a value for each real-valued gene i uniformly
     randomly from the interval [i-v,i+v], where $v = i/2$.

     PGAContext *ctx;
     double *median, *percent;
     int i, stringlen;
     :
     stringlen = PGAGetStringLen(ctx);
     median  = (double *) malloc(stringlen*sizeof(double));
     percent = (double *) malloc(stringlen*sizeof(double));
     for(i=0;i<stringlen;i++) {
        median[i]  = (double) i;
        percent[i] = 0.5;
     }
     PGASetRealInitPercent(ctx, median, percent);

****************************************************************************U*/
void PGASetRealInitPercent ( PGAContext *ctx, double *median, double *percent)
{
     int i;
     double offset;

     PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGASetRealInitPercent",
		   "Entered", PGA_VOID, NULL );
      
     for (i = 0; i < ctx->ga.StringLen; i++)
     {
	  offset = fabs(median[i] * percent[i]);
	  ctx->init.RealMin[i] = median[i] - offset;
	  ctx->init.RealMax[i] = median[i] + offset;
     }

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

/*U****************************************************************************
  PGASetRealInitLU - sets the upper and lower bounds for randomly
  initializing real-valued genes.  For each gene these bounds define an
  interval from which the initial allele value is selected uniformly randomly.
  The user specifies two arrays containing lower and bound for each gene to
  define the interval.  This is the default strategy for initializing
  real-valued strings.  The default interval is $[0,1.0]$ for each gene.

  Category: Initialization

  Inputs:
     ctx - context variable
     min - array containing the lower bound of the interval for each gene
     mac - array containing the upper bound of the interval for each gene
      
  Outputs:
     initializes the population via side effect
      
  Example:
     This example will select a value for each real-valued gene i uniformly
     randomly from the interval [-10.,i]

     PGAContext *ctx;
     double *low, *high;
     int i, stringlen;
     :
     stringlen = PGAGetStringLen(ctx);
     low  = (double *) malloc(stringlen*sizeof(double));
     high = (double *) malloc(stringlen*sizeof(double));
     for(i=0;i<stringlen;i++) {
        low[i]  = -10.0;
        high[i] = i;
     }
     PGASetRealInitLU(ctx, low, high);

****************************************************************************U*/
void PGASetRealInitLU (PGAContext *ctx, double *min, double *max)
{
     int i;
     PGADebugPrint(ctx, PGADEBUG_ENTERED, "PGASetRealInitLU", "Entered",
		   PGA_VOID, NULL);

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

     PGADebugPrint(ctx, PGADEBUG_EXIT, "PGASetRealInitLU", "Entered",
		   PGA_VOID, NULL);
}

/*I****************************************************************************
   PGARealRandomize - randomly initialize a string of type PGAReal

   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;
      PGAReal *s;
      PGARealRandomize (ctx, s);
   
****************************************************************************I*/
void PGARealRandomize ( PGAContext *ctx, int p, int pop)
{
     int i;
     PGAReal *c = (PGAReal *)PGAGetIndividual(ctx, p, pop)->chrom;
    
     PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGARealRandomize", "Entered", 
		   PGA_VOID, NULL );
    
     for (i = 0; i < ctx->ga.StringLen; i++)
	  c[i] = PGARandomUniform(ctx, ctx->init.RealMin[i],
				  ctx->init.RealMax[i]);
     PGADebugPrint (ctx, PGADEBUG_EXIT, "PGARealRandomize", "Exit", PGA_VOID,
		    NULL);
}

/*U****************************************************************************
   PGAGetRealAllele - returns the value of real-valued allele i in string p
   in population pop

   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 real-valued allele of string p
      in population PGA_NEWPOP
      
      PGAContext *ctx;
      int p, i, r;
      r =  PGAGetRealAllele (ctx, p, PGA_NEWPOP, i)

****************************************************************************U*/
double PGAGetRealAllele (PGAContext *ctx, int p, int pop, int i)
{
    PGAIndividual *ind;
    PGAReal      *chrom;

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

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


/*U****************************************************************************
   PGASetRealAllele - sets the value of real-valued allele i in string p
   in population pop

   Category: Allele

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

   Example:
      Sets the value of the ith allele of string p
      in population PGA_NEWPOP to 1.57
      
      PGAContext *ctx;
      int i, p;
      :
      PGASetRealAllele ( ctx, p, PGA_NEWPOP, i, 1.57)
   
****************************************************************************U*/
void PGASetRealAllele (PGAContext *ctx, int p, int pop, int i, double value)
{
    PGAIndividual *ind;
    PGAReal      *chrom;

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

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

/*I****************************************************************************
   PGARealWriteString - writes a real-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; 
      PGARealWriteString( ctx, stdout, s );

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

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

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


/*I****************************************************************************
   PGARealCopyString - Copy one real-valued string 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 string x to y (both are implicitly assumed to be of length
      WL)
      
      void *x, *y;
      int WL;
      PGARealCopyString (ctx, x, y);

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

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

    return;
}

/*I****************************************************************************
   PGARealMutation - randomly mutates a floating point string with probability
   mr.  The formula used is v = v +- p*v.  That is the new value of v
   (allele i) is the old value + or - a percentage, p, of the old value.
   There are three possibilities for choosing p: (1) constant value (2)
   selected uniformly on [0,UB] (UB means upper bound) and (3) selected from 
   a (0,sigma) Gaussian distribution (with mean 0 and standard deviation
   sigma).  The change to an allele, p*v, is added or subtracted to the old
   value with a probability of .5.  Alleles to mutate are randomly selected
   as usual.  The value set by the routine PGASetMutationRealVal is used as p
   in case (1), as UB in case (2), or as sigma in case 3

   Inputs:
      ctx - context variable
      p        - string index
      pop      - symbolic constant of the population string p is in
      mr  - probability of mutating a real-valued gene

   Outputs: The number of mutations performed.

   Example:
      Sets the value of the ith gene of string p
      in population PGA_NEWPOP to one
      
      PGAContext *ctx;
      void *s;
      PGARealMutation( ctx, s, .001 );

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

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

     c = (PGAReal *)PGAGetIndividual(ctx, p, pop)->chrom;
     for(i=0; i<ctx->ga.StringLen; i++)
	  if ( PGARandomFlip(ctx, mr) )      /* randomly choose an allele   */
	  {
	       switch (ctx->ga.MutationType)
	       {
	       case PGA_MUTATION_FIXED:
	       case PGA_MUTATION_STRINGLEN:
	       case PGA_MUTATION_HAMMING:
		    val = ctx->ga.MutateRealVal;
		    break;
	       case PGA_MUTATION_UNIFORM:
		    val = PGARandomUniform (ctx, 0.0,ctx->ga.MutateRealVal);
		    break;
	       case PGA_MUTATION_GAUSSIAN:
		    val = PGARandomGaussian(ctx, 0.0,ctx->ga.MutateRealVal);
		    break;
	       default:
		    PGAError(ctx, "PGARealMutation: Invalid value of "
			     "ga.MutationType:", PGA_FATAL, PGA_INT,
			     (void *) &(ctx->ga.MutationType));
		    break;
	       }
	       if ( PGARandomFlip(ctx, .5) )  /* add or subtract from allele */
		    c[i] += val*c[i];
	       else
		    c[i] -= val*c[i];
	       count++;
	  }
     return(count);
}

/*I****************************************************************************
   PGARealOneptCrossover - this routine performs one point crossover on two
   parent strings, producing (via side effect) the crossed children child1 and
   child2
   
   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;
      PGARealOneptCrossover( ctx, m, d, s, b );

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

    PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGARealOneptCrossover", "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****************************************************************************
   PGARealTwoptCrossover - 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;
      PGARealTwoptCrossover( ctx, m, d, s, b );

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

    PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGARealTwoptCrossover", "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****************************************************************************
   PGARealUniformCrossover - 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;
      PGARealUniformCrossover( ctx, m, d, s, b );

****************************************************************************I*/
void PGARealUniformCrossover( PGAContext *ctx, int p1, int p2, int pop1,
			     int c1, int c2, int pop2)
{
     PGAReal *parent1 = (PGAReal *)PGAGetIndividual(ctx, p1,
						    pop1)->chrom;
     PGAReal *parent2 = (PGAReal *)PGAGetIndividual(ctx, p2,
						    pop1)->chrom;
     PGAReal *child1  = (PGAReal *)PGAGetIndividual(ctx, c1,
						    pop2)->chrom;
     PGAReal *child2  = (PGAReal *)PGAGetIndividual(ctx, c2,
						    pop2)->chrom;
     int i;
    
     PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGARealUniformCrossover",
                   "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****************************************************************************
   PGARealDuplicate - Returns true if real-valued string a is a duplicate of
   real-valued 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 strings x with y to see if they are duplicates
      
      void *x, *y;
      if ( PGARealDuplicate( ctx, x, y ) )
          printf("strings are duplicates\n");

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

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