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

  1. /**CFile***********************************************************************
  2. FileName [cuddGenetic.c]
  3. PackageName [cudd]
  4. Synopsis [Genetic algorithm for variable reordering.]
  5. Description [Internal procedures included in this file:
  6. <ul>
  7. <li> cuddGa()
  8. </ul>
  9. Static procedures included in this module:
  10. <ul>
  11. <li> make_random()
  12. <li> sift_up()
  13. <li> build_dd()
  14. <li> largest()
  15. <li> rand_int()
  16. <li> array_hash()
  17. <li> array_compare()
  18. <li> find_best()
  19. <li> find_average_fitness()
  20. <li> PMX()
  21. <li> roulette()
  22. </ul>
  23. The genetic algorithm implemented here is as follows. We start with
  24. the current DD order. We sift this order and use this as the
  25. reference DD. We only keep 1 DD around for the entire process and
  26. simply rearrange the order of this DD, storing the various orders
  27. and their corresponding DD sizes. We generate more random orders to
  28. build an initial population. This initial population is 3 times the
  29. number of variables, with a maximum of 120. Each random order is
  30. built (from the reference DD) and its size stored. Each random
  31. order is also sifted to keep the DD sizes fairly small. Then a
  32. crossover is performed between two orders (picked randomly) and the
  33. two resulting DDs are built and sifted. For each new order, if its
  34. size is smaller than any DD in the population, it is inserted into
  35. the population and the DD with the largest number of nodes is thrown
  36. out. The crossover process happens up to 50 times, and at this point
  37. the DD in the population with the smallest size is chosen as the
  38. result. This DD must then be built from the reference DD.]
  39. SeeAlso []
  40. Author [Curt Musfeldt, Alan Shuler, Fabio Somenzi]
  41. Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
  42. All rights reserved.
  43. Redistribution and use in source and binary forms, with or without
  44. modification, are permitted provided that the following conditions
  45. are met:
  46. Redistributions of source code must retain the above copyright
  47. notice, this list of conditions and the following disclaimer.
  48. Redistributions in binary form must reproduce the above copyright
  49. notice, this list of conditions and the following disclaimer in the
  50. documentation and/or other materials provided with the distribution.
  51. Neither the name of the University of Colorado nor the names of its
  52. contributors may be used to endorse or promote products derived from
  53. this software without specific prior written permission.
  54. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  55. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  56. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  57. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  58. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  59. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  60. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  61. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  62. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  63. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  64. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  65. POSSIBILITY OF SUCH DAMAGE.]
  66. ******************************************************************************/
  67. #include "util.h"
  68. #include "cuddInt.h"
  69. /*---------------------------------------------------------------------------*/
  70. /* Constant declarations */
  71. /*---------------------------------------------------------------------------*/
  72. /*---------------------------------------------------------------------------*/
  73. /* Stucture declarations */
  74. /*---------------------------------------------------------------------------*/
  75. /*---------------------------------------------------------------------------*/
  76. /* Type declarations */
  77. /*---------------------------------------------------------------------------*/
  78. /*---------------------------------------------------------------------------*/
  79. /* Variable declarations */
  80. /*---------------------------------------------------------------------------*/
  81. #ifndef lint
  82. static char rcsid[] DD_UNUSED = "$Id: cuddGenetic.c,v 1.30 2012/02/05 01:07:18 fabio Exp $";
  83. #endif
  84. static int popsize; /* the size of the population */
  85. static int numvars; /* the number of input variables in the ckt. */
  86. /* storedd stores the population orders and sizes. This table has two
  87. ** extra rows and one extras column. The two extra rows are used for the
  88. ** offspring produced by a crossover. Each row stores one order and its
  89. ** size. The order is stored by storing the indices of variables in the
  90. ** order in which they appear in the order. The table is in reality a
  91. ** one-dimensional array which is accessed via a macro to give the illusion
  92. ** it is a two-dimensional structure.
  93. */
  94. static int *storedd;
  95. static st_table *computed; /* hash table to identify existing orders */
  96. static int *repeat; /* how many times an order is present */
  97. static int large; /* stores the index of the population with
  98. ** the largest number of nodes in the DD */
  99. static int result;
  100. static int cross; /* the number of crossovers to perform */
  101. /*---------------------------------------------------------------------------*/
  102. /* Macro declarations */
  103. /*---------------------------------------------------------------------------*/
  104. /* macro used to access the population table as if it were a
  105. ** two-dimensional structure.
  106. */
  107. #define STOREDD(i,j) storedd[(i)*(numvars+1)+(j)]
  108. #ifdef __cplusplus
  109. extern "C" {
  110. #endif
  111. /**AutomaticStart*************************************************************/
  112. /*---------------------------------------------------------------------------*/
  113. /* Static function prototypes */
  114. /*---------------------------------------------------------------------------*/
  115. static int make_random (DdManager *table, int lower);
  116. static int sift_up (DdManager *table, int x, int x_low);
  117. static int build_dd (DdManager *table, int num, int lower, int upper);
  118. static int largest (void);
  119. static int rand_int (int a);
  120. static int array_hash (char *array, int modulus);
  121. static int array_compare (const char *array1, const char *array2);
  122. static int find_best (void);
  123. #ifdef DD_STATS
  124. static double find_average_fitness (void);
  125. #endif
  126. static int PMX (int maxvar);
  127. static int roulette (int *p1, int *p2);
  128. /**AutomaticEnd***************************************************************/
  129. #ifdef __cplusplus
  130. }
  131. #endif
  132. /*---------------------------------------------------------------------------*/
  133. /* Definition of exported functions */
  134. /*---------------------------------------------------------------------------*/
  135. /*---------------------------------------------------------------------------*/
  136. /* Definition of internal functions */
  137. /*---------------------------------------------------------------------------*/
  138. /**Function********************************************************************
  139. Synopsis [Genetic algorithm for DD reordering.]
  140. Description [Genetic algorithm for DD reordering.
  141. The two children of a crossover will be stored in
  142. storedd[popsize] and storedd[popsize+1] --- the last two slots in the
  143. storedd array. (This will make comparisons and replacement easy.)
  144. Returns 1 in case of success; 0 otherwise.]
  145. SideEffects [None]
  146. SeeAlso []
  147. ******************************************************************************/
  148. int
  149. cuddGa(
  150. DdManager * table /* manager */,
  151. int lower /* lowest level to be reordered */,
  152. int upper /* highest level to be reorderded */)
  153. {
  154. int i,n,m; /* dummy/loop vars */
  155. int index;
  156. #ifdef DD_STATS
  157. double average_fitness;
  158. #endif
  159. int small; /* index of smallest DD in population */
  160. /* Do an initial sifting to produce at least one reasonable individual. */
  161. if (!cuddSifting(table,lower,upper)) return(0);
  162. /* Get the initial values. */
  163. numvars = upper - lower + 1; /* number of variables to be reordered */
  164. if (table->populationSize == 0) {
  165. popsize = 3 * numvars; /* population size is 3 times # of vars */
  166. if (popsize > 120) {
  167. popsize = 120; /* Maximum population size is 120 */
  168. }
  169. } else {
  170. popsize = table->populationSize; /* user specified value */
  171. }
  172. if (popsize < 4) popsize = 4; /* enforce minimum population size */
  173. /* Allocate population table. */
  174. storedd = ALLOC(int,(popsize+2)*(numvars+1));
  175. if (storedd == NULL) {
  176. table->errorCode = CUDD_MEMORY_OUT;
  177. return(0);
  178. }
  179. /* Initialize the computed table. This table is made up of two data
  180. ** structures: A hash table with the key given by the order, which says
  181. ** if a given order is present in the population; and the repeat
  182. ** vector, which says how many copies of a given order are stored in
  183. ** the population table. If there are multiple copies of an order, only
  184. ** one has a repeat count greater than 1. This copy is the one pointed
  185. ** by the computed table.
  186. */
  187. repeat = ALLOC(int,popsize);
  188. if (repeat == NULL) {
  189. table->errorCode = CUDD_MEMORY_OUT;
  190. FREE(storedd);
  191. return(0);
  192. }
  193. for (i = 0; i < popsize; i++) {
  194. repeat[i] = 0;
  195. }
  196. computed = st_init_table(array_compare,array_hash);
  197. if (computed == NULL) {
  198. table->errorCode = CUDD_MEMORY_OUT;
  199. FREE(storedd);
  200. FREE(repeat);
  201. return(0);
  202. }
  203. /* Copy the current DD and its size to the population table. */
  204. for (i = 0; i < numvars; i++) {
  205. STOREDD(0,i) = table->invperm[i+lower]; /* order of initial DD */
  206. }
  207. STOREDD(0,numvars) = table->keys - table->isolated; /* size of initial DD */
  208. /* Store the initial order in the computed table. */
  209. if (st_insert(computed,(char *)storedd,(char *) 0) == ST_OUT_OF_MEM) {
  210. FREE(storedd);
  211. FREE(repeat);
  212. st_free_table(computed);
  213. return(0);
  214. }
  215. repeat[0]++;
  216. /* Insert the reverse order as second element of the population. */
  217. for (i = 0; i < numvars; i++) {
  218. STOREDD(1,numvars-1-i) = table->invperm[i+lower]; /* reverse order */
  219. }
  220. /* Now create the random orders. make_random fills the population
  221. ** table with random permutations. The successive loop builds and sifts
  222. ** the DDs for the reverse order and each random permutation, and stores
  223. ** the results in the computed table.
  224. */
  225. if (!make_random(table,lower)) {
  226. table->errorCode = CUDD_MEMORY_OUT;
  227. FREE(storedd);
  228. FREE(repeat);
  229. st_free_table(computed);
  230. return(0);
  231. }
  232. for (i = 1; i < popsize; i++) {
  233. result = build_dd(table,i,lower,upper); /* build and sift order */
  234. if (!result) {
  235. FREE(storedd);
  236. FREE(repeat);
  237. st_free_table(computed);
  238. return(0);
  239. }
  240. if (st_lookup_int(computed,(char *)&STOREDD(i,0),&index)) {
  241. repeat[index]++;
  242. } else {
  243. if (st_insert(computed,(char *)&STOREDD(i,0),(char *)(long)i) ==
  244. ST_OUT_OF_MEM) {
  245. FREE(storedd);
  246. FREE(repeat);
  247. st_free_table(computed);
  248. return(0);
  249. }
  250. repeat[i]++;
  251. }
  252. }
  253. #if 0
  254. #ifdef DD_STATS
  255. /* Print the initial population. */
  256. (void) fprintf(table->out,"Initial population after sifting\n");
  257. for (m = 0; m < popsize; m++) {
  258. for (i = 0; i < numvars; i++) {
  259. (void) fprintf(table->out," %2d",STOREDD(m,i));
  260. }
  261. (void) fprintf(table->out," : %3d (%d)\n",
  262. STOREDD(m,numvars),repeat[m]);
  263. }
  264. #endif
  265. #endif
  266. small = find_best();
  267. #ifdef DD_STATS
  268. average_fitness = find_average_fitness();
  269. (void) fprintf(table->out,"\nInitial population: best fitness = %d, average fitness %8.3f",STOREDD(small,numvars),average_fitness);
  270. #endif
  271. /* Decide how many crossovers should be tried. */
  272. if (table->numberXovers == 0) {
  273. cross = 3*numvars;
  274. if (cross > 60) { /* do a maximum of 50 crossovers */
  275. cross = 60;
  276. }
  277. } else {
  278. cross = table->numberXovers; /* use user specified value */
  279. }
  280. if (cross >= popsize) {
  281. cross = popsize;
  282. }
  283. /* Perform the crossovers to get the best order. */
  284. for (m = 0; m < cross; m++) {
  285. if (!PMX(table->size)) { /* perform one crossover */
  286. table->errorCode = CUDD_MEMORY_OUT;
  287. FREE(storedd);
  288. FREE(repeat);
  289. st_free_table(computed);
  290. return(0);
  291. }
  292. /* The offsprings are left in the last two entries of the
  293. ** population table. These are now considered in turn.
  294. */
  295. for (i = popsize; i <= popsize+1; i++) {
  296. result = build_dd(table,i,lower,upper); /* build and sift child */
  297. if (!result) {
  298. FREE(storedd);
  299. FREE(repeat);
  300. st_free_table(computed);
  301. return(0);
  302. }
  303. large = largest(); /* find the largest DD in population */
  304. /* If the new child is smaller than the largest DD in the current
  305. ** population, enter it into the population in place of the
  306. ** largest DD.
  307. */
  308. if (STOREDD(i,numvars) < STOREDD(large,numvars)) {
  309. /* Look up the largest DD in the computed table.
  310. ** Decrease its repetition count. If the repetition count
  311. ** goes to 0, remove the largest DD from the computed table.
  312. */
  313. result = st_lookup_int(computed,(char *)&STOREDD(large,0),
  314. &index);
  315. if (!result) {
  316. FREE(storedd);
  317. FREE(repeat);
  318. st_free_table(computed);
  319. return(0);
  320. }
  321. repeat[index]--;
  322. if (repeat[index] == 0) {
  323. int *pointer = &STOREDD(index,0);
  324. result = st_delete(computed, &pointer, NULL);
  325. if (!result) {
  326. FREE(storedd);
  327. FREE(repeat);
  328. st_free_table(computed);
  329. return(0);
  330. }
  331. }
  332. /* Copy the new individual to the entry of the
  333. ** population table just made available and update the
  334. ** computed table.
  335. */
  336. for (n = 0; n <= numvars; n++) {
  337. STOREDD(large,n) = STOREDD(i,n);
  338. }
  339. if (st_lookup_int(computed,(char *)&STOREDD(large,0),
  340. &index)) {
  341. repeat[index]++;
  342. } else {
  343. if (st_insert(computed,(char *)&STOREDD(large,0),
  344. (char *)(long)large) == ST_OUT_OF_MEM) {
  345. FREE(storedd);
  346. FREE(repeat);
  347. st_free_table(computed);
  348. return(0);
  349. }
  350. repeat[large]++;
  351. }
  352. }
  353. }
  354. }
  355. /* Find the smallest DD in the population and build it;
  356. ** that will be the result.
  357. */
  358. small = find_best();
  359. /* Print stats on the final population. */
  360. #ifdef DD_STATS
  361. average_fitness = find_average_fitness();
  362. (void) fprintf(table->out,"\nFinal population: best fitness = %d, average fitness %8.3f",STOREDD(small,numvars),average_fitness);
  363. #endif
  364. /* Clean up, build the result DD, and return. */
  365. st_free_table(computed);
  366. computed = NULL;
  367. result = build_dd(table,small,lower,upper);
  368. FREE(storedd);
  369. FREE(repeat);
  370. return(result);
  371. } /* end of cuddGa */
  372. /*---------------------------------------------------------------------------*/
  373. /* Definition of static functions */
  374. /*---------------------------------------------------------------------------*/
  375. /**Function********************************************************************
  376. Synopsis [Generates the random sequences for the initial population.]
  377. Description [Generates the random sequences for the initial population.
  378. The sequences are permutations of the indices between lower and
  379. upper in the current order.]
  380. SideEffects [None]
  381. SeeAlso []
  382. ******************************************************************************/
  383. static int
  384. make_random(
  385. DdManager * table,
  386. int lower)
  387. {
  388. int i,j; /* loop variables */
  389. int *used; /* is a number already in a permutation */
  390. int next; /* next random number without repetitions */
  391. used = ALLOC(int,numvars);
  392. if (used == NULL) {
  393. table->errorCode = CUDD_MEMORY_OUT;
  394. return(0);
  395. }
  396. #if 0
  397. #ifdef DD_STATS
  398. (void) fprintf(table->out,"Initial population before sifting\n");
  399. for (i = 0; i < 2; i++) {
  400. for (j = 0; j < numvars; j++) {
  401. (void) fprintf(table->out," %2d",STOREDD(i,j));
  402. }
  403. (void) fprintf(table->out,"\n");
  404. }
  405. #endif
  406. #endif
  407. for (i = 2; i < popsize; i++) {
  408. for (j = 0; j < numvars; j++) {
  409. used[j] = 0;
  410. }
  411. /* Generate a permutation of {0...numvars-1} and use it to
  412. ** permute the variables in the layesr from lower to upper.
  413. */
  414. for (j = 0; j < numvars; j++) {
  415. do {
  416. next = rand_int(numvars-1);
  417. } while (used[next] != 0);
  418. used[next] = 1;
  419. STOREDD(i,j) = table->invperm[next+lower];
  420. }
  421. #if 0
  422. #ifdef DD_STATS
  423. /* Print the order just generated. */
  424. for (j = 0; j < numvars; j++) {
  425. (void) fprintf(table->out," %2d",STOREDD(i,j));
  426. }
  427. (void) fprintf(table->out,"\n");
  428. #endif
  429. #endif
  430. }
  431. FREE(used);
  432. return(1);
  433. } /* end of make_random */
  434. /**Function********************************************************************
  435. Synopsis [Moves one variable up.]
  436. Description [Takes a variable from position x and sifts it up to
  437. position x_low; x_low should be less than x. Returns 1 if successful;
  438. 0 otherwise]
  439. SideEffects [None]
  440. SeeAlso []
  441. ******************************************************************************/
  442. static int
  443. sift_up(
  444. DdManager * table,
  445. int x,
  446. int x_low)
  447. {
  448. int y;
  449. int size;
  450. y = cuddNextLow(table,x);
  451. while (y >= x_low) {
  452. size = cuddSwapInPlace(table,y,x);
  453. if (size == 0) {
  454. return(0);
  455. }
  456. x = y;
  457. y = cuddNextLow(table,x);
  458. }
  459. return(1);
  460. } /* end of sift_up */
  461. /**Function********************************************************************
  462. Synopsis [Builds a DD from a given order.]
  463. Description [Builds a DD from a given order. This procedure also
  464. sifts the final order and inserts into the array the size in nodes
  465. of the result. Returns 1 if successful; 0 otherwise.]
  466. SideEffects [None]
  467. SeeAlso []
  468. ******************************************************************************/
  469. static int
  470. build_dd(
  471. DdManager * table,
  472. int num /* the index of the individual to be built */,
  473. int lower,
  474. int upper)
  475. {
  476. int i,j; /* loop vars */
  477. int position;
  478. int index;
  479. int limit; /* how large the DD for this order can grow */
  480. int size;
  481. /* Check the computed table. If the order already exists, it
  482. ** suffices to copy the size from the existing entry.
  483. */
  484. if (computed && st_lookup_int(computed,(char *)&STOREDD(num,0),&index)) {
  485. STOREDD(num,numvars) = STOREDD(index,numvars);
  486. #ifdef DD_STATS
  487. (void) fprintf(table->out,"\nCache hit for index %d", index);
  488. #endif
  489. return(1);
  490. }
  491. /* Stop if the DD grows 20 times larges than the reference size. */
  492. limit = 20 * STOREDD(0,numvars);
  493. /* Sift up the variables so as to build the desired permutation.
  494. ** First the variable that has to be on top is sifted to the top.
  495. ** Then the variable that has to occupy the secon position is sifted
  496. ** up to the second position, and so on.
  497. */
  498. for (j = 0; j < numvars; j++) {
  499. i = STOREDD(num,j);
  500. position = table->perm[i];
  501. result = sift_up(table,position,j+lower);
  502. if (!result) return(0);
  503. size = table->keys - table->isolated;
  504. if (size > limit) break;
  505. }
  506. /* Sift the DD just built. */
  507. #ifdef DD_STATS
  508. (void) fprintf(table->out,"\n");
  509. #endif
  510. result = cuddSifting(table,lower,upper);
  511. if (!result) return(0);
  512. /* Copy order and size to table. */
  513. for (j = 0; j < numvars; j++) {
  514. STOREDD(num,j) = table->invperm[lower+j];
  515. }
  516. STOREDD(num,numvars) = table->keys - table->isolated; /* size of new DD */
  517. return(1);
  518. } /* end of build_dd */
  519. /**Function********************************************************************
  520. Synopsis [Finds the largest DD in the population.]
  521. Description [Finds the largest DD in the population. If an order is
  522. repeated, it avoids choosing the copy that is in the computed table
  523. (it has repeat[i] > 1).]
  524. SideEffects [None]
  525. SeeAlso []
  526. ******************************************************************************/
  527. static int
  528. largest(void)
  529. {
  530. int i; /* loop var */
  531. int big; /* temporary holder to return result */
  532. big = 0;
  533. while (repeat[big] > 1) big++;
  534. for (i = big + 1; i < popsize; i++) {
  535. if (STOREDD(i,numvars) >= STOREDD(big,numvars) && repeat[i] <= 1) {
  536. big = i;
  537. }
  538. }
  539. return(big);
  540. } /* end of largest */
  541. /**Function********************************************************************
  542. Synopsis [Generates a random number between 0 and the integer a.]
  543. Description []
  544. SideEffects [None]
  545. SeeAlso []
  546. ******************************************************************************/
  547. static int
  548. rand_int(
  549. int a)
  550. {
  551. return(Cudd_Random() % (a+1));
  552. } /* end of rand_int */
  553. /**Function********************************************************************
  554. Synopsis [Hash function for the computed table.]
  555. Description [Hash function for the computed table. Returns the bucket
  556. number.]
  557. SideEffects [None]
  558. SeeAlso []
  559. ******************************************************************************/
  560. static int
  561. array_hash(
  562. char * array,
  563. int modulus)
  564. {
  565. int val = 0;
  566. int i;
  567. int *intarray;
  568. intarray = (int *) array;
  569. for (i = 0; i < numvars; i++) {
  570. val = val * 997 + intarray[i];
  571. }
  572. return ((val < 0) ? -val : val) % modulus;
  573. } /* end of array_hash */
  574. /**Function********************************************************************
  575. Synopsis [Comparison function for the computed table.]
  576. Description [Comparison function for the computed table. Returns 0 if
  577. the two arrays are equal; 1 otherwise.]
  578. SideEffects [None]
  579. SeeAlso []
  580. ******************************************************************************/
  581. static int
  582. array_compare(
  583. const char * array1,
  584. const char * array2)
  585. {
  586. int i;
  587. int *intarray1, *intarray2;
  588. intarray1 = (int *) array1;
  589. intarray2 = (int *) array2;
  590. for (i = 0; i < numvars; i++) {
  591. if (intarray1[i] != intarray2[i]) return(1);
  592. }
  593. return(0);
  594. } /* end of array_compare */
  595. /**Function********************************************************************
  596. Synopsis [Returns the index of the fittest individual.]
  597. Description []
  598. SideEffects [None]
  599. SeeAlso []
  600. ******************************************************************************/
  601. static int
  602. find_best(void)
  603. {
  604. int i,small;
  605. small = 0;
  606. for (i = 1; i < popsize; i++) {
  607. if (STOREDD(i,numvars) < STOREDD(small,numvars)) {
  608. small = i;
  609. }
  610. }
  611. return(small);
  612. } /* end of find_best */
  613. /**Function********************************************************************
  614. Synopsis [Returns the average fitness of the population.]
  615. Description []
  616. SideEffects [None]
  617. SeeAlso []
  618. ******************************************************************************/
  619. #ifdef DD_STATS
  620. static double
  621. find_average_fitness(void)
  622. {
  623. int i;
  624. int total_fitness = 0;
  625. double average_fitness;
  626. for (i = 0; i < popsize; i++) {
  627. total_fitness += STOREDD(i,numvars);
  628. }
  629. average_fitness = (double) total_fitness / (double) popsize;
  630. return(average_fitness);
  631. } /* end of find_average_fitness */
  632. #endif
  633. /**Function********************************************************************
  634. Synopsis [Performs the crossover between two parents.]
  635. Description [Performs the crossover between two randomly chosen
  636. parents, and creates two children, x1 and x2. Uses the Partially
  637. Matched Crossover operator.]
  638. SideEffects [None]
  639. SeeAlso []
  640. ******************************************************************************/
  641. static int
  642. PMX(
  643. int maxvar)
  644. {
  645. int cut1,cut2; /* the two cut positions (random) */
  646. int mom,dad; /* the two randomly chosen parents */
  647. int *inv1; /* inverse permutations for repair algo */
  648. int *inv2;
  649. int i; /* loop vars */
  650. int u,v; /* aux vars */
  651. inv1 = ALLOC(int,maxvar);
  652. if (inv1 == NULL) {
  653. return(0);
  654. }
  655. inv2 = ALLOC(int,maxvar);
  656. if (inv2 == NULL) {
  657. FREE(inv1);
  658. return(0);
  659. }
  660. /* Choose two orders from the population using roulette wheel. */
  661. if (!roulette(&mom,&dad)) {
  662. FREE(inv1);
  663. FREE(inv2);
  664. return(0);
  665. }
  666. /* Choose two random cut positions. A cut in position i means that
  667. ** the cut immediately precedes position i. If cut1 < cut2, we
  668. ** exchange the middle of the two orderings; otherwise, we
  669. ** exchange the beginnings and the ends.
  670. */
  671. cut1 = rand_int(numvars-1);
  672. do {
  673. cut2 = rand_int(numvars-1);
  674. } while (cut1 == cut2);
  675. #if 0
  676. /* Print out the parents. */
  677. (void) fprintf(table->out,
  678. "Crossover of %d (mom) and %d (dad) between %d and %d\n",
  679. mom,dad,cut1,cut2);
  680. for (i = 0; i < numvars; i++) {
  681. if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
  682. (void) fprintf(table->out,"%2d ",STOREDD(mom,i));
  683. }
  684. (void) fprintf(table->out,"\n");
  685. for (i = 0; i < numvars; i++) {
  686. if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
  687. (void) fprintf(table->out,"%2d ",STOREDD(dad,i));
  688. }
  689. (void) fprintf(table->out,"\n");
  690. #endif
  691. /* Initialize the inverse permutations: -1 means yet undetermined. */
  692. for (i = 0; i < maxvar; i++) {
  693. inv1[i] = -1;
  694. inv2[i] = -1;
  695. }
  696. /* Copy the portions whithin the cuts. */
  697. for (i = cut1; i != cut2; i = (i == numvars-1) ? 0 : i+1) {
  698. STOREDD(popsize,i) = STOREDD(dad,i);
  699. inv1[STOREDD(popsize,i)] = i;
  700. STOREDD(popsize+1,i) = STOREDD(mom,i);
  701. inv2[STOREDD(popsize+1,i)] = i;
  702. }
  703. /* Now apply the repair algorithm outside the cuts. */
  704. for (i = cut2; i != cut1; i = (i == numvars-1 ) ? 0 : i+1) {
  705. v = i;
  706. do {
  707. u = STOREDD(mom,v);
  708. v = inv1[u];
  709. } while (v != -1);
  710. STOREDD(popsize,i) = u;
  711. inv1[u] = i;
  712. v = i;
  713. do {
  714. u = STOREDD(dad,v);
  715. v = inv2[u];
  716. } while (v != -1);
  717. STOREDD(popsize+1,i) = u;
  718. inv2[u] = i;
  719. }
  720. #if 0
  721. /* Print the results of crossover. */
  722. for (i = 0; i < numvars; i++) {
  723. if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
  724. (void) fprintf(table->out,"%2d ",STOREDD(popsize,i));
  725. }
  726. (void) fprintf(table->out,"\n");
  727. for (i = 0; i < numvars; i++) {
  728. if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
  729. (void) fprintf(table->out,"%2d ",STOREDD(popsize+1,i));
  730. }
  731. (void) fprintf(table->out,"\n");
  732. #endif
  733. FREE(inv1);
  734. FREE(inv2);
  735. return(1);
  736. } /* end of PMX */
  737. /**Function********************************************************************
  738. Synopsis [Selects two parents with the roulette wheel method.]
  739. Description [Selects two distinct parents with the roulette wheel method.]
  740. SideEffects [The indices of the selected parents are returned as side
  741. effects.]
  742. SeeAlso []
  743. ******************************************************************************/
  744. static int
  745. roulette(
  746. int * p1,
  747. int * p2)
  748. {
  749. double *wheel;
  750. double spin;
  751. int i;
  752. wheel = ALLOC(double,popsize);
  753. if (wheel == NULL) {
  754. return(0);
  755. }
  756. /* The fitness of an individual is the reciprocal of its size. */
  757. wheel[0] = 1.0 / (double) STOREDD(0,numvars);
  758. for (i = 1; i < popsize; i++) {
  759. wheel[i] = wheel[i-1] + 1.0 / (double) STOREDD(i,numvars);
  760. }
  761. /* Get a random number between 0 and wheel[popsize-1] (that is,
  762. ** the sum of all fitness values. 2147483561 is the largest number
  763. ** returned by Cudd_Random.
  764. */
  765. spin = wheel[numvars-1] * (double) Cudd_Random() / 2147483561.0;
  766. /* Find the lucky element by scanning the wheel. */
  767. for (i = 0; i < popsize; i++) {
  768. if (spin <= wheel[i]) break;
  769. }
  770. *p1 = i;
  771. /* Repeat the process for the second parent, making sure it is
  772. ** distinct from the first.
  773. */
  774. do {
  775. spin = wheel[popsize-1] * (double) Cudd_Random() / 2147483561.0;
  776. for (i = 0; i < popsize; i++) {
  777. if (spin <= wheel[i]) break;
  778. }
  779. } while (i == *p1);
  780. *p2 = i;
  781. FREE(wheel);
  782. return(1);
  783. } /* end of roulette */