cuddGenetic.c 30.1 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

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

137 138 139
#ifdef __cplusplus
extern "C" {
#endif
Alan Mishchenko committed
140 141 142 143 144 145 146

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

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

147 148 149 150 151 152 153 154 155 156 157 158 159
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
160 161 162

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

163 164 165
#ifdef __cplusplus
}
#endif
Alan Mishchenko committed
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196

/*---------------------------------------------------------------------------*/
/* 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 */)
{
197 198 199 200 201 202
    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
203 204 205 206 207 208 209

    /* 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) {
210 211 212 213
        popsize = 3 * numvars;  /* population size is 3 times # of vars */
        if (popsize > 120) {
            popsize = 120;      /* Maximum population size is 120 */
        }
Alan Mishchenko committed
214
    } else {
215
        popsize = table->populationSize;  /* user specified value */
Alan Mishchenko committed
216
    }
217
    if (popsize < 4) popsize = 4;       /* enforce minimum population size */
Alan Mishchenko committed
218 219

    /* Allocate population table. */
Alan Mishchenko committed
220
    storedd = ABC_ALLOC(int,(popsize+2)*(numvars+1));
Alan Mishchenko committed
221
    if (storedd == NULL) {
222 223
        table->errorCode = CUDD_MEMORY_OUT;
        return(0);
Alan Mishchenko committed
224 225 226 227 228 229 230 231 232 233
    }

    /* 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
234
    repeat = ABC_ALLOC(int,popsize);
Alan Mishchenko committed
235
    if (repeat == NULL) {
236 237 238
        table->errorCode = CUDD_MEMORY_OUT;
        ABC_FREE(storedd);
        return(0);
Alan Mishchenko committed
239 240
    }
    for (i = 0; i < popsize; i++) {
241
        repeat[i] = 0;
Alan Mishchenko committed
242
    }
243
    computed = st__init_table(array_compare,array_hash);
Alan Mishchenko committed
244
    if (computed == NULL) {
245 246 247 248
        table->errorCode = CUDD_MEMORY_OUT;
        ABC_FREE(storedd);
        ABC_FREE(repeat);
        return(0);
Alan Mishchenko committed
249 250 251 252
    }

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

    /* Store the initial order in the computed table. */
258
    if ( st__insert(computed,(char *)storedd,(char *) 0) == st__OUT_OF_MEM) {
259 260
        ABC_FREE(storedd);
        ABC_FREE(repeat);
261
        st__free_table(computed);
262
        return(0);
Alan Mishchenko committed
263 264 265 266 267
    }
    repeat[0]++;

    /* Insert the reverse order as second element of the population. */
    for (i = 0; i < numvars; i++) {
268
        STOREDD(1,numvars-1-i) = table->invperm[i+lower]; /* reverse order */
Alan Mishchenko committed
269 270 271 272 273 274 275 276
    }

    /* 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)) {
277
        table->errorCode = CUDD_MEMORY_OUT;
Alan Mishchenko committed
278 279
        ABC_FREE(storedd);
        ABC_FREE(repeat);
280
        st__free_table(computed);
Alan Mishchenko committed
281 282
        return(0);
    }
283 284 285 286 287
    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);
288
            st__free_table(computed);
289 290
            return(0);
        }
291
        if ( st__lookup_int(computed,(char *)&STOREDD(i,0),&index)) {
292 293
            repeat[index]++;
        } else {
294 295
            if ( st__insert(computed,(char *)&STOREDD(i,0),(char *)(long)i) ==
            st__OUT_OF_MEM) {
296 297
                ABC_FREE(storedd);
                ABC_FREE(repeat);
298
                st__free_table(computed);
299 300 301
                return(0);
            }
            repeat[i]++;
Alan Mishchenko committed
302 303 304 305 306 307 308 309
        }
    }

#if 0
#ifdef DD_STATS
    /* Print the initial population. */
    (void) fprintf(table->out,"Initial population after sifting\n");
    for (m = 0; m < popsize; m++) {
310 311 312 313 314
        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
315 316 317 318 319 320
    }
#endif
#endif

    small = find_best();
#ifdef DD_STATS
321
    average_fitness = find_average_fitness();
Alan Mishchenko committed
322 323 324 325 326
    (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) {
327 328 329 330
        cross = 3*numvars;
        if (cross > 60) {       /* do a maximum of 50 crossovers */
            cross = 60;
        }
Alan Mishchenko committed
331
    } else {
332
        cross = table->numberXovers;      /* use user specified value */
Alan Mishchenko committed
333 334 335 336
    }

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

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

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

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

    /* 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++) {
585 586 587 588 589 590
        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
591 592 593 594 595 596 597 598 599 600 601
    }

    /* 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++) {
602
        STOREDD(num,j) = table->invperm[lower+j];
Alan Mishchenko committed
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
    }
    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
624
largest(void)
Alan Mishchenko committed
625
{
626
    int i;      /* loop var */
