/* NETGEN -- Copyright 1989, Massimo A. Sivilotti, Caltech */ #include "config.h" #include #include #include "hash.h" #include "objlist.h" #include "embed.h" #include "timing.h" #include "print.h" #include "dbug.h" int MaxCPUTime = 100; /* max number of seconds to burn */ #define MAX_SIM_ANNEAL_ITER 10 #define MAX_CHANGES_PER_ITER 2 #if 0 float RandomUniform(void) { /* DANGER! DANGER! Non-portable code below!! */ return ((float)(rand()) / ((1<<15) - 1.0)); } #endif int GenerateAnnealPartition(int left, int right, int level) /* tries to find a balanced partition, as far as leaf cell usage */ { int i; int IncludedElements, partition; int ChangesMade, Iterations; int leftfanout, rightfanout; float T; level++; /* just to keep to compiler from whining about unused parameter */ IncludedElements = (right - left) / 2; partition = left + IncludedElements - 1; /* don't actually use {left,right}fanout, but need to initialize leftnodes and rightnodes arrays */ leftfanout = PartitionFanout(left, partition, LEFT); rightfanout = PartitionFanout(partition + 1, right, RIGHT); #if 0 /* someday, need an escape clause here */ if (leftfanout <= TreeFanout[level] && rightfanout <= TreeFanout[level]) return(partition); #endif Printf("called generateannealpartition with left = %d, right = %d\n",left,right); /* actually do the annealing now */ T = 3.0; do { int el1, el2; int delta; Iterations = 0; ChangesMade = 0; do { el1 = Random(partition - left + 1) + left; el2 = Random(right - partition) + partition + 1; Iterations++; delta = 0; for (i = 1; i <= Nodes; i++) { /* could do the following test with XOR */ if (CSTAR[permutation[el1]][i] == 0 && CSTAR[permutation[el2]][i] == 0) continue; if (CSTAR[permutation[el1]][i] != 0 && CSTAR[permutation[el2]][i] != 0) continue; /* only one of these is non-zero */ if (CSTAR[permutation[el1]][i] != 0) { if (rightnodes[i] == 0) { /* things are not good unless all the fanout is captured in el1 */ if (CSTAR[permutation[el1]][i] != leftnodes[i]) delta++; } else { /* things are good if all fanout is captured in el1 */ if (CSTAR[permutation[el1]][i] == leftnodes[i]) delta--; } } else { if (leftnodes[i] == 0) { /* things are not good unless all the fanout is captured in el2 */ if (CSTAR[permutation[el2]][i] != rightnodes[i]) delta++; } else { /* things are good if all fanout is captured in el2 */ if (CSTAR[permutation[el2]][i] == rightnodes[i]) delta--; } } } DBUG_EXECUTE("place", Printf("\n"); Printf("considering swapping %d and %d\n",permutation[el1],permutation[el2]); Printf("E1: "); for (i = 1; i <= Nodes; i++) Printf("%2d ",CSTAR[permutation[el1]][i]); Printf("\nL: "); for (i = 1; i <= Nodes; i++) Printf("%2d ",leftnodes[i]); Printf("\nE2: "); for (i = 1; i <= Nodes; i++) Printf("%2d ",CSTAR[permutation[el2]][i]); Printf("\nR: "); for (i = 1; i <= Nodes; i++) Printf("%2d ",rightnodes[i]); Printf("\nC0: "); for (i = 1; i <= Nodes; i++) Printf("%2d ",CSTAR[0][i]); Printf("\ndelta = %d\n", delta); ); if (delta < 0 || exp(-delta / T) > RandomUniform()) { int tmp; if (delta < 0) ChangesMade++; /* update the {left, right}nodes arrays */ for (i = 1; i <= Nodes; i++) { leftnodes[i] += CSTAR[permutation[el2]][i] - CSTAR[permutation[el1]][i]; rightnodes[i] -= CSTAR[permutation[el2]][i] - CSTAR[permutation[el1]][i]; } /* now swap the elements */ DBUG_EXECUTE("place", Printf("swapping elements %d and %d\n", permutation[el1],permutation[el2]); ); tmp = permutation[el1]; permutation[el1] = permutation[el2]; permutation[el2] = tmp; } } while (ChangesMade <= MAX_CHANGES_PER_ITER && Iterations < MAX_SIM_ANNEAL_ITER); T = 0.90 * T; Printf("decreasing T to %.2f after %d iterations.\n",T,Iterations); } while (ChangesMade > 0); return (partition); } int AnnealPartition(int left, int right, int level) /* return index of new element, if successful partition has been found */ { int partition; int iterations; int found; int OriginalNewN; int leftelement, rightelement; #define MAX_PARTITION_ITERATIONS 10 DBUG_ENTER("AnnealPartition"); OriginalNewN = NewN; if (level < LEVEL(permutation[left])) { Fprintf(stdout,"Failed at level %d; subtree too deep\n",level); DBUG_RETURN(0); } if (left == right) DBUG_RETURN(permutation[left]); if (right - left == 1) { /* don't bother annealing, just add it to the list */ AddNewElement(permutation[left], permutation[right]); DBUG_RETURN(NewN); } /* use simulated annealing to gather about 1/2 of the elements, Then check to see if it is valid. */ DBUG_PRINT("place",("trying to partition %d, %d",left,right)); iterations = 0; do { int i; int leftfanout, rightfanout; iterations++; partition = GenerateAnnealPartition(left, right, level); if (partition == 0) DBUG_RETURN(0); /* no valid partition */ found = 0; leftfanout = PartitionFanout(left,partition,LEFT); rightfanout = PartitionFanout(partition+1, right, RIGHT); if (leftfanout <= TreeFanout[level] && rightfanout <= TreeFanout[level]) found = 1; if (!found || level > TopDownStartLevel - 2) { for (i = MAX_TREE_DEPTH; i > level; i--) Fprintf(stdout, " "); Fprintf(stdout, "Level: %d; L (%d leaves) fanout %d; R (%d leaves) fanout %d (<= %d) %s\n", level, (partition - left + 1), leftfanout, (right - partition), rightfanout, TreeFanout[level], found ? "SUCCESSFUL" : "UNSUCCESSFUL"); } #if 0 if (!found) { int IterationLimit; for (IterationLimit = 0; IterationLimit < 20 && GradientDescent(left, right, partition); IterationLimit++); found = 0; leftfanout = PartitionFanout(left,partition,LEFT); rightfanout = PartitionFanout(partition+1, right, RIGHT); if (leftfanout <= TreeFanout[level] && rightfanout <= TreeFanout[level]) found = 1; for (i = MAX_TREE_DEPTH; i > level; i--) Fprintf(stdout, " "); Fprintf(stdout, " Iteration %2d: L fanout %d; R fanout %d (<= %d) %s\n", iterations, leftfanout, rightfanout, TreeFanout[level], found ? "SUCCESSFUL" : "UNSUCCESSFUL"); } #endif DBUG_EXECUTE("place", Fprintf(DBUG_FILE,"Level %d: ",level); Dbug_print_cells(left,partition); Dbug_print_cells(partition+1,right); Fprintf(DBUG_FILE,"\n"); { int i; Fprintf(DBUG_FILE,"L "); for (i = 1; i <= Nodes; i++) Fprintf(DBUG_FILE,"%2d ",leftnodes[i]); Fprintf(DBUG_FILE,"\nR "); for (i = 1; i <= Nodes; i++) Fprintf(DBUG_FILE,"%2d ",rightnodes[i]); Fprintf(DBUG_FILE,"\n"); } Fprintf(DBUG_FILE, "%s\n", found?"SUCCESSFUL":"UNSUCCESSFUL"); ); } while (iterations < MAX_PARTITION_ITERATIONS && !found); if (!found) { Fprintf(stdout,"Failed embedding at level %d; no partition\n",level); goto fail; } leftelement = AnnealPartition(left, partition, level-1); if (leftelement == 0) goto fail; rightelement = AnnealPartition(partition+1, right, level-1); if (rightelement == 0) goto fail; /* add it to the list */ AddNewElement(leftelement, rightelement); DBUG_RETURN(NewN); fail: NewN = OriginalNewN; DBUG_RETURN(0); }