00001
00083 #include "util.h"
00084 #include "cuddInt.h"
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 #ifndef lint
00103 static char rcsid[] DD_UNUSED = "$Id: cuddGenetic.c,v 1.28 2004/08/13 18:04:48 fabio Exp $";
00104 #endif
00105
00106 static int popsize;
00107 static int numvars;
00108
00109
00110
00111
00112
00113
00114
00115
00116 static int *storedd;
00117 static st_table *computed;
00118 static int *repeat;
00119 static int large;
00120
00121 static int result;
00122 static int cross;
00123
00124
00125
00126
00127
00128
00129
00130
00131 #define STOREDD(i,j) storedd[(i)*(numvars+1)+(j)]
00132
00133 #ifdef __cplusplus
00134 extern "C" {
00135 #endif
00136
00139
00140
00141
00142
00143 static int make_random (DdManager *table, int lower);
00144 static int sift_up (DdManager *table, int x, int x_low);
00145 static int build_dd (DdManager *table, int num, int lower, int upper);
00146 static int largest (void);
00147 static int rand_int (int a);
00148 static int array_hash (char *array, int modulus);
00149 static int array_compare (const char *array1, const char *array2);
00150 static int find_best (void);
00151 #ifdef DD_STATS
00152 static double find_average_fitness (void);
00153 #endif
00154 static int PMX (int maxvar);
00155 static int roulette (int *p1, int *p2);
00156
00159 #ifdef __cplusplus
00160 }
00161 #endif
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00187 int
00188 cuddGa(
00189 DdManager * table ,
00190 int lower ,
00191 int upper )
00192 {
00193 int i,n,m;
00194 int index;
00195 #ifdef DD_STATS
00196 double average_fitness;
00197 #endif
00198 int small;
00199
00200
00201 if (!cuddSifting(table,lower,upper)) return(0);
00202
00203
00204 numvars = upper - lower + 1;
00205 if (table->populationSize == 0) {
00206 popsize = 3 * numvars;
00207 if (popsize > 120) {
00208 popsize = 120;
00209 }
00210 } else {
00211 popsize = table->populationSize;
00212 }
00213 if (popsize < 4) popsize = 4;
00214
00215
00216 storedd = ALLOC(int,(popsize+2)*(numvars+1));
00217 if (storedd == NULL) {
00218 table->errorCode = CUDD_MEMORY_OUT;
00219 return(0);
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 repeat = ALLOC(int,popsize);
00231 if (repeat == NULL) {
00232 table->errorCode = CUDD_MEMORY_OUT;
00233 FREE(storedd);
00234 return(0);
00235 }
00236 for (i = 0; i < popsize; i++) {
00237 repeat[i] = 0;
00238 }
00239 computed = st_init_table(array_compare,array_hash);
00240 if (computed == NULL) {
00241 table->errorCode = CUDD_MEMORY_OUT;
00242 FREE(storedd);
00243 FREE(repeat);
00244 return(0);
00245 }
00246
00247
00248 for (i = 0; i < numvars; i++) {
00249 STOREDD(0,i) = table->invperm[i+lower];
00250 }
00251 STOREDD(0,numvars) = table->keys - table->isolated;
00252
00253
00254 if (st_insert(computed,(char *)storedd,(char *) 0) == ST_OUT_OF_MEM) {
00255 FREE(storedd);
00256 FREE(repeat);
00257 st_free_table(computed);
00258 return(0);
00259 }
00260 repeat[0]++;
00261
00262
00263 for (i = 0; i < numvars; i++) {
00264 STOREDD(1,numvars-1-i) = table->invperm[i+lower];
00265 }
00266
00267
00268
00269
00270
00271
00272 if (!make_random(table,lower)) {
00273 table->errorCode = CUDD_MEMORY_OUT;
00274 FREE(storedd);
00275 FREE(repeat);
00276 st_free_table(computed);
00277 return(0);
00278 }
00279 for (i = 1; i < popsize; i++) {
00280 result = build_dd(table,i,lower,upper);
00281 if (!result) {
00282 FREE(storedd);
00283 FREE(repeat);
00284 st_free_table(computed);
00285 return(0);
00286 }
00287 if (st_lookup_int(computed,(char *)&STOREDD(i,0),&index)) {
00288 repeat[index]++;
00289 } else {
00290 if (st_insert(computed,(char *)&STOREDD(i,0),(char *)(long)i) ==
00291 ST_OUT_OF_MEM) {
00292 FREE(storedd);
00293 FREE(repeat);
00294 st_free_table(computed);
00295 return(0);
00296 }
00297 repeat[i]++;
00298 }
00299 }
00300
00301 #if 0
00302 #ifdef DD_STATS
00303
00304 (void) fprintf(table->out,"Initial population after sifting\n");
00305 for (m = 0; m < popsize; m++) {
00306 for (i = 0; i < numvars; i++) {
00307 (void) fprintf(table->out," %2d",STOREDD(m,i));
00308 }
00309 (void) fprintf(table->out," : %3d (%d)\n",
00310 STOREDD(m,numvars),repeat[m]);
00311 }
00312 #endif
00313 #endif
00314
00315 small = find_best();
00316 #ifdef DD_STATS
00317 average_fitness = find_average_fitness();
00318 (void) fprintf(table->out,"\nInitial population: best fitness = %d, average fitness %8.3f",STOREDD(small,numvars),average_fitness);
00319 #endif
00320
00321
00322 if (table->numberXovers == 0) {
00323 cross = 3*numvars;
00324 if (cross > 60) {
00325 cross = 60;
00326 }
00327 } else {
00328 cross = table->numberXovers;
00329 }
00330
00331
00332 for (m = 0; m < cross; m++) {
00333 if (!PMX(table->size)) {
00334 table->errorCode = CUDD_MEMORY_OUT;
00335 FREE(storedd);
00336 FREE(repeat);
00337 st_free_table(computed);
00338 return(0);
00339 }
00340
00341
00342
00343 for (i = popsize; i <= popsize+1; i++) {
00344 result = build_dd(table,i,lower,upper);
00345 if (!result) {
00346 FREE(storedd);
00347 FREE(repeat);
00348 st_free_table(computed);
00349 return(0);
00350 }
00351 large = largest();
00352
00353
00354
00355
00356
00357 if (STOREDD(i,numvars) < STOREDD(large,numvars)) {
00358
00359
00360
00361
00362 result = st_lookup_int(computed,(char *)&STOREDD(large,0),
00363 &index);
00364 if (!result) {
00365 FREE(storedd);
00366 FREE(repeat);
00367 st_free_table(computed);
00368 return(0);
00369 }
00370 repeat[index]--;
00371 if (repeat[index] == 0) {
00372 int *pointer = &STOREDD(index,0);
00373 result = st_delete(computed, &pointer, NULL);
00374 if (!result) {
00375 FREE(storedd);
00376 FREE(repeat);
00377 st_free_table(computed);
00378 return(0);
00379 }
00380 }
00381
00382
00383
00384
00385 for (n = 0; n <= numvars; n++) {
00386 STOREDD(large,n) = STOREDD(i,n);
00387 }
00388 if (st_lookup_int(computed,(char *)&STOREDD(large,0),
00389 &index)) {
00390 repeat[index]++;
00391 } else {
00392 if (st_insert(computed,(char *)&STOREDD(large,0),
00393 (char *)(long)large) == ST_OUT_OF_MEM) {
00394 FREE(storedd);
00395 FREE(repeat);
00396 st_free_table(computed);
00397 return(0);
00398 }
00399 repeat[large]++;
00400 }
00401 }
00402 }
00403 }
00404
00405
00406
00407
00408 small = find_best();
00409
00410
00411 #ifdef DD_STATS
00412 average_fitness = find_average_fitness();
00413 (void) fprintf(table->out,"\nFinal population: best fitness = %d, average fitness %8.3f",STOREDD(small,numvars),average_fitness);
00414 #endif
00415
00416
00417 st_free_table(computed);
00418 computed = NULL;
00419 result = build_dd(table,small,lower,upper);
00420 FREE(storedd);
00421 FREE(repeat);
00422 return(result);
00423
00424 }
00425
00426
00427
00428
00429
00430
00444 static int
00445 make_random(
00446 DdManager * table,
00447 int lower)
00448 {
00449 int i,j;
00450 int *used;
00451 int next;
00452
00453 used = ALLOC(int,numvars);
00454 if (used == NULL) {
00455 table->errorCode = CUDD_MEMORY_OUT;
00456 return(0);
00457 }
00458 #if 0
00459 #ifdef DD_STATS
00460 (void) fprintf(table->out,"Initial population before sifting\n");
00461 for (i = 0; i < 2; i++) {
00462 for (j = 0; j < numvars; j++) {
00463 (void) fprintf(table->out," %2d",STOREDD(i,j));
00464 }
00465 (void) fprintf(table->out,"\n");
00466 }
00467 #endif
00468 #endif
00469 for (i = 2; i < popsize; i++) {
00470 for (j = 0; j < numvars; j++) {
00471 used[j] = 0;
00472 }
00473
00474
00475
00476 for (j = 0; j < numvars; j++) {
00477 do {
00478 next = rand_int(numvars-1);
00479 } while (used[next] != 0);
00480 used[next] = 1;
00481 STOREDD(i,j) = table->invperm[next+lower];
00482 }
00483 #if 0
00484 #ifdef DD_STATS
00485
00486 for (j = 0; j < numvars; j++) {
00487 (void) fprintf(table->out," %2d",STOREDD(i,j));
00488 }
00489 (void) fprintf(table->out,"\n");
00490 #endif
00491 #endif
00492 }
00493 FREE(used);
00494 return(1);
00495
00496 }
00497
00498
00512 static int
00513 sift_up(
00514 DdManager * table,
00515 int x,
00516 int x_low)
00517 {
00518 int y;
00519 int size;
00520
00521 y = cuddNextLow(table,x);
00522 while (y >= x_low) {
00523 size = cuddSwapInPlace(table,y,x);
00524 if (size == 0) {
00525 return(0);
00526 }
00527 x = y;
00528 y = cuddNextLow(table,x);
00529 }
00530 return(1);
00531
00532 }
00533
00534
00548 static int
00549 build_dd(
00550 DdManager * table,
00551 int num ,
00552 int lower,
00553 int upper)
00554 {
00555 int i,j;
00556 int position;
00557 int index;
00558 int limit;
00559 int size;
00560
00561
00562
00563
00564 if (computed && st_lookup_int(computed,(char *)&STOREDD(num,0),&index)) {
00565 STOREDD(num,numvars) = STOREDD(index,numvars);
00566 #ifdef DD_STATS
00567 (void) fprintf(table->out,"\nCache hit for index %d", index);
00568 #endif
00569 return(1);
00570 }
00571
00572
00573 limit = 20 * STOREDD(0,numvars);
00574
00575
00576
00577
00578
00579
00580 for (j = 0; j < numvars; j++) {
00581 i = STOREDD(num,j);
00582 position = table->perm[i];
00583 result = sift_up(table,position,j+lower);
00584 if (!result) return(0);
00585 size = table->keys - table->isolated;
00586 if (size > limit) break;
00587 }
00588
00589
00590 #ifdef DD_STATS
00591 (void) fprintf(table->out,"\n");
00592 #endif
00593 result = cuddSifting(table,lower,upper);
00594 if (!result) return(0);
00595
00596
00597 for (j = 0; j < numvars; j++) {
00598 STOREDD(num,j) = table->invperm[lower+j];
00599 }
00600 STOREDD(num,numvars) = table->keys - table->isolated;
00601 return(1);
00602
00603 }
00604
00605
00619 static int
00620 largest(void)
00621 {
00622 int i;
00623 int big;
00624
00625 big = 0;
00626 while (repeat[big] > 1) big++;
00627 for (i = big + 1; i < popsize; i++) {
00628 if (STOREDD(i,numvars) >= STOREDD(big,numvars) && repeat[i] <= 1) {
00629 big = i;
00630 }
00631 }
00632 return(big);
00633
00634 }
00635
00636
00648 static int
00649 rand_int(
00650 int a)
00651 {
00652 return(Cudd_Random() % (a+1));
00653
00654 }
00655
00656
00669 static int
00670 array_hash(
00671 char * array,
00672 int modulus)
00673 {
00674 int val = 0;
00675 int i;
00676 int *intarray;
00677
00678 intarray = (int *) array;
00679
00680 for (i = 0; i < numvars; i++) {
00681 val = val * 997 + intarray[i];
00682 }
00683
00684 return ((val < 0) ? -val : val) % modulus;
00685
00686 }
00687
00688
00701 static int
00702 array_compare(
00703 const char * array1,
00704 const char * array2)
00705 {
00706 int i;
00707 int *intarray1, *intarray2;
00708
00709 intarray1 = (int *) array1;
00710 intarray2 = (int *) array2;
00711
00712 for (i = 0; i < numvars; i++) {
00713 if (intarray1[i] != intarray2[i]) return(1);
00714 }
00715 return(0);
00716
00717 }
00718
00719
00731 static int
00732 find_best(void)
00733 {
00734 int i,small;
00735
00736 small = 0;
00737 for (i = 1; i < popsize; i++) {
00738 if (STOREDD(i,numvars) < STOREDD(small,numvars)) {
00739 small = i;
00740 }
00741 }
00742 return(small);
00743
00744 }
00745
00746
00758 #ifdef DD_STATS
00759 static double
00760 find_average_fitness(void)
00761 {
00762 int i;
00763 int total_fitness = 0;
00764 double average_fitness;
00765
00766 for (i = 0; i < popsize; i++) {
00767 total_fitness += STOREDD(i,numvars);
00768 }
00769 average_fitness = (double) total_fitness / (double) popsize;
00770 return(average_fitness);
00771
00772 }
00773 #endif
00774
00775
00789 static int
00790 PMX(
00791 int maxvar)
00792 {
00793 int cut1,cut2;
00794 int mom,dad;
00795 int *inv1;
00796 int *inv2;
00797 int i;
00798 int u,v;
00799
00800 inv1 = ALLOC(int,maxvar);
00801 if (inv1 == NULL) {
00802 return(0);
00803 }
00804 inv2 = ALLOC(int,maxvar);
00805 if (inv2 == NULL) {
00806 FREE(inv1);
00807 return(0);
00808 }
00809
00810
00811 if (!roulette(&mom,&dad)) {
00812 FREE(inv1);
00813 FREE(inv2);
00814 return(0);
00815 }
00816
00817
00818
00819
00820
00821
00822 cut1 = rand_int(numvars-1);
00823 do {
00824 cut2 = rand_int(numvars-1);
00825 } while (cut1 == cut2);
00826
00827 #if 0
00828
00829 (void) fprintf(table->out,
00830 "Crossover of %d (mom) and %d (dad) between %d and %d\n",
00831 mom,dad,cut1,cut2);
00832 for (i = 0; i < numvars; i++) {
00833 if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
00834 (void) fprintf(table->out,"%2d ",STOREDD(mom,i));
00835 }
00836 (void) fprintf(table->out,"\n");
00837 for (i = 0; i < numvars; i++) {
00838 if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
00839 (void) fprintf(table->out,"%2d ",STOREDD(dad,i));
00840 }
00841 (void) fprintf(table->out,"\n");
00842 #endif
00843
00844
00845 for (i = 0; i < maxvar; i++) {
00846 inv1[i] = -1;
00847 inv2[i] = -1;
00848 }
00849
00850
00851 for (i = cut1; i != cut2; i = (i == numvars-1) ? 0 : i+1) {
00852 STOREDD(popsize,i) = STOREDD(dad,i);
00853 inv1[STOREDD(popsize,i)] = i;
00854 STOREDD(popsize+1,i) = STOREDD(mom,i);
00855 inv2[STOREDD(popsize+1,i)] = i;
00856 }
00857
00858
00859 for (i = cut2; i != cut1; i = (i == numvars-1 ) ? 0 : i+1) {
00860 v = i;
00861 do {
00862 u = STOREDD(mom,v);
00863 v = inv1[u];
00864 } while (v != -1);
00865 STOREDD(popsize,i) = u;
00866 inv1[u] = i;
00867 v = i;
00868 do {
00869 u = STOREDD(dad,v);
00870 v = inv2[u];
00871 } while (v != -1);
00872 STOREDD(popsize+1,i) = u;
00873 inv2[u] = i;
00874 }
00875
00876 #if 0
00877
00878 for (i = 0; i < numvars; i++) {
00879 if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
00880 (void) fprintf(table->out,"%2d ",STOREDD(popsize,i));
00881 }
00882 (void) fprintf(table->out,"\n");
00883 for (i = 0; i < numvars; i++) {
00884 if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
00885 (void) fprintf(table->out,"%2d ",STOREDD(popsize+1,i));
00886 }
00887 (void) fprintf(table->out,"\n");
00888 #endif
00889
00890 FREE(inv1);
00891 FREE(inv2);
00892 return(1);
00893
00894 }
00895
00896
00909 static int
00910 roulette(
00911 int * p1,
00912 int * p2)
00913 {
00914 double *wheel;
00915 double spin;
00916 int i;
00917
00918 wheel = ALLOC(double,popsize);
00919 if (wheel == NULL) {
00920 return(0);
00921 }
00922
00923
00924 wheel[0] = 1.0 / (double) STOREDD(0,numvars);
00925
00926 for (i = 1; i < popsize; i++) {
00927 wheel[i] = wheel[i-1] + 1.0 / (double) STOREDD(i,numvars);
00928 }
00929
00930
00931
00932
00933
00934 spin = wheel[numvars-1] * (double) Cudd_Random() / 2147483561.0;
00935
00936
00937 for (i = 0; i < popsize; i++) {
00938 if (spin <= wheel[i]) break;
00939 }
00940 *p1 = i;
00941
00942
00943
00944
00945 do {
00946 spin = wheel[popsize-1] * (double) Cudd_Random() / 2147483561.0;
00947 for (i = 0; i < popsize; i++) {
00948 if (spin <= wheel[i]) break;
00949 }
00950 } while (i == *p1);
00951 *p2 = i;
00952
00953 FREE(wheel);
00954 return(1);
00955
00956 }
00957