You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
960 lines
27 KiB
960 lines
27 KiB
/**CFile***********************************************************************
|
|
|
|
FileName [cuddGenetic.c]
|
|
|
|
PackageName [cudd]
|
|
|
|
Synopsis [Genetic algorithm for variable reordering.]
|
|
|
|
Description [Internal procedures included in this file:
|
|
<ul>
|
|
<li> cuddGa()
|
|
</ul>
|
|
Static procedures included in this module:
|
|
<ul>
|
|
<li> make_random()
|
|
<li> sift_up()
|
|
<li> build_dd()
|
|
<li> largest()
|
|
<li> rand_int()
|
|
<li> array_hash()
|
|
<li> array_compare()
|
|
<li> find_best()
|
|
<li> find_average_fitness()
|
|
<li> PMX()
|
|
<li> roulette()
|
|
</ul>
|
|
|
|
The genetic algorithm implemented here is as follows. We start with
|
|
the current DD order. We sift this order and use this as the
|
|
reference DD. We only keep 1 DD around for the entire process and
|
|
simply rearrange the order of this DD, storing the various orders
|
|
and their corresponding DD sizes. We generate more random orders to
|
|
build an initial population. This initial population is 3 times the
|
|
number of variables, with a maximum of 120. Each random order is
|
|
built (from the reference DD) and its size stored. Each random
|
|
order is also sifted to keep the DD sizes fairly small. Then a
|
|
crossover is performed between two orders (picked randomly) and the
|
|
two resulting DDs are built and sifted. For each new order, if its
|
|
size is smaller than any DD in the population, it is inserted into
|
|
the population and the DD with the largest number of nodes is thrown
|
|
out. The crossover process happens up to 50 times, and at this point
|
|
the DD in the population with the smallest size is chosen as the
|
|
result. This DD must then be built from the reference DD.]
|
|
|
|
SeeAlso []
|
|
|
|
Author [Curt Musfeldt, Alan Shuler, Fabio Somenzi]
|
|
|
|
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
|
|
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
Neither the name of the University of Colorado nor the names of its
|
|
contributors may be used to endorse or promote products derived from
|
|
this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.]
|
|
|
|
******************************************************************************/
|
|
|
|
#include "util.h"
|
|
#include "cuddInt.h"
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Constant declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Stucture declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Type declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Variable declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#ifndef lint
|
|
static char rcsid[] DD_UNUSED = "$Id: cuddGenetic.c,v 1.30 2012/02/05 01:07:18 fabio Exp $";
|
|
#endif
|
|
|
|
static int popsize; /* the size of the population */
|
|
static int numvars; /* the number of input variables in the ckt. */
|
|
/* storedd stores the population orders and sizes. This table has two
|
|
** extra rows and one extras column. The two extra rows are used for the
|
|
** offspring produced by a crossover. Each row stores one order and its
|
|
** size. The order is stored by storing the indices of variables in the
|
|
** order in which they appear in the order. The table is in reality a
|
|
** one-dimensional array which is accessed via a macro to give the illusion
|
|
** it is a two-dimensional structure.
|
|
*/
|
|
static int *storedd;
|
|
static st_table *computed; /* hash table to identify existing orders */
|
|
static int *repeat; /* how many times an order is present */
|
|
static int large; /* stores the index of the population with
|
|
** the largest number of nodes in the DD */
|
|
static int result;
|
|
static int cross; /* the number of crossovers to perform */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Macro declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* macro used to access the population table as if it were a
|
|
** two-dimensional structure.
|
|
*/
|
|
#define STOREDD(i,j) storedd[(i)*(numvars+1)+(j)]
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**AutomaticStart*************************************************************/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Static function prototypes */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int make_random (DdManager *table, int lower);
|
|
static int sift_up (DdManager *table, int x, int x_low);
|
|
static int build_dd (DdManager *table, int num, int lower, int upper);
|
|
static int largest (void);
|
|
static int rand_int (int a);
|
|
static int array_hash (char *array, int modulus);
|
|
static int array_compare (const char *array1, const char *array2);
|
|
static int find_best (void);
|
|
#ifdef DD_STATS
|
|
static double find_average_fitness (void);
|
|
#endif
|
|
static int PMX (int maxvar);
|
|
static int roulette (int *p1, int *p2);
|
|
|
|
/**AutomaticEnd***************************************************************/
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of exported functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of internal functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Genetic algorithm for DD reordering.]
|
|
|
|
Description [Genetic algorithm for DD reordering.
|
|
The two children of a crossover will be stored in
|
|
storedd[popsize] and storedd[popsize+1] --- the last two slots in the
|
|
storedd array. (This will make comparisons and replacement easy.)
|
|
Returns 1 in case of success; 0 otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
int
|
|
cuddGa(
|
|
DdManager * table /* manager */,
|
|
int lower /* lowest level to be reordered */,
|
|
int upper /* highest level to be reorderded */)
|
|
{
|
|
int i,n,m; /* dummy/loop vars */
|
|
int index;
|
|
#ifdef DD_STATS
|
|
double average_fitness;
|
|
#endif
|
|
int small; /* index of smallest DD in population */
|
|
|
|
/* Do an initial sifting to produce at least one reasonable individual. */
|
|
if (!cuddSifting(table,lower,upper)) return(0);
|
|
|
|
/* Get the initial values. */
|
|
numvars = upper - lower + 1; /* number of variables to be reordered */
|
|
if (table->populationSize == 0) {
|
|
popsize = 3 * numvars; /* population size is 3 times # of vars */
|
|
if (popsize > 120) {
|
|
popsize = 120; /* Maximum population size is 120 */
|
|
}
|
|
} else {
|
|
popsize = table->populationSize; /* user specified value */
|
|
}
|
|
if (popsize < 4) popsize = 4; /* enforce minimum population size */
|
|
|
|
/* Allocate population table. */
|
|
storedd = ALLOC(int,(popsize+2)*(numvars+1));
|
|
if (storedd == NULL) {
|
|
table->errorCode = CUDD_MEMORY_OUT;
|
|
return(0);
|
|
}
|
|
|
|
/* Initialize the computed table. This table is made up of two data
|
|
** structures: A hash table with the key given by the order, which says
|
|
** if a given order is present in the population; and the repeat
|
|
** vector, which says how many copies of a given order are stored in
|
|
** the population table. If there are multiple copies of an order, only
|
|
** one has a repeat count greater than 1. This copy is the one pointed
|
|
** by the computed table.
|
|
*/
|
|
repeat = ALLOC(int,popsize);
|
|
if (repeat == NULL) {
|
|
table->errorCode = CUDD_MEMORY_OUT;
|
|
FREE(storedd);
|
|
return(0);
|
|
}
|
|
for (i = 0; i < popsize; i++) {
|
|
repeat[i] = 0;
|
|
}
|
|
computed = st_init_table(array_compare,array_hash);
|
|
if (computed == NULL) {
|
|
table->errorCode = CUDD_MEMORY_OUT;
|
|
FREE(storedd);
|
|
FREE(repeat);
|
|
return(0);
|
|
}
|
|
|
|
/* Copy the current DD and its size to the population table. */
|
|
for (i = 0; i < numvars; i++) {
|
|
STOREDD(0,i) = table->invperm[i+lower]; /* order of initial DD */
|
|
}
|
|
STOREDD(0,numvars) = table->keys - table->isolated; /* size of initial DD */
|
|
|
|
/* Store the initial order in the computed table. */
|
|
if (st_insert(computed,(char *)storedd,(char *) 0) == ST_OUT_OF_MEM) {
|
|
FREE(storedd);
|
|
FREE(repeat);
|
|
st_free_table(computed);
|
|
return(0);
|
|
}
|
|
repeat[0]++;
|
|
|
|
/* Insert the reverse order as second element of the population. */
|
|
for (i = 0; i < numvars; i++) {
|
|
STOREDD(1,numvars-1-i) = table->invperm[i+lower]; /* reverse order */
|
|
}
|
|
|
|
/* Now create the random orders. make_random fills the population
|
|
** table with random permutations. The successive loop builds and sifts
|
|
** the DDs for the reverse order and each random permutation, and stores
|
|
** the results in the computed table.
|
|
*/
|
|
if (!make_random(table,lower)) {
|
|
table->errorCode = CUDD_MEMORY_OUT;
|
|
FREE(storedd);
|
|
FREE(repeat);
|
|
st_free_table(computed);
|
|
return(0);
|
|
}
|
|
for (i = 1; i < popsize; i++) {
|
|
result = build_dd(table,i,lower,upper); /* build and sift order */
|
|
if (!result) {
|
|
FREE(storedd);
|
|
FREE(repeat);
|
|
st_free_table(computed);
|
|
return(0);
|
|
}
|
|
if (st_lookup_int(computed,(char *)&STOREDD(i,0),&index)) {
|
|
repeat[index]++;
|
|
} else {
|
|
if (st_insert(computed,(char *)&STOREDD(i,0),(char *)(long)i) ==
|
|
ST_OUT_OF_MEM) {
|
|
FREE(storedd);
|
|
FREE(repeat);
|
|
st_free_table(computed);
|
|
return(0);
|
|
}
|
|
repeat[i]++;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
#ifdef DD_STATS
|
|
/* Print the initial population. */
|
|
(void) fprintf(table->out,"Initial population after sifting\n");
|
|
for (m = 0; m < popsize; m++) {
|
|
for (i = 0; i < numvars; i++) {
|
|
(void) fprintf(table->out," %2d",STOREDD(m,i));
|
|
}
|
|
(void) fprintf(table->out," : %3d (%d)\n",
|
|
STOREDD(m,numvars),repeat[m]);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
small = find_best();
|
|
#ifdef DD_STATS
|
|
average_fitness = find_average_fitness();
|
|
(void) fprintf(table->out,"\nInitial population: best fitness = %d, average fitness %8.3f",STOREDD(small,numvars),average_fitness);
|
|
#endif
|
|
|
|
/* Decide how many crossovers should be tried. */
|
|
if (table->numberXovers == 0) {
|
|
cross = 3*numvars;
|
|
if (cross > 60) { /* do a maximum of 50 crossovers */
|
|
cross = 60;
|
|
}
|
|
} else {
|
|
cross = table->numberXovers; /* use user specified value */
|
|
}
|
|
if (cross >= popsize) {
|
|
cross = popsize;
|
|
}
|
|
|
|
/* Perform the crossovers to get the best order. */
|
|
for (m = 0; m < cross; m++) {
|
|
if (!PMX(table->size)) { /* perform one crossover */
|
|
table->errorCode = CUDD_MEMORY_OUT;
|
|
FREE(storedd);
|
|
FREE(repeat);
|
|
st_free_table(computed);
|
|
return(0);
|
|
}
|
|
/* The offsprings are left in the last two entries of the
|
|
** population table. These are now considered in turn.
|
|
*/
|
|
for (i = popsize; i <= popsize+1; i++) {
|
|
result = build_dd(table,i,lower,upper); /* build and sift child */
|
|
if (!result) {
|
|
FREE(storedd);
|
|
FREE(repeat);
|
|
st_free_table(computed);
|
|
return(0);
|
|
}
|
|
large = largest(); /* find the largest DD in population */
|
|
|
|
/* If the new child is smaller than the largest DD in the current
|
|
** population, enter it into the population in place of the
|
|
** largest DD.
|
|
*/
|
|
if (STOREDD(i,numvars) < STOREDD(large,numvars)) {
|
|
/* Look up the largest DD in the computed table.
|
|
** Decrease its repetition count. If the repetition count
|
|
** goes to 0, remove the largest DD from the computed table.
|
|
*/
|
|
result = st_lookup_int(computed,(char *)&STOREDD(large,0),
|
|
&index);
|
|
if (!result) {
|
|
FREE(storedd);
|
|
FREE(repeat);
|
|
st_free_table(computed);
|
|
return(0);
|
|
}
|
|
repeat[index]--;
|
|
if (repeat[index] == 0) {
|
|
int *pointer = &STOREDD(index,0);
|
|
result = st_delete(computed, &pointer, NULL);
|
|
if (!result) {
|
|
FREE(storedd);
|
|
FREE(repeat);
|
|
st_free_table(computed);
|
|
return(0);
|
|
}
|
|
}
|
|
/* Copy the new individual to the entry of the
|
|
** population table just made available and update the
|
|
** computed table.
|
|
*/
|
|
for (n = 0; n <= numvars; n++) {
|
|
STOREDD(large,n) = STOREDD(i,n);
|
|
}
|
|
if (st_lookup_int(computed,(char *)&STOREDD(large,0),
|
|
&index)) {
|
|
repeat[index]++;
|
|
} else {
|
|
if (st_insert(computed,(char *)&STOREDD(large,0),
|
|
(char *)(long)large) == ST_OUT_OF_MEM) {
|
|
FREE(storedd);
|
|
FREE(repeat);
|
|
st_free_table(computed);
|
|
return(0);
|
|
}
|
|
repeat[large]++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Find the smallest DD in the population and build it;
|
|
** that will be the result.
|
|
*/
|
|
small = find_best();
|
|
|
|
/* Print stats on the final population. */
|
|
#ifdef DD_STATS
|
|
average_fitness = find_average_fitness();
|
|
(void) fprintf(table->out,"\nFinal population: best fitness = %d, average fitness %8.3f",STOREDD(small,numvars),average_fitness);
|
|
#endif
|
|
|
|
/* Clean up, build the result DD, and return. */
|
|
st_free_table(computed);
|
|
computed = NULL;
|
|
result = build_dd(table,small,lower,upper);
|
|
FREE(storedd);
|
|
FREE(repeat);
|
|
return(result);
|
|
|
|
} /* end of cuddGa */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of static functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Generates the random sequences for the initial population.]
|
|
|
|
Description [Generates the random sequences for the initial population.
|
|
The sequences are permutations of the indices between lower and
|
|
upper in the current order.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
static int
|
|
make_random(
|
|
DdManager * table,
|
|
int lower)
|
|
{
|
|
int i,j; /* loop variables */
|
|
int *used; /* is a number already in a permutation */
|
|
int next; /* next random number without repetitions */
|
|
|
|
used = ALLOC(int,numvars);
|
|
if (used == NULL) {
|
|
table->errorCode = CUDD_MEMORY_OUT;
|
|
return(0);
|
|
}
|
|
#if 0
|
|
#ifdef DD_STATS
|
|
(void) fprintf(table->out,"Initial population before sifting\n");
|
|
for (i = 0; i < 2; i++) {
|
|
for (j = 0; j < numvars; j++) {
|
|
(void) fprintf(table->out," %2d",STOREDD(i,j));
|
|
}
|
|
(void) fprintf(table->out,"\n");
|
|
}
|
|
#endif
|
|
#endif
|
|
for (i = 2; i < popsize; i++) {
|
|
for (j = 0; j < numvars; j++) {
|
|
used[j] = 0;
|
|
}
|
|
/* Generate a permutation of {0...numvars-1} and use it to
|
|
** permute the variables in the layesr from lower to upper.
|
|
*/
|
|
for (j = 0; j < numvars; j++) {
|
|
do {
|
|
next = rand_int(numvars-1);
|
|
} while (used[next] != 0);
|
|
used[next] = 1;
|
|
STOREDD(i,j) = table->invperm[next+lower];
|
|
}
|
|
#if 0
|
|
#ifdef DD_STATS
|
|
/* Print the order just generated. */
|
|
for (j = 0; j < numvars; j++) {
|
|
(void) fprintf(table->out," %2d",STOREDD(i,j));
|
|
}
|
|
(void) fprintf(table->out,"\n");
|
|
#endif
|
|
#endif
|
|
}
|
|
FREE(used);
|
|
return(1);
|
|
|
|
} /* end of make_random */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Moves one variable up.]
|
|
|
|
Description [Takes a variable from position x and sifts it up to
|
|
position x_low; x_low should be less than x. Returns 1 if successful;
|
|
0 otherwise]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
static int
|
|
sift_up(
|
|
DdManager * table,
|
|
int x,
|
|
int x_low)
|
|
{
|
|
int y;
|
|
int size;
|
|
|
|
y = cuddNextLow(table,x);
|
|
while (y >= x_low) {
|
|
size = cuddSwapInPlace(table,y,x);
|
|
if (size == 0) {
|
|
return(0);
|
|
}
|
|
x = y;
|
|
y = cuddNextLow(table,x);
|
|
}
|
|
return(1);
|
|
|
|
} /* end of sift_up */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Builds a DD from a given order.]
|
|
|
|
Description [Builds a DD from a given order. This procedure also
|
|
sifts the final order and inserts into the array the size in nodes
|
|
of the result. Returns 1 if successful; 0 otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
static int
|
|
build_dd(
|
|
DdManager * table,
|
|
int num /* the index of the individual to be built */,
|
|
int lower,
|
|
int upper)
|
|
{
|
|
int i,j; /* loop vars */
|
|
int position;
|
|
int index;
|
|
int limit; /* how large the DD for this order can grow */
|
|
int size;
|
|
|
|
/* Check the computed table. If the order already exists, it
|
|
** suffices to copy the size from the existing entry.
|
|
*/
|
|
if (computed && st_lookup_int(computed,(char *)&STOREDD(num,0),&index)) {
|
|
STOREDD(num,numvars) = STOREDD(index,numvars);
|
|
#ifdef DD_STATS
|
|
(void) fprintf(table->out,"\nCache hit for index %d", index);
|
|
#endif
|
|
return(1);
|
|
}
|
|
|
|
/* Stop if the DD grows 20 times larges than the reference size. */
|
|
limit = 20 * STOREDD(0,numvars);
|
|
|
|
/* Sift up the variables so as to build the desired permutation.
|
|
** First the variable that has to be on top is sifted to the top.
|
|
** Then the variable that has to occupy the secon position is sifted
|
|
** up to the second position, and so on.
|
|
*/
|
|
for (j = 0; j < numvars; j++) {
|
|
i = STOREDD(num,j);
|
|
position = table->perm[i];
|
|
result = sift_up(table,position,j+lower);
|
|
if (!result) return(0);
|
|
size = table->keys - table->isolated;
|
|
if (size > limit) break;
|
|
}
|
|
|
|
/* Sift the DD just built. */
|
|
#ifdef DD_STATS
|
|
(void) fprintf(table->out,"\n");
|
|
#endif
|
|
result = cuddSifting(table,lower,upper);
|
|
if (!result) return(0);
|
|
|
|
/* Copy order and size to table. */
|
|
for (j = 0; j < numvars; j++) {
|
|
STOREDD(num,j) = table->invperm[lower+j];
|
|
}
|
|
STOREDD(num,numvars) = table->keys - table->isolated; /* size of new DD */
|
|
return(1);
|
|
|
|
} /* end of build_dd */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Finds the largest DD in the population.]
|
|
|
|
Description [Finds the largest DD in the population. If an order is
|
|
repeated, it avoids choosing the copy that is in the computed table
|
|
(it has repeat[i] > 1).]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
static int
|
|
largest(void)
|
|
{
|
|
int i; /* loop var */
|
|
int big; /* temporary holder to return result */
|
|
|
|
big = 0;
|
|
while (repeat[big] > 1) big++;
|
|
for (i = big + 1; i < popsize; i++) {
|
|
if (STOREDD(i,numvars) >= STOREDD(big,numvars) && repeat[i] <= 1) {
|
|
big = i;
|
|
}
|
|
}
|
|
return(big);
|
|
|
|
} /* end of largest */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Generates a random number between 0 and the integer a.]
|
|
|
|
Description []
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
static int
|
|
rand_int(
|
|
int a)
|
|
{
|
|
return(Cudd_Random() % (a+1));
|
|
|
|
} /* end of rand_int */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Hash function for the computed table.]
|
|
|
|
Description [Hash function for the computed table. Returns the bucket
|
|
number.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
static int
|
|
array_hash(
|
|
char * array,
|
|
int modulus)
|
|
{
|
|
int val = 0;
|
|
int i;
|
|
int *intarray;
|
|
|
|
intarray = (int *) array;
|
|
|
|
for (i = 0; i < numvars; i++) {
|
|
val = val * 997 + intarray[i];
|
|
}
|
|
|
|
return ((val < 0) ? -val : val) % modulus;
|
|
|
|
} /* end of array_hash */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Comparison function for the computed table.]
|
|
|
|
Description [Comparison function for the computed table. Returns 0 if
|
|
the two arrays are equal; 1 otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
static int
|
|
array_compare(
|
|
const char * array1,
|
|
const char * array2)
|
|
{
|
|
int i;
|
|
int *intarray1, *intarray2;
|
|
|
|
intarray1 = (int *) array1;
|
|
intarray2 = (int *) array2;
|
|
|
|
for (i = 0; i < numvars; i++) {
|
|
if (intarray1[i] != intarray2[i]) return(1);
|
|
}
|
|
return(0);
|
|
|
|
} /* end of array_compare */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Returns the index of the fittest individual.]
|
|
|
|
Description []
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
static int
|
|
find_best(void)
|
|
{
|
|
int i,small;
|
|
|
|
small = 0;
|
|
for (i = 1; i < popsize; i++) {
|
|
if (STOREDD(i,numvars) < STOREDD(small,numvars)) {
|
|
small = i;
|
|
}
|
|
}
|
|
return(small);
|
|
|
|
} /* end of find_best */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Returns the average fitness of the population.]
|
|
|
|
Description []
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
#ifdef DD_STATS
|
|
static double
|
|
find_average_fitness(void)
|
|
{
|
|
int i;
|
|
int total_fitness = 0;
|
|
double average_fitness;
|
|
|
|
for (i = 0; i < popsize; i++) {
|
|
total_fitness += STOREDD(i,numvars);
|
|
}
|
|
average_fitness = (double) total_fitness / (double) popsize;
|
|
return(average_fitness);
|
|
|
|
} /* end of find_average_fitness */
|
|
#endif
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Performs the crossover between two parents.]
|
|
|
|
Description [Performs the crossover between two randomly chosen
|
|
parents, and creates two children, x1 and x2. Uses the Partially
|
|
Matched Crossover operator.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
static int
|
|
PMX(
|
|
int maxvar)
|
|
{
|
|
int cut1,cut2; /* the two cut positions (random) */
|
|
int mom,dad; /* the two randomly chosen parents */
|
|
int *inv1; /* inverse permutations for repair algo */
|
|
int *inv2;
|
|
int i; /* loop vars */
|
|
int u,v; /* aux vars */
|
|
|
|
inv1 = ALLOC(int,maxvar);
|
|
if (inv1 == NULL) {
|
|
return(0);
|
|
}
|
|
inv2 = ALLOC(int,maxvar);
|
|
if (inv2 == NULL) {
|
|
FREE(inv1);
|
|
return(0);
|
|
}
|
|
|
|
/* Choose two orders from the population using roulette wheel. */
|
|
if (!roulette(&mom,&dad)) {
|
|
FREE(inv1);
|
|
FREE(inv2);
|
|
return(0);
|
|
}
|
|
|
|
/* Choose two random cut positions. A cut in position i means that
|
|
** the cut immediately precedes position i. If cut1 < cut2, we
|
|
** exchange the middle of the two orderings; otherwise, we
|
|
** exchange the beginnings and the ends.
|
|
*/
|
|
cut1 = rand_int(numvars-1);
|
|
do {
|
|
cut2 = rand_int(numvars-1);
|
|
} while (cut1 == cut2);
|
|
|
|
#if 0
|
|
/* Print out the parents. */
|
|
(void) fprintf(table->out,
|
|
"Crossover of %d (mom) and %d (dad) between %d and %d\n",
|
|
mom,dad,cut1,cut2);
|
|
for (i = 0; i < numvars; i++) {
|
|
if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
|
|
(void) fprintf(table->out,"%2d ",STOREDD(mom,i));
|
|
}
|
|
(void) fprintf(table->out,"\n");
|
|
for (i = 0; i < numvars; i++) {
|
|
if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
|
|
(void) fprintf(table->out,"%2d ",STOREDD(dad,i));
|
|
}
|
|
(void) fprintf(table->out,"\n");
|
|
#endif
|
|
|
|
/* Initialize the inverse permutations: -1 means yet undetermined. */
|
|
for (i = 0; i < maxvar; i++) {
|
|
inv1[i] = -1;
|
|
inv2[i] = -1;
|
|
}
|
|
|
|
/* Copy the portions whithin the cuts. */
|
|
for (i = cut1; i != cut2; i = (i == numvars-1) ? 0 : i+1) {
|
|
STOREDD(popsize,i) = STOREDD(dad,i);
|
|
inv1[STOREDD(popsize,i)] = i;
|
|
STOREDD(popsize+1,i) = STOREDD(mom,i);
|
|
inv2[STOREDD(popsize+1,i)] = i;
|
|
}
|
|
|
|
/* Now apply the repair algorithm outside the cuts. */
|
|
for (i = cut2; i != cut1; i = (i == numvars-1 ) ? 0 : i+1) {
|
|
v = i;
|
|
do {
|
|
u = STOREDD(mom,v);
|
|
v = inv1[u];
|
|
} while (v != -1);
|
|
STOREDD(popsize,i) = u;
|
|
inv1[u] = i;
|
|
v = i;
|
|
do {
|
|
u = STOREDD(dad,v);
|
|
v = inv2[u];
|
|
} while (v != -1);
|
|
STOREDD(popsize+1,i) = u;
|
|
inv2[u] = i;
|
|
}
|
|
|
|
#if 0
|
|
/* Print the results of crossover. */
|
|
for (i = 0; i < numvars; i++) {
|
|
if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
|
|
(void) fprintf(table->out,"%2d ",STOREDD(popsize,i));
|
|
}
|
|
(void) fprintf(table->out,"\n");
|
|
for (i = 0; i < numvars; i++) {
|
|
if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
|
|
(void) fprintf(table->out,"%2d ",STOREDD(popsize+1,i));
|
|
}
|
|
(void) fprintf(table->out,"\n");
|
|
#endif
|
|
|
|
FREE(inv1);
|
|
FREE(inv2);
|
|
return(1);
|
|
|
|
} /* end of PMX */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Selects two parents with the roulette wheel method.]
|
|
|
|
Description [Selects two distinct parents with the roulette wheel method.]
|
|
|
|
SideEffects [The indices of the selected parents are returned as side
|
|
effects.]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
static int
|
|
roulette(
|
|
int * p1,
|
|
int * p2)
|
|
{
|
|
double *wheel;
|
|
double spin;
|
|
int i;
|
|
|
|
wheel = ALLOC(double,popsize);
|
|
if (wheel == NULL) {
|
|
return(0);
|
|
}
|
|
|
|
/* The fitness of an individual is the reciprocal of its size. */
|
|
wheel[0] = 1.0 / (double) STOREDD(0,numvars);
|
|
|
|
for (i = 1; i < popsize; i++) {
|
|
wheel[i] = wheel[i-1] + 1.0 / (double) STOREDD(i,numvars);
|
|
}
|
|
|
|
/* Get a random number between 0 and wheel[popsize-1] (that is,
|
|
** the sum of all fitness values. 2147483561 is the largest number
|
|
** returned by Cudd_Random.
|
|
*/
|
|
spin = wheel[numvars-1] * (double) Cudd_Random() / 2147483561.0;
|
|
|
|
/* Find the lucky element by scanning the wheel. */
|
|
for (i = 0; i < popsize; i++) {
|
|
if (spin <= wheel[i]) break;
|
|
}
|
|
*p1 = i;
|
|
|
|
/* Repeat the process for the second parent, making sure it is
|
|
** distinct from the first.
|
|
*/
|
|
do {
|
|
spin = wheel[popsize-1] * (double) Cudd_Random() / 2147483561.0;
|
|
for (i = 0; i < popsize; i++) {
|
|
if (spin <= wheel[i]) break;
|
|
}
|
|
} while (i == *p1);
|
|
*p2 = i;
|
|
|
|
FREE(wheel);
|
|
return(1);
|
|
|
|
} /* end of roulette */
|
|
|