/*****************************************************************************
*     FILE: duplicate.c: This file contains the routines that have to do with
*                        testing for duplicate strings
*
*     Authors: David M. Levine, Philip L. Hallstrom, David M. Noelle
*****************************************************************************/

#include "pgapack.h"

/*U****************************************************************************
  PGADuplicate - determines if a specified string is a duplicate of one
  already in an existing population

  Category: Generation

  Inputs:
     ctx  - context variable
     p    - string index
     pop1 - symbolic constant of the population containing string p
     pop2 - symbolic constant of the (possibly partial) population containing
            strings to compare string p against
     n    - the number of strings in pop2 to compare string p against
            (indexed 0,...,n-1)
      
  Outputs:
     Returns returns true if PGAGetNoDuplicates returns PGATRUE and
     string p in population pop1 is a duplicate of at least one strings
     0,...,n-1 in population pop2.  Otherwise returns PGAFALSE

  Example:
     To check if string b in population PGA_OLDPOP is a duplicate of any
     of the strings in the first half of population PGA_NEWPOP use

     PGAContext *ctx;
     int b, n;
     :
     b  = PGAGetBest(ctx, PGA_OLDPOP);
     n  = PGAGetPopsize(ctx);
     n /= 2;
     PGADuplicate(ctx, b, PGA_OLDPOP, PGA_NEWPOP, n);

****************************************************************************U*/
int PGADuplicate(PGAContext *ctx, int p, int pop1, int pop2, int n)
{
     int p2;

     PGADebugPrint( ctx, PGADEBUG_ENTERED, "PGADuplicate", "Entered", 
                   PGA_VOID, NULL );
     PGADebugPrint( ctx, PGADEBUG_PRINTVAR,"PGADuplicate", "p = ", 
                   PGA_INT, (void *) &p );
     PGADebugPrint( ctx, PGADEBUG_PRINTVAR,"PGADuplicate", "pop1 = ", 
                   PGA_INT, (void *) &pop1 );
     PGADebugPrint( ctx, PGADEBUG_PRINTVAR,"PGADuplicate", "pop2 = ", 
                   PGA_INT, (void *) &pop2 );
     PGADebugPrint( ctx, PGADEBUG_PRINTVAR,"PGADuplicate", "n  = ", 
                   PGA_INT, (void *) &n );

     if (ctx->ga.NoDuplicates == PGAFALSE)  /* return not a duplicate if   */
	  return(PGAFALSE);                 /* not checking for duplicates */

     for (p2 = 0; p2 < n; p2++)
	  if ((*ctx->ops.Duplicate)(ctx, p, pop1, p2, pop2))
	       return(PGATRUE);

     PGADebugPrint( ctx, PGADEBUG_EXIT, "PGADuplicate", "Exit", 
                   PGA_VOID, NULL );
     return(PGAFALSE);
}


/*U****************************************************************************
  PGAChange - Repeatedly applies mutation to a string (with am increasing
  mutation rate) until one or more mutations have occurred.  This routine is
  usually used with PGADuplicate to modify a duplicate string.  It is not
  intended to replace PGAMutation

  Category: Generation

  Inputs:
     ctx  - context variable
     p    - string index
     pop  - symbolic constant of the population containing string p
      
  Outputs:
     Mutates string p in population pop via side effect.

  Example:
     To change (via mutation) string b in population PGA_OLDPOP
     (in place) use

     PGAContext *ctx;
     int b;
     PGAChange(ctx, b, PGA_OLDPOP);

****************************************************************************U*/
void PGAChange( PGAContext *ctx, int p, int pop )
{	   
    int changed = PGAFALSE;
    int nflips;
    double mr;

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

    mr = ctx->ga.MutationProb;
    PGADebugPrint( ctx, PGADEBUG_PRINTVAR, "PGAChange", " mr = ", 
                   PGA_DOUBLE, (void *) &mr );
    while ( changed == PGAFALSE ) {
	nflips = (*ctx->ops.Mutation)( ctx, p, pop, mr );
        if ( nflips > 0 )
            changed = PGATRUE;
        else
            mr = 1.1*mr;
    }

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