The source code and dockerfile for the GSW2024 AI Lab.
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.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

904 lines
26 KiB

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