cuddGenetic.c 30 KB
Newer Older
Alan Mishchenko committed
1 2 3 4 5 6 7 8 9
/**CFile***********************************************************************

  FileName    [cuddGenetic.c]

  PackageName [cudd]

  Synopsis    [Genetic algorithm for variable reordering.]

  Description [Internal procedures included in this file:
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
                <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>
Alan Mishchenko committed
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

  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]

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
  Copyright   [Copyright (c) 1995-2004, 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.]
Alan Mishchenko committed
80 81 82

******************************************************************************/

83
#include "misc/util/util_hack.h"
Alan Mishchenko committed
84 85
#include "cuddInt.h"

86 87 88
ABC_NAMESPACE_IMPL_START


89

Alan Mishchenko committed
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
/*---------------------------------------------------------------------------*/
/* Constant declarations                                                     */
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/* Stucture declarations                                                     */
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/* Type declarations                                                         */
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/* Variable declarations                                                     */
/*---------------------------------------------------------------------------*/

#ifndef lint
107
static char rcsid[] DD_UNUSED = "$Id: cuddGenetic.c,v 1.28 2004/08/13 18:04:48 fabio Exp $";
Alan Mishchenko committed
108 109
#endif

110 111
static int popsize;             /* the size of the population */
static int numvars;             /* the number of input variables in the ckt. */
Alan Mishchenko committed
112 113 114 115 116 117 118 119 120
/* 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;
121
static st__table *computed;      /* hash table to identify existing orders */
122 123 124
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 */
Alan Mishchenko committed
125
static int result;
126
static int cross;               /* the number of crossovers to perform */
Alan Mishchenko committed
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142

/*---------------------------------------------------------------------------*/
/* 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)]

/**AutomaticStart*************************************************************/

/*---------------------------------------------------------------------------*/
/* Static function prototypes                                                */
/*---------------------------------------------------------------------------*/

143 144 145 146 147 148 149 150 151 152 153 154 155
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 (const 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);
Alan Mishchenko committed
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188

/**AutomaticEnd***************************************************************/

/*---------------------------------------------------------------------------*/
/* 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 */)
{
189 190 191 192 193 194
    int         i,n,m;          /* dummy/loop vars */
    int         index;
#ifdef DD_STATS
    double      average_fitness;
#endif
    int         small;          /* index of smallest DD in population */
Alan Mishchenko committed
195 196 197 198 199 200 201

    /* 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) {
202 203 204 205
        popsize = 3 * numvars;  /* population size is 3 times # of vars */
        if (popsize > 120) {
            popsize = 120;      /* Maximum population size is 120 */
        }
Alan Mishchenko committed
206
    } else {
207
        popsize = table->populationSize;  /* user specified value */
Alan Mishchenko committed
208
    }
209
    if (popsize < 4) popsize = 4;       /* enforce minimum population size */
Alan Mishchenko committed
210 211

    /* Allocate population table. */
Alan Mishchenko committed
212
    storedd = ABC_ALLOC(int,(popsize+2)*(numvars+1));
Alan Mishchenko committed
213
    if (storedd == NULL) {
214 215
        table->errorCode = CUDD_MEMORY_OUT;
        return(0);
Alan Mishchenko committed
216 217 218 219 220 221 222 223 224 225
    }

    /* 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.
    */
Alan Mishchenko committed
226
    repeat = ABC_ALLOC(int,popsize);
Alan Mishchenko committed
227
    if (repeat == NULL) {
228 229 230
        table->errorCode = CUDD_MEMORY_OUT;
        ABC_FREE(storedd);
        return(0);
Alan Mishchenko committed
231 232
    }
    for (i = 0; i < popsize; i++) {
233
        repeat[i] = 0;
Alan Mishchenko committed
234
    }
235
    computed = st__init_table(array_compare,array_hash);
Alan Mishchenko committed
236
    if (computed == NULL) {
237 238 239 240
        table->errorCode = CUDD_MEMORY_OUT;
        ABC_FREE(storedd);
        ABC_FREE(repeat);
        return(0);
Alan Mishchenko committed
241 242 243 244
    }

    /* Copy the current DD and its size to the population table. */
    for (i = 0; i < numvars; i++) {
245
        STOREDD(0,i) = table->invperm[i+lower]; /* order of initial DD */
Alan Mishchenko committed
246 247 248 249
    }
    STOREDD(0,numvars) = table->keys - table->isolated; /* size of initial DD */

    /* Store the initial order in the computed table. */
