1 /**CFile**********************************************************************
3 FileName [dddmpNodeCnf.c]
7 Synopsis [Functions to handle BDD node infos and numbering
8 while storing a CNF formula from a BDD or an array of BDDs]
10 Description [Functions to handle BDD node infos and numbering
11 while storing a CNF formula from a BDD or an array of BDDs.
14 Author [Gianpiero Cabodi and Stefano Quer]
17 Copyright (c) 2004 by Politecnico di Torino.
18 All Rights Reserved. This software is for educational purposes only.
19 Permission is given to academic institutions to use, copy, and modify
20 this software and its documentation provided that this introductory
21 message is not removed, that this software and its documentation is
22 used for the institutions' internal research and educational purposes,
23 and that no monies are exchanged. No guarantee is expressed or implied
24 by the distribution of this code.
25 Send bug-reports and/or questions to:
26 {gianpiero.cabodi,stefano.quer}@polito.it.
29 ******************************************************************************/
33 /*---------------------------------------------------------------------------*/
34 /* Stucture declarations */
35 /*---------------------------------------------------------------------------*/
37 /*---------------------------------------------------------------------------*/
38 /* Type declarations */
39 /*---------------------------------------------------------------------------*/
41 /*---------------------------------------------------------------------------*/
42 /* Variable declarations */
43 /*---------------------------------------------------------------------------*/
45 #define DDDMP_DEBUG_CNF 0
47 /*---------------------------------------------------------------------------*/
48 /* Macro declarations */
49 /*---------------------------------------------------------------------------*/
51 /**AutomaticStart*************************************************************/
53 /*---------------------------------------------------------------------------*/
54 /* Static function prototypes */
55 /*---------------------------------------------------------------------------*/
57 static int DddmpWriteNodeIndexCnfWithTerminalCheck(DdNode
*f
, int *cnfIds
, int id
);
58 static int DddmpClearVisitedCnfRecur(DdNode
*f
);
59 static void DddmpClearVisitedCnf(DdNode
*f
);
60 static int NumberNodeRecurCnf(DdNode
*f
, int *cnfIds
, int id
);
61 static void DddmpDdNodesCheckIncomingAndScanPath(DdNode
*f
, int pathLengthCurrent
, int edgeInTh
, int pathLengthTh
);
62 static int DddmpDdNodesNumberEdgesRecur(DdNode
*f
, int *cnfIds
, int id
);
63 static int DddmpDdNodesResetCountRecur(DdNode
*f
);
64 static int DddmpDdNodesCountEdgesRecur(DdNode
*f
);
65 static void RemoveFromUniqueRecurCnf(DdManager
*ddMgr
, DdNode
*f
);
66 static void RestoreInUniqueRecurCnf(DdManager
*ddMgr
, DdNode
*f
);
67 static int DddmpPrintBddAndNextRecur(DdManager
*ddMgr
, DdNode
*f
);
69 /**AutomaticEnd***************************************************************/
71 /*---------------------------------------------------------------------------*/
72 /* Definition of exported functions */
73 /*---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------*/
76 /* Definition of internal functions */
77 /*---------------------------------------------------------------------------*/
79 /**Function********************************************************************
81 Synopsis [Removes nodes from unique table and numbers them]
83 Description [Node numbering is required to convert pointers to integers.
84 Since nodes are removed from unique table, no new nodes should
85 be generated before re-inserting nodes in the unique table
86 (DddmpUnnumberDdNodesCnf()).
89 SideEffects [Nodes are temporarily removed from unique table]
91 SeeAlso [RemoveFromUniqueRecurCnf(), NumberNodeRecurCnf(),
92 DddmpUnnumberDdNodesCnf()]
94 ******************************************************************************/
97 DddmpNumberDdNodesCnf (
98 DdManager
*ddMgr
/* IN: DD Manager */,
99 DdNode
**f
/* IN: array of BDDs */,
100 int rootN
/* IN: number of BDD roots in the array of BDDs */,
101 int *cnfIds
/* OUT: CNF identifiers for variables */,
102 int id
/* OUT: number of Temporary Variables Introduced */
107 for (i
=0; i
<rootN
; i
++) {
108 RemoveFromUniqueRecurCnf (ddMgr
, f
[i
]);
111 for (i
=0; i
<rootN
; i
++) {
112 id
= NumberNodeRecurCnf (f
[i
], cnfIds
, id
);
118 /**Function********************************************************************
120 Synopsis [Removes nodes from unique table and numbers each node according
121 to the number of its incoming BDD edges.
124 Description [Removes nodes from unique table and numbers each node according
125 to the number of its incoming BDD edges.
128 SideEffects [Nodes are temporarily removed from unique table]
130 SeeAlso [RemoveFromUniqueRecurCnf()]
132 ******************************************************************************/
135 DddmpDdNodesCountEdgesAndNumber (
136 DdManager
*ddMgr
/* IN: DD Manager */,
137 DdNode
**f
/* IN: Array of BDDs */,
138 int rootN
/* IN: Number of BDD roots in the array of BDDs */,
139 int edgeInTh
/* IN: Max # In-Edges, after a Insert Cut Point */,
140 int pathLengthTh
/* IN: Max Path Length (after, Insert a Cut Point) */,
141 int *cnfIds
/* OUT: CNF identifiers for variables */,
142 int id
/* OUT: Number of Temporary Variables Introduced */
147 /*-------------------------- Remove From Unique ---------------------------*/
149 for (i
=0; i
<rootN
; i
++) {
150 RemoveFromUniqueRecurCnf (ddMgr
, f
[i
]);
153 /*-------------------- Reset Counter and Reset Visited --------------------*/
155 for (i
=0; i
<rootN
; i
++) {
156 retValue
= DddmpDdNodesResetCountRecur (f
[i
]);
159 /* Here we must have:
166 fprintf (stdout
, "###---> BDDs After Count Reset:\n");
167 DddmpPrintBddAndNext (ddMgr
, f
, rootN
);
170 /*----------------------- Count Incoming Edges ----------------------------*/
172 for (i
=0; i
<rootN
; i
++) {
173 retValue
= DddmpDdNodesCountEdgesRecur (f
[i
]);
176 /* Here we must have:
177 * cnfIndex = incoming edge count
178 * visitedFlag = 0 (AGAIN ... remains untouched)
183 fprintf (stdout
, "###---> BDDs After Count Recur:\n");
184 DddmpPrintBddAndNext (ddMgr
, f
, rootN
);
187 /*------------------------- Count Path Length ----------------------------*/
189 for (i
=0; i
<rootN
; i
++) {
190 DddmpDdNodesCheckIncomingAndScanPath (f
[i
], 0, edgeInTh
,
194 /* Here we must have:
195 * cnfIndex = 1 if we want to insert there a cut point
196 * 0 if we do NOT want to insert there a cut point
202 fprintf (stdout
, "###---> BDDs After Check Incoming And Scan Path:\n");
203 DddmpPrintBddAndNext (ddMgr
, f
, rootN
);
206 /*-------------------- Number Nodes and Set Visited -----------------------*/
208 for (i
=0; i
<rootN
; i
++) {
209 id
= DddmpDdNodesNumberEdgesRecur (f
[i
], cnfIds
, id
);
212 /* Here we must have:
213 * cnfIndex = CNF auxiliary variable enumeration
219 fprintf (stdout
, "###---> BDDs After Count Edges Recur:\n");
220 DddmpPrintBddAndNext (ddMgr
, f
, rootN
);
226 /**Function********************************************************************
228 Synopsis [Restores nodes in unique table, loosing numbering]
230 Description [Node indexes are no more needed. Nodes are re-linked in the
236 SeeAlso [DddmpNumberDdNode()]
238 ******************************************************************************/
241 DddmpUnnumberDdNodesCnf(
242 DdManager
*ddMgr
/* IN: DD Manager */,
243 DdNode
**f
/* IN: array of BDDs */,
244 int rootN
/* IN: number of BDD roots in the array of BDDs */
249 for (i
=0; i
<rootN
; i
++) {
250 RestoreInUniqueRecurCnf (ddMgr
, f
[i
]);
256 /**Function********************************************************************
258 Synopsis [Prints debug information]
260 Description [Prints debug information for an array of BDDs on the screen]
266 ******************************************************************************/
269 DddmpPrintBddAndNext (
270 DdManager
*ddMgr
/* IN: DD Manager */,
271 DdNode
**f
/* IN: Array of BDDs to be displayed */,
272 int rootN
/* IN: Number of BDD roots in the array of BDDs */
277 for (i
=0; i
<rootN
; i
++) {
278 fprintf (stdout
, "---> Bdd %d:\n", i
);
280 DddmpPrintBddAndNextRecur (ddMgr
, f
[i
]);
283 return (DDDMP_SUCCESS
);
286 /**Function********************************************************************
288 Synopsis [Write index to node]
290 Description [The index of the node is written in the "next" field of
291 a DdNode struct. LSB is not used (set to 0). It is used as
292 "visited" flag in DD traversals.
297 SeeAlso [DddmpReadNodeIndexCnf(), DddmpSetVisitedCnf (),
301 ******************************************************************************/
304 DddmpWriteNodeIndexCnf (
305 DdNode
*f
/* IN: BDD node */,
306 int id
/* IN: index to be written */
309 if (!Cudd_IsConstant (f
)) {
310 f
->next
= (struct DdNode
*)((ptruint
)((id
)<<1));
313 return (DDDMP_SUCCESS
);
316 /**Function********************************************************************
318 Synopsis [Returns true if node is visited]
320 Description [Returns true if node is visited]
324 SeeAlso [DddmpSetVisitedCnf (), DddmpClearVisitedCnf ()]
326 ******************************************************************************/
330 DdNode
*f
/* IN: BDD node to be tested */
335 return ((int)((ptruint
)(f
->next
)) & (01));
338 /**Function********************************************************************
340 Synopsis [Marks a node as visited]
342 Description [Marks a node as visited]
346 SeeAlso [DddmpVisitedCnf (), DddmpClearVisitedCnf ()]
348 ******************************************************************************/
352 DdNode
*f
/* IN: BDD node to be marked (as visited) */
357 f
->next
= (DdNode
*)(ptruint
)((int)((ptruint
)(f
->next
))|01);
362 /**Function********************************************************************
364 Synopsis [Reads the index of a node]
366 Description [Reads the index of a node. LSB is skipped (used as visited
372 SeeAlso [DddmpWriteNodeIndexCnf(), DddmpSetVisitedCnf (),
375 ******************************************************************************/
378 DddmpReadNodeIndexCnf (
379 DdNode
*f
/* IN: BDD node */
382 if (!Cudd_IsConstant (f
)) {
383 return ((int)(((ptruint
)(f
->next
))>>1));
389 /*---------------------------------------------------------------------------*/
390 /* Definition of static functions */
391 /*---------------------------------------------------------------------------*/
393 /**Function********************************************************************
395 Synopsis [Write index to node]
397 Description [The index of the node is written in the "next" field of
398 a DdNode struct. LSB is not used (set to 0). It is used as
399 "visited" flag in DD traversals. The index corresponds to
400 the BDD node variable if both the node's children are a
401 constant node, otherwise a new CNF variable is used.
406 SeeAlso [DddmpReadNodeIndexCnf(), DddmpSetVisitedCnf (),
409 *****************************************************************************/
412 DddmpWriteNodeIndexCnfWithTerminalCheck (
413 DdNode
*f
/* IN: BDD node */,
414 int *cnfIds
/* IN: possible source for the index to be written */,
415 int id
/* IN: possible source for the index to be written */
418 if (!Cudd_IsConstant (f
)) {
419 if (Cudd_IsConstant (cuddT (f
)) && Cudd_IsConstant (cuddE (f
))) {
420 /* If Variable SET ID as Variable ID */
421 f
->next
= (struct DdNode
*)((ptruint
)((cnfIds
[f
->index
])<<1));
423 f
->next
= (struct DdNode
*)((ptruint
)((id
)<<1));
431 /**Function********************************************************************
433 Synopsis [Mark ALL nodes as not visited]
435 Description [Mark ALL nodes as not visited (it recurs on the node children)]
439 SeeAlso [DddmpVisitedCnf (), DddmpSetVisitedCnf ()]
441 ******************************************************************************/
444 DddmpClearVisitedCnfRecur (
445 DdNode
*f
/* IN: root of the BDD to be marked */
452 if (cuddIsConstant (f
)) {
453 return (DDDMP_SUCCESS
);
456 if (!DddmpVisitedCnf (f
)) {
457 return (DDDMP_SUCCESS
);
460 retValue
= DddmpClearVisitedCnfRecur (cuddT (f
));
461 retValue
= DddmpClearVisitedCnfRecur (cuddE (f
));
463 DddmpClearVisitedCnf (f
);
465 return (DDDMP_SUCCESS
);
468 /**Function********************************************************************
470 Synopsis [Marks a node as not visited]
472 Description [Marks a node as not visited]
476 SeeAlso [DddmpVisitedCnf (), DddmpSetVisitedCnf ()]
478 ******************************************************************************/
481 DddmpClearVisitedCnf (
482 DdNode
*f
/* IN: BDD node to be marked (as not visited) */
485 f
= Cudd_Regular (f
);
487 f
->next
= (DdNode
*)(ptruint
)((int)((ptruint
)(f
->next
)) & (~01));
492 /**Function********************************************************************
494 Synopsis [Number nodes recursively in post-order]
496 Description [Number nodes recursively in post-order.
497 The "visited" flag is used with inverse polarity, because all nodes
498 were set "visited" when removing them from unique.
501 SideEffects ["visited" flags are reset.]
505 ******************************************************************************/
509 DdNode
*f
/* IN: root of the BDD to be numbered */,
510 int *cnfIds
/* IN: possible source for numbering */,
511 int id
/* IN/OUT: possible source for numbering */
516 if (!DddmpVisitedCnf (f
)) {
520 if (!cuddIsConstant (f
)) {
521 id
= NumberNodeRecurCnf (cuddT (f
), cnfIds
, id
);
522 id
= NumberNodeRecurCnf (cuddE (f
), cnfIds
, id
);
525 id
= DddmpWriteNodeIndexCnfWithTerminalCheck (f
, cnfIds
, id
);
526 DddmpClearVisitedCnf (f
);
531 /**Function********************************************************************
533 Synopsis [Number nodes recursively in post-order]
535 Description [Number nodes recursively in post-order.
536 The "visited" flag is used with the right polarity.
537 The node is assigned to a new CNF variable only if it is a "shared"
538 node (i.e. the number of its incoming edges is greater than 1).
541 SideEffects ["visited" flags are set.]
545 ******************************************************************************/
548 DddmpDdNodesCheckIncomingAndScanPath (
549 DdNode
*f
/* IN: BDD node to be numbered */,
550 int pathLengthCurrent
/* IN: Current Path Length */,
551 int edgeInTh
/* IN: Max # In-Edges, after a Insert Cut Point */,
552 int pathLengthTh
/* IN: Max Path Length (after, Insert a Cut Point) */
559 if (DddmpVisitedCnf (f
)) {
563 if (cuddIsConstant (f
)) {
568 retValue
= DddmpReadNodeIndexCnf (f
);
570 if ( ((edgeInTh
>= 0) && (retValue
> edgeInTh
)) ||
571 ((pathLengthTh
>= 0) && (pathLengthCurrent
> pathLengthTh
))
573 DddmpWriteNodeIndexCnf (f
, 1);
574 pathLengthCurrent
= 0;
576 DddmpWriteNodeIndexCnf (f
, 0);
579 DddmpDdNodesCheckIncomingAndScanPath (cuddT (f
), pathLengthCurrent
,
580 edgeInTh
, pathLengthTh
);
581 DddmpDdNodesCheckIncomingAndScanPath (cuddE (f
), pathLengthCurrent
,
582 edgeInTh
, pathLengthTh
);
584 DddmpSetVisitedCnf (f
);
589 /**Function********************************************************************
591 Synopsis [Number nodes recursively in post-order]
593 Description [Number nodes recursively in post-order.
594 The "visited" flag is used with the inverse polarity.
595 Numbering follows the subsequent strategy:
596 * if the index = 0 it remains so
597 * if the index >= 1 it gets enumerated.
598 This implies that the node is assigned to a new CNF variable only if
599 it is not a terminal node otherwise it is assigned the index of
603 SideEffects ["visited" flags are reset.]
607 ******************************************************************************/
610 DddmpDdNodesNumberEdgesRecur (
611 DdNode
*f
/* IN: BDD node to be numbered */,
612 int *cnfIds
/* IN: possible source for numbering */,
613 int id
/* IN/OUT: possible source for numbering */
620 if (!DddmpVisitedCnf (f
)) {
624 if (cuddIsConstant (f
)) {
628 id
= DddmpDdNodesNumberEdgesRecur (cuddT (f
), cnfIds
, id
);
629 id
= DddmpDdNodesNumberEdgesRecur (cuddE (f
), cnfIds
, id
);
631 retValue
= DddmpReadNodeIndexCnf (f
);
633 id
= DddmpWriteNodeIndexCnfWithTerminalCheck (f
, cnfIds
, id
);
635 DddmpWriteNodeIndexCnf (f
, 0);
638 DddmpClearVisitedCnf (f
);
643 /**Function********************************************************************
645 Synopsis [Resets counter and visited flag for ALL nodes of a BDD]
647 Description [Resets counter and visited flag for ALL nodes of a BDD (it
648 recurs on the node children). The index field of the node is
656 ******************************************************************************/
659 DddmpDdNodesResetCountRecur (
660 DdNode
*f
/* IN: root of the BDD whose counters are reset */
665 f
= Cudd_Regular (f
);
667 if (!DddmpVisitedCnf (f
)) {
668 return (DDDMP_SUCCESS
);
671 if (!cuddIsConstant (f
)) {
672 retValue
= DddmpDdNodesResetCountRecur (cuddT (f
));
673 retValue
= DddmpDdNodesResetCountRecur (cuddE (f
));
676 DddmpWriteNodeIndexCnf (f
, 0);
677 DddmpClearVisitedCnf (f
);
679 return (DDDMP_SUCCESS
);
682 /**Function********************************************************************
684 Synopsis [Counts the number of incoming edges for each node of a BDD]
686 Description [Counts (recursively) the number of incoming edges for each
687 node of a BDD. This number is stored in the index field.
690 SideEffects ["visited" flags remain untouched.]
694 ******************************************************************************/
697 DddmpDdNodesCountEdgesRecur (
698 DdNode
*f
/* IN: root of the BDD */
701 int indexValue
, retValue
;
703 f
= Cudd_Regular (f
);
705 if (cuddIsConstant (f
)) {
706 return (DDDMP_SUCCESS
);
709 if (Cudd_IsConstant (cuddT (f
)) && Cudd_IsConstant (cuddE (f
))) {
710 return (DDDMP_SUCCESS
);
713 indexValue
= DddmpReadNodeIndexCnf (f
);
715 /* IF (first time) THEN recur */
716 if (indexValue
== 0) {
717 retValue
= DddmpDdNodesCountEdgesRecur (cuddT (f
));
718 retValue
= DddmpDdNodesCountEdgesRecur (cuddE (f
));
721 /* Increment Incoming-Edge Count Flag */
723 DddmpWriteNodeIndexCnf (f
, indexValue
);
725 return (DDDMP_SUCCESS
);
728 /**Function********************************************************************
730 Synopsis [Removes a node from unique table]
732 Description [Removes a node from the unique table by locating the proper
733 subtable and unlinking the node from it. It recurs on on the
734 children of the node. Constants remain untouched.
737 SideEffects [Nodes are left with the "visited" flag true.]
739 SeeAlso [RestoreInUniqueRecurCnf()]
741 ******************************************************************************/
744 RemoveFromUniqueRecurCnf (
745 DdManager
*ddMgr
/* IN: DD Manager */,
746 DdNode
*f
/* IN: root of the BDD to be extracted */
749 DdNode
*node
, *last
, *next
;
750 DdNode
*sentinel
= &(ddMgr
->sentinel
);
752 DdSubtable
*subtable
;
755 f
= Cudd_Regular (f
);
757 if (DddmpVisitedCnf (f
)) {
761 if (!cuddIsConstant (f
)) {
763 RemoveFromUniqueRecurCnf (ddMgr
, cuddT (f
));
764 RemoveFromUniqueRecurCnf (ddMgr
, cuddE (f
));
766 level
= ddMgr
->perm
[f
->index
];
767 subtable
= &(ddMgr
->subtables
[level
]);
769 nodelist
= subtable
->nodelist
;
771 pos
= ddHash (cuddT (f
), cuddE (f
), subtable
->shift
);
772 node
= nodelist
[pos
];
774 while (node
!= sentinel
) {
780 nodelist
[pos
] = next
;
792 DddmpSetVisitedCnf (f
);
797 /**Function********************************************************************
799 Synopsis [Restores a node in unique table]
801 Description [Restores a node in unique table (recursive)]
803 SideEffects [Nodes are not restored in the same order as before removal]
805 SeeAlso [RemoveFromUnique()]
807 ******************************************************************************/
810 RestoreInUniqueRecurCnf (
811 DdManager
*ddMgr
/* IN: DD Manager */,
812 DdNode
*f
/* IN: root of the BDD to be restored */
816 DdNode
*T
, *E
, *looking
;
817 DdNodePtr
*previousP
;
818 DdSubtable
*subtable
;
822 DdNode
*sentinel
= &(ddMgr
->sentinel
);
827 if (!Cudd_IsComplement (f
->next
)) {
831 if (cuddIsConstant (f
)) {
833 Bug fixed --> restore NULL within the next field */
834 /*DddmpClearVisitedCnf (f);*/
840 RestoreInUniqueRecurCnf (ddMgr
, cuddT (f
));
841 RestoreInUniqueRecurCnf (ddMgr
, cuddE (f
));
843 level
= ddMgr
->perm
[f
->index
];
844 subtable
= &(ddMgr
->subtables
[level
]);
846 nodelist
= subtable
->nodelist
;
848 pos
= ddHash (cuddT (f
), cuddE (f
), subtable
->shift
);
851 /* verify uniqueness to avoid duplicate nodes in unique table */
852 for (node
=nodelist
[pos
]; node
!= sentinel
; node
=node
->next
)
858 previousP
= &(nodelist
[pos
]);
859 looking
= *previousP
;
861 while (T
< cuddT (looking
)) {
862 previousP
= &(looking
->next
);
863 looking
= *previousP
;
866 while (T
== cuddT (looking
) && E
< cuddE (looking
)) {
867 previousP
= &(looking
->next
);
868 looking
= *previousP
;
870 f
->next
= *previousP
;
876 /**Function********************************************************************
878 Synopsis [Prints debug info]
880 Description [Prints debug info for a BDD on the screen. It recurs on
888 ******************************************************************************/
891 DddmpPrintBddAndNextRecur (
892 DdManager
*ddMgr
/* IN: DD Manager */,
893 DdNode
*f
/* IN: root of the BDD to be displayed */
897 DdNode
*fPtr
, *tPtr
, *ePtr
;
899 fPtr
= Cudd_Regular (f
);
901 if (Cudd_IsComplement (f
)) {
902 fprintf (stdout
, "sign=- ptr=%ld ", ((long int) fPtr
));
904 fprintf (stdout
, "sign=+ ptr=%ld ", ((long int) fPtr
));
907 if (cuddIsConstant (fPtr
)) {
908 fprintf (stdout
, "one\n");
910 return (DDDMP_SUCCESS
);
914 "thenPtr=%ld elsePtr=%ld BddId=%d CnfId=%d Visited=%d\n",
915 ((long int) cuddT (fPtr
)), ((long int) cuddE (fPtr
)),
916 fPtr
->index
, DddmpReadNodeIndexCnf (fPtr
),
917 DddmpVisitedCnf (fPtr
));
921 if (Cudd_IsComplement (f
)) {
922 tPtr
= Cudd_Not (tPtr
);
923 ePtr
= Cudd_Not (ePtr
);
926 retValue
= DddmpPrintBddAndNextRecur (ddMgr
, tPtr
);
927 retValue
= DddmpPrintBddAndNextRecur (ddMgr
, ePtr
);
929 return (DDDMP_SUCCESS
);