/*****************************************************************************
*     FILE: binary.c: This file contains routines specific to the binary data
*                     structure.
*
*     Authors: David M. Levine, Philip L. Hallstrom, David M. Noelle
*****************************************************************************/
#include "pgapack.h"

/*I****************************************************************************
   PGABinaryCreateString - Allocate memory for a string of type PGABinary

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

****************************************************************************I*/
void PGABinaryCreateString(PGAContext *ctx, int p, int pop, int initflag) 
{
     int i;
     PGABinary *s;
     PGAIndividual *new = PGAGetIndividual(ctx, p, pop);

     PGADebugPrint( ctx, PGADEBUG_ENTEREDHIGH, "PGABinaryCreateString",
                   "Entered", PGA_VOID, NULL );
     PGADebugPrint( ctx, PGADEBUG_PRINTVAR, "PGABinaryCreateString",
                   "initflag = ", PGA_INT, (void *) &initflag );

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

/*I****************************************************************************
   PGABinaryRandomize - randomly initialize a string of type PGABinary

   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;
      PGABinary *s;
      PGABinaryRandomize ( ctx, s );
   
****************************************************************************I*/
void PGABinaryRandomize(PGAContext *ctx, int p, int pop)
{
     PGABinary *c = (PGABinary *)PGAGetIndividual(ctx, p, pop)->chrom;
     int i;
     int windex;        /* index of the computer word allele i is in      */
     int bix;           /* binary position in word chrom[windex] of allele i */

     PGADebugPrint(ctx, PGADEBUG_ENTEREDHIGH, "PGABinaryRandomize", "Entered", 
                   PGA_VOID, NULL );

     for (i = 0; i < ctx->ga.tw; i++)
	  c[i] = 0;
     for (i = 0; i < ctx->ga.StringLen; i++)
     {
	  INDEX(windex,bix,i,WL);
	  if ( PGARandomFlip(ctx, ctx->init.BinaryProbability) )
	       SET  ( bix, c[windex] );
     }
}
     

/*U****************************************************************************
   PGAGetBinaryAllele - returns the value of a (binary) allele in the string
   (binary string)

   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 binary allele of string p
      in population PGA_NEWPOP
      
      PGAContext *ctx;
      int p, i, bit;
      bit =  PGAGetBinaryAllele ( ctx, p, PGA_NEWPOP, i )

****************************************************************************U*/
int PGAGetBinaryAllele ( PGAContext *ctx, int p, int pop, int i )
{

    int windex;        /* index of the computer word allele i is in      */
    int bix;           /* bit position in word chrom[windex] of allele i */
    PGAIndividual *ind;
    PGABinary *chrom;

    PGADebugPrint( ctx, PGADEBUG_ENTEREDHIGH, "PGAGetBinaryAllele", "Entered", 
                   PGA_VOID, NULL );
    

    INDEX( windex,bix,i,WL );
    ind = PGAGetIndividual ( ctx, p, pop );
    chrom = (PGABinary *)ind->chrom;
    if ( BIT( bix, chrom[windex] ) )
        return 1;
    else
        return 0;
}
    

/*U****************************************************************************
   PGASetBinaryAllele - sets the value of a (binary) allele

   Category: Allele

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

   Example:
      Sets the value of the ith bit of string p
      in population PGA_NEWPOP to one
      
      PGAContext *ctx;
      int p, i;
      PGASetBinaryAllele ( ctx, p, PGA_NEWPOP, i, 1 )
   

****************************************************************************U*/
void PGASetBinaryAllele ( PGAContext *ctx, int p, int pop, int i, int val )
{
    int windex;        /* index of the computer word allele i is in      */
    int bix;           /* bit position in word chrom[windex] of allele i */
    PGAIndividual *ind;
    PGABinary *chrom;

    PGADebugPrint( ctx, PGADEBUG_ENTEREDHIGH, "PGASetBinaryAllele", "Entered", 
                   PGA_VOID, NULL );
    

    INDEX( windex,bix,i,WL );
    ind = PGAGetIndividual ( ctx, p, pop );
    chrom = (PGABinary *)ind->chrom;
    if ( val == 1 )
          SET( bix, chrom[windex] );
    else 
        UNSET( bix, chrom[windex] );
}


/*I****************************************************************************
   PGABinaryMutation - randomly mutates a bit 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 (toggling) the bit
      
   Outputs:
      Returns the number of mutations

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

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

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

     c = (PGABinary *)PGAGetIndividual(ctx, p, pop)->chrom;
     for(wi=0; wi<ctx->ga.fw; wi++)
	  for(i=0;i<WL;++i)
	       if ( PGARandomFlip(ctx, mr) )
	       {
		    TOGGLE(i,c[wi]);
		    count++;
	       }		

     /* clean up the partial word if eb > 0 */
     if (ctx->ga.eb > 0 ) 
	  for(i=0;i<ctx->ga.eb;++i)
	       if ( PGARandomFlip(ctx, mr) )
	       {
		    TOGGLE(i,c[ctx->ga.fw]);
		    count++;
	       }

    return(count);
}

