00001
00056 #include "util_hack.h"
00057 #include "cuddInt.h"
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 #ifndef lint
00076 static char rcsid[] DD_UNUSED = "$Id: cuddGenetic.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
00077 #endif
00078
00079 static int popsize;
00080 static int numvars;
00081
00082
00083
00084
00085
00086
00087
00088
00089 static int *storedd;
00090 static st_table *computed;
00091 static int *repeat;
00092 static int large;
00093
00094 static int result;
00095 static int cross;
00096
00097
00098
00099
00100
00101
00102
00103
00104 #define STOREDD(i,j) storedd[(i)*(numvars+1)+(j)]
00105
00106
00109
00110
00111
00112
00113 static int make_random ARGS((DdManager *table, int lower));
00114 static int sift_up ARGS((DdManager *table, int x, int x_low));
00115 static int build_dd ARGS((DdManager *table, int num, int lower, int upper));
00116 static int largest ARGS(());
00117 static int rand_int ARGS((int a));
00118 static int array_hash ARGS((char *array, int modulus));
00119 static int array_compare ARGS((const char *array1, const char *array2));
00120 static int find_best ARGS(());
00121 static double find_average_fitness ARGS(());
00122 static int PMX ARGS((int maxvar));
00123 static int roulette ARGS((int *p1, int *p2));
00124
00128
00129
00130
00131
00132
00133
00134
00135
00136
00152 int
00153 cuddGa(
00154 DdManager * table ,
00155 int lower ,
00156 int upper )
00157 {
00158 int i,n,m;
00159 int index;
00160 double average_fitness;
00161 int small;
00162
00163
00164 if (!cuddSifting(table,lower,upper)) return(0);
00165
00166
00167 numvars = upper - lower + 1;
00168 if (table->populationSize == 0) {
00169 popsize = 3 * numvars;
00170 if (popsize > 120) {
00171 popsize = 120;
00172 }
00173 } else {
00174 popsize = table->populationSize;
00175 }
00176 if (popsize < 4) popsize = 4;
00177
00178
00179 storedd = ALLOC(int,(popsize+2)*(numvars+1));
00180 if (storedd == NULL) {
00181 table->errorCode = CUDD_MEMORY_OUT;
00182 return(0);
00183 }
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193 repeat = ALLOC(int,popsize);
00194 if (repeat == NULL) {
00195 table->errorCode = CUDD_MEMORY_OUT;
00196 FREE(storedd);
00197 return(0);
00198 }
00199 for (i = 0; i < popsize; i++) {
00200 repeat[i] = 0;
00201 }
00202 computed = st_init_table(array_compare,array_hash);
00203 if (computed == NULL) {
00204 table->errorCode = CUDD_MEMORY_OUT;
00205 FREE(storedd);
00206 FREE(repeat);
00207 return(0);
00208 }
00209
00210
00211 for (i = 0; i < numvars; i++) {
00212 STOREDD(0,i) = table->invperm[i+lower];
00213 }
00214 STOREDD(0,numvars) = table->keys - table->isolated;
00215
00216
00217 if (st_insert(computed,(char *)storedd,(char *) 0) == ST_OUT_OF_MEM) {
00218 FREE(storedd);
00219 FREE(repeat);
00220 st_free_table(computed);
00221 return(0);
00222 }
00223 repeat[0]++;
00224
00225
00226 for (i = 0; i < numvars; i++) {
00227 STOREDD(1,numvars-1-i) = table->invperm[i+lower];
00228 }
00229
00230
00231
00232
00233
00234
00235 if (!make_random(table,lower)) {
00236 table->errorCode = CUDD_MEMORY_OUT;
00237 FREE(storedd);
00238 FREE(repeat);
00239 st_free_table(computed);
00240 return(0);
00241 }
00242 for (i = 1; i < popsize; i++) {
00243 result = build_dd(table,i,lower,upper);
00244 if (!result) {
00245 FREE(storedd);
00246 FREE(repeat);
00247 st_free_table(computed);
00248 return(0);
00249 }
00250 if (st_lookup(computed,(char *)&STOREDD(i,0),(char **)&index)) {
00251 repeat[index]++;
00252 } else {
00253 if (st_insert(computed,(char *)&STOREDD(i,0),(char *)(long)i) ==
00254 ST_OUT_OF_MEM) {
00255 FREE(storedd);
00256 FREE(repeat);
00257 st_free_table(computed);
00258 return(0);
00259 }
00260 repeat[i]++;
00261 }
00262 }
00263
00264 #if 0
00265 #ifdef DD_STATS
00266
00267 (void) fprintf(table->out,"Initial population after sifting\n");
00268 for (m = 0; m < popsize; m++) {
00269 for (i = 0; i < numvars; i++) {
00270 (void) fprintf(table->out," %2d",STOREDD(m,i));
00271 }
00272 (void) fprintf(table->out," : %3d (%d)\n",
00273 STOREDD(m,numvars),repeat[m]);
00274 }
00275 #endif
00276 #endif
00277
00278 small = find_best();
00279 average_fitness = find_average_fitness();
00280 #ifdef DD_STATS
00281 (void) fprintf(table->out,"\nInitial population: best fitness = %d, average fitness %8.3f",STOREDD(small,numvars),average_fitness);
00282 #endif
00283
00284
00285 if (table->numberXovers == 0) {
00286 cross = 3*numvars;
00287 if (cross > 60) {
00288 cross = 60;
00289 }
00290 } else {
00291 cross = table->numberXovers;
00292 }
00293
00294
00295 for (m = 0; m < cross; m++) {
00296 if (!PMX(table->size)) {
00297 table->errorCode = CUDD_MEMORY_OUT;
00298 FREE(storedd);
00299 FREE(repeat);
00300 st_free_table(computed);
00301 return(0);
00302 }
00303
00304
00305
00306 for (i = popsize; i <= popsize+1; i++) {
00307 result = build_dd(table,i,lower,upper);
00308 if (!result) {
00309 FREE(storedd);
00310 FREE(repeat);
00311 st_free_table(computed);
00312 return(0);
00313 }
00314 large = largest();
00315
00316
00317
00318
00319
00320 if (STOREDD(i,numvars) < STOREDD(large,numvars)) {
00321
00322
00323
00324
00325 result = st_lookup(computed,(char *)&STOREDD(large,0),(char
00326 **)&index);
00327 if (!result) {
00328 FREE(storedd);
00329 FREE(repeat);
00330 st_free_table(computed);
00331 return(0);
00332 }
00333 repeat[index]--;
00334 if (repeat[index] == 0) {
00335 int *pointer = &STOREDD(index,0);
00336 result = st_delete(computed, (char **)&pointer,NULL);
00337 if (!result) {
00338 FREE(storedd);
00339 FREE(repeat);
00340 st_free_table(computed);
00341 return(0);
00342 }
00343 }
00344
00345
00346
00347
00348 for (n = 0; n <= numvars; n++) {
00349 STOREDD(large,n) = STOREDD(i,n);
00350 }
00351 if (st_lookup(computed,(char *)&STOREDD(large,0),(char
00352 **)&index)) {
00353 repeat[index]++;
00354 } else {
00355 if (st_insert(computed,(char *)&STOREDD(large,0),
00356 (char *)(long)large) == ST_OUT_OF_MEM) {
00357 FREE(storedd);
00358 FREE(repeat);
00359 st_free_table(computed);
00360 return(0);
00361 }
00362 repeat[large]++;
00363 }
00364 }
00365 }
00366 }
00367
00368
00369
00370
00371 small = find_best();
00372
00373
00374 #ifdef DD_STATS
00375 average_fitness = find_average_fitness();
00376 (void) fprintf(table->out,"\nFinal population: best fitness = %d, average fitness %8.3f",STOREDD(small,numvars),average_fitness);
00377 #endif
00378
00379
00380 st_free_table(computed);
00381 computed = NULL;
00382 result = build_dd(table,small,lower,upper);
00383 FREE(storedd);
00384 FREE(repeat);
00385 return(result);
00386
00387 }
00388
00389
00390
00391
00392
00393
00407 static int
00408 make_random(
00409 DdManager * table,
00410 int lower)
00411 {
00412 int i,j;
00413 int *used;
00414 int next;
00415
00416 used = ALLOC(int,numvars);
00417 if (used == NULL) {
00418 table->errorCode = CUDD_MEMORY_OUT;
00419 return(0);
00420 }
00421 #if 0
00422 #ifdef DD_STATS
00423 (void) fprintf(table->out,"Initial population before sifting\n");
00424 for (i = 0; i < 2; i++) {
00425 for (j = 0; j < numvars; j++) {
00426 (void) fprintf(table->out," %2d",STOREDD(i,j));
00427 }
00428 (void) fprintf(table->out,"\n");
00429 }
00430 #endif
00431 #endif
00432 for (i = 2; i < popsize; i++) {
00433 for (j = 0; j < numvars; j++) {
00434 used[j] = 0;
00435 }
00436
00437
00438
00439 for (j = 0; j < numvars; j++) {
00440 do {
00441 next = rand_int(numvars-1);
00442 } while (used[next] != 0);
00443 used[next] = 1;
00444 STOREDD(i,j) = table->invperm[next+lower];
00445 }
00446 #if 0
00447 #ifdef DD_STATS
00448
00449 for (j = 0; j < numvars; j++) {
00450 (void) fprintf(table->out," %2d",STOREDD(i,j));
00451 }
00452 (void) fprintf(table->out,"\n");
00453 #endif
00454 #endif
00455 }
00456 FREE(used);
00457 return(1);
00458
00459 }
00460
00461
00475 static int
00476 sift_up(
00477 DdManager * table,
00478 int x,
00479 int x_low)
00480 {
00481 int y;
00482 int size;
00483
00484 y = cuddNextLow(table,x);
00485 while (y >= x_low) {
00486 size = cuddSwapInPlace(table,y,x);
00487 if (size == 0) {
00488 return(0);
00489 }
00490 x = y;
00491 y = cuddNextLow(table,x);
00492 }
00493 return(1);
00494
00495 }
00496
00497
00511 static int
00512 build_dd(
00513 DdManager * table,
00514 int num ,
00515 int lower,
00516 int upper)
00517 {
00518 int i,j;
00519 int position;
00520 int index;
00521 int limit;
00522 int size;
00523
00524
00525
00526
00527 if (computed && st_lookup(computed,(char *)&STOREDD(num,0),(char **)&index)) {
00528 STOREDD(num,numvars) = STOREDD(index,numvars);
00529 #ifdef DD_STATS
00530 (void) fprintf(table->out,"\nCache hit for index %d", index);
00531 #endif
00532 return(1);
00533 }
00534
00535
00536 limit = 20 * STOREDD(0,numvars);
00537
00538
00539
00540
00541
00542
00543 for (j = 0; j < numvars; j++) {
00544 i = STOREDD(num,j);
00545 position = table->perm[i];
00546 result = sift_up(table,position,j+lower);
00547 if (!result) return(0);
00548 size = table->keys - table->isolated;
00549 if (size > limit) break;
00550 }
00551
00552
00553 #ifdef DD_STATS
00554 (void) fprintf(table->out,"\n");
00555 #endif
00556 result = cuddSifting(table,lower,upper);
00557 if (!result) return(0);
00558
00559
00560 for (j = 0; j < numvars; j++) {
00561 STOREDD(num,j) = table->invperm[lower+j];
00562 }
00563 STOREDD(num,numvars) = table->keys - table->isolated;
00564 return(1);
00565
00566 }
00567
00568
00582 static int
00583 largest(
00584 )
00585 {
00586 int i;
00587 int big;
00588
00589 big = 0;
00590 while (repeat[big] > 1) big++;
00591 for (i = big + 1; i < popsize; i++) {
00592 if (STOREDD(i,numvars) >= STOREDD(big,numvars) && repeat[i] <= 1) {
00593 big = i;
00594 }
00595 }
00596 return(big);
00597
00598 }
00599
00600
00612 static int
00613 rand_int(
00614 int a)
00615 {
00616 return(Cudd_Random() % (a+1));
00617
00618 }
00619
00620
00633 static int
00634 array_hash(
00635 char * array,
00636 int modulus)
00637 {
00638 int val = 0;
00639 int i;
00640 int *intarray;
00641
00642 intarray = (int *) array;
00643
00644 for (i = 0; i < numvars; i++) {
00645 val = val * 997 + intarray[i];
00646 }
00647
00648 return ((val < 0) ? -val : val) % modulus;
00649
00650 }
00651
00652
00665 static int
00666 array_compare(
00667 const char * array1,
00668 const char * array2)
00669 {
00670 int i;
00671 int *intarray1, *intarray2;
00672
00673 intarray1 = (int *) array1;
00674 intarray2 = (int *) array2;
00675
00676 for (i = 0; i < numvars; i++) {
00677 if (intarray1[i] != intarray2[i]) return(1);
00678 }
00679 return(0);
00680
00681 }
00682
00683
00695 static int
00696 find_best(
00697 )
00698 {
00699 int i,small;
00700
00701 small = 0;
00702 for (i = 1; i < popsize; i++) {
00703 if (STOREDD(i,numvars) < STOREDD(small,numvars)) {
00704 small = i;
00705 }
00706 }
00707 return(small);
00708
00709 }
00710
00711
00723 static double
00724 find_average_fitness(
00725 )
00726 {
00727 int i;
00728 int total_fitness = 0;
00729 double average_fitness;
00730
00731 for (i = 0; i < popsize; i++) {
00732 total_fitness += STOREDD(i,numvars);
00733 }
00734 average_fitness = (double) total_fitness / (double) popsize;
00735 return(average_fitness);
00736
00737 }
00738
00739
00753 static int
00754 PMX(
00755 int maxvar)
00756 {
00757 int cut1,cut2;
00758 int mom,dad;
00759 int *inv1;
00760 int *inv2;
00761 int i;
00762 int u,v;
00763
00764 inv1 = ALLOC(int,maxvar);
00765 if (inv1 == NULL) {
00766 return(0);
00767 }
00768 inv2 = ALLOC(int,maxvar);
00769 if (inv2 == NULL) {
00770 FREE(inv1);
00771 return(0);
00772 }
00773
00774
00775 if (!roulette(&mom,&dad)) {
00776 FREE(inv1);
00777 FREE(inv2);
00778 return(0);
00779 }
00780
00781
00782
00783
00784
00785
00786 cut1 = rand_int(numvars-1);
00787 do {
00788 cut2 = rand_int(numvars-1);
00789 } while (cut1 == cut2);
00790
00791 #if 0
00792
00793 (void) fprintf(table->out,
00794 "Crossover of %d (mom) and %d (dad) between %d and %d\n",
00795 mom,dad,cut1,cut2);
00796 for (i = 0; i < numvars; i++) {
00797 if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
00798 (void) fprintf(table->out,"%2d ",STOREDD(mom,i));
00799 }
00800 (void) fprintf(table->out,"\n");
00801 for (i = 0; i < numvars; i++) {
00802 if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
00803 (void) fprintf(table->out,"%2d ",STOREDD(dad,i));
00804 }
00805 (void) fprintf(table->out,"\n");
00806 #endif
00807
00808
00809 for (i = 0; i < maxvar; i++) {
00810 inv1[i] = -1;
00811 inv2[i] = -1;
00812 }
00813
00814
00815 for (i = cut1; i != cut2; i = (i == numvars-1) ? 0 : i+1) {
00816 STOREDD(popsize,i) = STOREDD(dad,i);
00817 inv1[STOREDD(popsize,i)] = i;
00818 STOREDD(popsize+1,i) = STOREDD(mom,i);
00819 inv2[STOREDD(popsize+1,i)] = i;
00820 }
00821
00822
00823 for (i = cut2; i != cut1; i = (i == numvars-1 ) ? 0 : i+1) {
00824 v = i;
00825 do {
00826 u = STOREDD(mom,v);
00827 v = inv1[u];
00828 } while (v != -1);
00829 STOREDD(popsize,i) = u;
00830 inv1[u] = i;
00831 v = i;
00832 do {
00833 u = STOREDD(dad,v);
00834 v = inv2[u];
00835 } while (v != -1);
00836 STOREDD(popsize+1,i) = u;
00837 inv2[u] = i;
00838 }
00839
00840 #if 0
00841
00842 for (i = 0; i < numvars; i++) {
00843 if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
00844 (void) fprintf(table->out,"%2d ",STOREDD(popsize,i));
00845 }
00846 (void) fprintf(table->out,"\n");
00847 for (i = 0; i < numvars; i++) {
00848 if (i == cut1 || i == cut2) (void) fprintf(table->out,"|");
00849 (void) fprintf(table->out,"%2d ",STOREDD(popsize+1,i));
00850 }
00851 (void) fprintf(table->out,"\n");
00852 #endif
00853
00854 FREE(inv1);
00855 FREE(inv2);
00856 return(1);
00857
00858 }
00859
00860
00873 static int
00874 roulette(
00875 int * p1,
00876 int * p2)
00877 {
00878 double *wheel;
00879 double spin;
00880 int i;
00881
00882 wheel = ALLOC(double,popsize);
00883 if (wheel == NULL) {
00884 return(0);
00885 }
00886
00887
00888 wheel[0] = 1.0 / (double) STOREDD(0,numvars);
00889
00890 for (i = 1; i < popsize; i++) {
00891 wheel[i] = wheel[i-1] + 1.0 / (double) STOREDD(i,numvars);
00892 }
00893
00894
00895
00896
00897
00898 spin = wheel[numvars-1] * (double) Cudd_Random() / 2147483561.0;
00899
00900
00901 for (i = 0; i < popsize; i++) {
00902 if (spin <= wheel[i]) break;
00903 }
00904 *p1 = i;
00905
00906
00907
00908
00909 do {
00910 spin = wheel[popsize-1] * (double) Cudd_Random() / 2147483561.0;
00911 for (i = 0; i < popsize; i++) {
00912 if (spin <= wheel[i]) break;
00913 }
00914 } while (i == *p1);
00915 *p2 = i;
00916
00917 FREE(wheel);
00918 return(1);
00919
00920 }
00921