250
    if ( st__insert(computed,(char *)storedd,(char *) 0) == st__OUT_OF_MEM) {
251 252
        ABC_FREE(storedd);
        ABC_FREE(repeat);
253
        st__free_table(computed);
254
        return(0);
Alan Mishchenko committed
255 256 257 258 259
    }
    repeat[0]++;

    /* Insert the reverse order as second element of the population. */
    for (i = 0; i < numvars; i++) {
260
        STOREDD(1,numvars-1-i) = table->invperm[i+lower]; /* reverse order */
Alan Mishchenko committed
261 262 263 264 265 266 267 268
    }

    /* 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)) {
269
        table->errorCode = CUDD_MEMORY_OUT;
Alan Mishchenko committed
270 271
        ABC_FREE(storedd);
        ABC_FREE(repeat);
272
        st__free_table(computed);
Alan Mishchenko committed
273 274
        return(0);
    }
275 276 277 278 279
    for (i = 1; i < popsize; i++) {
        result = build_dd(table,i,lower,upper); /* build and sift order */
        if (!result) {
            ABC_FREE(storedd);
            ABC_FREE(repeat);
280
            st__free_table(computed);
281 282
            return(0);
        }
283
        if ( st__lookup_int(computed,(char *)&STOREDD(i,0),&index)) {
284 285
            repeat[index]++;
        } else {
286 287
            if ( st__insert(computed,(char *)&STOREDD(i,0),(char *)(long)i) ==
            st__OUT_OF_MEM) {
288 289
                ABC_FREE(storedd);
                ABC_FREE(repeat);
290
                st__free_table(computed);
291 292 293
                return(0);
            }
            repeat[i]++;
Alan Mishchenko committed
294 295 296 297 298 299 300 301
        }
    }

#if 0
#ifdef DD_STATS
    /* Print the initial population. */
    (void) fprintf(table->out,"Initial population after sifting\n");
    for (m = 0; m < popsize; m++) {
302 303 304 305 306
        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]);
Alan Mishchenko committed
307 308 309 310 311 312
    }
#endif
#endif

    small = find_best();
#ifdef DD_STATS
313
    average_fitness = find_average_fitness();
Alan Mishchenko committed
314 315 316 317 318
    (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) {
319 320 321 322
        cross = 3*numvars;
        if (cross > 60) {       /* do a maximum of 50 crossovers */
            cross = 60;
        }
Alan Mishchenko committed
323
    } else {
324
        cross = table->numberXovers;      /* use user specified value */
Alan Mishchenko committed
325 326 327 328
    }

    /* Perform the crossovers to get the best order. */
    for (m = 0; m < cross; m++) {
329 330
        if (!PMX(table->size)) {        /* perform one crossover */
            table->errorCode = CUDD_MEMORY_OUT;
Alan Mishchenko committed
331 332
            ABC_FREE(storedd);
            ABC_FREE(repeat);
333
            st__free_table(computed);
Alan Mishchenko committed
334 335
            return(0);
        }
336 337 338 339 340
        /* 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 */
Alan Mishchenko committed
341
            if (!result) {
342 343
                ABC_FREE(storedd);
                ABC_FREE(repeat);
344
                st__free_table(computed);
345
                return(0);
Alan Mishchenko committed
346
            }
347 348 349 350 351 352 353 354 355 356 357
            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.
                */
358
                result = st__lookup_int(computed,(char *)&STOREDD(large,0),
359 360 361 362
                                       &index);
                if (!result) {
                    ABC_FREE(storedd);
                    ABC_FREE(repeat);
363
                    st__free_table(computed);
364 365 366 367 368
                    return(0);
                }
                repeat[index]--;
                if (repeat[index] == 0) {
                    int *pointer = &STOREDD(index,0);
369
                    result = st__delete(computed, (const char **)&pointer, NULL);
370 371 372
                    if (!result) {
                        ABC_FREE(storedd);
                        ABC_FREE(repeat);
373
                        st__free_table(computed);
374 375 376 377 378 379 380 381 382 383
                        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);
                }
384
                if ( st__lookup_int(computed,(char *)&STOREDD(large,0),
385 386 387
                                  &index)) {
                    repeat[index]++;
                } else {
388 389
                    if ( st__insert(computed,(char *)&STOREDD(large,0),
                    (char *)(long)large) == st__OUT_OF_MEM) {
390 391
                        ABC_FREE(storedd);
                        ABC_FREE(repeat);
392
                        st__free_table(computed);
393 394 395 396
                        return(0);
                    }
                    repeat[large]++;
                }
Alan Mishchenko committed
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
            }
        }
    }

    /* 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. */
413
    st__free_table(computed);
Alan Mishchenko committed
414 415
    computed = NULL;
    result = build_dd(table,small,lower,upper);
Alan Mishchenko committed
416 417
    ABC_FREE(storedd);
    ABC_FREE(repeat);