/*I****************************************************************************
   PGABinaryOneptCrossover - performs one-point crossover on two parent strings
   to create 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;
      PGABinaryOneptCrossover( ctx, m, d, s, b );

****************************************************************************I*/
void PGABinaryOneptCrossover(PGAContext *ctx, int p1, int p2, int pop1, int c1,
			     int c2, int pop2)
{
    PGABinary *parent1 = (PGABinary *)PGAGetIndividual(ctx, p1, pop1)->chrom;
    PGABinary *parent2 = (PGABinary *)PGAGetIndividual(ctx, p2, pop1)->chrom;
    PGABinary *child1  = (PGABinary *)PGAGetIndividual(ctx, c1, pop2)->chrom;
    PGABinary *child2  = (PGABinary *)PGAGetIndividual(ctx, c2, pop2)->chrom;
    
    /*
      If the bits are numbered from 0 as follows:

      b   b   b   b   b   b   b   b          b  b
      0   1   2   3   4   5   6   7         30 31

      Then if the cross site is bit 5 (which is the sixth bit by our
      numbering scheme) we would get

      o   o   o   o   o   n   n   n          n  n
      0   1   2   3   4   5   6   7         30 31

      where o indicates the original bit and n is a new bit from the crossover
      operator.
    */
    
    PGABinary mask;
    int windex;   /* index of the word the crossover bit position is in */
    int bix;      /* bit position to perform crossover (mod WL)         */
    int i;
    int xsite;    

    PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGABinaryOneptCrossover", "Entered", 
                   PGA_VOID, NULL );
    
    xsite = PGARandomInterval(ctx, 1,ctx->ga.StringLen-1);

    INDEX(windex,bix,xsite,WL);

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

    mask = ~0;
    mask = mask >> bix;
    
    child1[windex] = (~mask & parent1[windex])|(mask & parent2[windex]);
    child2[windex] = (~mask & parent2[windex])|(mask & parent1[windex]);

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

}


/*I****************************************************************************
   PGABinaryTwoptCrossover - 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;
      PGABinaryTwoptCrossover( ctx, m, d, s, b );

****************************************************************************I*/
void PGABinaryTwoptCrossover(PGAContext *ctx, int p1, int p2, int pop1, int c1,
			     int c2, int pop2)
{
    PGABinary *parent1 = (PGABinary *)PGAGetIndividual(ctx, p1, pop1)->chrom;
    PGABinary *parent2 = (PGABinary *)PGAGetIndividual(ctx, p2, pop1)->chrom;
    PGABinary *child1  = (PGABinary *)PGAGetIndividual(ctx, c1, pop2)->chrom;
    PGABinary *child2  = (PGABinary *)PGAGetIndividual(ctx, c2, pop2)->chrom;
    
    PGABinary mask, mask1, mask2;
    int windex1, windex2;
    int bix1, bix2;
    int i;
    int xsite1, xsite2;
    int temp;

    PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGABinaryTwoptCrossover", "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;
    }

    INDEX(windex1,bix1,xsite1,WL);
    INDEX(windex2,bix2,xsite2,WL);

    if ( windex1 == windex2 ) {     /* both cross sites in the same word */

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

        mask1 = ~0;
        mask1 = mask1 << (WL-bix1);
        mask2 = ~0;
        mask2 = mask2 >>bix2;
        mask  = mask1 | mask2;

        child1[windex1] = (mask & parent1[windex1])|(~mask & parent2[windex1]);
        child2[windex1] = (mask & parent2[windex1])|(~mask & parent1[windex1]);

        for(i=windex1+1;i<ctx->ga.tw;i++) {
            child1[i] = parent1[i];
            child2[i] = parent2[i];
        }
    }
    else {                          /* cross sites in different words */

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

        mask = ~0;
        mask = mask >>bix1;

        child1[windex1] = (~mask & parent1[windex1])|(mask & parent2[windex1]);
        child2[windex1] = (~mask & parent2[windex1])|(mask & parent1[windex1]);

        for(i=windex1+1;i<windex2;i++) {
            child1[i] = parent2[i];
            child2[i] = parent1[i];
        }

        mask = ~0;
        mask = mask >>bix2;

        child1[windex2] = (mask & parent1[windex2])|(~mask & parent2[windex2]);
        child2[windex2] = (mask & parent2[windex2])|(~mask & parent1[windex2]);

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


/*I****************************************************************************
   PGABinaryUniformCrossover - 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;
      PGABinaryUniformCrossover( ctx, m, d, s, b );

****************************************************************************I*/
void PGABinaryUniformCrossover(PGAContext *ctx, int p1, int p2, int pop1,
			       int c1, int c2, int pop2)
{
     PGABinary *parent1 = (PGABinary *)PGAGetIndividual(ctx, p1, pop1)->chrom;
     PGABinary *parent2 = (PGABinary *)PGAGetIndividual(ctx, p2, pop1)->chrom;
     PGABinary *child1  = (PGABinary *)PGAGetIndividual(ctx, c1, pop2)->chrom;
     PGABinary *child2  = (PGABinary *)PGAGetIndividual(ctx, c2, pop2)->chrom;
     PGABinary mask;
     int j,wi;
    
    PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGABinaryUniformCrossover", "Entered", 
                   PGA_VOID, NULL );

    for(wi=0;wi<ctx->ga.tw;wi++) {
        if ( parent1[wi] == parent2[wi] ) {
            child1[wi] = parent1[wi];
            child2[wi] = parent2[wi];
        }
        else {
            mask = 0;
            for (j=0;j<WL;j++)
                if(PGARandomFlip(ctx, ctx->ga.UniformCrossProb))
                    SET(j,mask);
            child1[wi] = (mask & parent1[wi])|(~mask & parent2[wi]);
            child2[wi] = (mask & parent2[wi])|(~mask & parent1[wi]);
        }
    }
}


