1 #include <AD/symbolic/bdd.h>
2 #include <AD/hash/lhash.h>
4 ///////////////////////////////////////////////////////////////////////////////
5 // Import some type definitions.
6 ///////////////////////////////////////////////////////////////////////////////
7 typedef BDDSet::Var Var
;
8 typedef BDDSet::BDDNode BDDNode
;
9 typedef BDDSet::BDD BDD
;
10 typedef BDDSet::Op Op
;
12 ///////////////////////////////////////////////////////////////////////////////
13 // Hashing and equality functions on a BDDNode
14 ///////////////////////////////////////////////////////////////////////////////
15 inline unsigned int hash(const BDDNode
& n
)
16 { return n
.var
+ n
.branches
[0] * 4 + n
.branches
[1] * 32; }
18 inline Bool
equal (const BDDNode
& a
, const BDDNode
& b
)
19 { return a
.var
== b
.var
&& a
.branches
[0] == b
.branches
[0]
20 && a
.branches
[1] == b
.branches
[1];
23 ///////////////////////////////////////////////////////////////////////////////
25 ///////////////////////////////////////////////////////////////////////////////
26 struct BDDTable
: public LHashTable
<BDDNode
, BDD
>
30 ///////////////////////////////////////////////////////////////////////////////
32 ///////////////////////////////////////////////////////////////////////////////
33 struct BDDMemo
: public LHashTable
<BDDNode
,BDD
>
37 ///////////////////////////////////////////////////////////////////////////////
39 ///////////////////////////////////////////////////////////////////////////////
40 BDDSet:: BDDSet(size_t default_nodes
)
44 table(new BDDTable
), memo(new BDDMemo
)
45 { bdds
= new BDDNode
[default_nodes
];
47 int n
= default_nodes
- 2;
48 bdd_highwater
= bdd_next
+ default_nodes
;
49 bdd_limit
= bdds
+ n
/ 2;
52 ///////////////////////////////////////////////////////////////////////////////
54 ///////////////////////////////////////////////////////////////////////////////
62 ///////////////////////////////////////////////////////////////////////////////
64 ///////////////////////////////////////////////////////////////////////////////
72 ///////////////////////////////////////////////////////////////////////////////
74 ///////////////////////////////////////////////////////////////////////////////
75 inline BDD
BDDSet::hash_cons(Var v
, BDD f
, BDD g
)
76 { if (bdd_next
== bdd_limit
) do_collect(); // garbage collect if full
78 Ix i
= table
->lookup(n
);
79 if (i
) return table
->value(i
);
80 BDDNode
* next
= bdd_next
++;
82 next
->branches
[0] = f
;
83 next
->branches
[1] = g
;
89 ///////////////////////////////////////////////////////////////////////////////
91 ///////////////////////////////////////////////////////////////////////////////
92 BDD
BDDSet::do_apply(Op op
, BDD f
, BDD g
)
95 { case Or
: if (f
== 1 || g
== 1) return 1;
96 if (f
== 0) return g
; // 0 + g = g
97 if (g
== 0) return f
; // f + 0 = f
99 case And
: if (f
== 0 || g
== 0) return 0;
100 if (f
== 1) return g
; // 1 * g = g
101 if (g
== 1) return f
; // f * 1 = f
103 case Not
: return do_negate(f
);
104 case Nor
: if (f
== 1 || g
== 1) return 0;
105 if (f
== 0) return do_negate(g
);
106 if (g
== 0) return do_negate(g
);
108 case Nand
: if (f
== 0 || g
== 0) return 1;
109 if (f
== 1) return do_negate(g
);
110 if (g
== 1) return do_negate(g
);
112 case Xor
: if (f
== 0) return g
; // 0 xor g = g
113 if (g
== 0) return f
; // f xor 0 = f
114 if (f
== 1) return do_negate(g
);
115 if (g
== 1) return do_negate(f
);
117 case Xnor
: if (f
== 0) return g
; // 1 xnor g = g
118 if (g
== 0) return f
; // f xnor 1 = f
119 if (f
== 1) return do_negate(g
);
120 if (g
== 1) return do_negate(f
);
124 // Check if result is already in place.
126 Ix i
= memo
->lookup(n
);
127 if (i
) return memo
->value(i
);
129 register Var fv
= var_of(f
);
130 register Var gv
= var_of(g
);
133 r
= hash_cons(fv
, do_apply(op
,bdds
[f
].branches
[0],bdds
[g
].branches
[0]),
134 do_apply(op
,bdds
[f
].branches
[1],bdds
[g
].branches
[1]));
136 r
= hash_cons(fv
, do_apply(op
,bdds
[f
].branches
[0],g
),
137 do_apply(op
,bdds
[f
].branches
[1],g
));
139 r
= hash_cons(gv
, do_apply(op
,f
,bdds
[g
].branches
[0]),
140 do_apply(op
,f
,bdds
[g
].branches
[1]));
142 memo
->insert(n
, r
); // update the memo map.
146 ///////////////////////////////////////////////////////////////////////////////
148 ///////////////////////////////////////////////////////////////////////////////
149 BDD
BDDSet::do_restrict(BDD f
, Var var
, BDD value
)
150 { if (f
== 0) return 0;
151 if (f
== 1) return 1;
153 if (fv
== var
) return bdds
[f
].branches
[value
];
154 BDDNode
n(Restrict
, f
, var
);
155 Ix i
= memo
->lookup(n
);
156 if (i
) return memo
->value(i
);
157 BDD r
= hash_cons(fv
,do_restrict(bdds
[f
].branches
[0], var
, value
),
158 do_restrict(bdds
[f
].branches
[1], var
, value
));
163 ///////////////////////////////////////////////////////////////////////////////
165 ///////////////////////////////////////////////////////////////////////////////
166 BDD
BDDSet::do_negate (BDD f
)
167 { if (f
== 0) return 1;
168 if (f
== 1) return 0;
169 BDDNode
n(Not
, f
, 0);
170 Ix i
= memo
->lookup(n
);
171 if (i
) return memo
->value(i
);
172 BDD r
= hash_cons (var_of(f
),
173 do_negate(bdds
[f
].branches
[0]),
174 do_negate(bdds
[f
].branches
[1]));
179 ///////////////////////////////////////////////////////////////////////////////
181 ///////////////////////////////////////////////////////////////////////////////
182 BDD
BDDSet::apply (Op op
, BDD f
, BDD g
)
185 return do_apply(op
, f
, g
);
188 ///////////////////////////////////////////////////////////////////////////////
190 ///////////////////////////////////////////////////////////////////////////////
191 BDD
BDDSet::restrict (BDD f
, Var var
, BDD value
)
194 return do_restrict(f
, var
, value
);
197 ///////////////////////////////////////////////////////////////////////////////
199 ///////////////////////////////////////////////////////////////////////////////
200 BDD
BDDSet::negate (BDD f
)
206 ///////////////////////////////////////////////////////////////////////////////
207 // Top level method to involve garbage collection.
208 ///////////////////////////////////////////////////////////////////////////////
209 void BDDSet::collect()
210 { bdd_last
= bdd_next
;
214 ///////////////////////////////////////////////////////////////////////////////
215 // Garbage collection.
216 ///////////////////////////////////////////////////////////////////////////////
217 void BDDSet::do_collect()
219 // Mark all user roots
220 for (int i
= 0; i
< size(); i
++)
223 // Everything from [bdd_last ... bdd_limit) must be non-garbage.
225 { for (register BDDNode
* p
= bdd_last
, * q
= bdd_limit
; p
< q
; p
++);
229 // Copy phase, use the to space as a queue.
233 // Exchange from/to space.