Alan Mishchenko committed
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
    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)
{
445 446 447
    int i,j;            /* loop variables */
    int *used;          /* is a number already in a permutation */
    int next;           /* next random number without repetitions */
Alan Mishchenko committed
448

Alan Mishchenko committed
449
    used = ABC_ALLOC(int,numvars);
Alan Mishchenko committed
450
    if (used == NULL) {
451 452
        table->errorCode = CUDD_MEMORY_OUT;
        return(0);
Alan Mishchenko committed
453 454 455 456 457
    }
#if 0
#ifdef DD_STATS
    (void) fprintf(table->out,"Initial population before sifting\n");
    for (i = 0; i < 2; i++) {
458 459 460 461
        for (j = 0; j < numvars; j++) {
            (void) fprintf(table->out," %2d",STOREDD(i,j));
        }
        (void) fprintf(table->out,"\n");
Alan Mishchenko committed
462 463 464 465
    }
#endif
#endif
    for (i = 2; i < popsize; i++) {
466 467 468 469 470 471 472 473 474 475 476 477 478
        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];
        }
Alan Mishchenko committed
479 480
#if 0
#ifdef DD_STATS
481 482 483 484 485
        /* Print the order just generated. */
        for (j = 0; j < numvars; j++) {
            (void) fprintf(table->out," %2d",STOREDD(i,j));
        }
        (void) fprintf(table->out,"\n");
Alan Mishchenko committed
486 487 488
#endif
#endif
    }
Alan Mishchenko committed
489
    ABC_FREE(used);
Alan Mishchenko committed
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
    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) {
519 520 521 522 523 524
        size = cuddSwapInPlace(table,y,x);
        if (size == 0) {
            return(0);
        }
        x = y;
        y = cuddNextLow(table,x);
Alan Mishchenko committed
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
    }
    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)
{
551 552 553 554 555
    int         i,j;            /* loop vars */
    int         position;
    int         index;
    int         limit;          /* how large the DD for this order can grow */
    int         size;
Alan Mishchenko committed
556 557 558 559

    /* Check the computed table. If the order already exists, it
    ** suffices to copy the size from the existing entry.
    */
560
    if (computed && st__lookup_int(computed,(char *)&STOREDD(num,0),&index)) {
561
        STOREDD(num,numvars) = STOREDD(index,numvars);
Alan Mishchenko committed
562
#ifdef DD_STATS
563
        (void) fprintf(table->out,"\nCache hit for index %d", index);
Alan Mishchenko committed
564
#endif
565
        return(1);
Alan Mishchenko committed
566 567 568 569 570 571 572 573 574 575 576
    }

    /* 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++) {
577 578 579 580 581 582
        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;
Alan Mishchenko committed
583 584 585 586 587 588 589 590 591 592 593
    }

    /* 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++) {
594
        STOREDD(num,j) = table->invperm[lower+j];
Alan Mishchenko committed
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
    }
    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
616
largest(void)
Alan Mishchenko committed
617
{
618
    int i;      /* loop var */
Alan Mishchenko committed
619 620 621 622 623
    int big;    /* temporary holder to return result */

    big = 0;
    while (repeat[big] > 1) big++;
    for (i = big + 1; i < popsize; i++) {
624 625 626
        if (STOREDD(i,numvars) >= STOREDD(big,numvars) && repeat[i] <= 1) {
            big = i;
        }
Alan Mishchenko committed
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
    }
    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(
667
  const char * array,
Alan Mishchenko committed
668 669 670 671
  int  modulus)
{
    int val = 0;
    int i;
672
    int *intarray;
Alan Mishchenko committed
673

674
    intarray = (int *) array;
Alan Mishchenko committed
675 676

    for (i = 0; i < numvars; i++) {
677
        val = val * 997 + intarray[i];
Alan Mishchenko committed
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
    }

    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++) {
709
        if (intarray1[i] != intarray2[i]) return(1);
Alan Mishchenko committed
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
    }
    return(0);

} /* end of array_compare */


/**Function********************************************************************

  Synopsis    [Returns the index of the fittest individual.]

  Description []

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
static int
728
find_best(void)
Alan Mishchenko committed
729 730 731 732 733
{
    int i,small;

    small = 0;
    for (i = 1; i < popsize; i++) {
734 735 736
        if (STOREDD(i,numvars) < STOREDD(small,numvars)) {
            small = i;
        }
Alan Mishchenko committed
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
    }
    return(small);

} /* end of find_best */


/**Function********************************************************************

  Synopsis    [Returns the average fitness of the population.]

  Description []

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
754
#ifdef DD_STATS
Alan Mishchenko committed
755
static double
756
find_average_fitness(void)
Alan Mishchenko committed
757 758 759 760 761 762
{
    int i;
    int total_fitness = 0;
    double average_fitness;

    for (i = 0; i < popsize; i++) {
763
        total_fitness += STOREDD(i,numvars);
Alan Mishchenko committed
764 765 766 767 768
    }
    average_fitness = (double) total_fitness / (double) popsize;
    return(average_fitness);

} /* end of find_average_fitness */
769
#endif
Alan Mishchenko committed
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788