/*I****************************************************************************
   PGABinaryHammingDistance - Returns the Hamming distance between two strings
   
   Inputs:
      ctx - context variable
      s1  - the first string to compare
      s2  - the second string to compare
      
   Outputs:
      The Hamming distance between two strings

   Example:
      Returns the Hamming distance between bit strings x and y.
      
      PGAContext *ctx;
      PGABinary *x, *y;
      PGABinaryHammingDistance( ctx, x, y );

****************************************************************************I*/
int PGABinaryHammingDistance ( PGAContext *ctx, PGABinary *s1, PGABinary *s2 )
{
    int j, wi, distance;
    unsigned int t1, t2, mask;
    
    PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGABinaryHammingDistance", "Entered", 
                   PGA_VOID, NULL );

    distance = 0;
    for(wi=0; wi<ctx->ga.tw; wi++)  /* step through each word in the string */
        if ( s1[wi] != s2[wi] ) {   /* if equal, no bits are different      */
            /*fprintf(stdout,"s1[wi] = %x, s2[wi] = %x\n",s1[wi],s2[wi]);*/
            mask = 1;
            for(j=0;j<WL;++j) {     /* not equal, compare all bits          */
                /* Build bit mask in position j. Mask bit from each         */
                /* string into t1 and t2 and test if bits are the same      */
                t1 = t2 = 0L;
                t1 = s1[wi] & mask;
                t2 = s2[wi] & mask;
                /*fprintf(stdout,"mask = %u, t1 = %u, t2 = %u, j = %d, wi = %d\n",mask,t1,t2,j,wi);*/
                if ( t1 != t2 )
                    distance++;
                mask <<= 1;          /* shift mask 1 position */
            }
        }
    return(distance);
}


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

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

     PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGABinaryWriteString", "Entered", 
                   PGA_VOID, NULL );
     
     for( i=0; i<ctx->ga.fw; i++ ) {
	  fprintf(fp,"[ ");        
	  PGABinaryWrite( ctx, fp, (c+i), WL );
	  fprintf(fp," ]\n");
     }
     if ( ctx->ga.eb > 0 ) {
	  fprintf(fp,"[ ");        
	  PGABinaryWrite( ctx, fp, (c+ctx->ga.fw), ctx->ga.eb );
	  fprintf(fp," ]");
     }
     
     return;
}


