SVF
cuddGroup.c
Go to the documentation of this file.
1 
80 #include "CUDD/util.h"
81 #include "CUDD/cuddInt.h"
82 
83 /*---------------------------------------------------------------------------*/
84 /* Constant declarations */
85 /*---------------------------------------------------------------------------*/
86 
87 /* Constants for lazy sifting */
88 #define DD_NORMAL_SIFT 0
89 #define DD_LAZY_SIFT 1
90 
91 /* Constants for sifting up and down */
92 #define DD_SIFT_DOWN 0
93 #define DD_SIFT_UP 1
94 
95 /*---------------------------------------------------------------------------*/
96 /* Stucture declarations */
97 /*---------------------------------------------------------------------------*/
98 
99 /*---------------------------------------------------------------------------*/
100 /* Type declarations */
101 /*---------------------------------------------------------------------------*/
102 
103 #ifdef __cplusplus
104 extern "C" {
105 #endif
106  typedef int (*DD_CHKFP)(DdManager *, int, int);
107 #ifdef __cplusplus
108 }
109 #endif
110 
111 /*---------------------------------------------------------------------------*/
112 /* Variable declarations */
113 /*---------------------------------------------------------------------------*/
114 
115 #ifndef lint
116 static char rcsid[] DD_UNUSED = "$Id: cuddGroup.c,v 1.49 2012/02/05 01:07:18 fabio Exp $";
117 #endif
118 
119 static int *entry;
120 extern int ddTotalNumberSwapping;
121 #ifdef DD_STATS
122 extern int ddTotalNISwaps;
123 static int extsymmcalls;
124 static int extsymm;
125 static int secdiffcalls;
126 static int secdiff;
127 static int secdiffmisfire;
128 #endif
129 #ifdef DD_DEBUG
130 static int pr = 0; /* flag to enable printing while debugging */
131  /* by depositing a 1 into it */
132 #endif
133 static unsigned int originalSize;
134 
135 /*---------------------------------------------------------------------------*/
136 /* Macro declarations */
137 /*---------------------------------------------------------------------------*/
138 
139 #ifdef __cplusplus
140 extern "C" {
141 #endif
142 
145 /*---------------------------------------------------------------------------*/
146 /* Static function prototypes */
147 /*---------------------------------------------------------------------------*/
148 
149 static int ddTreeSiftingAux (DdManager *table, MtrNode *treenode, Cudd_ReorderingType method);
150 #ifdef DD_STATS
151 static int ddCountInternalMtrNodes (DdManager *table, MtrNode *treenode);
152 #endif
153 static int ddReorderChildren (DdManager *table, MtrNode *treenode, Cudd_ReorderingType method);
154 static void ddFindNodeHiLo (DdManager *table, MtrNode *treenode, int *lower, int *upper);
155 static int ddUniqueCompareGroup (int *ptrX, int *ptrY);
156 static int ddGroupSifting (DdManager *table, int lower, int upper, DD_CHKFP checkFunction, int lazyFlag);
157 static void ddCreateGroup (DdManager *table, int x, int y);
158 static int ddGroupSiftingAux (DdManager *table, int x, int xLow, int xHigh, DD_CHKFP checkFunction, int lazyFlag);
159 static int ddGroupSiftingUp (DdManager *table, int y, int xLow, DD_CHKFP checkFunction, Move **moves);
160 static int ddGroupSiftingDown (DdManager *table, int x, int xHigh, DD_CHKFP checkFunction, Move **moves);
161 static int ddGroupMove (DdManager *table, int x, int y, Move **moves);
162 static int ddGroupMoveBackward (DdManager *table, int x, int y);
163 static int ddGroupSiftingBackward (DdManager *table, Move *moves, int size, int upFlag, int lazyFlag);
164 static void ddMergeGroups (DdManager *table, MtrNode *treenode, int low, int high);
165 static void ddDissolveGroup (DdManager *table, int x, int y);
166 static int ddNoCheck (DdManager *table, int x, int y);
167 static int ddSecDiffCheck (DdManager *table, int x, int y);
168 static int ddExtSymmCheck (DdManager *table, int x, int y);
169 static int ddVarGroupCheck (DdManager * table, int x, int y);
170 static int ddSetVarHandled (DdManager *dd, int index);
171 static int ddResetVarHandled (DdManager *dd, int index);
172 static int ddIsVarHandled (DdManager *dd, int index);
173 
176 #ifdef __cplusplus
177 }
178 #endif
179 
180 /*---------------------------------------------------------------------------*/
181 /* Definition of exported functions */
182 /*---------------------------------------------------------------------------*/
183 
184 
202 MtrNode *
204  DdManager * dd /* manager */,
205  unsigned int low /* index of the first group variable */,
206  unsigned int size /* number of variables in the group */,
207  unsigned int type /* MTR_DEFAULT or MTR_FIXED */)
208 {
209  MtrNode *group;
210  MtrNode *tree;
211  unsigned int level;
212 
213  /* If the variable does not exist yet, the position is assumed to be
214  ** the same as the index. Therefore, applications that rely on
215  ** Cudd_bddNewVarAtLevel or Cudd_addNewVarAtLevel to create new
216  ** variables have to create the variables before they group them.
217  */
218  level = (low < (unsigned int) dd->size) ? dd->perm[low] : low;
219 
220  if (level + size - 1> (int) MTR_MAXHIGH)
221  return(NULL);
222 
223  /* If the tree does not exist yet, create it. */
224  tree = dd->tree;
225  if (tree == NULL) {
226  dd->tree = tree = Mtr_InitGroupTree(0, dd->size);
227  if (tree == NULL)
228  return(NULL);
229  tree->index = dd->size == 0 ? 0 : dd->invperm[0];
230  }
231 
232  /* Extend the upper bound of the tree if necessary. This allows the
233  ** application to create groups even before the variables are created.
234  */
235  tree->size = ddMax(tree->size, ddMax(level + size, (unsigned) dd->size));
236 
237  /* Create the group. */
238  group = Mtr_MakeGroup(tree, level, size, type);
239  if (group == NULL)
240  return(NULL);
241 
242  /* Initialize the index field to the index of the variable currently
243  ** in position low. This field will be updated by the reordering
244  ** procedure to provide a handle to the group once it has been moved.
245  */
246  group->index = (MtrHalfWord) low;
247 
248  return(group);
249 
250 } /* end of Cudd_MakeTreeNode */
251 
252 
253 /*---------------------------------------------------------------------------*/
254 /* Definition of internal functions */
255 /*---------------------------------------------------------------------------*/
256 
257 
270 int
272  DdManager * table /* DD table */,
273  Cudd_ReorderingType method /* reordering method for the groups of leaves */)
274 {
275  int i;
276  int nvars;
277  int result;
278  int tempTree;
279 
280  /* If no tree is provided we create a temporary one in which all
281  ** variables are in a single group. After reordering this tree is
282  ** destroyed.
283  */
284  tempTree = table->tree == NULL;
285  if (tempTree) {
286  table->tree = Mtr_InitGroupTree(0,table->size);
287  table->tree->index = table->invperm[0];
288  }
289  nvars = table->size;
290 
291 #ifdef DD_DEBUG
292  if (pr > 0 && !tempTree) (void) fprintf(table->out,"cuddTreeSifting:");
293  Mtr_PrintGroups(table->tree,pr <= 0);
294 #endif
295 
296 #ifdef DD_STATS
297  extsymmcalls = 0;
298  extsymm = 0;
299  secdiffcalls = 0;
300  secdiff = 0;
301  secdiffmisfire = 0;
302 
303  (void) fprintf(table->out,"\n");
304  if (!tempTree)
305  (void) fprintf(table->out,"#:IM_NODES %8d: group tree nodes\n",
306  ddCountInternalMtrNodes(table,table->tree));
307 #endif
308 
309  /* Initialize the group of each subtable to itself. Initially
310  ** there are no groups. Groups are created according to the tree
311  ** structure in postorder fashion.
312  */
313  for (i = 0; i < nvars; i++)
314  table->subtables[i].next = i;
315 
316 
317  /* Reorder. */
318  result = ddTreeSiftingAux(table, table->tree, method);
319 
320 #ifdef DD_STATS /* print stats */
321  if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
322  (table->groupcheck == CUDD_GROUP_CHECK7 ||
323  table->groupcheck == CUDD_GROUP_CHECK5)) {
324  (void) fprintf(table->out,"\nextsymmcalls = %d\n",extsymmcalls);
325  (void) fprintf(table->out,"extsymm = %d",extsymm);
326  }
327  if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
328  table->groupcheck == CUDD_GROUP_CHECK7) {
329  (void) fprintf(table->out,"\nsecdiffcalls = %d\n",secdiffcalls);
330  (void) fprintf(table->out,"secdiff = %d\n",secdiff);
331  (void) fprintf(table->out,"secdiffmisfire = %d",secdiffmisfire);
332  }
333 #endif
334 
335  if (tempTree)
336  Cudd_FreeTree(table);
337  else
338  Mtr_ReorderGroups(table->tree, table->perm);
339 
340  return(result);
341 
342 } /* end of cuddTreeSifting */
343 
344 
345 /*---------------------------------------------------------------------------*/
346 /* Definition of static functions */
347 /*---------------------------------------------------------------------------*/
348 
349 
360 static int
362  DdManager * table,
363  MtrNode * treenode,
364  Cudd_ReorderingType method)
365 {
366  MtrNode *auxnode;
367  int res;
368  Cudd_AggregationType saveCheck;
369 
370 #ifdef DD_DEBUG
371  Mtr_PrintGroups(treenode,1);
372 #endif
373 
374  auxnode = treenode;
375  while (auxnode != NULL) {
376  if (auxnode->child != NULL) {
377  if (!ddTreeSiftingAux(table, auxnode->child, method))
378  return(0);
379  saveCheck = table->groupcheck;
380  table->groupcheck = CUDD_NO_CHECK;
381  if (method != CUDD_REORDER_LAZY_SIFT)
382  res = ddReorderChildren(table, auxnode, CUDD_REORDER_GROUP_SIFT);
383  else
384  res = ddReorderChildren(table, auxnode, CUDD_REORDER_LAZY_SIFT);
385  table->groupcheck = saveCheck;
386 
387  if (res == 0)
388  return(0);
389  } else if (auxnode->size > 1) {
390  if (!ddReorderChildren(table, auxnode, method))
391  return(0);
392  }
393  auxnode = auxnode->younger;
394  }
395 
396  return(1);
397 
398 } /* end of ddTreeSiftingAux */
399 
400 
401 #ifdef DD_STATS
402 
412 static int
413 ddCountInternalMtrNodes(
414  DdManager * table,
415  MtrNode * treenode)
416 {
417  MtrNode *auxnode;
418  int count,nodeCount;
419 
420 
421  nodeCount = 0;
422  auxnode = treenode;
423  while (auxnode != NULL) {
424  if (!(MTR_TEST(auxnode,MTR_TERMINAL))) {
425  nodeCount++;
426  count = ddCountInternalMtrNodes(table,auxnode->child);
427  nodeCount += count;
428  }
429  auxnode = auxnode->younger;
430  }
431 
432  return(nodeCount);
433 
434 } /* end of ddCountInternalMtrNodes */
435 #endif
436 
437 
452 static int
454  DdManager * table,
455  MtrNode * treenode,
456  Cudd_ReorderingType method)
457 {
458  int lower;
459  int upper;
460  int result;
461  unsigned int initialSize;
462 
463  ddFindNodeHiLo(table,treenode,&lower,&upper);
464  /* If upper == -1 these variables do not exist yet. */
465  if (upper == -1)
466  return(1);
467 
468  if (treenode->flags == MTR_FIXED) {
469  result = 1;
470  } else {
471 #ifdef DD_STATS
472  (void) fprintf(table->out," ");
473 #endif
474  switch (method) {
475  case CUDD_REORDER_RANDOM:
477  result = cuddSwapping(table,lower,upper,method);
478  break;
479  case CUDD_REORDER_SIFT:
480  result = cuddSifting(table,lower,upper);
481  break;
483  do {
484  initialSize = table->keys - table->isolated;
485  result = cuddSifting(table,lower,upper);
486  if (initialSize <= table->keys - table->isolated)
487  break;
488 #ifdef DD_STATS
489  else
490  (void) fprintf(table->out,"\n");
491 #endif
492  } while (result != 0);
493  break;
495  result = cuddSymmSifting(table,lower,upper);
496  break;
498  result = cuddSymmSiftingConv(table,lower,upper);
499  break;
501  if (table->groupcheck == CUDD_NO_CHECK) {
502  result = ddGroupSifting(table,lower,upper,ddNoCheck,
504  } else if (table->groupcheck == CUDD_GROUP_CHECK5) {
505  result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
507  } else if (table->groupcheck == CUDD_GROUP_CHECK7) {
508  result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
510  } else {
511  (void) fprintf(table->err,
512  "Unknown group ckecking method\n");
513  result = 0;
514  }
515  break;
517  do {
518  initialSize = table->keys - table->isolated;
519  if (table->groupcheck == CUDD_NO_CHECK) {
520  result = ddGroupSifting(table,lower,upper,ddNoCheck,
522  } else if (table->groupcheck == CUDD_GROUP_CHECK5) {
523  result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
525  } else if (table->groupcheck == CUDD_GROUP_CHECK7) {
526  result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
528  } else {
529  (void) fprintf(table->err,
530  "Unknown group ckecking method\n");
531  result = 0;
532  }
533 #ifdef DD_STATS
534  (void) fprintf(table->out,"\n");
535 #endif
536  result = cuddWindowReorder(table,lower,upper,
538  if (initialSize <= table->keys - table->isolated)
539  break;
540 #ifdef DD_STATS
541  else
542  (void) fprintf(table->out,"\n");
543 #endif
544  } while (result != 0);
545  break;
552  result = cuddWindowReorder(table,lower,upper,method);
553  break;
555  result = cuddAnnealing(table,lower,upper);
556  break;
558  result = cuddGa(table,lower,upper);
559  break;
560  case CUDD_REORDER_LINEAR:
561  result = cuddLinearAndSifting(table,lower,upper);
562  break;
564  do {
565  initialSize = table->keys - table->isolated;
566  result = cuddLinearAndSifting(table,lower,upper);
567  if (initialSize <= table->keys - table->isolated)
568  break;
569 #ifdef DD_STATS
570  else
571  (void) fprintf(table->out,"\n");
572 #endif
573  } while (result != 0);
574  break;
575  case CUDD_REORDER_EXACT:
576  result = cuddExact(table,lower,upper);
577  break;
579  result = ddGroupSifting(table,lower,upper,ddVarGroupCheck,
580  DD_LAZY_SIFT);
581  break;
582  default:
583  return(0);
584  }
585  }
586 
587  /* Create a single group for all the variables that were sifted,
588  ** so that they will be treated as a single block by successive
589  ** invocations of ddGroupSifting.
590  */
591  ddMergeGroups(table,treenode,lower,upper);
592 
593 #ifdef DD_DEBUG
594  if (pr > 0) (void) fprintf(table->out,"ddReorderChildren:");
595 #endif
596 
597  return(result);
598 
599 } /* end of ddReorderChildren */
600 
601 
616 static void
618  DdManager * table,
619  MtrNode * treenode,
620  int * lower,
621  int * upper)
622 {
623  int low;
624  int high;
625 
626  /* Check whether no variables in this group already exist.
627  ** If so, return immediately. The calling procedure will know from
628  ** the values of upper that no reordering is needed.
629  */
630  if ((int) treenode->low >= table->size) {
631  *lower = table->size;
632  *upper = -1;
633  return;
634  }
635 
636  *lower = low = (unsigned int) table->perm[treenode->index];
637  high = (int) (low + treenode->size - 1);
638 
639  if (high >= table->size) {
640  /* This is the case of a partially existing group. The aim is to
641  ** reorder as many variables as safely possible. If the tree
642  ** node is terminal, we just reorder the subset of the group
643  ** that is currently in existence. If the group has
644  ** subgroups, then we only reorder those subgroups that are
645  ** fully instantiated. This way we avoid breaking up a group.
646  */
647  MtrNode *auxnode = treenode->child;
648  if (auxnode == NULL) {
649  *upper = (unsigned int) table->size - 1;
650  } else {
651  /* Search the subgroup that strands the table->size line.
652  ** If the first group starts at 0 and goes past table->size
653  ** upper will get -1, thus correctly signaling that no reordering
654  ** should take place.
655  */
656  while (auxnode != NULL) {
657  int thisLower = table->perm[auxnode->low];
658  int thisUpper = thisLower + auxnode->size - 1;
659  if (thisUpper >= table->size && thisLower < table->size)
660  *upper = (unsigned int) thisLower - 1;
661  auxnode = auxnode->younger;
662  }
663  }
664  } else {
665  /* Normal case: All the variables of the group exist. */
666  *upper = (unsigned int) high;
667  }
668 
669 #ifdef DD_DEBUG
670  /* Make sure that all variables in group are contiguous. */
671  assert(treenode->size >= *upper - *lower + 1);
672 #endif
673 
674  return;
675 
676 } /* end of ddFindNodeHiLo */
677 
678 
691 static int
693  int * ptrX,
694  int * ptrY)
695 {
696 #if 0
697  if (entry[*ptrY] == entry[*ptrX]) {
698  return((*ptrX) - (*ptrY));
699  }
700 #endif
701  return(entry[*ptrY] - entry[*ptrX]);
702 
703 } /* end of ddUniqueCompareGroup */
704 
705 
719 static int
721  DdManager * table,
722  int lower,
723  int upper,
724  DD_CHKFP checkFunction,
725  int lazyFlag)
726 {
727  int *var;
728  int i,j,x,xInit;
729  int nvars;
730  int classes;
731  int result;
732  int *sifted;
733  int merged;
734  int dissolve;
735 #ifdef DD_STATS
736  unsigned previousSize;
737 #endif
738  int xindex;
739 
740  nvars = table->size;
741 
742  /* Order variables to sift. */
743  entry = NULL;
744  sifted = NULL;
745  var = ALLOC(int,nvars);
746  if (var == NULL) {
747  table->errorCode = CUDD_MEMORY_OUT;
748  goto ddGroupSiftingOutOfMem;
749  }
750  entry = ALLOC(int,nvars);
751  if (entry == NULL) {
752  table->errorCode = CUDD_MEMORY_OUT;
753  goto ddGroupSiftingOutOfMem;
754  }
755  sifted = ALLOC(int,nvars);
756  if (sifted == NULL) {
757  table->errorCode = CUDD_MEMORY_OUT;
758  goto ddGroupSiftingOutOfMem;
759  }
760 
761  /* Here we consider only one representative for each group. */
762  for (i = 0, classes = 0; i < nvars; i++) {
763  sifted[i] = 0;
764  x = table->perm[i];
765  if ((unsigned) x >= table->subtables[x].next) {
766  entry[i] = table->subtables[x].keys;
767  var[classes] = i;
768  classes++;
769  }
770  }
771 
772  qsort((void *)var,classes,sizeof(int),
774 
775  if (lazyFlag) {
776  for (i = 0; i < nvars; i ++) {
777  ddResetVarHandled(table, i);
778  }
779  }
780 
781  /* Now sift. */
782  for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) {
783  if (ddTotalNumberSwapping >= table->siftMaxSwap)
784  break;
785  if (util_cpu_time() - table->startTime + table->reordTime
786  > table->timeLimit) {
787  table->autoDyn = 0; /* prevent further reordering */
788  break;
789  }
790  xindex = var[i];
791  if (sifted[xindex] == 1) /* variable already sifted as part of group */
792  continue;
793  x = table->perm[xindex]; /* find current level of this variable */
794 
795  if (x < lower || x > upper || table->subtables[x].bindVar == 1)
796  continue;
797 #ifdef DD_STATS
798  previousSize = table->keys - table->isolated;
799 #endif
800 #ifdef DD_DEBUG
801  /* x is bottom of group */
802  assert((unsigned) x >= table->subtables[x].next);
803 #endif
804  if ((unsigned) x == table->subtables[x].next) {
805  dissolve = 1;
806  result = ddGroupSiftingAux(table,x,lower,upper,checkFunction,
807  lazyFlag);
808  } else {
809  dissolve = 0;
810  result = ddGroupSiftingAux(table,x,lower,upper,ddNoCheck,lazyFlag);
811  }
812  if (!result) goto ddGroupSiftingOutOfMem;
813 
814  /* check for aggregation */
815  merged = 0;
816  if (lazyFlag == 0 && table->groupcheck == CUDD_GROUP_CHECK7) {
817  x = table->perm[xindex]; /* find current level */
818  if ((unsigned) x == table->subtables[x].next) { /* not part of a group */
819  if (x != upper && sifted[table->invperm[x+1]] == 0 &&
820  (unsigned) x+1 == table->subtables[x+1].next) {
821  if (ddSecDiffCheck(table,x,x+1)) {
822  merged =1;
823  ddCreateGroup(table,x,x+1);
824  }
825  }
826  if (x != lower && sifted[table->invperm[x-1]] == 0 &&
827  (unsigned) x-1 == table->subtables[x-1].next) {
828  if (ddSecDiffCheck(table,x-1,x)) {
829  merged =1;
830  ddCreateGroup(table,x-1,x);
831  }
832  }
833  }
834  }
835 
836  if (merged) { /* a group was created */
837  /* move x to bottom of group */
838  while ((unsigned) x < table->subtables[x].next)
839  x = table->subtables[x].next;
840  /* sift */
841  result = ddGroupSiftingAux(table,x,lower,upper,ddNoCheck,lazyFlag);
842  if (!result) goto ddGroupSiftingOutOfMem;
843 #ifdef DD_STATS
844  if (table->keys < previousSize + table->isolated) {
845  (void) fprintf(table->out,"_");
846  } else if (table->keys > previousSize + table->isolated) {
847  (void) fprintf(table->out,"^");
848  } else {
849  (void) fprintf(table->out,"*");
850  }
851  fflush(table->out);
852  } else {
853  if (table->keys < previousSize + table->isolated) {
854  (void) fprintf(table->out,"-");
855  } else if (table->keys > previousSize + table->isolated) {
856  (void) fprintf(table->out,"+");
857  } else {
858  (void) fprintf(table->out,"=");
859  }
860  fflush(table->out);
861 #endif
862  }
863 
864  /* Mark variables in the group just sifted. */
865  x = table->perm[xindex];
866  if ((unsigned) x != table->subtables[x].next) {
867  xInit = x;
868  do {
869  j = table->invperm[x];
870  sifted[j] = 1;
871  x = table->subtables[x].next;
872  } while (x != xInit);
873 
874  /* Dissolve the group if it was created. */
875  if (lazyFlag == 0 && dissolve) {
876  do {
877  j = table->subtables[x].next;
878  table->subtables[x].next = x;
879  x = j;
880  } while (x != xInit);
881  }
882  }
883 
884 #ifdef DD_DEBUG
885  if (pr > 0) (void) fprintf(table->out,"ddGroupSifting:");
886 #endif
887 
888  if (lazyFlag) ddSetVarHandled(table, xindex);
889  } /* for */
890 
891  FREE(sifted);
892  FREE(var);
893  FREE(entry);
894 
895  return(1);
896 
897 ddGroupSiftingOutOfMem:
898  if (entry != NULL) FREE(entry);
899  if (var != NULL) FREE(var);
900  if (sifted != NULL) FREE(sifted);
901 
902  return(0);
903 
904 } /* end of ddGroupSifting */
905 
906 
919 static void
921  DdManager * table,
922  int x,
923  int y)
924 {
925  int gybot;
926 
927 #ifdef DD_DEBUG
928  assert(y == x+1);
929 #endif
930 
931  /* Find bottom of second group. */
932  gybot = y;
933  while ((unsigned) gybot < table->subtables[gybot].next)
934  gybot = table->subtables[gybot].next;
935 
936  /* Link groups. */
937  table->subtables[x].next = y;
938  table->subtables[gybot].next = x;
939 
940  return;
941 
942 } /* ddCreateGroup */
943 
944 
960 static int
962  DdManager * table,
963  int x,
964  int xLow,
965  int xHigh,
966  DD_CHKFP checkFunction,
967  int lazyFlag)
968 {
969  Move *move;
970  Move *moves; /* list of moves */
971  int initialSize;
972  int result;
973  int y;
974  int topbot;
975 
976 #ifdef DD_DEBUG
977  if (pr > 0) (void) fprintf(table->out,
978  "ddGroupSiftingAux from %d to %d\n",xLow,xHigh);
979  assert((unsigned) x >= table->subtables[x].next); /* x is bottom of group */
980 #endif
981 
982  initialSize = table->keys - table->isolated;
983  moves = NULL;
984 
985  originalSize = initialSize; /* for lazy sifting */
986 
987  /* If we have a singleton, we check for aggregation in both
988  ** directions before we sift.
989  */
990  if ((unsigned) x == table->subtables[x].next) {
991  /* Will go down first, unless x == xHigh:
992  ** Look for aggregation above x.
993  */
994  for (y = x; y > xLow; y--) {
995  if (!checkFunction(table,y-1,y))
996  break;
997  topbot = table->subtables[y-1].next; /* find top of y-1's group */
998  table->subtables[y-1].next = y;
999  table->subtables[x].next = topbot; /* x is bottom of group so its */
1000  /* next is top of y-1's group */
1001  y = topbot + 1; /* add 1 for y--; new y is top of group */
1002  }
1003  /* Will go up first unless x == xlow:
1004  ** Look for aggregation below x.
1005  */
1006  for (y = x; y < xHigh; y++) {
1007  if (!checkFunction(table,y,y+1))
1008  break;
1009  /* find bottom of y+1's group */
1010  topbot = y + 1;
1011  while ((unsigned) topbot < table->subtables[topbot].next) {
1012  topbot = table->subtables[topbot].next;
1013  }
1014  table->subtables[topbot].next = table->subtables[y].next;
1015  table->subtables[y].next = y + 1;
1016  y = topbot - 1; /* subtract 1 for y++; new y is bottom of group */
1017  }
1018  }
1019 
1020  /* Now x may be in the middle of a group.
1021  ** Find bottom of x's group.
1022  */
1023  while ((unsigned) x < table->subtables[x].next)
1024  x = table->subtables[x].next;
1025 
1026  if (x == xLow) { /* Sift down */
1027 #ifdef DD_DEBUG
1028  /* x must be a singleton */
1029  assert((unsigned) x == table->subtables[x].next);
1030 #endif
1031  if (x == xHigh) return(1); /* just one variable */
1032 
1033  if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
1034  goto ddGroupSiftingAuxOutOfMem;
1035  /* at this point x == xHigh, unless early term */
1036 
1037  /* move backward and stop at best position */
1038  result = ddGroupSiftingBackward(table,moves,initialSize,
1039  DD_SIFT_DOWN,lazyFlag);
1040 #ifdef DD_DEBUG
1041  assert(table->keys - table->isolated <= (unsigned) initialSize);
1042 #endif
1043  if (!result) goto ddGroupSiftingAuxOutOfMem;
1044 
1045  } else if (cuddNextHigh(table,x) > xHigh) { /* Sift up */
1046 #ifdef DD_DEBUG
1047  /* x is bottom of group */
1048  assert((unsigned) x >= table->subtables[x].next);
1049 #endif
1050  /* Find top of x's group */
1051  x = table->subtables[x].next;
1052 
1053  if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
1054  goto ddGroupSiftingAuxOutOfMem;
1055  /* at this point x == xLow, unless early term */
1056 
1057  /* move backward and stop at best position */
1058  result = ddGroupSiftingBackward(table,moves,initialSize,
1059  DD_SIFT_UP,lazyFlag);
1060 #ifdef DD_DEBUG
1061  assert(table->keys - table->isolated <= (unsigned) initialSize);
1062 #endif
1063  if (!result) goto ddGroupSiftingAuxOutOfMem;
1064 
1065  } else if (x - xLow > xHigh - x) { /* must go down first: shorter */
1066  if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
1067  goto ddGroupSiftingAuxOutOfMem;
1068  /* at this point x == xHigh, unless early term */
1069 
1070  /* Find top of group */
1071  if (moves) {
1072  x = moves->y;
1073  }
1074  while ((unsigned) x < table->subtables[x].next)
1075  x = table->subtables[x].next;
1076  x = table->subtables[x].next;
1077 #ifdef DD_DEBUG
1078  /* x should be the top of a group */
1079  assert((unsigned) x <= table->subtables[x].next);
1080 #endif
1081 
1082  if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
1083  goto ddGroupSiftingAuxOutOfMem;
1084 
1085  /* move backward and stop at best position */
1086  result = ddGroupSiftingBackward(table,moves,initialSize,
1087  DD_SIFT_UP,lazyFlag);
1088 #ifdef DD_DEBUG
1089  assert(table->keys - table->isolated <= (unsigned) initialSize);
1090 #endif
1091  if (!result) goto ddGroupSiftingAuxOutOfMem;
1092 
1093  } else { /* moving up first: shorter */
1094  /* Find top of x's group */
1095  x = table->subtables[x].next;
1096 
1097  if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
1098  goto ddGroupSiftingAuxOutOfMem;
1099  /* at this point x == xHigh, unless early term */
1100 
1101  if (moves) {
1102  x = moves->x;
1103  }
1104  while ((unsigned) x < table->subtables[x].next)
1105  x = table->subtables[x].next;
1106 #ifdef DD_DEBUG
1107  /* x is bottom of a group */
1108  assert((unsigned) x >= table->subtables[x].next);
1109 #endif
1110 
1111  if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
1112  goto ddGroupSiftingAuxOutOfMem;
1113 
1114  /* move backward and stop at best position */
1115  result = ddGroupSiftingBackward(table,moves,initialSize,
1116  DD_SIFT_DOWN,lazyFlag);
1117 #ifdef DD_DEBUG
1118  assert(table->keys - table->isolated <= (unsigned) initialSize);
1119 #endif
1120  if (!result) goto ddGroupSiftingAuxOutOfMem;
1121  }
1122 
1123  while (moves != NULL) {
1124  move = moves->next;
1125  cuddDeallocMove(table, moves);
1126  moves = move;
1127  }
1128 
1129  return(1);
1130 
1131 ddGroupSiftingAuxOutOfMem:
1132  while (moves != NULL) {
1133  move = moves->next;
1134  cuddDeallocMove(table, moves);
1135  moves = move;
1136  }
1137 
1138  return(0);
1139 
1140 } /* end of ddGroupSiftingAux */
1141 
1142 
1158 static int
1160  DdManager * table,
1161  int y,
1162  int xLow,
1163  DD_CHKFP checkFunction,
1164  Move ** moves)
1165 {
1166  Move *move;
1167  int x;
1168  int size;
1169  int i;
1170  int gxtop,gybot;
1171  int limitSize;
1172  int xindex, yindex;
1173  int zindex;
1174  int z;
1175  int isolated;
1176  int L; /* lower bound on DD size */
1177 #ifdef DD_DEBUG
1178  int checkL;
1179 #endif
1180 
1181  yindex = table->invperm[y];
1182 
1183  /* Initialize the lower bound.
1184  ** The part of the DD below the bottom of y's group will not change.
1185  ** The part of the DD above y that does not interact with any
1186  ** variable of y's group will not change.
1187  ** The rest may vanish in the best case, except for
1188  ** the nodes at level xLow, which will not vanish, regardless.
1189  ** What we use here is not really a lower bound, because we ignore
1190  ** the interactions with all variables except y.
1191  */
1192  limitSize = L = table->keys - table->isolated;
1193  gybot = y;
1194  while ((unsigned) gybot < table->subtables[gybot].next)
1195  gybot = table->subtables[gybot].next;
1196  for (z = xLow + 1; z <= gybot; z++) {
1197  zindex = table->invperm[z];
1198  if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
1199  isolated = table->vars[zindex]->ref == 1;
1200  L -= table->subtables[z].keys - isolated;
1201  }
1202  }
1203 
1204  x = cuddNextLow(table,y);
1205  while (x >= xLow && L <= limitSize) {
1206 #ifdef DD_DEBUG
1207  gybot = y;
1208  while ((unsigned) gybot < table->subtables[gybot].next)
1209  gybot = table->subtables[gybot].next;
1210  checkL = table->keys - table->isolated;
1211  for (z = xLow + 1; z <= gybot; z++) {
1212  zindex = table->invperm[z];
1213  if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
1214  isolated = table->vars[zindex]->ref == 1;
1215  checkL -= table->subtables[z].keys - isolated;
1216  }
1217  }
1218  if (pr > 0 && L != checkL) {
1219  (void) fprintf(table->out,
1220  "Inaccurate lower bound: L = %d checkL = %d\n",
1221  L, checkL);
1222  }
1223 #endif
1224  gxtop = table->subtables[x].next;
1225  if (checkFunction(table,x,y)) {
1226  /* Group found, attach groups */
1227  table->subtables[x].next = y;
1228  i = table->subtables[y].next;
1229  while (table->subtables[i].next != (unsigned) y)
1230  i = table->subtables[i].next;
1231  table->subtables[i].next = gxtop;
1232  move = (Move *)cuddDynamicAllocNode(table);
1233  if (move == NULL) goto ddGroupSiftingUpOutOfMem;
1234  move->x = x;
1235  move->y = y;
1236  move->flags = MTR_NEWNODE;
1237  move->size = table->keys - table->isolated;
1238  move->next = *moves;
1239  *moves = move;
1240  } else if (table->subtables[x].next == (unsigned) x &&
1241  table->subtables[y].next == (unsigned) y) {
1242  /* x and y are self groups */
1243  xindex = table->invperm[x];
1244  size = cuddSwapInPlace(table,x,y);
1245 #ifdef DD_DEBUG
1246  assert(table->subtables[x].next == (unsigned) x);
1247  assert(table->subtables[y].next == (unsigned) y);
1248 #endif
1249  if (size == 0) goto ddGroupSiftingUpOutOfMem;
1250  /* Update the lower bound. */
1251  if (cuddTestInteract(table,xindex,yindex)) {
1252  isolated = table->vars[xindex]->ref == 1;
1253  L += table->subtables[y].keys - isolated;
1254  }
1255  move = (Move *)cuddDynamicAllocNode(table);
1256  if (move == NULL) goto ddGroupSiftingUpOutOfMem;
1257  move->x = x;
1258  move->y = y;
1259  move->flags = MTR_DEFAULT;
1260  move->size = size;
1261  move->next = *moves;
1262  *moves = move;
1263 
1264 #ifdef DD_DEBUG
1265  if (pr > 0) (void) fprintf(table->out,
1266  "ddGroupSiftingUp (2 single groups):\n");
1267 #endif
1268  if ((double) size > (double) limitSize * table->maxGrowth)
1269  return(1);
1270  if (size < limitSize) limitSize = size;
1271  } else { /* Group move */
1272  size = ddGroupMove(table,x,y,moves);
1273  if (size == 0) goto ddGroupSiftingUpOutOfMem;
1274  /* Update the lower bound. */
1275  z = (*moves)->y;
1276  do {
1277  zindex = table->invperm[z];
1278  if (cuddTestInteract(table,zindex,yindex)) {
1279  isolated = table->vars[zindex]->ref == 1;
1280  L += table->subtables[z].keys - isolated;
1281  }
1282  z = table->subtables[z].next;
1283  } while (z != (int) (*moves)->y);
1284  if ((double) size > (double) limitSize * table->maxGrowth)
1285  return(1);
1286  if (size < limitSize) limitSize = size;
1287  }
1288  y = gxtop;
1289  x = cuddNextLow(table,y);
1290  }
1291 
1292  return(1);
1293 
1294 ddGroupSiftingUpOutOfMem:
1295  while (*moves != NULL) {
1296  move = (*moves)->next;
1297  cuddDeallocMove(table, *moves);
1298  *moves = move;
1299  }
1300  return(0);
1301 
1302 } /* end of ddGroupSiftingUp */
1303 
1304 
1316 static int
1318  DdManager * table,
1319  int x,
1320  int xHigh,
1321  DD_CHKFP checkFunction,
1322  Move ** moves)
1323 {
1324  Move *move;
1325  int y;
1326  int size;
1327  int limitSize;
1328  int gxtop,gybot;
1329  int R; /* upper bound on node decrease */
1330  int xindex, yindex;
1331  int isolated, allVars;
1332  int z;
1333  int zindex;
1334 #ifdef DD_DEBUG
1335  int checkR;
1336 #endif
1337 
1338  /* If the group consists of simple variables, there is no point in
1339  ** sifting it down. This check is redundant if the projection functions
1340  ** do not have external references, because the computation of the
1341  ** lower bound takes care of the problem. It is necessary otherwise to
1342  ** prevent the sifting down of simple variables. */
1343  y = x;
1344  allVars = 1;
1345  do {
1346  if (table->subtables[y].keys != 1) {
1347  allVars = 0;
1348  break;
1349  }
1350  y = table->subtables[y].next;
1351  } while (table->subtables[y].next != (unsigned) x);
1352  if (allVars)
1353  return(1);
1354 
1355  /* Initialize R. */
1356  xindex = table->invperm[x];
1357  gxtop = table->subtables[x].next;
1358  limitSize = size = table->keys - table->isolated;
1359  R = 0;
1360  for (z = xHigh; z > gxtop; z--) {
1361  zindex = table->invperm[z];
1362  if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
1363  isolated = table->vars[zindex]->ref == 1;
1364  R += table->subtables[z].keys - isolated;
1365  }
1366  }
1367 
1368  y = cuddNextHigh(table,x);
1369  while (y <= xHigh && size - R < limitSize) {
1370 #ifdef DD_DEBUG
1371  gxtop = table->subtables[x].next;
1372  checkR = 0;
1373  for (z = xHigh; z > gxtop; z--) {
1374  zindex = table->invperm[z];
1375  if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
1376  isolated = table->vars[zindex]->ref == 1;
1377  checkR += table->subtables[z].keys - isolated;
1378  }
1379  }
1380  assert(R >= checkR);
1381 #endif
1382  /* Find bottom of y group. */
1383  gybot = table->subtables[y].next;
1384  while (table->subtables[gybot].next != (unsigned) y)
1385  gybot = table->subtables[gybot].next;
1386 
1387  if (checkFunction(table,x,y)) {
1388  /* Group found: attach groups and record move. */
1389  gxtop = table->subtables[x].next;
1390  table->subtables[x].next = y;
1391  table->subtables[gybot].next = gxtop;
1392  move = (Move *)cuddDynamicAllocNode(table);
1393  if (move == NULL) goto ddGroupSiftingDownOutOfMem;
1394  move->x = x;
1395  move->y = y;
1396  move->flags = MTR_NEWNODE;
1397  move->size = table->keys - table->isolated;
1398  move->next = *moves;
1399  *moves = move;
1400  } else if (table->subtables[x].next == (unsigned) x &&
1401  table->subtables[y].next == (unsigned) y) {
1402  /* x and y are self groups */
1403  /* Update upper bound on node decrease. */
1404  yindex = table->invperm[y];
1405  if (cuddTestInteract(table,xindex,yindex)) {
1406  isolated = table->vars[yindex]->ref == 1;
1407  R -= table->subtables[y].keys - isolated;
1408  }
1409  size = cuddSwapInPlace(table,x,y);
1410 #ifdef DD_DEBUG
1411  assert(table->subtables[x].next == (unsigned) x);
1412  assert(table->subtables[y].next == (unsigned) y);
1413 #endif
1414  if (size == 0) goto ddGroupSiftingDownOutOfMem;
1415 
1416  /* Record move. */
1417  move = (Move *) cuddDynamicAllocNode(table);
1418  if (move == NULL) goto ddGroupSiftingDownOutOfMem;
1419  move->x = x;
1420  move->y = y;
1421  move->flags = MTR_DEFAULT;
1422  move->size = size;
1423  move->next = *moves;
1424  *moves = move;
1425 
1426 #ifdef DD_DEBUG
1427  if (pr > 0) (void) fprintf(table->out,
1428  "ddGroupSiftingDown (2 single groups):\n");
1429 #endif
1430  if ((double) size > (double) limitSize * table->maxGrowth)
1431  return(1);
1432  if (size < limitSize) limitSize = size;
1433 
1434  x = y;
1435  y = cuddNextHigh(table,x);
1436  } else { /* Group move */
1437  /* Update upper bound on node decrease: first phase. */
1438  gxtop = table->subtables[x].next;
1439  z = gxtop + 1;
1440  do {
1441  zindex = table->invperm[z];
1442  if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
1443  isolated = table->vars[zindex]->ref == 1;
1444  R -= table->subtables[z].keys - isolated;
1445  }
1446  z++;
1447  } while (z <= gybot);
1448  size = ddGroupMove(table,x,y,moves);
1449  if (size == 0) goto ddGroupSiftingDownOutOfMem;
1450  if ((double) size > (double) limitSize * table->maxGrowth)
1451  return(1);
1452  if (size < limitSize) limitSize = size;
1453 
1454  /* Update upper bound on node decrease: second phase. */
1455  gxtop = table->subtables[gybot].next;
1456  for (z = gxtop + 1; z <= gybot; z++) {
1457  zindex = table->invperm[z];
1458  if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
1459  isolated = table->vars[zindex]->ref == 1;
1460  R += table->subtables[z].keys - isolated;
1461  }
1462  }
1463  }
1464  x = gybot;
1465  y = cuddNextHigh(table,x);
1466  }
1467 
1468  return(1);
1469 
1470 ddGroupSiftingDownOutOfMem:
1471  while (*moves != NULL) {
1472  move = (*moves)->next;
1473  cuddDeallocMove(table, *moves);
1474  *moves = move;
1475  }
1476 
1477  return(0);
1478 
1479 } /* end of ddGroupSiftingDown */
1480 
1481 
1492 static int
1494  DdManager * table,
1495  int x,
1496  int y,
1497  Move ** moves)
1498 {
1499  Move *move;
1500  int size;
1501  int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
1502  int swapx,swapy;
1503 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
1504  int initialSize,bestSize;
1505 #endif
1506 
1507 #ifdef DD_DEBUG
1508  /* We assume that x < y */
1509  assert(x < y);
1510 #endif
1511  /* Find top, bottom, and size for the two groups. */
1512  xbot = x;
1513  xtop = table->subtables[x].next;
1514  xsize = xbot - xtop + 1;
1515  ybot = y;
1516  while ((unsigned) ybot < table->subtables[ybot].next)
1517  ybot = table->subtables[ybot].next;
1518  ytop = y;
1519  ysize = ybot - ytop + 1;
1520 
1521 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
1522  initialSize = bestSize = table->keys - table->isolated;
1523 #endif
1524  /* Sift the variables of the second group up through the first group */
1525  for (i = 1; i <= ysize; i++) {
1526  for (j = 1; j <= xsize; j++) {
1527  size = cuddSwapInPlace(table,x,y);
1528  if (size == 0) goto ddGroupMoveOutOfMem;
1529 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
1530  if (size < bestSize)
1531  bestSize = size;
1532 #endif
1533  swapx = x; swapy = y;
1534  y = x;
1535  x = cuddNextLow(table,y);
1536  }
1537  y = ytop + i;
1538  x = cuddNextLow(table,y);
1539  }
1540 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
1541  if ((bestSize < initialSize) && (bestSize < size))
1542  (void) fprintf(table->out,"Missed local minimum: initialSize:%d bestSize:%d finalSize:%d\n",initialSize,bestSize,size);
1543 #endif
1544 
1545  /* fix groups */
1546  y = xtop; /* ytop is now where xtop used to be */
1547  for (i = 0; i < ysize - 1; i++) {
1548  table->subtables[y].next = cuddNextHigh(table,y);
1549  y = cuddNextHigh(table,y);
1550  }
1551  table->subtables[y].next = xtop; /* y is bottom of its group, join */
1552  /* it to top of its group */
1553  x = cuddNextHigh(table,y);
1554  newxtop = x;
1555  for (i = 0; i < xsize - 1; i++) {
1556  table->subtables[x].next = cuddNextHigh(table,x);
1557  x = cuddNextHigh(table,x);
1558  }
1559  table->subtables[x].next = newxtop; /* x is bottom of its group, join */
1560  /* it to top of its group */
1561 #ifdef DD_DEBUG
1562  if (pr > 0) (void) fprintf(table->out,"ddGroupMove:\n");
1563 #endif
1564 
1565  /* Store group move */
1566  move = (Move *) cuddDynamicAllocNode(table);
1567  if (move == NULL) goto ddGroupMoveOutOfMem;
1568  move->x = swapx;
1569  move->y = swapy;
1570  move->flags = MTR_DEFAULT;
1571  move->size = table->keys - table->isolated;
1572  move->next = *moves;
1573  *moves = move;
1574 
1575  return(table->keys - table->isolated);
1576 
1577 ddGroupMoveOutOfMem:
1578  while (*moves != NULL) {
1579  move = (*moves)->next;
1580  cuddDeallocMove(table, *moves);
1581  *moves = move;
1582  }
1583  return(0);
1584 
1585 } /* end of ddGroupMove */
1586 
1587 
1598 static int
1600  DdManager * table,
1601  int x,
1602  int y)
1603 {
1604  int size;
1605  int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
1606 
1607 
1608 #ifdef DD_DEBUG
1609  /* We assume that x < y */
1610  assert(x < y);
1611 #endif
1612 
1613  /* Find top, bottom, and size for the two groups. */
1614  xbot = x;
1615  xtop = table->subtables[x].next;
1616  xsize = xbot - xtop + 1;
1617  ybot = y;
1618  while ((unsigned) ybot < table->subtables[ybot].next)
1619  ybot = table->subtables[ybot].next;
1620  ytop = y;
1621  ysize = ybot - ytop + 1;
1622 
1623  /* Sift the variables of the second group up through the first group */
1624  for (i = 1; i <= ysize; i++) {
1625  for (j = 1; j <= xsize; j++) {
1626  size = cuddSwapInPlace(table,x,y);
1627  if (size == 0)
1628  return(0);
1629  y = x;
1630  x = cuddNextLow(table,y);
1631  }
1632  y = ytop + i;
1633  x = cuddNextLow(table,y);
1634  }
1635 
1636  /* fix groups */
1637  y = xtop;
1638  for (i = 0; i < ysize - 1; i++) {
1639  table->subtables[y].next = cuddNextHigh(table,y);
1640  y = cuddNextHigh(table,y);
1641  }
1642  table->subtables[y].next = xtop; /* y is bottom of its group, join */
1643  /* to its top */
1644  x = cuddNextHigh(table,y);
1645  newxtop = x;
1646  for (i = 0; i < xsize - 1; i++) {
1647  table->subtables[x].next = cuddNextHigh(table,x);
1648  x = cuddNextHigh(table,x);
1649  }
1650  table->subtables[x].next = newxtop; /* x is bottom of its group, join */
1651  /* to its top */
1652 #ifdef DD_DEBUG
1653  if (pr > 0) (void) fprintf(table->out,"ddGroupMoveBackward:\n");
1654 #endif
1655 
1656  return(1);
1657 
1658 } /* end of ddGroupMoveBackward */
1659 
1660 
1672 static int
1674  DdManager * table,
1675  Move * moves,
1676  int size,
1677  int upFlag,
1678  int lazyFlag)
1679 {
1680  Move *move;
1681  int res;
1682  Move *end_move;
1683  int diff, tmp_diff;
1684  int index;
1685  unsigned int pairlev;
1686 
1687  if (lazyFlag) {
1688  end_move = NULL;
1689 
1690  /* Find the minimum size, and the earliest position at which it
1691  ** was achieved. */
1692  for (move = moves; move != NULL; move = move->next) {
1693  if (move->size < size) {
1694  size = move->size;
1695  end_move = move;
1696  } else if (move->size == size) {
1697  if (end_move == NULL) end_move = move;
1698  }
1699  }
1700 
1701  /* Find among the moves that give minimum size the one that
1702  ** minimizes the distance from the corresponding variable. */
1703  if (moves != NULL) {
1704  diff = Cudd_ReadSize(table) + 1;
1705  index = (upFlag == 1) ?
1706  table->invperm[moves->x] : table->invperm[moves->y];
1707  pairlev =
1708  (unsigned) table->perm[Cudd_bddReadPairIndex(table, index)];
1709 
1710  for (move = moves; move != NULL; move = move->next) {
1711  if (move->size == size) {
1712  if (upFlag == 1) {
1713  tmp_diff = (move->x > pairlev) ?
1714  move->x - pairlev : pairlev - move->x;
1715  } else {
1716  tmp_diff = (move->y > pairlev) ?
1717  move->y - pairlev : pairlev - move->y;
1718  }
1719  if (tmp_diff < diff) {
1720  diff = tmp_diff;
1721  end_move = move;
1722  }
1723  }
1724  }
1725  }
1726  } else {
1727  /* Find the minimum size. */
1728  for (move = moves; move != NULL; move = move->next) {
1729  if (move->size < size) {
1730  size = move->size;
1731  }
1732  }
1733  }
1734 
1735  /* In case of lazy sifting, end_move identifies the position at
1736  ** which we want to stop. Otherwise, we stop as soon as we meet
1737  ** the minimum size. */
1738  for (move = moves; move != NULL; move = move->next) {
1739  if (lazyFlag) {
1740  if (move == end_move) return(1);
1741  } else {
1742  if (move->size == size) return(1);
1743  }
1744  if ((table->subtables[move->x].next == move->x) &&
1745  (table->subtables[move->y].next == move->y)) {
1746  res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
1747  if (!res) return(0);
1748 #ifdef DD_DEBUG
1749  if (pr > 0) (void) fprintf(table->out,"ddGroupSiftingBackward:\n");
1750  assert(table->subtables[move->x].next == move->x);
1751  assert(table->subtables[move->y].next == move->y);
1752 #endif
1753  } else { /* Group move necessary */
1754  if (move->flags == MTR_NEWNODE) {
1755  ddDissolveGroup(table,(int)move->x,(int)move->y);
1756  } else {
1757  res = ddGroupMoveBackward(table,(int)move->x,(int)move->y);
1758  if (!res) return(0);
1759  }
1760  }
1761 
1762  }
1763 
1764  return(1);
1765 
1766 } /* end of ddGroupSiftingBackward */
1767 
1768 
1779 static void
1781  DdManager * table,
1782  MtrNode * treenode,
1783  int low,
1784  int high)
1785 {
1786  int i;
1787  MtrNode *auxnode;
1788  int saveindex;
1789  int newindex;
1790 
1791  /* Merge all variables from low to high in one group, unless
1792  ** this is the topmost group. In such a case we do not merge lest
1793  ** we lose the symmetry information. */
1794  if (treenode != table->tree) {
1795  for (i = low; i < high; i++)
1796  table->subtables[i].next = i+1;
1797  table->subtables[high].next = low;
1798  }
1799 
1800  /* Adjust the index fields of the tree nodes. If a node is the
1801  ** first child of its parent, then the parent may also need adjustment. */
1802  saveindex = treenode->index;
1803  newindex = table->invperm[low];
1804  auxnode = treenode;
1805  do {
1806  auxnode->index = newindex;
1807  if (auxnode->parent == NULL ||
1808  (int) auxnode->parent->index != saveindex)
1809  break;
1810  auxnode = auxnode->parent;
1811  } while (1);
1812  return;
1813 
1814 } /* end of ddMergeGroups */
1815 
1816 
1827 static void
1829  DdManager * table,
1830  int x,
1831  int y)
1832 {
1833  int topx;
1834  int boty;
1835 
1836  /* find top and bottom of the two groups */
1837  boty = y;
1838  while ((unsigned) boty < table->subtables[boty].next)
1839  boty = table->subtables[boty].next;
1840 
1841  topx = table->subtables[boty].next;
1842 
1843  table->subtables[boty].next = y;
1844  table->subtables[x].next = topx;
1845 
1846  return;
1847 
1848 } /* end of ddDissolveGroup */
1849 
1850 
1861 static int
1863  DdManager * table,
1864  int x,
1865  int y)
1866 {
1867  return(0);
1868 
1869 } /* end of ddNoCheck */
1870 
1871 
1885 static int
1887  DdManager * table,
1888  int x,
1889  int y)
1890 {
1891  double Nx,Nx_1;
1892  double Sx;
1893  double threshold;
1894  int xindex,yindex;
1895 
1896  if (x==0) return(0);
1897 
1898 #ifdef DD_STATS
1899  secdiffcalls++;
1900 #endif
1901  Nx = (double) table->subtables[x].keys;
1902  Nx_1 = (double) table->subtables[x-1].keys;
1903  Sx = (table->subtables[y].keys/Nx) - (Nx/Nx_1);
1904 
1905  threshold = table->recomb / 100.0;
1906  if (Sx < threshold) {
1907  xindex = table->invperm[x];
1908  yindex = table->invperm[y];
1909  if (cuddTestInteract(table,xindex,yindex)) {
1910 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
1911  (void) fprintf(table->out,
1912  "Second difference for %d = %g Pos(%d)\n",
1913  table->invperm[x],Sx,x);
1914 #endif
1915 #ifdef DD_STATS
1916  secdiff++;
1917 #endif
1918  return(1);
1919  } else {
1920 #ifdef DD_STATS
1921  secdiffmisfire++;
1922 #endif
1923  return(0);
1924  }
1925 
1926  }
1927  return(0);
1928 
1929 } /* end of ddSecDiffCheck */
1930 
1931 
1942 static int
1944  DdManager * table,
1945  int x,
1946  int y)
1947 {
1948  DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10;
1949  DdNode *one;
1950  unsigned comple; /* f0 is complemented */
1951  int notproj; /* f is not a projection function */
1952  int arccount; /* number of arcs from layer x to layer y */
1953  int TotalRefCount; /* total reference count of layer y minus 1 */
1954  int counter; /* number of nodes of layer x that are allowed */
1955  /* to violate extended symmetry conditions */
1956  int arccounter; /* number of arcs into layer y that are allowed */
1957  /* to come from layers other than x */
1958  int i;
1959  int xindex;
1960  int yindex;
1961  int res;
1962  int slots;
1963  DdNodePtr *list;
1964  DdNode *sentinel = &(table->sentinel);
1965 
1966  xindex = table->invperm[x];
1967  yindex = table->invperm[y];
1968 
1969  /* If the two variables do not interact, we do not want to merge them. */
1970  if (!cuddTestInteract(table,xindex,yindex))
1971  return(0);
1972 
1973 #ifdef DD_DEBUG
1974  /* Checks that x and y do not contain just the projection functions.
1975  ** With the test on interaction, these test become redundant,
1976  ** because an isolated projection function does not interact with
1977  ** any other variable.
1978  */
1979  if (table->subtables[x].keys == 1) {
1980  assert(table->vars[xindex]->ref != 1);
1981  }
1982  if (table->subtables[y].keys == 1) {
1983  assert(table->vars[yindex]->ref != 1);
1984  }
1985 #endif
1986 
1987 #ifdef DD_STATS
1988  extsymmcalls++;
1989 #endif
1990 
1991  arccount = 0;
1992  counter = (int) (table->subtables[x].keys *
1993  (table->symmviolation/100.0) + 0.5);
1994  one = DD_ONE(table);
1995 
1996  slots = table->subtables[x].slots;
1997  list = table->subtables[x].nodelist;
1998  for (i = 0; i < slots; i++) {
1999  f = list[i];
2000  while (f != sentinel) {
2001  /* Find f1, f0, f11, f10, f01, f00. */
2002  f1 = cuddT(f);
2003  f0 = Cudd_Regular(cuddE(f));
2004  comple = Cudd_IsComplement(cuddE(f));
2005  notproj = f1 != one || f0 != one || f->ref != (DdHalfWord) 1;
2006  if (f1->index == (unsigned) yindex) {
2007  arccount++;
2008  f11 = cuddT(f1); f10 = cuddE(f1);
2009  } else {
2010  if ((int) f0->index != yindex) {
2011  /* If f is an isolated projection function it is
2012  ** allowed to bypass layer y.
2013  */
2014  if (notproj) {
2015  if (counter == 0)
2016  return(0);
2017  counter--; /* f bypasses layer y */
2018  }
2019  }
2020  f11 = f10 = f1;
2021  }
2022  if ((int) f0->index == yindex) {
2023  arccount++;
2024  f01 = cuddT(f0); f00 = cuddE(f0);
2025  } else {
2026  f01 = f00 = f0;
2027  }
2028  if (comple) {
2029  f01 = Cudd_Not(f01);
2030  f00 = Cudd_Not(f00);
2031  }
2032 
2033  /* Unless we are looking at a projection function
2034  ** without external references except the one from the
2035  ** table, we insist that f01 == f10 or f11 == f00
2036  */
2037  if (notproj) {
2038  if (f01 != f10 && f11 != f00) {
2039  if (counter == 0)
2040  return(0);
2041  counter--;
2042  }
2043  }
2044 
2045  f = f->next;
2046  } /* while */
2047  } /* for */
2048 
2049  /* Calculate the total reference counts of y */
2050  TotalRefCount = -1; /* -1 for projection function */
2051  slots = table->subtables[y].slots;
2052  list = table->subtables[y].nodelist;
2053  for (i = 0; i < slots; i++) {
2054  f = list[i];
2055  while (f != sentinel) {
2056  TotalRefCount += f->ref;
2057  f = f->next;
2058  }
2059  }
2060 
2061  arccounter = (int) (table->subtables[y].keys *
2062  (table->arcviolation/100.0) + 0.5);
2063  res = arccount >= TotalRefCount - arccounter;
2064 
2065 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
2066  if (res) {
2067  (void) fprintf(table->out,
2068  "Found extended symmetry! x = %d\ty = %d\tPos(%d,%d)\n",
2069  xindex,yindex,x,y);
2070  }
2071 #endif
2072 
2073 #ifdef DD_STATS
2074  if (res)
2075  extsymm++;
2076 #endif
2077  return(res);
2078 
2079 } /* end ddExtSymmCheck */
2080 
2081 
2092 static int
2094  DdManager * table,
2095  int x,
2096  int y)
2097 {
2098  int xindex = table->invperm[x];
2099  int yindex = table->invperm[y];
2100 
2101  if (Cudd_bddIsVarToBeUngrouped(table, xindex)) return(0);
2102 
2103  if (Cudd_bddReadPairIndex(table, xindex) == yindex) {
2104  if (ddIsVarHandled(table, xindex) ||
2105  ddIsVarHandled(table, yindex)) {
2106  if (Cudd_bddIsVarToBeGrouped(table, xindex) ||
2107  Cudd_bddIsVarToBeGrouped(table, yindex) ) {
2108  if (table->keys - table->isolated <= originalSize) {
2109  return(1);
2110  }
2111  }
2112  }
2113  }
2114 
2115  return(0);
2116 
2117 } /* end of ddVarGroupCheck */
2118 
2119 
2132 static int
2134  DdManager *dd,
2135  int index)
2136 {
2137  if (index >= dd->size || index < 0) return(0);
2138  dd->subtables[dd->perm[index]].varHandled = 1;
2139  return(1);
2140 
2141 } /* end of ddSetVarHandled */
2142 
2143 
2156 static int
2158  DdManager *dd,
2159  int index)
2160 {
2161  if (index >= dd->size || index < 0) return(0);
2162  dd->subtables[dd->perm[index]].varHandled = 0;
2163  return(1);
2164 
2165 } /* end of ddResetVarHandled */
2166 
2167 
2180 static int
2182  DdManager *dd,
2183  int index)
2184 {
2185  if (index >= dd->size || index < 0) return(-1);
2186  return dd->subtables[dd->perm[index]].varHandled;
2187 
2188 } /* end of ddIsVarHandled */
#define MTR_MAXHIGH
Definition: mtr.h:107
#define DD_SIFT_DOWN
Definition: cuddGroup.c:92
DdHalfWord ref
Definition: cudd.h:272
#define MTR_TERMINAL
Definition: mtr.h:95
Cudd_AggregationType groupcheck
Definition: cuddInt.h:410
unsigned int keys
Definition: cuddInt.h:314
MtrHalfWord flags
Definition: mtr.h:127
unsigned short DdHalfWord
Definition: cudd.h:259
unsigned short MtrHalfWord
Definition: mtr.h:123
#define cuddDeallocMove(unique, node)
Definition: cuddInt.h:537
unsigned long reordTime
Definition: cuddInt.h:434
Cudd_AggregationType
Definition: cudd.h:180
static unsigned int originalSize
Definition: cuddGroup.c:133
static int ddGroupSifting(DdManager *table, int lower, int upper, DD_CHKFP checkFunction, int lazyFlag)
Definition: cuddGroup.c:720
Definition: cudd.h:270
static int ddGroupSiftingUp(DdManager *table, int y, int xLow, DD_CHKFP checkFunction, Move **moves)
Definition: cuddGroup.c:1159
#define Cudd_Not(node)
Definition: cudd.h:354
MtrHalfWord size
Definition: mtr.h:129
#define FREE(obj)
Definition: util.h:80
static int ddIsVarHandled(DdManager *dd, int index)
Definition: cuddGroup.c:2181
int siftMaxSwap
Definition: cuddInt.h:396
int cuddAnnealing(DdManager *table, int lower, int upper)
Definition: cuddAnneal.c:154
int(* DD_QSFP)(const void *, const void *)
Definition: cudd.h:313
unsigned long startTime
Definition: cuddInt.h:426
MtrNode * Cudd_MakeTreeNode(DdManager *dd, unsigned int low, unsigned int size, unsigned int type)
Definition: cuddGroup.c:203
#define assert(ex)
Definition: util.h:141
int size
Definition: cuddInt.h:345
Definition: cuddInt.h:469
#define Cudd_Regular(node)
Definition: cudd.h:384
static int ddGroupMoveBackward(DdManager *table, int x, int y)
Definition: cuddGroup.c:1599
int cuddNextLow(DdManager *table, int x)
Definition: cuddReorder.c:737
static int ddNoCheck(DdManager *table, int x, int y)
Definition: cuddGroup.c:1862
int cuddSifting(DdManager *table, int lower, int upper)
Definition: cuddReorder.c:502
double maxGrowth
Definition: cuddInt.h:397
static int ddSetVarHandled(DdManager *dd, int index)
Definition: cuddGroup.c:2133
FILE * err
Definition: cuddInt.h:424
#define MTR_FIXED
Definition: mtr.h:97
int bindVar
Definition: cuddInt.h:318
DdSubtable * subtables
Definition: cuddInt.h:349
void Mtr_ReorderGroups(MtrNode *treenode, int *permutation)
Definition: mtrGroup.c:524
struct MtrNode * parent
Definition: mtr.h:131
int(* DD_CHKFP)(DdManager *, int, int)
Definition: cuddGroup.c:106
static int ddExtSymmCheck(DdManager *table, int x, int y)
Definition: cuddGroup.c:1943
#define MTR_DEFAULT
Definition: mtr.h:94
MtrNode * tree
Definition: cuddInt.h:408
#define MTR_TEST(node, flag)
Definition: mtr.h:150
int Cudd_ReadSize(DdManager *dd)
Definition: cuddAPI.c:1681
int cuddExact(DdManager *table, int lower, int upper)
Definition: cuddExact.c:149
static int * entry
Definition: cuddGroup.c:119
void Cudd_FreeTree(DdManager *dd)
Definition: cuddAPI.c:2462
int cuddSymmSiftingConv(DdManager *table, int lower, int upper)
Definition: cuddSymmetry.c:439
static int ddGroupSiftingDown(DdManager *table, int x, int xHigh, DD_CHKFP checkFunction, Move **moves)
Definition: cuddGroup.c:1317
struct MtrNode * younger
Definition: mtr.h:134
static DdNode * one
Definition: cuddSat.c:105
static int ddResetVarHandled(DdManager *dd, int index)
Definition: cuddGroup.c:2157
int ddTotalNumberSwapping
Definition: cuddReorder.c:103
#define Cudd_IsComplement(node)
Definition: cudd.h:412
int recomb
Definition: cuddInt.h:411
DdNode sentinel
Definition: cuddInt.h:328
MtrHalfWord index
Definition: mtr.h:130
unsigned int keys
Definition: cuddInt.h:353
#define DD_SIFT_UP
Definition: cuddGroup.c:93
#define ALLOC(type, num)
Definition: util.h:76
FILE * out
Definition: cuddInt.h:423
unsigned int flags
Definition: cuddInt.h:472
static void ddFindNodeHiLo(DdManager *table, MtrNode *treenode, int *lower, int *upper)
Definition: cuddGroup.c:617
static void ddMergeGroups(DdManager *table, MtrNode *treenode, int low, int high)
Definition: cuddGroup.c:1780
DdHalfWord x
Definition: cuddInt.h:470
DdNode * next
Definition: cudd.h:273
static int ddGroupMove(DdManager *table, int x, int y, Move **moves)
Definition: cuddGroup.c:1493
#define DD_NORMAL_SIFT
Definition: cuddGroup.c:88
#define MTR_NEWNODE
Definition: mtr.h:98
#define ddMax(x, y)
Definition: cuddInt.h:785
int symmviolation
Definition: cuddInt.h:412
DdNode ** nodelist
Definition: cuddInt.h:311
#define ddMin(x, y)
Definition: cuddInt.h:771
MtrHalfWord low
Definition: mtr.h:128
long util_cpu_time(void)
Definition: cpu_time.c:34
int cuddTreeSifting(DdManager *table, Cudd_ReorderingType method)
Definition: cuddGroup.c:271
#define cuddT(node)
Definition: cuddInt.h:609
int Cudd_bddIsVarToBeUngrouped(DdManager *dd, int index)
Definition: cuddAPI.c:4754
static int ddGroupSiftingBackward(DdManager *table, Move *moves, int size, int upFlag, int lazyFlag)
Definition: cuddGroup.c:1673
int cuddWindowReorder(DdManager *table, int low, int high, Cudd_ReorderingType submethod)
Definition: cuddWindow.c:138
DdNode * cuddDynamicAllocNode(DdManager *table)
Definition: cuddReorder.c:405
Definition: mtr.h:126
int varHandled
Definition: cuddInt.h:322
static int ddTreeSiftingAux(DdManager *table, MtrNode *treenode, Cudd_ReorderingType method)
Definition: cuddGroup.c:361
int cuddSwapping(DdManager *table, int lower, int upper, Cudd_ReorderingType heuristic)
Definition: cuddReorder.c:604
int cuddNextHigh(DdManager *table, int x)
Definition: cuddReorder.c:715
int cuddGa(DdManager *table, int lower, int upper)
Definition: cuddGenetic.c:188
static int ddSecDiffCheck(DdManager *table, int x, int y)
Definition: cuddGroup.c:1886
void Mtr_PrintGroups(MtrNode *root, int silent)
Definition: mtrGroup.c:595
int siftMaxVar
Definition: cuddInt.h:395
static void ddCreateGroup(DdManager *table, int x, int y)
Definition: cuddGroup.c:920
int Cudd_bddIsVarToBeGrouped(DdManager *dd, int index)
Definition: cuddAPI.c:4702
static int ddVarGroupCheck(DdManager *table, int x, int y)
Definition: cuddGroup.c:2093
static char rcsid [] DD_UNUSED
Definition: cuddGroup.c:116
int cuddSwapInPlace(DdManager *table, int x, int y)
Definition: cuddReorder.c:760
MtrNode * Mtr_InitGroupTree(int lower, int size)
Definition: mtrGroup.c:120
DdHalfWord index
Definition: cudd.h:271
unsigned int slots
Definition: cuddInt.h:313
#define DD_LAZY_SIFT
Definition: cuddGroup.c:89
DdHalfWord y
Definition: cuddInt.h:471
static void ddDissolveGroup(DdManager *table, int x, int y)
Definition: cuddGroup.c:1828
DdNode ** vars
Definition: cuddInt.h:373
static int ddReorderChildren(DdManager *table, MtrNode *treenode, Cudd_ReorderingType method)
Definition: cuddGroup.c:453
unsigned int next
Definition: cuddInt.h:317
int Cudd_bddReadPairIndex(DdManager *dd, int index)
Definition: cuddAPI.c:4601
#define cuddE(node)
Definition: cuddInt.h:625
struct Move * next
Definition: cuddInt.h:474
int arcviolation
Definition: cuddInt.h:413
static int ddGroupSiftingAux(DdManager *table, int x, int xLow, int xHigh, DD_CHKFP checkFunction, int lazyFlag)
Definition: cuddGroup.c:961
static int ddUniqueCompareGroup(int *ptrX, int *ptrY)
Definition: cuddGroup.c:692
int * invperm
Definition: cuddInt.h:371
static int result
Definition: cuddGenetic.c:121
int isolated
Definition: cuddInt.h:368
int cuddLinearAndSifting(DdManager *table, int lower, int upper)
Definition: cuddLinear.c:236
MtrNode * Mtr_MakeGroup(MtrNode *root, unsigned int low, unsigned int high, unsigned int flags)
Definition: mtrGroup.c:156
int cuddTestInteract(DdManager *table, int x, int y)
Definition: cuddInteract.c:188
int autoDyn
Definition: cuddInt.h:400
#define DD_ONE(dd)
Definition: cuddInt.h:864
Cudd_ReorderingType
Definition: cudd.h:147
int cuddSymmSifting(DdManager *table, int lower, int upper)
Definition: cuddSymmetry.c:318
struct MtrNode * child
Definition: mtr.h:132
int * perm
Definition: cuddInt.h:369
unsigned long timeLimit
Definition: cuddInt.h:427
int size
Definition: cuddInt.h:473
Cudd_ErrorType errorCode
Definition: cuddInt.h:425