1#[allow(unused_imports)]
9use crate::prelude::*;
10use core::fmt;
11
12pub type VarId = u32;
14
15pub type NodeId = usize;
18
19pub const BDD_FALSE: NodeId = 0;
21pub const BDD_TRUE: NodeId = 1;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26struct BddNode {
27 var: VarId,
28 low: NodeId,
29 high: NodeId,
30}
31
32#[derive(Debug, Clone)]
35pub struct BddManager {
36 nodes: Vec<BddNode>,
38 unique_table: FxHashMap<(VarId, NodeId, NodeId), NodeId>,
40 op_cache: FxHashMap<(BddOp, NodeId, NodeId), NodeId>,
42 not_cache: FxHashMap<NodeId, NodeId>,
48 ite_cache: FxHashMap<(NodeId, NodeId, NodeId), NodeId>,
50}
51
52enum NotStep {
54 Enter(NodeId),
56 Combine(NodeId),
58}
59
60enum IteStep {
62 Enter(IteKey),
64 Combine {
66 key: IteKey,
67 top_var: VarId,
68 low: IteKey,
69 high: IteKey,
70 },
71}
72
73type IteKey = (NodeId, NodeId, NodeId);
75
76type ApplyKey = (BddOp, NodeId, NodeId);
79
80enum ApplyStep {
82 Enter(ApplyKey),
84 Combine {
86 key: ApplyKey,
87 var: VarId,
88 low: ApplyKey,
89 high: ApplyKey,
90 },
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
94enum BddOp {
95 And,
96 Or,
97 Xor,
98}
99
100impl BddManager {
101 pub fn new() -> Self {
103 let mut manager = Self {
104 nodes: Vec::new(),
105 unique_table: FxHashMap::default(),
106 op_cache: FxHashMap::default(),
107 not_cache: FxHashMap::default(),
108 ite_cache: FxHashMap::default(),
109 };
110
111 manager.nodes.push(BddNode {
114 var: u32::MAX,
115 low: 0,
116 high: 0,
117 });
118
119 manager.nodes.push(BddNode {
121 var: u32::MAX,
122 low: 1,
123 high: 1,
124 });
125
126 manager
127 }
128
129 pub fn constant_false(&self) -> NodeId {
131 BDD_FALSE
132 }
133
134 pub fn constant_true(&self) -> NodeId {
136 BDD_TRUE
137 }
138
139 pub fn variable(&mut self, var: VarId) -> NodeId {
141 self.make_node(var, BDD_FALSE, BDD_TRUE)
142 }
143
144 fn make_node(&mut self, var: VarId, low: NodeId, high: NodeId) -> NodeId {
149 if low == high {
151 return low;
152 }
153
154 let key = (var, low, high);
156 if let Some(&node_id) = self.unique_table.get(&key) {
157 return node_id;
158 }
159
160 let node_id = self.nodes.len();
162 self.nodes.push(BddNode { var, low, high });
163 self.unique_table.insert(key, node_id);
164 node_id
165 }
166
167 pub fn not(&mut self, node: NodeId) -> NodeId {
179 if node == BDD_FALSE {
180 return BDD_TRUE;
181 }
182 if node == BDD_TRUE {
183 return BDD_FALSE;
184 }
185 if let Some(&result) = self.not_cache.get(&node) {
186 return result;
187 }
188
189 let mut stack = vec![NotStep::Enter(node)];
190 while let Some(step) = stack.pop() {
191 match step {
192 NotStep::Enter(id) => {
193 if id == BDD_FALSE || id == BDD_TRUE || self.not_cache.contains_key(&id) {
194 continue;
195 }
196 let n = self.nodes[id];
197 stack.push(NotStep::Combine(id));
198 stack.push(NotStep::Enter(n.low));
199 stack.push(NotStep::Enter(n.high));
200 }
201 NotStep::Combine(id) => {
202 if self.not_cache.contains_key(&id) {
203 continue;
204 }
205 let n = self.nodes[id];
206 let low = self.negated(n.low);
207 let high = self.negated(n.high);
208 let result = self.make_node(n.var, low, high);
209 self.not_cache.insert(id, result);
210 }
211 }
212 }
213
214 self.not_cache[&node]
215 }
216
217 fn negated(&self, node: NodeId) -> NodeId {
222 if node == BDD_FALSE {
223 return BDD_TRUE;
224 }
225 if node == BDD_TRUE {
226 return BDD_FALSE;
227 }
228 self.not_cache[&node]
229 }
230
231 pub fn and(&mut self, left: NodeId, right: NodeId) -> NodeId {
233 self.apply(BddOp::And, left, right)
234 }
235
236 pub fn or(&mut self, left: NodeId, right: NodeId) -> NodeId {
238 self.apply(BddOp::Or, left, right)
239 }
240
241 pub fn xor(&mut self, left: NodeId, right: NodeId) -> NodeId {
243 self.apply(BddOp::Xor, left, right)
244 }
245
246 pub fn implies(&mut self, left: NodeId, right: NodeId) -> NodeId {
248 let not_left = self.not(left);
249 self.or(not_left, right)
250 }
251
252 pub fn iff(&mut self, left: NodeId, right: NodeId) -> NodeId {
254 let not_xor = self.xor(left, right);
255 self.not(not_xor)
256 }
257
258 fn apply(&mut self, op: BddOp, left: NodeId, right: NodeId) -> NodeId {
266 let root = (op, left, right);
267 if let Some(result) = self.apply_resolved(root) {
268 return result;
269 }
270
271 let mut stack = vec![ApplyStep::Enter(root)];
272 while let Some(step) = stack.pop() {
273 match step {
274 ApplyStep::Enter(key) => {
275 if self.apply_resolved(key).is_some() {
276 continue;
277 }
278 let (var, low, high) = self.apply_cofactors(key);
279 stack.push(ApplyStep::Combine {
280 key,
281 var,
282 low,
283 high,
284 });
285 stack.push(ApplyStep::Enter(low));
286 stack.push(ApplyStep::Enter(high));
287 }
288 ApplyStep::Combine {
289 key,
290 var,
291 low,
292 high,
293 } => {
294 if self.op_cache.contains_key(&key) {
295 continue;
296 }
297 let (Some(low_id), Some(high_id)) =
299 (self.apply_resolved(low), self.apply_resolved(high))
300 else {
301 continue;
302 };
303 let result = self.make_node(var, low_id, high_id);
304 self.op_cache.insert(key, result);
305 }
306 }
307 }
308
309 self.op_cache[&root]
310 }
311
312 fn apply_resolved(&mut self, (op, left, right): ApplyKey) -> Option<NodeId> {
315 match op {
317 BddOp::And => {
318 if left == BDD_FALSE || right == BDD_FALSE {
319 return Some(BDD_FALSE);
320 }
321 if left == BDD_TRUE {
322 return Some(right);
323 }
324 if right == BDD_TRUE {
325 return Some(left);
326 }
327 if left == right {
328 return Some(left);
329 }
330 }
331 BddOp::Or => {
332 if left == BDD_TRUE || right == BDD_TRUE {
333 return Some(BDD_TRUE);
334 }
335 if left == BDD_FALSE {
336 return Some(right);
337 }
338 if right == BDD_FALSE {
339 return Some(left);
340 }
341 if left == right {
342 return Some(left);
343 }
344 }
345 BddOp::Xor => {
346 if left == BDD_FALSE {
347 return Some(right);
348 }
349 if right == BDD_FALSE {
350 return Some(left);
351 }
352 if left == BDD_TRUE {
353 return Some(self.not(right));
354 }
355 if right == BDD_TRUE {
356 return Some(self.not(left));
357 }
358 if left == right {
359 return Some(BDD_FALSE);
360 }
361 }
362 }
363
364 self.op_cache.get(&(op, left, right)).copied()
365 }
366
367 fn apply_cofactors(&self, (op, left, right): ApplyKey) -> (VarId, ApplyKey, ApplyKey) {
371 let left_node = self.nodes[left];
372 let right_node = self.nodes[right];
373
374 if left_node.var == right_node.var {
375 (
377 left_node.var,
378 (op, left_node.low, right_node.low),
379 (op, left_node.high, right_node.high),
380 )
381 } else if left_node.var < right_node.var {
382 (
384 left_node.var,
385 (op, left_node.low, right),
386 (op, left_node.high, right),
387 )
388 } else {
389 (
391 right_node.var,
392 (op, left, right_node.low),
393 (op, left, right_node.high),
394 )
395 }
396 }
397
398 pub fn ite(&mut self, cond: NodeId, then_node: NodeId, else_node: NodeId) -> NodeId {
407 let root: IteKey = (cond, then_node, else_node);
408 if let Some(result) = self.ite_resolved(root) {
409 return result;
410 }
411
412 let mut stack = vec![IteStep::Enter(root)];
413 while let Some(step) = stack.pop() {
414 match step {
415 IteStep::Enter(key) => {
416 if self.ite_resolved(key).is_some() {
417 continue;
418 }
419 let (top_var, low, high) = self.ite_cofactors(key);
420 stack.push(IteStep::Combine {
421 key,
422 top_var,
423 low,
424 high,
425 });
426 stack.push(IteStep::Enter(low));
427 stack.push(IteStep::Enter(high));
428 }
429 IteStep::Combine {
430 key,
431 top_var,
432 low,
433 high,
434 } => {
435 if self.ite_cache.contains_key(&key) {
436 continue;
437 }
438 let (Some(low_id), Some(high_id)) =
441 (self.ite_resolved(low), self.ite_resolved(high))
442 else {
443 continue;
444 };
445 let result = self.make_node(top_var, low_id, high_id);
446 self.ite_cache.insert(key, result);
447 }
448 }
449 }
450
451 self.ite_cache[&root]
452 }
453
454 fn ite_resolved(&self, (cond, then_node, else_node): IteKey) -> Option<NodeId> {
457 if cond == BDD_TRUE {
458 return Some(then_node);
459 }
460 if cond == BDD_FALSE {
461 return Some(else_node);
462 }
463 if then_node == else_node {
464 return Some(then_node);
465 }
466 if then_node == BDD_TRUE && else_node == BDD_FALSE {
467 return Some(cond);
468 }
469 self.ite_cache.get(&(cond, then_node, else_node)).copied()
470 }
471
472 fn ite_cofactors(&self, (cond, then_node, else_node): IteKey) -> (VarId, IteKey, IteKey) {
476 let cond_node = self.nodes[cond];
477 let then_n = if then_node <= BDD_TRUE {
478 None
479 } else {
480 Some(self.nodes[then_node])
481 };
482 let else_n = if else_node <= BDD_TRUE {
483 None
484 } else {
485 Some(self.nodes[else_node])
486 };
487
488 let mut top_var = cond_node.var;
490 if let Some(n) = then_n
491 && n.var < top_var
492 {
493 top_var = n.var;
494 }
495 if let Some(n) = else_n
496 && n.var < top_var
497 {
498 top_var = n.var;
499 }
500
501 let cond_low = if cond_node.var == top_var {
503 cond_node.low
504 } else {
505 cond
506 };
507 let cond_high = if cond_node.var == top_var {
508 cond_node.high
509 } else {
510 cond
511 };
512
513 let then_low = if let Some(n) = then_n {
514 if n.var == top_var { n.low } else { then_node }
515 } else {
516 then_node
517 };
518 let then_high = if let Some(n) = then_n {
519 if n.var == top_var { n.high } else { then_node }
520 } else {
521 then_node
522 };
523
524 let else_low = if let Some(n) = else_n {
525 if n.var == top_var { n.low } else { else_node }
526 } else {
527 else_node
528 };
529 let else_high = if let Some(n) = else_n {
530 if n.var == top_var { n.high } else { else_node }
531 } else {
532 else_node
533 };
534
535 (
536 top_var,
537 (cond_low, then_low, else_low),
538 (cond_high, then_high, else_high),
539 )
540 }
541
542 pub fn eval(&self, node: NodeId, assignment: &FxHashMap<VarId, bool>) -> bool {
544 if node == BDD_FALSE {
545 return false;
546 }
547 if node == BDD_TRUE {
548 return true;
549 }
550
551 let n = self.nodes[node];
552 let var_value = assignment.get(&n.var).copied().unwrap_or(false);
553
554 if var_value {
555 self.eval(n.high, assignment)
556 } else {
557 self.eval(n.low, assignment)
558 }
559 }
560
561 pub fn sat_count(&self, node: NodeId, num_vars: u32) -> u64 {
563 let mut cache = FxHashMap::default();
564 self.sat_count_rec(node, &mut cache)
565 * (1u64 << num_vars.saturating_sub(self.max_var(node).map_or(0, |v| v + 1)))
566 }
567
568 fn sat_count_rec(&self, node: NodeId, cache: &mut FxHashMap<NodeId, u64>) -> u64 {
569 if node == BDD_FALSE {
570 return 0;
571 }
572 if node == BDD_TRUE {
573 return 1;
574 }
575
576 if let Some(&count) = cache.get(&node) {
577 return count;
578 }
579
580 let n = self.nodes[node];
581 let low_count = self.sat_count_rec(n.low, cache);
582 let high_count = self.sat_count_rec(n.high, cache);
583
584 let low_mult = if n.low <= BDD_TRUE {
586 1
587 } else {
588 let low_var = self.nodes[n.low].var;
589 1u64 << (low_var - n.var - 1)
590 };
591 let high_mult = if n.high <= BDD_TRUE {
592 1
593 } else {
594 let high_var = self.nodes[n.high].var;
595 1u64 << (high_var - n.var - 1)
596 };
597
598 let count = low_count * low_mult + high_count * high_mult;
599 cache.insert(node, count);
600 count
601 }
602
603 fn max_var(&self, node: NodeId) -> Option<VarId> {
605 if node <= BDD_TRUE {
606 return None;
607 }
608 Some(self.nodes[node].var)
609 }
610
611 pub fn node_count(&self) -> usize {
613 self.nodes.len()
614 }
615
616 pub fn clear_cache(&mut self) {
618 self.op_cache.clear();
619 self.not_cache.clear();
620 self.ite_cache.clear();
621 }
622}
623
624impl Default for BddManager {
625 fn default() -> Self {
626 Self::new()
627 }
628}
629
630impl fmt::Display for BddManager {
631 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
632 writeln!(f, "BDD Manager: {} nodes", self.nodes.len())?;
633 writeln!(f, " Cache size: {}", self.op_cache.len())?;
634 Ok(())
635 }
636}
637
638#[derive(Debug, Clone)]
647pub struct ZddManager {
648 nodes: Vec<BddNode>,
649 unique_table: FxHashMap<(VarId, NodeId, NodeId), NodeId>,
650 op_cache: FxHashMap<(ZddOp, NodeId, NodeId), NodeId>,
651}
652
653#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
654enum ZddOp {
655 Union,
656 Intersection,
657 Difference,
658}
659
660pub const ZDD_EMPTY: NodeId = 0;
662pub const ZDD_BASE: NodeId = 1;
664
665impl ZddManager {
666 pub fn new() -> Self {
668 let mut manager = Self {
669 nodes: Vec::new(),
670 unique_table: FxHashMap::default(),
671 op_cache: FxHashMap::default(),
672 };
673
674 manager.nodes.push(BddNode {
676 var: u32::MAX,
677 low: 0,
678 high: 0,
679 });
680
681 manager.nodes.push(BddNode {
683 var: u32::MAX,
684 low: 1,
685 high: 1,
686 });
687
688 manager
689 }
690
691 pub fn empty(&self) -> NodeId {
693 ZDD_EMPTY
694 }
695
696 pub fn base(&self) -> NodeId {
698 ZDD_BASE
699 }
700
701 pub fn singleton(&mut self, var: VarId) -> NodeId {
703 self.make_node(var, ZDD_EMPTY, ZDD_BASE)
704 }
705
706 fn make_node(&mut self, var: VarId, low: NodeId, high: NodeId) -> NodeId {
709 if high == ZDD_EMPTY {
711 return low;
712 }
713
714 let key = (var, low, high);
716 if let Some(&node_id) = self.unique_table.get(&key) {
717 return node_id;
718 }
719
720 let node_id = self.nodes.len();
722 self.nodes.push(BddNode { var, low, high });
723 self.unique_table.insert(key, node_id);
724 node_id
725 }
726
727 pub fn union(&mut self, left: NodeId, right: NodeId) -> NodeId {
729 self.apply(ZddOp::Union, left, right)
730 }
731
732 pub fn intersection(&mut self, left: NodeId, right: NodeId) -> NodeId {
734 self.apply(ZddOp::Intersection, left, right)
735 }
736
737 pub fn difference(&mut self, left: NodeId, right: NodeId) -> NodeId {
739 self.apply(ZddOp::Difference, left, right)
740 }
741
742 fn apply(&mut self, op: ZddOp, left: NodeId, right: NodeId) -> NodeId {
743 match op {
745 ZddOp::Union => {
746 if left == ZDD_EMPTY {
747 return right;
748 }
749 if right == ZDD_EMPTY {
750 return left;
751 }
752 if left == right {
753 return left;
754 }
755 }
756 ZddOp::Intersection => {
757 if left == ZDD_EMPTY || right == ZDD_EMPTY {
758 return ZDD_EMPTY;
759 }
760 if left == right {
761 return left;
762 }
763 if left == ZDD_BASE || right == ZDD_BASE {
765 return ZDD_EMPTY;
766 }
767 }
768 ZddOp::Difference => {
769 if left == ZDD_EMPTY {
770 return ZDD_EMPTY;
771 }
772 if right == ZDD_EMPTY {
773 return left;
774 }
775 if left == right {
776 return ZDD_EMPTY;
777 }
778 }
779 }
780
781 let cache_key = (op, left, right);
783 if let Some(&result) = self.op_cache.get(&cache_key) {
784 return result;
785 }
786
787 let left_node = self.nodes[left];
789 let right_node = self.nodes[right];
790
791 let result = if left_node.var == right_node.var {
792 let low = self.apply(op, left_node.low, right_node.low);
793 let high = self.apply(op, left_node.high, right_node.high);
794 self.make_node(left_node.var, low, high)
795 } else if left_node.var < right_node.var {
796 let low = self.apply(op, left_node.low, right);
797 let high = match op {
798 ZddOp::Union => left_node.high,
799 ZddOp::Intersection => self.apply(op, left_node.high, right),
800 ZddOp::Difference => left_node.high,
801 };
802 self.make_node(left_node.var, low, high)
803 } else {
804 let low = self.apply(op, left, right_node.low);
805 let high = match op {
806 ZddOp::Union => right_node.high,
807 ZddOp::Intersection => self.apply(op, left, right_node.high),
808 ZddOp::Difference => ZDD_EMPTY,
809 };
810 self.make_node(right_node.var, low, high)
811 };
812
813 self.op_cache.insert(cache_key, result);
814 result
815 }
816
817 pub fn count(&self, node: NodeId) -> u64 {
819 let mut cache = FxHashMap::default();
820 self.count_rec(node, &mut cache)
821 }
822
823 fn count_rec(&self, node: NodeId, cache: &mut FxHashMap<NodeId, u64>) -> u64 {
824 if node == ZDD_EMPTY {
825 return 0;
826 }
827 if node == ZDD_BASE {
828 return 1;
829 }
830
831 if let Some(&count) = cache.get(&node) {
832 return count;
833 }
834
835 let n = self.nodes[node];
836 let count = self.count_rec(n.low, cache) + self.count_rec(n.high, cache);
837 cache.insert(node, count);
838 count
839 }
840
841 pub fn node_count(&self) -> usize {
843 self.nodes.len()
844 }
845
846 pub fn clear_cache(&mut self) {
848 self.op_cache.clear();
849 }
850}
851
852impl Default for ZddManager {
853 fn default() -> Self {
854 Self::new()
855 }
856}
857
858impl fmt::Display for ZddManager {
859 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
860 writeln!(f, "ZDD Manager: {} nodes", self.nodes.len())?;
861 writeln!(f, " Cache size: {}", self.op_cache.len())?;
862 Ok(())
863 }
864}
865
866use num_rational::BigRational;
872use num_traits::Zero;
873
874#[derive(Debug, Clone, PartialEq, Eq, Hash)]
876enum AddNode {
877 Terminal(BigRational),
879 Internal {
881 var: VarId,
882 low: NodeId,
883 high: NodeId,
884 },
885}
886
887#[derive(Debug, Clone)]
889pub struct AddManager {
890 nodes: Vec<AddNode>,
891 unique_table: FxHashMap<AddNode, NodeId>,
892 op_cache: FxHashMap<(AddOp, NodeId, NodeId), NodeId>,
893}
894
895#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
896enum AddOp {
897 Add,
898 Mul,
899 Max,
900 Min,
901}
902
903impl AddManager {
904 pub fn new() -> Self {
906 let mut manager = Self {
907 nodes: Vec::new(),
908 unique_table: FxHashMap::default(),
909 op_cache: FxHashMap::default(),
910 };
911
912 let zero = AddNode::Terminal(BigRational::zero());
914 manager.nodes.push(zero.clone());
915 manager.unique_table.insert(zero, 0);
916
917 manager
918 }
919
920 pub fn constant(&mut self, value: BigRational) -> NodeId {
922 let node = AddNode::Terminal(value);
923
924 if let Some(&id) = self.unique_table.get(&node) {
926 return id;
927 }
928
929 let id = self.nodes.len();
930 self.nodes.push(node.clone());
931 self.unique_table.insert(node, id);
932 id
933 }
934
935 pub fn variable(&mut self, var: VarId) -> NodeId {
937 let zero = self.constant(BigRational::zero());
938 let one = self.constant(BigRational::from_integer(1.into()));
939 self.make_node(var, zero, one)
940 }
941
942 fn make_node(&mut self, var: VarId, low: NodeId, high: NodeId) -> NodeId {
944 if low == high {
946 return low;
947 }
948
949 let node = AddNode::Internal { var, low, high };
950
951 if let Some(&id) = self.unique_table.get(&node) {
953 return id;
954 }
955
956 let id = self.nodes.len();
958 self.nodes.push(node.clone());
959 self.unique_table.insert(node, id);
960 id
961 }
962
963 pub fn eval(&self, node: NodeId, assignment: &FxHashMap<VarId, bool>) -> BigRational {
965 match &self.nodes[node] {
966 AddNode::Terminal(value) => value.clone(),
967 AddNode::Internal { var, low, high } => {
968 if *assignment.get(var).unwrap_or(&false) {
969 self.eval(*high, assignment)
970 } else {
971 self.eval(*low, assignment)
972 }
973 }
974 }
975 }
976
977 pub fn add(&mut self, left: NodeId, right: NodeId) -> NodeId {
979 self.apply(AddOp::Add, left, right)
980 }
981
982 pub fn mul(&mut self, left: NodeId, right: NodeId) -> NodeId {
984 self.apply(AddOp::Mul, left, right)
985 }
986
987 pub fn max(&mut self, left: NodeId, right: NodeId) -> NodeId {
989 self.apply(AddOp::Max, left, right)
990 }
991
992 pub fn min(&mut self, left: NodeId, right: NodeId) -> NodeId {
994 self.apply(AddOp::Min, left, right)
995 }
996
997 pub fn scale(&mut self, node: NodeId, scalar: &BigRational) -> NodeId {
999 let scalar_node = self.constant(scalar.clone());
1000 self.mul(node, scalar_node)
1001 }
1002
1003 fn apply(&mut self, op: AddOp, left: NodeId, right: NodeId) -> NodeId {
1005 if let (AddNode::Terminal(l), AddNode::Terminal(r)) =
1007 (&self.nodes[left], &self.nodes[right])
1008 {
1009 let result_value = match op {
1010 AddOp::Add => l + r,
1011 AddOp::Mul => l * r,
1012 AddOp::Max => {
1013 if l > r {
1014 l.clone()
1015 } else {
1016 r.clone()
1017 }
1018 }
1019 AddOp::Min => {
1020 if l < r {
1021 l.clone()
1022 } else {
1023 r.clone()
1024 }
1025 }
1026 };
1027 return self.constant(result_value);
1028 }
1029
1030 let cache_key = (op, left, right);
1032 if let Some(&result) = self.op_cache.get(&cache_key) {
1033 return result;
1034 }
1035
1036 let (var, left_low, left_high, right_low, right_high) = self.split_nodes(left, right);
1038
1039 let low = self.apply(op, left_low, right_low);
1040 let high = self.apply(op, left_high, right_high);
1041
1042 let result = self.make_node(var, low, high);
1043 self.op_cache.insert(cache_key, result);
1044 result
1045 }
1046
1047 fn split_nodes(&self, left: NodeId, right: NodeId) -> (VarId, NodeId, NodeId, NodeId, NodeId) {
1049 let (left_var, left_low, left_high) = match &self.nodes[left] {
1050 AddNode::Terminal(_) => (u32::MAX, left, left),
1051 AddNode::Internal { var, low, high } => (*var, *low, *high),
1052 };
1053
1054 let (right_var, right_low, right_high) = match &self.nodes[right] {
1055 AddNode::Terminal(_) => (u32::MAX, right, right),
1056 AddNode::Internal { var, low, high } => (*var, *low, *high),
1057 };
1058
1059 if left_var == u32::MAX && right_var == u32::MAX {
1060 panic!("Both nodes are terminals - should have been handled earlier");
1061 }
1062
1063 if left_var == right_var {
1064 (left_var, left_low, left_high, right_low, right_high)
1065 } else if left_var < right_var {
1066 (left_var, left_low, left_high, right, right)
1067 } else {
1068 (right_var, left, left, right_low, right_high)
1069 }
1070 }
1071
1072 pub fn ite(&mut self, cond: NodeId, then_add: NodeId, else_add: NodeId) -> NodeId {
1074 let one = self.constant(BigRational::from_integer(1.into()));
1077 let neg_one = BigRational::from_integer((-1).into());
1078 let scaled_cond = self.scale(cond, &neg_one);
1079 let not_cond = self.apply(AddOp::Add, one, scaled_cond);
1080
1081 let then_part = self.mul(cond, then_add);
1082 let else_part = self.mul(not_cond, else_add);
1083 self.add(then_part, else_part)
1084 }
1085
1086 pub fn node_count(&self) -> usize {
1088 self.nodes.len()
1089 }
1090
1091 pub fn clear_cache(&mut self) {
1093 self.op_cache.clear();
1094 }
1095
1096 pub fn get_var(&self, node: NodeId) -> Option<VarId> {
1098 match &self.nodes[node] {
1099 AddNode::Terminal(_) => None,
1100 AddNode::Internal { var, .. } => Some(*var),
1101 }
1102 }
1103
1104 pub fn get_value(&self, node: NodeId) -> Option<&BigRational> {
1106 match &self.nodes[node] {
1107 AddNode::Terminal(value) => Some(value),
1108 AddNode::Internal { .. } => None,
1109 }
1110 }
1111}
1112
1113impl Default for AddManager {
1114 fn default() -> Self {
1115 Self::new()
1116 }
1117}
1118
1119impl fmt::Display for AddManager {
1120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1121 writeln!(f, "ADD Manager: {} nodes", self.nodes.len())?;
1122 writeln!(f, " Cache size: {}", self.op_cache.len())?;
1123 Ok(())
1124 }
1125}
1126
1127#[cfg(test)]
1128mod tests {
1129 use super::*;
1130
1131 #[test]
1132 fn test_bdd_constants() {
1133 let manager = BddManager::new();
1134 assert_eq!(manager.constant_false(), BDD_FALSE);
1135 assert_eq!(manager.constant_true(), BDD_TRUE);
1136 }
1137
1138 #[test]
1139 fn test_bdd_variable() {
1140 let mut manager = BddManager::new();
1141 let x = manager.variable(0);
1142
1143 let mut assignment = FxHashMap::default();
1144 assignment.insert(0, true);
1145 assert!(manager.eval(x, &assignment));
1146
1147 assignment.insert(0, false);
1148 assert!(!manager.eval(x, &assignment));
1149 }
1150
1151 fn conjunction_chain(manager: &mut BddManager, vars: u32) -> NodeId {
1155 let mut node = BDD_TRUE;
1156 for var in (0..vars).rev() {
1157 node = manager.make_node(var, BDD_FALSE, node);
1158 }
1159 node
1160 }
1161
1162 #[test]
1166 fn test_not_deep_diagram_does_not_overflow() {
1167 let worker = std::thread::Builder::new().stack_size(1 << 20).spawn(|| {
1168 let mut manager = BddManager::new();
1169 let chain = conjunction_chain(&mut manager, 100_000);
1170 let negated = manager.not(chain);
1171 (negated != chain, manager.not(negated) == chain)
1172 });
1173 let (differs, involutive) = match worker.map(std::thread::JoinHandle::join) {
1174 Ok(Ok(result)) => result,
1175 _ => panic!("deep-BDD negation worker thread did not complete"),
1176 };
1177 assert!(differs);
1178 assert!(involutive);
1179 }
1180
1181 #[test]
1183 fn test_apply_and_ite_deep_diagram_do_not_overflow() {
1184 let worker = std::thread::Builder::new().stack_size(1 << 20).spawn(|| {
1185 let mut manager = BddManager::new();
1186 let chain = conjunction_chain(&mut manager, 100_000);
1187 let shifted = {
1188 let mut node = BDD_TRUE;
1189 for var in (0..100_000u32).rev() {
1190 node = manager.make_node(var, node, BDD_FALSE);
1191 }
1192 node
1193 };
1194 let conj = manager.and(chain, shifted);
1195 let selected = manager.ite(chain, shifted, BDD_FALSE);
1196 (conj, selected)
1197 });
1198 let (conj, selected) = match worker.map(std::thread::JoinHandle::join) {
1199 Ok(Ok(result)) => result,
1200 _ => panic!("deep-BDD apply/ite worker thread did not complete"),
1201 };
1202 assert_eq!(conj, BDD_FALSE);
1205 assert_eq!(selected, BDD_FALSE);
1206 }
1207
1208 #[test]
1212 fn test_not_on_parity_bdd_uses_computed_table() {
1213 let mut manager = BddManager::new();
1214 let mut parity = BDD_FALSE;
1215 for var in 0..40 {
1216 let x = manager.variable(var);
1217 parity = manager.xor(parity, x);
1218 }
1219 let negated = manager.not(parity);
1220 assert_ne!(negated, parity);
1221 assert_eq!(manager.not(negated), parity);
1222
1223 let complement = manager.xor(parity, BDD_TRUE);
1225 assert_eq!(negated, complement);
1226 }
1227
1228 #[test]
1229 fn test_bdd_not() {
1230 let mut manager = BddManager::new();
1231 let x = manager.variable(0);
1232 let not_x = manager.not(x);
1233
1234 let mut assignment = FxHashMap::default();
1235 assignment.insert(0, true);
1236 assert!(!manager.eval(not_x, &assignment));
1237
1238 assignment.insert(0, false);
1239 assert!(manager.eval(not_x, &assignment));
1240 }
1241
1242 #[test]
1243 fn test_bdd_and() {
1244 let mut manager = BddManager::new();
1245 let x = manager.variable(0);
1246 let y = manager.variable(1);
1247 let x_and_y = manager.and(x, y);
1248
1249 let mut assignment = FxHashMap::default();
1250 assignment.insert(0, true);
1251 assignment.insert(1, true);
1252 assert!(manager.eval(x_and_y, &assignment));
1253
1254 assignment.insert(0, false);
1255 assert!(!manager.eval(x_and_y, &assignment));
1256 }
1257
1258 #[test]
1259 fn test_bdd_or() {
1260 let mut manager = BddManager::new();
1261 let x = manager.variable(0);
1262 let y = manager.variable(1);
1263 let x_or_y = manager.or(x, y);
1264
1265 let mut assignment = FxHashMap::default();
1266 assignment.insert(0, false);
1267 assignment.insert(1, false);
1268 assert!(!manager.eval(x_or_y, &assignment));
1269
1270 assignment.insert(0, true);
1271 assert!(manager.eval(x_or_y, &assignment));
1272 }
1273
1274 #[test]
1275 fn test_bdd_xor() {
1276 let mut manager = BddManager::new();
1277 let x = manager.variable(0);
1278 let y = manager.variable(1);
1279 let x_xor_y = manager.xor(x, y);
1280
1281 let mut assignment = FxHashMap::default();
1282 assignment.insert(0, true);
1283 assignment.insert(1, true);
1284 assert!(!manager.eval(x_xor_y, &assignment));
1285
1286 assignment.insert(0, true);
1287 assignment.insert(1, false);
1288 assert!(manager.eval(x_xor_y, &assignment));
1289 }
1290
1291 #[test]
1292 fn test_bdd_ite() {
1293 let mut manager = BddManager::new();
1294 let x = manager.variable(0);
1295 let y = manager.variable(1);
1296 let z = manager.variable(2);
1297
1298 let result = manager.ite(x, y, z);
1300
1301 let mut assignment = FxHashMap::default();
1302 assignment.insert(0, true);
1303 assignment.insert(1, true);
1304 assignment.insert(2, false);
1305 assert!(manager.eval(result, &assignment)); assignment.insert(0, false);
1308 assignment.insert(1, true);
1309 assignment.insert(2, false);
1310 assert!(!manager.eval(result, &assignment)); }
1312
1313 #[test]
1314 fn test_bdd_implies() {
1315 let mut manager = BddManager::new();
1316 let x = manager.variable(0);
1317 let y = manager.variable(1);
1318 let x_implies_y = manager.implies(x, y);
1319
1320 let mut assignment = FxHashMap::default();
1321 assignment.insert(0, true);
1322 assignment.insert(1, false);
1323 assert!(!manager.eval(x_implies_y, &assignment));
1324
1325 assignment.insert(0, false);
1326 assignment.insert(1, false);
1327 assert!(manager.eval(x_implies_y, &assignment));
1328 }
1329
1330 #[test]
1331 fn test_bdd_sharing() {
1332 let mut manager = BddManager::new();
1333 let x = manager.variable(0);
1334 let y = manager.variable(0); assert_eq!(x, y); }
1337
1338 #[test]
1340 fn test_zdd_empty_and_base() {
1341 let manager = ZddManager::new();
1342 assert_eq!(manager.empty(), ZDD_EMPTY);
1343 assert_eq!(manager.base(), ZDD_BASE);
1344 assert_eq!(manager.count(ZDD_EMPTY), 0);
1345 assert_eq!(manager.count(ZDD_BASE), 1);
1346 }
1347
1348 #[test]
1349 fn test_zdd_singleton() {
1350 let mut manager = ZddManager::new();
1351 let x = manager.singleton(0);
1352 assert_eq!(manager.count(x), 1); assert_ne!(x, ZDD_EMPTY);
1354 assert_ne!(x, ZDD_BASE);
1355 }
1356
1357 #[test]
1358 fn test_zdd_union() {
1359 let mut manager = ZddManager::new();
1360 let x = manager.singleton(0);
1361 let y = manager.singleton(1);
1362 let union = manager.union(x, y);
1363
1364 assert_eq!(manager.count(union), 2);
1366 }
1367
1368 #[test]
1369 fn test_zdd_intersection() {
1370 let mut manager = ZddManager::new();
1371 let x = manager.singleton(0);
1372 let y = manager.singleton(1);
1373 let intersection = manager.intersection(x, y);
1374
1375 assert_eq!(intersection, ZDD_EMPTY);
1377 assert_eq!(manager.count(intersection), 0);
1378 }
1379
1380 #[test]
1381 fn test_zdd_difference() {
1382 let mut manager = ZddManager::new();
1383 let x = manager.singleton(0);
1384 let y = manager.singleton(1);
1385
1386 let diff1 = manager.difference(x, y);
1387 assert_eq!(manager.count(diff1), 1); let diff2 = manager.difference(x, x);
1390 assert_eq!(diff2, ZDD_EMPTY); }
1392
1393 #[test]
1394 fn test_zdd_union_associative() {
1395 let mut manager = ZddManager::new();
1396 let x = manager.singleton(0);
1397 let y = manager.singleton(1);
1398 let z = manager.singleton(2);
1399
1400 let xy = manager.union(x, y);
1401 let xyz1 = manager.union(xy, z);
1402
1403 let yz = manager.union(y, z);
1404 let xyz2 = manager.union(x, yz);
1405
1406 assert_eq!(manager.count(xyz1), manager.count(xyz2));
1407 assert_eq!(manager.count(xyz1), 3); }
1409
1410 #[test]
1412 fn test_add_constant() {
1413 use num_bigint::BigInt;
1414 let mut manager = AddManager::new();
1415 let five = manager.constant(BigRational::from_integer(BigInt::from(5)));
1416
1417 let assignment = FxHashMap::default();
1418 let result = manager.eval(five, &assignment);
1419 assert_eq!(result, BigRational::from_integer(BigInt::from(5)));
1420 }
1421
1422 #[test]
1423 fn test_add_variable() {
1424 use num_bigint::BigInt;
1425 let mut manager = AddManager::new();
1426 let x = manager.variable(0);
1427
1428 let mut assignment = FxHashMap::default();
1429 assignment.insert(0, true);
1430 let result = manager.eval(x, &assignment);
1431 assert_eq!(result, BigRational::from_integer(BigInt::from(1)));
1432
1433 assignment.insert(0, false);
1434 let result = manager.eval(x, &assignment);
1435 assert_eq!(result, BigRational::from_integer(BigInt::from(0)));
1436 }
1437
1438 #[test]
1439 fn test_add_addition() {
1440 use num_bigint::BigInt;
1441 let mut manager = AddManager::new();
1442 let three = manager.constant(BigRational::from_integer(BigInt::from(3)));
1443 let five = manager.constant(BigRational::from_integer(BigInt::from(5)));
1444 let sum = manager.add(three, five);
1445
1446 let assignment = FxHashMap::default();
1447 let result = manager.eval(sum, &assignment);
1448 assert_eq!(result, BigRational::from_integer(BigInt::from(8)));
1449 }
1450
1451 #[test]
1452 fn test_add_multiplication() {
1453 use num_bigint::BigInt;
1454 let mut manager = AddManager::new();
1455 let three = manager.constant(BigRational::from_integer(BigInt::from(3)));
1456 let five = manager.constant(BigRational::from_integer(BigInt::from(5)));
1457 let product = manager.mul(three, five);
1458
1459 let assignment = FxHashMap::default();
1460 let result = manager.eval(product, &assignment);
1461 assert_eq!(result, BigRational::from_integer(BigInt::from(15)));
1462 }
1463
1464 #[test]
1465 fn test_add_max_min() {
1466 use num_bigint::BigInt;
1467 let mut manager = AddManager::new();
1468 let three = manager.constant(BigRational::from_integer(BigInt::from(3)));
1469 let five = manager.constant(BigRational::from_integer(BigInt::from(5)));
1470
1471 let max_val = manager.max(three, five);
1472 let min_val = manager.min(three, five);
1473
1474 let assignment = FxHashMap::default();
1475 assert_eq!(
1476 manager.eval(max_val, &assignment),
1477 BigRational::from_integer(BigInt::from(5))
1478 );
1479 assert_eq!(
1480 manager.eval(min_val, &assignment),
1481 BigRational::from_integer(BigInt::from(3))
1482 );
1483 }
1484
1485 #[test]
1486 fn test_add_scale() {
1487 use num_bigint::BigInt;
1488 let mut manager = AddManager::new();
1489 let x = manager.variable(0);
1490 let scaled = manager.scale(x, &BigRational::from_integer(BigInt::from(5)));
1491
1492 let mut assignment = FxHashMap::default();
1493 assignment.insert(0, true);
1494 let result = manager.eval(scaled, &assignment);
1495 assert_eq!(result, BigRational::from_integer(BigInt::from(5)));
1496
1497 assignment.insert(0, false);
1498 let result = manager.eval(scaled, &assignment);
1499 assert_eq!(result, BigRational::from_integer(BigInt::from(0)));
1500 }
1501
1502 #[test]
1503 fn test_add_sharing() {
1504 use num_bigint::BigInt;
1505 let mut manager = AddManager::new();
1506 let x = manager.constant(BigRational::from_integer(BigInt::from(5)));
1507 let y = manager.constant(BigRational::from_integer(BigInt::from(5)));
1508 assert_eq!(x, y); }
1510}