/*I****************************************************************************
   PGABinaryWrite - writes a bit string to a file.  Puts the binary
   representation of the bit string pointed to by chrom into a character
   string and writes that out. Assumes there's enough space in s for bits+1
   characters.
   
   Inputs:
      ctx   - context variable
      fp    - file to write the bit string to
      chrom - pointer to the bit string to write
      nb    - number of bits to write out
      
   Outputs:

   Example:
      Write string s to stdout.
      
      FILE *stdout;
      PGABinary *bitstring;
      int WL;
      PGABinaryWrite( stdout, bitstring, WL );

****************************************************************************I*/
void PGABinaryWrite( PGAContext *ctx, FILE *fp, PGABinary *chrom, int nb )
{
     char *s,string[WL+1];
     PGABinary mask;
     int i=0;

     mask = 1<<(WL-1);
     s = string;  
     for(i=0;i<nb;mask>>=1,i++)                /* mask each bit and set the  */
	  *s++ = (mask&(*chrom)?'1':'0');      /* appropriate character      */
     *s=0;                                     /* string terminator          */
     s = string;                               /* point at start of string   */
     fprintf(fp, "%s", string);                /* print out character string */
}


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

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

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

    return;
}


/*I****************************************************************************
   PGABinaryDuplicate - Returns true if bit string a is a duplicate of bit
   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 bit string x with y to see if they are duplicates
      
      void *x, *y;
      if ( PGABinaryDuplicate( ctx, x, y ) )
          printf("strings are duplicates\n");

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

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


/*U****************************************************************************
  PGAGetRealFromBinary - interpets a binary string as encoding a real value
  and returns the real value it represents.

  Category: Allele

  Inputs:
      ctx   - context variable
      p     - string index
      pop   - symbolic constant of the population the string is in
      start - starting bit position in the binary representation
      end   - ending bit position in the binary representation
      lower - lower bound of the interval the real number is defined on
      upper - lower bound of the interval the real number is defined on
      
  Outputs:
      The real value encoded by the binary string      

  Example:

      If the real value x lies on the interval [-10,20] and is represented
      using the 20 bits in bit positions 10--29 in string p in population
      PGA_NEWPOP use

      double x;
      :
      x = PGAGetRealFromBinary(ctx,p,PGA_NEWPOP,10,29,-10.0,20.0);

      to retrieve the value of x

****************************************************************************U*/
double PGAGetRealFromBinary(PGAContext *ctx, int p, int pop, int start,
			    int end, double lower, double upper)
{
     int length, sum;
     double value;

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

     length = end - start + 1;
     if (start < 0)
	  PGAError(ctx, "PGAGetRealFromBinary: start less than 0:",
		   PGA_FATAL, PGA_INT, (void *) &start);
     if (end >= PGAGetStringLen(ctx))
	  PGAError(ctx, "PGAGetRealFromBinary: end greater than string "
		   "length:", PGA_FATAL, PGA_INT, (void *) &end);
     if (start >= end)
	  PGAError(ctx, "PGAGetRealFromBinary: start exceeds end:",
		   PGA_FATAL, PGA_INT, (void *) &start);
     if (lower >= upper)
	  PGAError(ctx, "PGAGetRealFromBinary: lower exceeds upper:",
		   PGA_FATAL, PGA_DOUBLE, (void *) &lower);
     sum = PGAGetIntegerFromBinary(ctx, p, pop, start, end);
     value = PGAMapIntegerToReal(ctx, sum, 0,
				 (length == sizeof(unsigned) * 8 - 1)
				 ? INT_MAX : (1u << length) - 1, lower, upper);

     PGADebugPrint(ctx, PGADEBUG_EXIT, "PGAGetRealFromBinary", "Exit",
		   PGA_VOID, NULL);
     return value;
}

/*U****************************************************************************
  PGAGetRealFromGrayCode - interpets a binary reflected Gray code sequence in
  a binary string as encoding a real value and returns the real value it
  represents.

  Category: Allele

  Inputs:
      ctx   - context variable
      p     - string index
      pop   - symbolic constant of the population the string is in
      start - starting bit position in the binary representation
      end   - ending bit position in the binary representation
      lower - lower bound of the interval the real number is defined on
      upper - lower bound of the interval the real number is defined on
      
  Outputs:
      The real value encoded by the binary reflected Gray code sequence

  Example:

      If the real value x lies on the interval [-10,20] and is represented
      using the 20 bits in bit positions 10--29 in Gary coded string p in
      population PGA_NEWPOP use

      double x;
      :
      x = PGAGetRealFromGrayCode(ctx,p,PGA_NEWPOP,10,29,-10.0,20.0);

      to retrieve the value of x

****************************************************************************U*/
double PGAGetRealFromGrayCode(PGAContext *ctx, int p, int pop, int start,
				  int end, double lower, double upper)
{
     int length, sum;
     double value;

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

     length = end - start + 1;
     if (start < 0)
	  PGAError(ctx, "PGAGetRealFromGrayCode: start less than 0:",
		   PGA_FATAL, PGA_INT, (void *) &start);
     if (end >= PGAGetStringLen(ctx))
	  PGAError(ctx, "PGAGetRealFromGrayCode: end greater than string "
		   "length:", PGA_FATAL, PGA_INT, (void *) &end);
     if (start >= end)
	  PGAError(ctx, "PGAGetRealFromGrayCode: start exceeds end:",
		   PGA_FATAL, PGA_INT, (void *) &start);
     if (lower >= upper)
	  PGAError(ctx, "PGAGetRealFromGrayCode: lower exceeds upper:",
		   PGA_FATAL, PGA_DOUBLE, (void *) &lower);

     sum = PGAGetIntegerFromGrayCode(ctx, p, pop, start, end);
     value = PGAMapIntegerToReal(ctx, sum, 0,
				 (length == sizeof(unsigned) * 8 - 1)
				 ? INT_MAX : (1u << length) - 1, lower, upper);

     PGADebugPrint(ctx, PGADEBUG_EXIT, "PGAGetRealFromGrayCode", "Exit",
		   PGA_VOID, NULL);
     return value;
}