/**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)
{
789 790 791 792 793 794
    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 */
Alan Mishchenko committed
795

Alan Mishchenko committed
796
    inv1 = ABC_ALLOC(int,maxvar);
Alan Mishchenko committed
797
    if (inv1 == NULL) {
798
        return(0);
Alan Mishchenko committed
799
    }
Alan Mishchenko committed
800
    inv2 = ABC_ALLOC(int,maxvar);
Alan Mishchenko committed
801
    if (inv2 == NULL) {
802 803
        ABC_FREE(inv1);
        return(0);
Alan Mishchenko committed
804 805 806 807
    }

    /* Choose two orders from the population using roulette wheel. */
    if (!roulette(&mom,&dad)) {
808 809 810
        ABC_FREE(inv1);
        ABC_FREE(inv2);
        return(0);
Alan Mishchenko committed
811 812 813 814 815 816 817 818 819
    }

    /* 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 {
820
        cut2 = rand_int(numvars-1);
Alan Mishchenko committed
821 822 823 824 825
    } while (cut1 == cut2);

#if 0
    /* Print out the parents. */
    (void) fprintf(table->out,
826 827
                   "Crossover of %d (mom) and %d (dad) between %d and %d\n",
                   mom,dad,cut1,cut2);
Alan Mishchenko committed
828
    for (i = 0; i < numvars; i++) {
829 830
        if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
        (void) fprintf(table->out,"%2d ",STOREDD(mom,i));
Alan Mishchenko committed
831 832 833
    }
    (void) fprintf(table->out,"\n");
    for (i = 0; i < numvars; i++) {
834 835
        if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
        (void) fprintf(table->out,"%2d ",STOREDD(dad,i));
Alan Mishchenko committed
836 837 838 839 840 841
    }
    (void) fprintf(table->out,"\n");
#endif

    /* Initialize the inverse permutations: -1 means yet undetermined. */
    for (i = 0; i < maxvar; i++) {
842 843
        inv1[i] = -1;
        inv2[i] = -1;
Alan Mishchenko committed
844 845 846 847
    }

    /* Copy the portions whithin the cuts. */
    for (i = cut1; i != cut2; i = (i == numvars-1) ? 0 : i+1) {
848 849 850 851
        STOREDD(popsize,i) = STOREDD(dad,i);
        inv1[STOREDD(popsize,i)] = i;
        STOREDD(popsize+1,i) = STOREDD(mom,i);
        inv2[STOREDD(popsize+1,i)] = i;
Alan Mishchenko committed
852 853 854 855
    }

    /* Now apply the repair algorithm outside the cuts. */
    for (i = cut2; i != cut1; i = (i == numvars-1 ) ? 0 : i+1) {
856 857 858 859 860 861 862 863 864 865 866 867 868 869
        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;
Alan Mishchenko committed
870 871 872 873 874
    }

#if 0
    /* Print the results of crossover. */
    for (i = 0; i < numvars; i++) {
875 876
        if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
        (void) fprintf(table->out,"%2d ",STOREDD(popsize,i));
Alan Mishchenko committed
877 878 879
    }
    (void) fprintf(table->out,"\n");
    for (i = 0; i < numvars; i++) {
880 881
        if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
        (void) fprintf(table->out,"%2d ",STOREDD(popsize+1,i));
Alan Mishchenko committed
882 883 884 885
    }
    (void) fprintf(table->out,"\n");
#endif

Alan Mishchenko committed
886 887
    ABC_FREE(inv1);
    ABC_FREE(inv2);
Alan Mishchenko committed
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913
    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;

Alan Mishchenko committed
914
    wheel = ABC_ALLOC(double,popsize);
Alan Mishchenko committed
915
    if (wheel == NULL) {
916
        return(0);
Alan Mishchenko committed
917 918 919 920 921 922
    }

    /* 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++) {
923
        wheel[i] = wheel[i-1] + 1.0 / (double) STOREDD(i,numvars);
Alan Mishchenko committed
924 925 926 927 928 929 930 931 932 933
    }

    /* 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++) {
934
        if (spin <= wheel[i]) break;
Alan Mishchenko committed
935 936 937 938 939 940 941
    }
    *p1 = i;

    /* Repeat the process for the second parent, making sure it is
    ** distinct from the first.
    */
    do {
942 943 944 945
        spin = wheel[popsize-1] * (double) Cudd_Random() / 2147483561.0;
        for (i = 0; i < popsize; i++) {
            if (spin <= wheel[i]) break;
        }
Alan Mishchenko committed
946 947 948
    } while (i == *p1);
    *p2 = i;

Alan Mishchenko committed
949
    ABC_FREE(wheel);
Alan Mishchenko committed
950 951 952 953
    return(1);

} /* end of roulette */

954

955 956
ABC_NAMESPACE_IMPL_END

957