Alan Mishchenko committed
627 628 629 630 631
    int big;    /* temporary holder to return result */

    big = 0;
    while (repeat[big] > 1) big++;
    for (i = big + 1; i < popsize; i++) {
632 633 634
        if (STOREDD(i,numvars) >= STOREDD(big,numvars) && repeat[i] <= 1) {
            big = i;
        }
Alan Mishchenko committed
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 667 668 669 670 671 672 673 674
    }
    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(
675
  const char * array,
Alan Mishchenko committed
676 677 678 679
  int  modulus)
{
    int val = 0;
    int i;
680
    int *intarray;
Alan Mishchenko committed
681

682
    intarray = (int *) array;
Alan Mishchenko committed
683 684

    for (i = 0; i < numvars; i++) {
685
        val = val * 997 + intarray[i];
Alan Mishchenko committed
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
    }

    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++) {
717
        if (intarray1[i] != intarray2[i]) return(1);
Alan Mishchenko committed
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735
    }
    return(0);

} /* end of array_compare */


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

  Synopsis    [Returns the index of the fittest individual.]

  Description []

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
static int
736
find_best(void)
Alan Mishchenko committed
737 738 739 740 741
{
    int i,small;

    small = 0;
    for (i = 1; i < popsize; i++) {
742 743 744
        if (STOREDD(i,numvars) < STOREDD(small,numvars)) {
            small = i;
        }
Alan Mishchenko committed
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
    }
    return(small);

} /* end of find_best */


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

  Synopsis    [Returns the average fitness of the population.]

  Description []

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
762
#ifdef DD_STATS
Alan Mishchenko committed
763
static double
764
find_average_fitness(void)
Alan Mishchenko committed
765 766 767 768 769 770
{
    int i;
    int total_fitness = 0;
    double average_fitness;

    for (i = 0; i < popsize; i++) {
771
        total_fitness += STOREDD(i,numvars);
Alan Mishchenko committed
772 773 774 775 776
    }
    average_fitness = (double) total_fitness / (double) popsize;
    return(average_fitness);

} /* end of find_average_fitness */
777
#endif
Alan Mishchenko committed
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796


/**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)
{
797 798 799 800 801 802
    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
803

Alan Mishchenko committed
804
    inv1 = ABC_ALLOC(int,maxvar);
Alan Mishchenko committed
805
    if (inv1 == NULL) {
806
        return(0);
Alan Mishchenko committed
807
    }
Alan Mishchenko committed
808
    inv2 = ABC_ALLOC(int,maxvar);
Alan Mishchenko committed
809
    if (inv2 == NULL) {
810 811
        ABC_FREE(inv1);
        return(0);
Alan Mishchenko committed
812 813 814 815
    }

    /* Choose two orders from the population using roulette wheel. */
    if (!roulette(&mom,&dad)) {
816 817 818
        ABC_FREE(inv1);
        ABC_FREE(inv2);
        return(0);
Alan Mishchenko committed
819 820 821 822 823 824 825 826 827
    }

    /* 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 {
828
        cut2 = rand_int(numvars-1);
Alan Mishchenko committed
829 830 831 832 833
    } while (cut1 == cut2);

#if 0
    /* Print out the parents. */
    (void) fprintf(table->out,
834 835
                   "Crossover of %d (mom) and %d (dad) between %d and %d\n",
                   mom,dad,cut1,cut2);
Alan Mishchenko committed
836
    for (i = 0; i < numvars; i++) {
837 838
        if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
        (void) fprintf(table->out,"%2d ",STOREDD(mom,i));
Alan Mishchenko committed
839 840 841
    }
    (void) fprintf(table->out,"\n");
    for (i = 0; i < numvars; i++) {
842 843
        if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
        (void) fprintf(table->out,"%2d ",STOREDD(dad,i));
Alan Mishchenko committed
844 845 846 847 848 849
    }
    (void) fprintf(table->out,"\n");
#endif

    /* Initialize the inverse permutations: -1 means yet undetermined. */
    for (i = 0; i < maxvar; i++) {
850 851
        inv1[i] = -1;
        inv2[i] = -1;
Alan Mishchenko committed
852 853 854 855
    }

    /* Copy the portions whithin the cuts. */
    for (i = cut1; i != cut2; i = (i == numvars-1) ? 0 : i+1) {
856 857 858 859
        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
860 861 862 863
    }

    /* Now apply the repair algorithm outside the cuts. */
    for (i = cut2; i != cut1; i = (i == numvars-1 ) ? 0 : i+1) {
864 865 866 867 868 869 870 871 872 873 874 875 876 877
        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
878 879 880 881 882
    }

#if 0
    /* Print the results of crossover. */
    for (i = 0; i < numvars; i++) {
883 884
        if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
        (void) fprintf(table->out,"%2d ",STOREDD(popsize,i));
Alan Mishchenko committed
885 886 887
    }
    (void) fprintf(table->out,"\n");
    for (i = 0; i < numvars; i++) {
888 889
        if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
        (void) fprintf(table->out,"%2d ",STOREDD(popsize+1,i));
Alan Mishchenko committed
890 891 892 893
    }
    (void) fprintf(table->out,"\n");
#endif

Alan Mishchenko committed
894 895
    ABC_FREE(inv1);
    ABC_FREE(inv2);
Alan Mishchenko committed
896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
    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
922
    wheel = ABC_ALLOC(double,popsize);
Alan Mishchenko committed
923
    if (wheel == NULL) {
924
        return(0);
Alan Mishchenko committed
925 926 927 928 929 930
    }

    /* 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++) {
931
        wheel[i] = wheel[i-1] + 1.0 / (double) STOREDD(i,numvars);
Alan Mishchenko committed
932 933 934 935 936 937 938 939 940 941
    }

    /* 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++) {
942
        if (spin <= wheel[i]) break;
Alan Mishchenko committed
943 944 945 946 947 948 949
    }
    *p1 = i;

    /* Repeat the process for the second parent, making sure it is
    ** distinct from the first.
    */
    do {
950 951 952 953
        spin = wheel[popsize-1] * (double) Cudd_Random() / 2147483561.0;
        for (i = 0; i < popsize; i++) {
            if (spin <= wheel[i]) break;
        }
Alan Mishchenko committed
954 955 956
    } while (i == *p1);
    *p2 = i;

Alan Mishchenko committed
957
    ABC_FREE(wheel);
Alan Mishchenko committed
958 959 960 961
    return(1);

} /* end of roulette */

962

963 964
ABC_NAMESPACE_IMPL_END

965