/*U****************************************************************************
  PGAEncodeRealAsBinary - encodes a real value as a binary string

  Category: Allele

  Inputs:
      ctx   - context variable
      p     - string index
      pop   - symbolic constant of the population the string is in
      start - starting bit position in p to encode val in
      end   - ending bit position in p to encode val in
      low   - lower bound of the interval the val is defined on
      high  - lower bound of the interval the val is defined on
      val   - the real number to be represented as a binary string
      
  Outputs:
      None

  Example:

      To encode 3.14 from the interval [0,10] in 30 bits in bit positions
      0--29 in string p in population PGA_NEWPOP use

      PGAEncodeRealAsBinary(ctx,p,PGA_NEWPOP,0,29,0.,10.,3.14);

****************************************************************************U*/
void PGAEncodeRealAsBinary(PGAContext *ctx, int p, int pop, int start,
			       int end, double low, double high, double val)
{
     int length, d;

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

     length = end - start + 1;
     if (start < 0)
	  PGAError(ctx, "PGAEncodeRealAsBinary: start less than 0:",
		   PGA_FATAL, PGA_INT, (void *) &start);
     if (end >= PGAGetStringLen(ctx))
	  PGAError(ctx, "PGAEncodeRealAsBinary: end greater than string "
		   "length:", PGA_FATAL, PGA_INT, (void *) &end);
     if (start >= end)
	  PGAError(ctx, "PGAEncodeRealAsBinary: start exceeds end:",
		   PGA_FATAL, PGA_INT, (void *) &start);
     if (low >= high)
	  PGAError(ctx, "PGAEncodeRealAsBinary: low exceeds high:",
		   PGA_FATAL, PGA_DOUBLE, (void *) &low);
     if (val < low || val > high)
	  PGAError(ctx, "PGAEncodeRealAsBinary: val outside of bounds:",
		   PGA_FATAL, PGA_DOUBLE, (void *) &val);
     d = PGAMapRealToInteger(ctx, val, low, high, 0,
			     (length == sizeof(unsigned) * 8 - 1)
			     ? INT_MAX : (1u << length) - 1);
     PGAEncodeIntegerAsBinary(ctx, p, pop, start, end, d);
     PGADebugPrint(ctx, PGADEBUG_EXIT, "PGAEncodeRealAsBinary", "Exit",
		   PGA_VOID, NULL);
}

