1 /**CFile***********************************************************************
3 FileName [cuddZddGroup.c]
7 Synopsis [Functions for ZDD group sifting.]
9 Description [External procedures included in this file:
11 <li> Cudd_MakeZddTreeNode()
13 Internal procedures included in this file:
15 <li> cuddZddTreeSifting()
17 Static procedures included in this module:
19 <li> zddTreeSiftingAux()
20 <li> zddCountInternalMtrNodes()
21 <li> zddReorderChildren()
22 <li> zddFindNodeHiLo()
23 <li> zddUniqueCompareGroup()
24 <li> zddGroupSifting()
25 <li> zddGroupSiftingAux()
26 <li> zddGroupSiftingUp()
27 <li> zddGroupSiftingDown()
29 <li> zddGroupMoveBackward()
30 <li> zddGroupSiftingBackward()
34 Author [Fabio Somenzi]
36 Copyright [Copyright (c) 1995-2004, Regents of the University of Colorado
40 Redistribution and use in source and binary forms, with or without
41 modification, are permitted provided that the following conditions
44 Redistributions of source code must retain the above copyright
45 notice, this list of conditions and the following disclaimer.
47 Redistributions in binary form must reproduce the above copyright
48 notice, this list of conditions and the following disclaimer in the
49 documentation and/or other materials provided with the distribution.
51 Neither the name of the University of Colorado nor the names of its
52 contributors may be used to endorse or promote products derived from
53 this software without specific prior written permission.
55 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
56 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
57 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
58 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
59 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
60 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
61 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
62 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
63 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
65 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
66 POSSIBILITY OF SUCH DAMAGE.]
68 ******************************************************************************/
73 /*---------------------------------------------------------------------------*/
74 /* Constant declarations */
75 /*---------------------------------------------------------------------------*/
77 /*---------------------------------------------------------------------------*/
78 /* Stucture declarations */
79 /*---------------------------------------------------------------------------*/
81 /*---------------------------------------------------------------------------*/
82 /* Type declarations */
83 /*---------------------------------------------------------------------------*/
85 /*---------------------------------------------------------------------------*/
86 /* Variable declarations */
87 /*---------------------------------------------------------------------------*/
90 static char rcsid
[] DD_UNUSED
= "$Id: cuddZddGroup.c,v 1.20 2009/02/19 16:25:36 fabio Exp $";
94 extern int zddTotalNumberSwapping
;
96 static int extsymmcalls
;
98 static int secdiffcalls
;
100 static int secdiffmisfire
;
103 static int pr
= 0; /* flag to enable printing while debugging */
104 /* by depositing a 1 into it */
107 /*---------------------------------------------------------------------------*/
108 /* Macro declarations */
109 /*---------------------------------------------------------------------------*/
111 /**AutomaticStart*************************************************************/
113 /*---------------------------------------------------------------------------*/
114 /* Static function prototypes */
115 /*---------------------------------------------------------------------------*/
117 static int zddTreeSiftingAux (DdManager
*table
, MtrNode
*treenode
, Cudd_ReorderingType method
);
119 static int zddCountInternalMtrNodes (DdManager
*table
, MtrNode
*treenode
);
121 static int zddReorderChildren (DdManager
*table
, MtrNode
*treenode
, Cudd_ReorderingType method
);
122 static void zddFindNodeHiLo (DdManager
*table
, MtrNode
*treenode
, int *lower
, int *upper
);
123 static int zddUniqueCompareGroup (int *ptrX
, int *ptrY
);
124 static int zddGroupSifting (DdManager
*table
, int lower
, int upper
);
125 static int zddGroupSiftingAux (DdManager
*table
, int x
, int xLow
, int xHigh
);
126 static int zddGroupSiftingUp (DdManager
*table
, int y
, int xLow
, Move
**moves
);
127 static int zddGroupSiftingDown (DdManager
*table
, int x
, int xHigh
, Move
**moves
);
128 static int zddGroupMove (DdManager
*table
, int x
, int y
, Move
**moves
);
129 static int zddGroupMoveBackward (DdManager
*table
, int x
, int y
);
130 static int zddGroupSiftingBackward (DdManager
*table
, Move
*moves
, int size
);
131 static void zddMergeGroups (DdManager
*table
, MtrNode
*treenode
, int low
, int high
);
133 /**AutomaticEnd***************************************************************/
136 /*---------------------------------------------------------------------------*/
137 /* Definition of exported functions */
138 /*---------------------------------------------------------------------------*/
141 /**Function********************************************************************
143 Synopsis [Creates a new ZDD variable group.]
145 Description [Creates a new ZDD variable group. The group starts at
146 variable and contains size variables. The parameter low is the index
147 of the first variable. If the variable already exists, its current
148 position in the order is known to the manager. If the variable does
149 not exist yet, the position is assumed to be the same as the index.
150 The group tree is created if it does not exist yet.
151 Returns a pointer to the group if successful; NULL otherwise.]
153 SideEffects [The ZDD variable tree is changed.]
155 SeeAlso [Cudd_MakeTreeNode]
157 ******************************************************************************/
159 Cudd_MakeZddTreeNode(
160 DdManager
* dd
/* manager */,
161 unsigned int low
/* index of the first group variable */,
162 unsigned int size
/* number of variables in the group */,
163 unsigned int type
/* MTR_DEFAULT or MTR_FIXED */)
169 /* If the variable does not exist yet, the position is assumed to be
170 ** the same as the index. Therefore, applications that rely on
171 ** Cudd_bddNewVarAtLevel or Cudd_addNewVarAtLevel to create new
172 ** variables have to create the variables before they group them.
174 level
= (low
< (unsigned int) dd
->sizeZ
) ? dd
->permZ
[low
] : low
;
176 if (level
+ size
- 1> (int) MTR_MAXHIGH
)
179 /* If the tree does not exist yet, create it. */
182 dd
->treeZ
= tree
= Mtr_InitGroupTree(0, dd
->sizeZ
);
185 tree
->index
= dd
->invpermZ
[0];
188 /* Extend the upper bound of the tree if necessary. This allows the
189 ** application to create groups even before the variables are created.
191 tree
->size
= ddMax(tree
->size
, level
+ size
);
193 /* Create the group. */
194 group
= Mtr_MakeGroup(tree
, level
, size
, type
);
198 /* Initialize the index field to the index of the variable currently
199 ** in position low. This field will be updated by the reordering
200 ** procedure to provide a handle to the group once it has been moved.
202 group
->index
= (MtrHalfWord
) low
;
206 } /* end of Cudd_MakeZddTreeNode */
209 /*---------------------------------------------------------------------------*/
210 /* Definition of internal functions */
211 /*---------------------------------------------------------------------------*/
214 /**Function********************************************************************
216 Synopsis [Tree sifting algorithm for ZDDs.]
218 Description [Tree sifting algorithm for ZDDs. Assumes that a tree
219 representing a group hierarchy is passed as a parameter. It then
220 reorders each group in postorder fashion by calling
221 zddTreeSiftingAux. Assumes that no dead nodes are present. Returns
222 1 if successful; 0 otherwise.]
226 ******************************************************************************/
229 DdManager
* table
/* DD table */,
230 Cudd_ReorderingType method
/* reordering method for the groups of leaves */)
237 /* If no tree is provided we create a temporary one in which all
238 ** variables are in a single group. After reordering this tree is
241 tempTree
= table
->treeZ
== NULL
;
243 table
->treeZ
= Mtr_InitGroupTree(0,table
->sizeZ
);
244 table
->treeZ
->index
= table
->invpermZ
[0];
246 nvars
= table
->sizeZ
;
249 if (pr
> 0 && !tempTree
)
250 (void) fprintf(table
->out
,"cuddZddTreeSifting:");
251 Mtr_PrintGroups(table
->treeZ
,pr
<= 0);
254 /* Debugging code. */
255 if (table
->tree
&& table
->treeZ
) {
256 (void) fprintf(table
->out
,"\n");
257 Mtr_PrintGroups(table
->tree
, 0);
258 cuddPrintVarGroups(table
,table
->tree
,0,0);
259 for (i
= 0; i
< table
->size
; i
++) {
260 (void) fprintf(table
->out
,"%s%d",
261 (i
== 0) ? "" : ",", table
->invperm
[i
]);
263 (void) fprintf(table
->out
,"\n");
264 for (i
= 0; i
< table
->size
; i
++) {
265 (void) fprintf(table
->out
,"%s%d",
266 (i
== 0) ? "" : ",", table
->perm
[i
]);
268 (void) fprintf(table
->out
,"\n\n");
269 Mtr_PrintGroups(table
->treeZ
,0);
270 cuddPrintVarGroups(table
,table
->treeZ
,1,0);
271 for (i
= 0; i
< table
->sizeZ
; i
++) {
272 (void) fprintf(table
->out
,"%s%d",
273 (i
== 0) ? "" : ",", table
->invpermZ
[i
]);
275 (void) fprintf(table
->out
,"\n");
276 for (i
= 0; i
< table
->sizeZ
; i
++) {
277 (void) fprintf(table
->out
,"%s%d",
278 (i
== 0) ? "" : ",", table
->permZ
[i
]);
280 (void) fprintf(table
->out
,"\n");
282 /* End of debugging code. */
291 (void) fprintf(table
->out
,"\n");
293 (void) fprintf(table
->out
,"#:IM_NODES %8d: group tree nodes\n",
294 zddCountInternalMtrNodes(table
,table
->treeZ
));
297 /* Initialize the group of each subtable to itself. Initially
298 ** there are no groups. Groups are created according to the tree
299 ** structure in postorder fashion.
301 for (i
= 0; i
< nvars
; i
++)
302 table
->subtableZ
[i
].next
= i
;
305 result
= zddTreeSiftingAux(table
, table
->treeZ
, method
);
307 #ifdef DD_STATS /* print stats */
308 if (!tempTree
&& method
== CUDD_REORDER_GROUP_SIFT
&&
309 (table
->groupcheck
== CUDD_GROUP_CHECK7
||
310 table
->groupcheck
== CUDD_GROUP_CHECK5
)) {
311 (void) fprintf(table
->out
,"\nextsymmcalls = %d\n",extsymmcalls
);
312 (void) fprintf(table
->out
,"extsymm = %d",extsymm
);
314 if (!tempTree
&& method
== CUDD_REORDER_GROUP_SIFT
&&
315 table
->groupcheck
== CUDD_GROUP_CHECK7
) {
316 (void) fprintf(table
->out
,"\nsecdiffcalls = %d\n",secdiffcalls
);
317 (void) fprintf(table
->out
,"secdiff = %d\n",secdiff
);
318 (void) fprintf(table
->out
,"secdiffmisfire = %d",secdiffmisfire
);
323 Cudd_FreeZddTree(table
);
326 } /* end of cuddZddTreeSifting */
329 /*---------------------------------------------------------------------------*/
330 /* Definition of static functions */
331 /*---------------------------------------------------------------------------*/
334 /**Function********************************************************************
336 Synopsis [Visits the group tree and reorders each group.]
338 Description [Recursively visits the group tree and reorders each
339 group in postorder fashion. Returns 1 if successful; 0 otherwise.]
343 ******************************************************************************/
348 Cudd_ReorderingType method
)
354 Mtr_PrintGroups(treenode
,1);
358 while (auxnode
!= NULL
) {
359 if (auxnode
->child
!= NULL
) {
360 if (!zddTreeSiftingAux(table
, auxnode
->child
, method
))
362 res
= zddReorderChildren(table
, auxnode
, CUDD_REORDER_GROUP_SIFT
);
365 } else if (auxnode
->size
> 1) {
366 if (!zddReorderChildren(table
, auxnode
, method
))
369 auxnode
= auxnode
->younger
;
374 } /* end of zddTreeSiftingAux */
378 /**Function********************************************************************
380 Synopsis [Counts the number of internal nodes of the group tree.]
382 Description [Counts the number of internal nodes of the group tree.
387 ******************************************************************************/
389 zddCountInternalMtrNodes(
399 while (auxnode
!= NULL
) {
400 if (!(MTR_TEST(auxnode
,MTR_TERMINAL
))) {
402 count
= zddCountInternalMtrNodes(table
,auxnode
->child
);
405 auxnode
= auxnode
->younger
;
410 } /* end of zddCountInternalMtrNodes */
414 /**Function********************************************************************
416 Synopsis [Reorders the children of a group tree node according to
419 Description [Reorders the children of a group tree node according to
420 the options. After reordering puts all the variables in the group
421 and/or its descendents in a single group. This allows hierarchical
422 reordering. If the variables in the group do not exist yet, simply
423 does nothing. Returns 1 if successful; 0 otherwise.]
427 ******************************************************************************/
432 Cudd_ReorderingType method
)
437 unsigned int initialSize
;
439 zddFindNodeHiLo(table
,treenode
,&lower
,&upper
);
440 /* If upper == -1 these variables do not exist yet. */
444 if (treenode
->flags
== MTR_FIXED
) {
448 (void) fprintf(table
->out
," ");
451 case CUDD_REORDER_RANDOM
:
452 case CUDD_REORDER_RANDOM_PIVOT
:
453 result
= cuddZddSwapping(table
,lower
,upper
,method
);
455 case CUDD_REORDER_SIFT
:
456 result
= cuddZddSifting(table
,lower
,upper
);
458 case CUDD_REORDER_SIFT_CONVERGE
:
460 initialSize
= table
->keysZ
;
461 result
= cuddZddSifting(table
,lower
,upper
);
462 if (initialSize
<= table
->keysZ
)
466 (void) fprintf(table
->out
,"\n");
468 } while (result
!= 0);
470 case CUDD_REORDER_SYMM_SIFT
:
471 result
= cuddZddSymmSifting(table
,lower
,upper
);
473 case CUDD_REORDER_SYMM_SIFT_CONV
:
474 result
= cuddZddSymmSiftingConv(table
,lower
,upper
);
476 case CUDD_REORDER_GROUP_SIFT
:
477 result
= zddGroupSifting(table
,lower
,upper
);
479 case CUDD_REORDER_LINEAR
:
480 result
= cuddZddLinearSifting(table
,lower
,upper
);
482 case CUDD_REORDER_LINEAR_CONVERGE
:
484 initialSize
= table
->keysZ
;
485 result
= cuddZddLinearSifting(table
,lower
,upper
);
486 if (initialSize
<= table
->keysZ
)
490 (void) fprintf(table
->out
,"\n");
492 } while (result
!= 0);
499 /* Create a single group for all the variables that were sifted,
500 ** so that they will be treated as a single block by successive
501 ** invocations of zddGroupSifting.
503 zddMergeGroups(table
,treenode
,lower
,upper
);
506 if (pr
> 0) (void) fprintf(table
->out
,"zddReorderChildren:");
511 } /* end of zddReorderChildren */
514 /**Function********************************************************************
516 Synopsis [Finds the lower and upper bounds of the group represented
519 Description [Finds the lower and upper bounds of the group represented
520 by treenode. The high and low fields of treenode are indices. From
521 those we need to derive the current positions, and find maximum and
524 SideEffects [The bounds are returned as side effects.]
528 ******************************************************************************/
539 /* Check whether no variables in this group already exist.
540 ** If so, return immediately. The calling procedure will know from
541 ** the values of upper that no reordering is needed.
543 if ((int) treenode
->low
>= table
->sizeZ
) {
544 *lower
= table
->sizeZ
;
549 *lower
= low
= (unsigned int) table
->permZ
[treenode
->index
];
550 high
= (int) (low
+ treenode
->size
- 1);
552 if (high
>= table
->sizeZ
) {
553 /* This is the case of a partially existing group. The aim is to
554 ** reorder as many variables as safely possible. If the tree
555 ** node is terminal, we just reorder the subset of the group
556 ** that is currently in existence. If the group has
557 ** subgroups, then we only reorder those subgroups that are
558 ** fully instantiated. This way we avoid breaking up a group.
560 MtrNode
*auxnode
= treenode
->child
;
561 if (auxnode
== NULL
) {
562 *upper
= (unsigned int) table
->sizeZ
- 1;
564 /* Search the subgroup that strands the table->sizeZ line.
565 ** If the first group starts at 0 and goes past table->sizeZ
566 ** upper will get -1, thus correctly signaling that no reordering
567 ** should take place.
569 while (auxnode
!= NULL
) {
570 int thisLower
= table
->permZ
[auxnode
->low
];
571 int thisUpper
= thisLower
+ auxnode
->size
- 1;
572 if (thisUpper
>= table
->sizeZ
&& thisLower
< table
->sizeZ
)
573 *upper
= (unsigned int) thisLower
- 1;
574 auxnode
= auxnode
->younger
;
578 /* Normal case: All the variables of the group exist. */
579 *upper
= (unsigned int) high
;
583 /* Make sure that all variables in group are contiguous. */
584 assert(treenode
->size
>= *upper
- *lower
+ 1);
589 } /* end of zddFindNodeHiLo */
592 /**Function********************************************************************
594 Synopsis [Comparison function used by qsort.]
596 Description [Comparison function used by qsort to order the variables
597 according to the number of keys in the subtables. Returns the
598 difference in number of keys between the two variables being
603 ******************************************************************************/
605 zddUniqueCompareGroup(
610 if (entry
[*ptrY
] == entry
[*ptrX
]) {
611 return((*ptrX
) - (*ptrY
));
614 return(entry
[*ptrY
] - entry
[*ptrX
]);
616 } /* end of zddUniqueCompareGroup */
619 /**Function********************************************************************
621 Synopsis [Sifts from treenode->low to treenode->high.]
623 Description [Sifts from treenode->low to treenode->high. If
624 croupcheck == CUDD_GROUP_CHECK7, it checks for group creation at the
625 end of the initial sifting. If a group is created, it is then sifted
626 again. After sifting one variable, the group that contains it is
627 dissolved. Returns 1 in case of success; 0 otherwise.]
631 ******************************************************************************/
645 unsigned previousSize
;
649 nvars
= table
->sizeZ
;
651 /* Order variables to sift. */
654 var
= ALLOC(int,nvars
);
656 table
->errorCode
= CUDD_MEMORY_OUT
;
657 goto zddGroupSiftingOutOfMem
;
659 entry
= ALLOC(int,nvars
);
661 table
->errorCode
= CUDD_MEMORY_OUT
;
662 goto zddGroupSiftingOutOfMem
;
664 sifted
= ALLOC(int,nvars
);
665 if (sifted
== NULL
) {
666 table
->errorCode
= CUDD_MEMORY_OUT
;
667 goto zddGroupSiftingOutOfMem
;
670 /* Here we consider only one representative for each group. */
671 for (i
= 0, classes
= 0; i
< nvars
; i
++) {
674 if ((unsigned) x
>= table
->subtableZ
[x
].next
) {
675 entry
[i
] = table
->subtableZ
[x
].keys
;
681 qsort((void *)var
,classes
,sizeof(int),(DD_QSFP
)zddUniqueCompareGroup
);
684 for (i
= 0; i
< ddMin(table
->siftMaxVar
,classes
); i
++) {
685 if (zddTotalNumberSwapping
>= table
->siftMaxSwap
)
688 if (sifted
[xindex
] == 1) /* variable already sifted as part of group */
690 x
= table
->permZ
[xindex
]; /* find current level of this variable */
691 if (x
< lower
|| x
> upper
)
694 previousSize
= table
->keysZ
;
697 /* x is bottom of group */
698 assert((unsigned) x
>= table
->subtableZ
[x
].next
);
700 result
= zddGroupSiftingAux(table
,x
,lower
,upper
);
701 if (!result
) goto zddGroupSiftingOutOfMem
;
704 if (table
->keysZ
< previousSize
) {
705 (void) fprintf(table
->out
,"-");
706 } else if (table
->keysZ
> previousSize
) {
707 (void) fprintf(table
->out
,"+");
709 (void) fprintf(table
->out
,"=");
714 /* Mark variables in the group just sifted. */
715 x
= table
->permZ
[xindex
];
716 if ((unsigned) x
!= table
->subtableZ
[x
].next
) {
719 j
= table
->invpermZ
[x
];
721 x
= table
->subtableZ
[x
].next
;
722 } while (x
!= xInit
);
726 if (pr
> 0) (void) fprintf(table
->out
,"zddGroupSifting:");
736 zddGroupSiftingOutOfMem
:
737 if (entry
!= NULL
) FREE(entry
);
738 if (var
!= NULL
) FREE(var
);
739 if (sifted
!= NULL
) FREE(sifted
);
743 } /* end of zddGroupSifting */
746 /**Function********************************************************************
748 Synopsis [Sifts one variable up and down until it has taken all
749 positions. Checks for aggregation.]
751 Description [Sifts one variable up and down until it has taken all
752 positions. Checks for aggregation. There may be at most two sweeps,
753 even if the group grows. Assumes that x is either an isolated
754 variable, or it is the bottom of a group. All groups may not have
755 been found. The variable being moved is returned to the best position
756 seen during sifting. Returns 1 in case of success; 0 otherwise.]
760 ******************************************************************************/
769 Move
*moves
; /* list of moves */
775 if (pr
> 0) (void) fprintf(table
->out
,"zddGroupSiftingAux from %d to %d\n",xLow
,xHigh
);
776 assert((unsigned) x
>= table
->subtableZ
[x
].next
); /* x is bottom of group */
779 initialSize
= table
->keysZ
;
782 if (x
== xLow
) { /* Sift down */
784 /* x must be a singleton */
785 assert((unsigned) x
== table
->subtableZ
[x
].next
);
787 if (x
== xHigh
) return(1); /* just one variable */
789 if (!zddGroupSiftingDown(table
,x
,xHigh
,&moves
))
790 goto zddGroupSiftingAuxOutOfMem
;
791 /* at this point x == xHigh, unless early term */
793 /* move backward and stop at best position */
794 result
= zddGroupSiftingBackward(table
,moves
,initialSize
);
796 assert(table
->keysZ
<= (unsigned) initialSize
);
798 if (!result
) goto zddGroupSiftingAuxOutOfMem
;
800 } else if (cuddZddNextHigh(table
,x
) > xHigh
) { /* Sift up */
802 /* x is bottom of group */
803 assert((unsigned) x
>= table
->subtableZ
[x
].next
);
805 /* Find top of x's group */
806 x
= table
->subtableZ
[x
].next
;
808 if (!zddGroupSiftingUp(table
,x
,xLow
,&moves
))
809 goto zddGroupSiftingAuxOutOfMem
;
810 /* at this point x == xLow, unless early term */
812 /* move backward and stop at best position */
813 result
= zddGroupSiftingBackward(table
,moves
,initialSize
);
815 assert(table
->keysZ
<= (unsigned) initialSize
);
817 if (!result
) goto zddGroupSiftingAuxOutOfMem
;
819 } else if (x
- xLow
> xHigh
- x
) { /* must go down first: shorter */
820 if (!zddGroupSiftingDown(table
,x
,xHigh
,&moves
))
821 goto zddGroupSiftingAuxOutOfMem
;
822 /* at this point x == xHigh, unless early term */
824 /* Find top of group */
828 while ((unsigned) x
< table
->subtableZ
[x
].next
)
829 x
= table
->subtableZ
[x
].next
;
830 x
= table
->subtableZ
[x
].next
;
832 /* x should be the top of a group */
833 assert((unsigned) x
<= table
->subtableZ
[x
].next
);
836 if (!zddGroupSiftingUp(table
,x
,xLow
,&moves
))
837 goto zddGroupSiftingAuxOutOfMem
;
839 /* move backward and stop at best position */
840 result
= zddGroupSiftingBackward(table
,moves
,initialSize
);
842 assert(table
->keysZ
<= (unsigned) initialSize
);
844 if (!result
) goto zddGroupSiftingAuxOutOfMem
;
846 } else { /* moving up first: shorter */
847 /* Find top of x's group */
848 x
= table
->subtableZ
[x
].next
;
850 if (!zddGroupSiftingUp(table
,x
,xLow
,&moves
))
851 goto zddGroupSiftingAuxOutOfMem
;
852 /* at this point x == xHigh, unless early term */
857 while ((unsigned) x
< table
->subtableZ
[x
].next
)
858 x
= table
->subtableZ
[x
].next
;
860 /* x is bottom of a group */
861 assert((unsigned) x
>= table
->subtableZ
[x
].next
);
864 if (!zddGroupSiftingDown(table
,x
,xHigh
,&moves
))
865 goto zddGroupSiftingAuxOutOfMem
;
867 /* move backward and stop at best position */
868 result
= zddGroupSiftingBackward(table
,moves
,initialSize
);
870 assert(table
->keysZ
<= (unsigned) initialSize
);
872 if (!result
) goto zddGroupSiftingAuxOutOfMem
;
875 while (moves
!= NULL
) {
877 cuddDeallocMove(table
, moves
);
883 zddGroupSiftingAuxOutOfMem
:
884 while (moves
!= NULL
) {
886 cuddDeallocMove(table
, moves
);
892 } /* end of zddGroupSiftingAux */
895 /**Function********************************************************************
897 Synopsis [Sifts up a variable until either it reaches position xLow
898 or the size of the DD heap increases too much.]
900 Description [Sifts up a variable until either it reaches position
901 xLow or the size of the DD heap increases too much. Assumes that y is
902 the top of a group (or a singleton). Checks y for aggregation to the
903 adjacent variables. Records all the moves that are appended to the
904 list of moves received as input and returned as a side effect.
905 Returns 1 in case of success; 0 otherwise.]
909 ******************************************************************************/
923 limitSize
= table
->keysZ
;
925 x
= cuddZddNextLow(table
,y
);
927 gxtop
= table
->subtableZ
[x
].next
;
928 if (table
->subtableZ
[x
].next
== (unsigned) x
&&
929 table
->subtableZ
[y
].next
== (unsigned) y
) {
930 /* x and y are self groups */
931 size
= cuddZddSwapInPlace(table
,x
,y
);
933 assert(table
->subtableZ
[x
].next
== (unsigned) x
);
934 assert(table
->subtableZ
[y
].next
== (unsigned) y
);
936 if (size
== 0) goto zddGroupSiftingUpOutOfMem
;
937 move
= (Move
*)cuddDynamicAllocNode(table
);
938 if (move
== NULL
) goto zddGroupSiftingUpOutOfMem
;
941 move
->flags
= MTR_DEFAULT
;
947 if (pr
> 0) (void) fprintf(table
->out
,"zddGroupSiftingUp (2 single groups):\n");
949 if ((double) size
> (double) limitSize
* table
->maxGrowth
)
951 if (size
< limitSize
) limitSize
= size
;
952 } else { /* group move */
953 size
= zddGroupMove(table
,x
,y
,moves
);
954 if (size
== 0) goto zddGroupSiftingUpOutOfMem
;
955 if ((double) size
> (double) limitSize
* table
->maxGrowth
)
957 if (size
< limitSize
) limitSize
= size
;
960 x
= cuddZddNextLow(table
,y
);
965 zddGroupSiftingUpOutOfMem
:
966 while (*moves
!= NULL
) {
967 move
= (*moves
)->next
;
968 cuddDeallocMove(table
, *moves
);
973 } /* end of zddGroupSiftingUp */
976 /**Function********************************************************************
978 Synopsis [Sifts down a variable until it reaches position xHigh.]
980 Description [Sifts down a variable until it reaches position xHigh.
981 Assumes that x is the bottom of a group (or a singleton). Records
982 all the moves. Returns 1 in case of success; 0 otherwise.]
986 ******************************************************************************/
1002 limitSize
= size
= table
->keysZ
;
1003 y
= cuddZddNextHigh(table
,x
);
1004 while (y
<= xHigh
) {
1005 /* Find bottom of y group. */
1006 gybot
= table
->subtableZ
[y
].next
;
1007 while (table
->subtableZ
[gybot
].next
!= (unsigned) y
)
1008 gybot
= table
->subtableZ
[gybot
].next
;
1010 if (table
->subtableZ
[x
].next
== (unsigned) x
&&
1011 table
->subtableZ
[y
].next
== (unsigned) y
) {
1012 /* x and y are self groups */
1013 size
= cuddZddSwapInPlace(table
,x
,y
);
1015 assert(table
->subtableZ
[x
].next
== (unsigned) x
);
1016 assert(table
->subtableZ
[y
].next
== (unsigned) y
);
1018 if (size
== 0) goto zddGroupSiftingDownOutOfMem
;
1021 move
= (Move
*) cuddDynamicAllocNode(table
);
1022 if (move
== NULL
) goto zddGroupSiftingDownOutOfMem
;
1025 move
->flags
= MTR_DEFAULT
;
1027 move
->next
= *moves
;
1031 if (pr
> 0) (void) fprintf(table
->out
,"zddGroupSiftingDown (2 single groups):\n");
1033 if ((double) size
> (double) limitSize
* table
->maxGrowth
)
1035 if (size
< limitSize
) limitSize
= size
;
1037 y
= cuddZddNextHigh(table
,x
);
1038 } else { /* Group move */
1039 size
= zddGroupMove(table
,x
,y
,moves
);
1040 if (size
== 0) goto zddGroupSiftingDownOutOfMem
;
1041 if ((double) size
> (double) limitSize
* table
->maxGrowth
)
1043 if (size
< limitSize
) limitSize
= size
;
1046 y
= cuddZddNextHigh(table
,x
);
1051 zddGroupSiftingDownOutOfMem
:
1052 while (*moves
!= NULL
) {
1053 move
= (*moves
)->next
;
1054 cuddDeallocMove(table
, *moves
);
1060 } /* end of zddGroupSiftingDown */
1063 /**Function********************************************************************
1065 Synopsis [Swaps two groups and records the move.]
1067 Description [Swaps two groups and records the move. Returns the
1068 number of keys in the DD table in case of success; 0 otherwise.]
1072 ******************************************************************************/
1082 int i
,j
,xtop
,xbot
,xsize
,ytop
,ybot
,ysize
,newxtop
;
1084 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
1085 int initialSize
,bestSize
;
1089 /* We assume that x < y */
1092 /* Find top, bottom, and size for the two groups. */
1094 xtop
= table
->subtableZ
[x
].next
;
1095 xsize
= xbot
- xtop
+ 1;
1097 while ((unsigned) ybot
< table
->subtableZ
[ybot
].next
)
1098 ybot
= table
->subtableZ
[ybot
].next
;
1100 ysize
= ybot
- ytop
+ 1;
1102 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
1103 initialSize
= bestSize
= table
->keysZ
;
1105 /* Sift the variables of the second group up through the first group */
1106 for (i
= 1; i
<= ysize
; i
++) {
1107 for (j
= 1; j
<= xsize
; j
++) {
1108 size
= cuddZddSwapInPlace(table
,x
,y
);
1109 if (size
== 0) goto zddGroupMoveOutOfMem
;
1110 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
1111 if (size
< bestSize
)
1114 swapx
= x
; swapy
= y
;
1116 x
= cuddZddNextLow(table
,y
);
1119 x
= cuddZddNextLow(table
,y
);
1121 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
1122 if ((bestSize
< initialSize
) && (bestSize
< size
))
1123 (void) fprintf(table
->out
,"Missed local minimum: initialSize:%d bestSize:%d finalSize:%d\n",initialSize
,bestSize
,size
);
1127 y
= xtop
; /* ytop is now where xtop used to be */
1128 for (i
= 0; i
< ysize
- 1; i
++) {
1129 table
->subtableZ
[y
].next
= cuddZddNextHigh(table
,y
);
1130 y
= cuddZddNextHigh(table
,y
);
1132 table
->subtableZ
[y
].next
= xtop
; /* y is bottom of its group, join */
1133 /* it to top of its group */
1134 x
= cuddZddNextHigh(table
,y
);
1136 for (i
= 0; i
< xsize
- 1; i
++) {
1137 table
->subtableZ
[x
].next
= cuddZddNextHigh(table
,x
);
1138 x
= cuddZddNextHigh(table
,x
);
1140 table
->subtableZ
[x
].next
= newxtop
; /* x is bottom of its group, join */
1141 /* it to top of its group */
1143 if (pr
> 0) (void) fprintf(table
->out
,"zddGroupMove:\n");
1146 /* Store group move */
1147 move
= (Move
*) cuddDynamicAllocNode(table
);
1148 if (move
== NULL
) goto zddGroupMoveOutOfMem
;
1151 move
->flags
= MTR_DEFAULT
;
1152 move
->size
= table
->keysZ
;
1153 move
->next
= *moves
;
1156 return(table
->keysZ
);
1158 zddGroupMoveOutOfMem
:
1159 while (*moves
!= NULL
) {
1160 move
= (*moves
)->next
;
1161 cuddDeallocMove(table
, *moves
);
1166 } /* end of zddGroupMove */
1169 /**Function********************************************************************
1171 Synopsis [Undoes the swap two groups.]
1173 Description [Undoes the swap two groups. Returns 1 in case of
1174 success; 0 otherwise.]
1178 ******************************************************************************/
1180 zddGroupMoveBackward(
1186 int i
,j
,xtop
,xbot
,xsize
,ytop
,ybot
,ysize
,newxtop
;
1190 /* We assume that x < y */
1194 /* Find top, bottom, and size for the two groups. */
1196 xtop
= table
->subtableZ
[x
].next
;
1197 xsize
= xbot
- xtop
+ 1;
1199 while ((unsigned) ybot
< table
->subtableZ
[ybot
].next
)
1200 ybot
= table
->subtableZ
[ybot
].next
;
1202 ysize
= ybot
- ytop
+ 1;
1204 /* Sift the variables of the second group up through the first group */
1205 for (i
= 1; i
<= ysize
; i
++) {
1206 for (j
= 1; j
<= xsize
; j
++) {
1207 size
= cuddZddSwapInPlace(table
,x
,y
);
1211 x
= cuddZddNextLow(table
,y
);
1214 x
= cuddZddNextLow(table
,y
);
1219 for (i
= 0; i
< ysize
- 1; i
++) {
1220 table
->subtableZ
[y
].next
= cuddZddNextHigh(table
,y
);
1221 y
= cuddZddNextHigh(table
,y
);
1223 table
->subtableZ
[y
].next
= xtop
; /* y is bottom of its group, join */
1225 x
= cuddZddNextHigh(table
,y
);
1227 for (i
= 0; i
< xsize
- 1; i
++) {
1228 table
->subtableZ
[x
].next
= cuddZddNextHigh(table
,x
);
1229 x
= cuddZddNextHigh(table
,x
);
1231 table
->subtableZ
[x
].next
= newxtop
; /* x is bottom of its group, join */
1234 if (pr
> 0) (void) fprintf(table
->out
,"zddGroupMoveBackward:\n");
1239 } /* end of zddGroupMoveBackward */
1242 /**Function********************************************************************
1244 Synopsis [Determines the best position for a variables and returns
1247 Description [Determines the best position for a variables and returns
1248 it there. Returns 1 in case of success; 0 otherwise.]
1252 ******************************************************************************/
1254 zddGroupSiftingBackward(
1263 for (move
= moves
; move
!= NULL
; move
= move
->next
) {
1264 if (move
->size
< size
) {
1269 for (move
= moves
; move
!= NULL
; move
= move
->next
) {
1270 if (move
->size
== size
) return(1);
1271 if ((table
->subtableZ
[move
->x
].next
== move
->x
) &&
1272 (table
->subtableZ
[move
->y
].next
== move
->y
)) {
1273 res
= cuddZddSwapInPlace(table
,(int)move
->x
,(int)move
->y
);
1274 if (!res
) return(0);
1276 if (pr
> 0) (void) fprintf(table
->out
,"zddGroupSiftingBackward:\n");
1277 assert(table
->subtableZ
[move
->x
].next
== move
->x
);
1278 assert(table
->subtableZ
[move
->y
].next
== move
->y
);
1280 } else { /* Group move necessary */
1281 res
= zddGroupMoveBackward(table
,(int)move
->x
,(int)move
->y
);
1282 if (!res
) return(0);
1288 } /* end of zddGroupSiftingBackward */
1291 /**Function********************************************************************
1293 Synopsis [Merges groups in the DD table.]
1295 Description [Creates a single group from low to high and adjusts the
1296 idex field of the tree node.]
1300 ******************************************************************************/
1313 /* Merge all variables from low to high in one group, unless
1314 ** this is the topmost group. In such a case we do not merge lest
1315 ** we lose the symmetry information. */
1316 if (treenode
!= table
->treeZ
) {
1317 for (i
= low
; i
< high
; i
++)
1318 table
->subtableZ
[i
].next
= i
+1;
1319 table
->subtableZ
[high
].next
= low
;
1322 /* Adjust the index fields of the tree nodes. If a node is the
1323 ** first child of its parent, then the parent may also need adjustment. */
1324 saveindex
= treenode
->index
;
1325 newindex
= table
->invpermZ
[low
];
1328 auxnode
->index
= newindex
;
1329 if (auxnode
->parent
== NULL
||
1330 (int) auxnode
->parent
->index
!= saveindex
)
1332 auxnode
= auxnode
->parent
;
1336 } /* end of zddMergeGroups */