/*U****************************************************************************
  PGAEncodeRealAsGrayCode - encodes a real value as a binary reflected Gray
  code sequence

  Category: Allele

  Inputs:
      ctx   - context variable
      p     - string index
      pop   - symbolic constant of the population the string is in
      start - starting bit position in p to encode val in
      end   - ending bit position in p to encode val in
      low   - lower bound of the interval the val is defined on
      high  - lower bound of the interval the val is defined on
      val   - the real number to be represented as a binary string
      
  Outputs:
      None

  Example:

      To encode 3.14 from the interval [0,10] in 30 bits in bit positions
      0--29 in string p in population PGA_NEWPOP as a binary reflected Gray
      code sequence use
      
      PGAEncodeRealAsGrayCode(ctx,p,PGA_NEWPOP,0,29,0.,10.,3.14);

****************************************************************************U*/
void PGAEncodeRealAsGrayCode(PGAContext *ctx, int p, int pop, int start,
			      int end, double low, double high, double val)
{
     int length, d;

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

     length = end - start + 1;
     if (start < 0)
	  PGAError(ctx, "PGAEncodeRealAsGrayCode: start less than 0:",
		   PGA_FATAL, PGA_INT, (void *) &start);
     if (end >= PGAGetStringLen(ctx))
	  PGAError(ctx, "PGAEncodeRealAsGrayCode: end greater than string "
		   "length:", PGA_FATAL, PGA_INT, (void *) &end);
     if (start >= end)
	  PGAError(ctx, "PGAEncodeRealAsGrayCode: start exceeds end:",
		   PGA_FATAL, PGA_INT, (void *) &start);
     if (low >= high)
	  PGAError(ctx, "PGAEncodeRealAsGrayCode: low exceeds high:",
		   PGA_FATAL, PGA_DOUBLE, (void *) &low);
     if (val < low || val > high)
	  PGAError(ctx, "PGAEncodeRealAsGrayCode: val outside of bounds:",
		   PGA_FATAL, PGA_DOUBLE, (void *) &val);

     d = PGAMapRealToInteger(ctx, val, low, high, 0,
			     (length == sizeof(unsigned) * 8 - 1) ? INT_MAX :
			     (1u << length) - 1);
     PGAEncodeIntegerAsGrayCode(ctx, p, pop, start, end, d);

     PGADebugPrint(ctx, PGADEBUG_EXIT, "PGAEncodeRealAsGrayCode", "Exit",
		   PGA_VOID, NULL);

}

/*I****************************************************************************
   PGAMapIntegerToReal - Maps the value v defined on [a,b] to r defined on
   [l,u].  In the context of PGAPack [a,b] is the discrete interval
   [0,2^nbits-1] (i.e., the number of bits in a binary string) and [l,u]
   represent the range of possible values of the real number r.

   Inputs:
      ctx      - context variable
      v        - value from original interval (usually the decoded bit string)
      a        - lower bound of original interval (usually 0)
      b        - upper bound of original interval (usually 2^nbits-1)
      l        - lower bound of new interval
      u        - upper bound of new interval
      
   Outputs:
      Scaled value of v defined on [l,u]

   Example:

****************************************************************************I*/
double PGAMapIntegerToReal (PGAContext *ctx, int v, int a, int b, double l,
			    double u)
{ 
     return (v-a) * (u-l) / (b-a) + l;
}

/*I****************************************************************************
   PGAMapRealToInteger - Maps the value r defined on [l,u] to v defined on
   [a,b].  In the context of PGAPack [a,b] is the discrete interval
   [0,2^nbits-1] (i.e., the number of bits in a binary string) and [l,u]
   represent the range of possible values of the real number r.

   Inputs:
      ctx      - context variable
      r        - real value defined on [l,u]
      l        - lower bound of real interval
      u        - upper bound of real interval
      a        - lower bound of original interval (usually 0)
      b        - upper bound of original interval (usually 2^nbits-1)
      
   Outputs:
      Scaled value of r defined on [a,b]

   Example:

****************************************************************************I*/
int PGAMapRealToInteger(PGAContext *ctx, double r, double l, double u, int a,
			int b)
{
     return PGARound(ctx, (b - a) * (r - l) / (u - l) + a);
}

/*U****************************************************************************
  PGAEncodeIntegerAsBinary - encodes a real value as a binary string

  Category: Allele

  Inputs:
      ctx   - context variable
      p     - string index
      pop   - symbolic constant of the population the string is in
      start - starting bit position in p to encode val in
      end   - ending bit position in p to encode val in
      val   - the integer value to be represented as a binary string
      
  Outputs:
      None

  Example:

      To encode 7 from the interval [5,15] in 20 bits in bit positions
      0--19 in string p in population PGA_NEWPOP use

      PGAEncodeIntegerAsBinary(ctx,p,PGA_NEWPOP,0,19,5,15,7);

****************************************************************************U*/
void PGAEncodeIntegerAsBinary(PGAContext *ctx, int p, int pop, int start,
			      int end, int val)
{
     int length, i;
     unsigned power2;

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

     length = end - start + 1;

     if (length > sizeof(int) * 8 - 1)
	  PGAError(ctx, "PGAEncodeIntegerAsBinary: length of bit string "
		   "exceeds size of type int:", PGA_FATAL, PGA_INT,
		   (void *) &length);
     if (start < 0)
	  PGAError(ctx, "PGAEncodeIntegerAsBinary: start less than 0:",
		   PGA_FATAL, PGA_INT, (void *) &start);
     if (end >= PGAGetStringLen(ctx))
	  PGAError(ctx, "PGAEncodeIntegerAsBinary: end greater than string "
		   "length:", PGA_FATAL, PGA_INT, (void *) &end);
     if (start >= end)
	  PGAError(ctx, "PGAEncodeIntegerAsBinary: start exceeds end:",
		   PGA_FATAL, PGA_INT, (void *) &start);
     if ((val > (1u << length) - 1) && (length != sizeof(int) * 8) - 1)
	  PGAError(ctx, "PGAEncodeIntegerAsBinary: Integer too big for string "
		   "length:", PGA_FATAL, PGA_INT, (void *) &val);
     if (val < 0)
	  PGAError(ctx, "PGAEncodeIntegerAsBinary: Integer less than zero:",
		   PGA_FATAL, PGA_INT, (void *) & val);

     power2 = 1u << (length - 1);
     for (i = 0; i < length; i++)
     {
	  if (val >= power2)
	  {
	       PGASetBinaryAllele(ctx, p, pop, start + i, 1);
	       val -= power2;
	  }
	  else
	       PGASetBinaryAllele(ctx, p, pop, start + i, 0);
	  power2 >>= 1;
     }
     PGADebugPrint(ctx, PGADEBUG_EXIT, "PGAEncodeIntegerAsBinary", "Exit",
		   PGA_VOID, NULL);
}

/*U****************************************************************************
  PGAEncodeIntegerAsGrayCode - encodes a real value as a binary reflected
  Gray code sequence

  Category: Allele

  Inputs:
      ctx   - context variable
      p     - string index
      pop   - symbolic constant of the population the string is in
      start - starting bit position in p to encode val in
      end   - ending bit position in p to encode val in
      val   - the integer value to be represented as a binary reflected
              Gray code sequence
      
  Outputs:
      None

  Example:

      To encode 7 from the interval [5,15] in 20 bits in bit positions
      0--19 in string p in population PGA_NEWPOP use

      PGAEncodeIntegerAsGrayCode(ctx,p,PGA_NEWPOP,0,19,5,15,7);

****************************************************************************U*/
void PGAEncodeIntegerAsGrayCode(PGAContext *ctx, int p, int pop, int start,
				int end, int val)
{
     int i, *bit, length;
     unsigned power2;

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

     length = end - start + 1;

     if (length > sizeof(int) * 8 - 1)
	  PGAError(ctx, "PGAEncodeIntegerAsGrayCode: length of bit string"
		   "exceeds size of type int:", PGA_FATAL, PGA_INT,
		   (void *) &length);
     if (start < 0)
	  PGAError(ctx, "PGAEncodeIntegerAsGrayCode: start less than 0:",
		   PGA_FATAL, PGA_INT, (void *) &start);
     if (end >= PGAGetStringLen(ctx))
	  PGAError(ctx, "PGAEncodeIntegerAsGrayCode: end greater than string "
		   "length:", PGA_FATAL, PGA_INT, (void *) &end);
     if (start >= end)
	  PGAError(ctx, "PGAEncodeIntegerAsGrayCode: start exceeds end:",
		   PGA_FATAL, PGA_INT, (void *) &start);
     if ((val > (1u << length) - 1) && (length != sizeof(int) * 8 - 1))
	  PGAError(ctx, "PGAEncodeIntegerAsGrayCode: Integer too big for "
		   "string length:", PGA_FATAL, PGA_INT, (void *) &val);
     if (val < 0)
	  PGAError(ctx, "PGAEncodeIntegerAsGrayCode: Integer less than zero:",
		   PGA_FATAL, PGA_INT, (void *) &val);
     
     bit = (int *) malloc(length * sizeof(int));
     if (bit == NULL)
	  PGAError(ctx, "PGAEncodeIntegerAsGrayCode: No room to allocate bit",
		   PGA_FATAL, PGA_VOID, NULL);
     power2 = 1u << (length - 1);
     for (i = 0; i < length; i++)
     {
	  if (val >= power2)
	  {
	       bit[i] = 1;
	       val -= power2;
	  }
	  else
	       bit[i] = 0;
	  power2 >>= 1;
     }
     PGASetBinaryAllele(ctx, p, pop, start, bit[0]);
     for(i = 1; i < length; i++)
	  PGASetBinaryAllele(ctx, p, pop, start + i, bit[i-1] ^ bit[i]);
     free(bit);
     PGADebugPrint(ctx, PGADEBUG_EXIT, "PGAEncodeIntegerAsGrayCode", "Exit",
		   PGA_VOID, NULL);
}

/*U****************************************************************************
  PGAGetIntegerFromBinary - interpets a binary string as encoding an integer
  value and returns the integer value it represents.

  Category: Allele

  Inputs:
      ctx   - context variable
      p     - string index
      pop   - symbolic constant of the population the string is in
      start - starting bit position in the binary representation
      end   - ending bit position in the binary representation
      
  Outputs:
      The integer value encoded by the binary string      

  Example:

      If the integer j is represented using the 20 bits in bit positions
      10--29 in string p in population PGA_NEWPOP use

      int j;
      :
      j = PGAGetIntegerFromBinary(ctx,p,PGA_NEWPOP,10,29);

      to retrieve the value of j

****************************************************************************U*/
int PGAGetIntegerFromBinary(PGAContext *ctx, int p, int pop, int start,
				 int end)
{
     int length, i, val;
     unsigned power2;

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

     length = end - start + 1;
     if (length > sizeof(int) * 8 - 1)
	  PGAError(ctx, "PGAGetIntegerFromBinary: length of bit string "
		   "exceeds sizeof type int:", PGA_FATAL, PGA_INT,
		   (void *) &length);
     if (start < 0)
	  PGAError(ctx, "PGAGetIntegerFromBinary: start less than 0:",
		   PGA_FATAL, PGA_INT, (void *) &start);
     if (end >= PGAGetStringLen(ctx))
	  PGAError(ctx, "PGAGetIntegerFromBinary: end greater than string "
		   "length:", PGA_FATAL, PGA_INT, (void *) &end);
     if (start >= end)
	  PGAError(ctx, "PGAGetIntegerFromBinary: start exceeds end:",
		   PGA_FATAL, PGA_INT, (void *) &start);

     val = 0;
     power2 = 1u << (length - 1);
     for (i = start; i <= end; i++)
     {
	  if (PGAGetBinaryAllele(ctx, p, pop, i))
	       val += power2;
	  power2 >>= 1;
     }

     PGADebugPrint(ctx, PGADEBUG_EXIT, "PGAGetIntegerFromBinary", "Exit",
		   PGA_VOID, NULL);
     return val;
}

/*U****************************************************************************
  PGAGetIntegerFromGrayCode - interpets a binary reflected Gray code sequence
  as encoding an integer value and returns the integer value it represents.

  Category: Allele

  Inputs:
      ctx   - context variable
      p     - string index
      pop   - symbolic constant of the population the string is in
      start - starting bit position in the binary representation
      end   - ending bit position in the binary representation
      
  Outputs:
      The integer value encoded by the binary reflected Gray code sequence

  Example:

      If the integer j is represented using the 20 bits in bit positions
      10--29 in string p in population PGA_NEWPOP use

      int j;
      :
      j = PGAGetIntegerFromGrayCode(ctx,p,PGA_NEWPOP,10,29);

      to retrieve the value of j

****************************************************************************U*/
int PGAGetIntegerFromGrayCode(PGAContext *ctx, int p, int pop, int start,
				   int end)
{
     int length, *BitString, i, val;
     unsigned power2;

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

     length = end - start + 1;
     if (length > sizeof(int) * 8 - 1)
	  PGAError(ctx, "PGAGetIntegerFromGrayCode: length of binary string "
		   "exceeds size of type int:", PGA_FATAL, PGA_INT,
		   (void *) &length);
     if (start < 0)
	  PGAError(ctx, "PGAGetIntegerFromGrayCode: start less than 0:",
		   PGA_FATAL, PGA_INT, (void *) &start);
     if (end >= PGAGetStringLen(ctx))
	  PGAError(ctx, "PGAGetIntegerFromGrayCode: end greater than string "
		   "length:", PGA_FATAL, PGA_INT, (void *) &end);
     if (start >= end)
	  PGAError(ctx, "PGAGetIntegerFromGrayCode: start exceeds end:",
		   PGA_FATAL, PGA_INT, (void *) &start);

     BitString = (int *) malloc(length * sizeof(int));
     if (!BitString)
	  PGAError(ctx, "PGAGetIntegerFromGrayCode: No room for BitString",
		   PGA_FATAL, PGA_VOID, NULL);
     BitString[0] = PGAGetBinaryAllele(ctx, p, pop, start);
     
     for(i = 1; i < length; i++)
	  BitString[i] = BitString[i-1] ^ PGAGetBinaryAllele(ctx, p, pop,
							     start + i);
     val = 0;
     power2 = 1u << (length - 1);
     for (i = 0; i < length; i++)
     {
	  if (BitString[i])
	       val += power2;
	  power2 >>= 1;
     }
     free(BitString);
     
     PGADebugPrint(ctx, PGADEBUG_EXIT, "PGAGetIntegerFromGrayCode", "Exit",
		   PGA_VOID, NULL);
     return val;
}
