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}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
45enum BddOp {
46 And,
47 Or,
48 Xor,
49}
50
51impl BddManager {
52 pub fn new() -> Self {
54 let mut manager = Self {
55 nodes: Vec::new(),
56 unique_table: FxHashMap::default(),
57 op_cache: FxHashMap::default(),
58 };
59
60 manager.nodes.push(BddNode {
63 var: u32::MAX,
64 low: 0,
65 high: 0,
66 });
67
68 manager.nodes.push(BddNode {
70 var: u32::MAX,
71 low: 1,
72 high: 1,
73 });
74
75 manager
76 }
77
78 pub fn constant_false(&self) -> NodeId {
80 BDD_FALSE
81 }
82
83 pub fn constant_true(&self) -> NodeId {
85 BDD_TRUE
86 }
87
88 pub fn variable(&mut self, var: VarId) -> NodeId {
90 self.make_node(var, BDD_FALSE, BDD_TRUE)
91 }
92
93 fn make_node(&mut self, var: VarId, low: NodeId, high: NodeId) -> NodeId {
98 if low == high {
100 return low;
101 }
102
103 let key = (var, low, high);
105 if let Some(&node_id) = self.unique_table.get(&key) {
106 return node_id;
107 }
108
109 let node_id = self.nodes.len();
111 self.nodes.push(BddNode { var, low, high });
112 self.unique_table.insert(key, node_id);
113 node_id
114 }
115
116 pub fn not(&mut self, node: NodeId) -> NodeId {
118 self.apply_not_rec(node)
119 }
120
121 fn apply_not_rec(&mut self, node: NodeId) -> NodeId {
122 if node == BDD_FALSE {
123 return BDD_TRUE;
124 }
125 if node == BDD_TRUE {
126 return BDD_FALSE;
127 }
128
129 let n = self.nodes[node];
130 let low = self.apply_not_rec(n.low);
131 let high = self.apply_not_rec(n.high);
132 self.make_node(n.var, low, high)
133 }
134
135 pub fn and(&mut self, left: NodeId, right: NodeId) -> NodeId {
137 self.apply(BddOp::And, left, right)
138 }
139
140 pub fn or(&mut self, left: NodeId, right: NodeId) -> NodeId {
142 self.apply(BddOp::Or, left, right)
143 }
144
145 pub fn xor(&mut self, left: NodeId, right: NodeId) -> NodeId {
147 self.apply(BddOp::Xor, left, right)
148 }
149
150 pub fn implies(&mut self, left: NodeId, right: NodeId) -> NodeId {
152 let not_left = self.not(left);
153 self.or(not_left, right)
154 }
155
156 pub fn iff(&mut self, left: NodeId, right: NodeId) -> NodeId {
158 let not_xor = self.xor(left, right);
159 self.not(not_xor)
160 }
161
162 fn apply(&mut self, op: BddOp, left: NodeId, right: NodeId) -> NodeId {
164 match op {
166 BddOp::And => {
167 if left == BDD_FALSE || right == BDD_FALSE {
168 return BDD_FALSE;
169 }
170 if left == BDD_TRUE {
171 return right;
172 }
173 if right == BDD_TRUE {
174 return left;
175 }
176 if left == right {
177 return left;
178 }
179 }
180 BddOp::Or => {
181 if left == BDD_TRUE || right == BDD_TRUE {
182 return BDD_TRUE;
183 }
184 if left == BDD_FALSE {
185 return right;
186 }
187 if right == BDD_FALSE {
188 return left;
189 }
190 if left == right {
191 return left;
192 }
193 }
194 BddOp::Xor => {
195 if left == BDD_FALSE {
196 return right;
197 }
198 if right == BDD_FALSE {
199 return left;
200 }
201 if left == BDD_TRUE {
202 return self.apply_not_rec(right);
203 }
204 if right == BDD_TRUE {
205 return self.apply_not_rec(left);
206 }
207 if left == right {
208 return BDD_FALSE;
209 }
210 }
211 }
212
213 let cache_key = (op, left, right);
215 if let Some(&result) = self.op_cache.get(&cache_key) {
216 return result;
217 }
218
219 let left_node = self.nodes[left];
221 let right_node = self.nodes[right];
222
223 let result = if left_node.var == right_node.var {
224 let low = self.apply(op, left_node.low, right_node.low);
226 let high = self.apply(op, left_node.high, right_node.high);
227 self.make_node(left_node.var, low, high)
228 } else if left_node.var < right_node.var {
229 let low = self.apply(op, left_node.low, right);
231 let high = self.apply(op, left_node.high, right);
232 self.make_node(left_node.var, low, high)
233 } else {
234 let low = self.apply(op, left, right_node.low);
236 let high = self.apply(op, left, right_node.high);
237 self.make_node(right_node.var, low, high)
238 };
239
240 self.op_cache.insert(cache_key, result);
241 result
242 }
243
244 pub fn ite(&mut self, cond: NodeId, then_node: NodeId, else_node: NodeId) -> NodeId {
246 if cond == BDD_TRUE {
248 return then_node;
249 }
250 if cond == BDD_FALSE {
251 return else_node;
252 }
253 if then_node == else_node {
254 return then_node;
255 }
256 if then_node == BDD_TRUE && else_node == BDD_FALSE {
257 return cond;
258 }
259
260 let cond_node = self.nodes[cond];
261 let then_n = if then_node <= BDD_TRUE {
262 None
263 } else {
264 Some(self.nodes[then_node])
265 };
266 let else_n = if else_node <= BDD_TRUE {
267 None
268 } else {
269 Some(self.nodes[else_node])
270 };
271
272 let mut top_var = cond_node.var;
274 if let Some(n) = then_n
275 && n.var < top_var
276 {
277 top_var = n.var;
278 }
279 if let Some(n) = else_n
280 && n.var < top_var
281 {
282 top_var = n.var;
283 }
284
285 let cond_low = if cond_node.var == top_var {
287 cond_node.low
288 } else {
289 cond
290 };
291 let cond_high = if cond_node.var == top_var {
292 cond_node.high
293 } else {
294 cond
295 };
296
297 let then_low = if let Some(n) = then_n {
298 if n.var == top_var { n.low } else { then_node }
299 } else {
300 then_node
301 };
302 let then_high = if let Some(n) = then_n {
303 if n.var == top_var { n.high } else { then_node }
304 } else {
305 then_node
306 };
307
308 let else_low = if let Some(n) = else_n {
309 if n.var == top_var { n.low } else { else_node }
310 } else {
311 else_node
312 };
313 let else_high = if let Some(n) = else_n {
314 if n.var == top_var { n.high } else { else_node }
315 } else {
316 else_node
317 };
318
319 let low = self.ite(cond_low, then_low, else_low);
320 let high = self.ite(cond_high, then_high, else_high);
321 self.make_node(top_var, low, high)
322 }
323
324 pub fn eval(&self, node: NodeId, assignment: &FxHashMap<VarId, bool>) -> bool {
326 if node == BDD_FALSE {
327 return false;
328 }
329 if node == BDD_TRUE {
330 return true;
331 }
332
333 let n = self.nodes[node];
334 let var_value = assignment.get(&n.var).copied().unwrap_or(false);
335
336 if var_value {
337 self.eval(n.high, assignment)
338 } else {
339 self.eval(n.low, assignment)
340 }
341 }
342
343 pub fn sat_count(&self, node: NodeId, num_vars: u32) -> u64 {
345 let mut cache = FxHashMap::default();
346 self.sat_count_rec(node, &mut cache)
347 * (1u64 << num_vars.saturating_sub(self.max_var(node).map_or(0, |v| v + 1)))
348 }
349
350 fn sat_count_rec(&self, node: NodeId, cache: &mut FxHashMap<NodeId, u64>) -> u64 {
351 if node == BDD_FALSE {
352 return 0;
353 }
354 if node == BDD_TRUE {
355 return 1;
356 }
357
358 if let Some(&count) = cache.get(&node) {
359 return count;
360 }
361
362 let n = self.nodes[node];
363 let low_count = self.sat_count_rec(n.low, cache);
364 let high_count = self.sat_count_rec(n.high, cache);
365
366 let low_mult = if n.low <= BDD_TRUE {
368 1
369 } else {
370 let low_var = self.nodes[n.low].var;
371 1u64 << (low_var - n.var - 1)
372 };
373 let high_mult = if n.high <= BDD_TRUE {
374 1
375 } else {
376 let high_var = self.nodes[n.high].var;
377 1u64 << (high_var - n.var - 1)
378 };
379
380 let count = low_count * low_mult + high_count * high_mult;
381 cache.insert(node, count);
382 count
383 }
384
385 fn max_var(&self, node: NodeId) -> Option<VarId> {
387 if node <= BDD_TRUE {
388 return None;
389 }
390 Some(self.nodes[node].var)
391 }
392
393 pub fn node_count(&self) -> usize {
395 self.nodes.len()
396 }
397
398 pub fn clear_cache(&mut self) {
400 self.op_cache.clear();
401 }
402}
403
404impl Default for BddManager {
405 fn default() -> Self {
406 Self::new()
407 }
408}
409
410impl fmt::Display for BddManager {
411 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
412 writeln!(f, "BDD Manager: {} nodes", self.nodes.len())?;
413 writeln!(f, " Cache size: {}", self.op_cache.len())?;
414 Ok(())
415 }
416}
417
418#[derive(Debug, Clone)]
427pub struct ZddManager {
428 nodes: Vec<BddNode>,
429 unique_table: FxHashMap<(VarId, NodeId, NodeId), NodeId>,
430 op_cache: FxHashMap<(ZddOp, NodeId, NodeId), NodeId>,
431}
432
433#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
434enum ZddOp {
435 Union,
436 Intersection,
437 Difference,
438}
439
440pub const ZDD_EMPTY: NodeId = 0;
442pub const ZDD_BASE: NodeId = 1;
444
445impl ZddManager {
446 pub fn new() -> Self {
448 let mut manager = Self {
449 nodes: Vec::new(),
450 unique_table: FxHashMap::default(),
451 op_cache: FxHashMap::default(),
452 };
453
454 manager.nodes.push(BddNode {
456 var: u32::MAX,
457 low: 0,
458 high: 0,
459 });
460
461 manager.nodes.push(BddNode {
463 var: u32::MAX,
464 low: 1,
465 high: 1,
466 });
467
468 manager
469 }
470
471 pub fn empty(&self) -> NodeId {
473 ZDD_EMPTY
474 }
475
476 pub fn base(&self) -> NodeId {
478 ZDD_BASE
479 }
480
481 pub fn singleton(&mut self, var: VarId) -> NodeId {
483 self.make_node(var, ZDD_EMPTY, ZDD_BASE)
484 }
485
486 fn make_node(&mut self, var: VarId, low: NodeId, high: NodeId) -> NodeId {
489 if high == ZDD_EMPTY {
491 return low;
492 }
493
494 let key = (var, low, high);
496 if let Some(&node_id) = self.unique_table.get(&key) {
497 return node_id;
498 }
499
500 let node_id = self.nodes.len();
502 self.nodes.push(BddNode { var, low, high });
503 self.unique_table.insert(key, node_id);
504 node_id
505 }
506
507 pub fn union(&mut self, left: NodeId, right: NodeId) -> NodeId {
509 self.apply(ZddOp::Union, left, right)
510 }
511
512 pub fn intersection(&mut self, left: NodeId, right: NodeId) -> NodeId {
514 self.apply(ZddOp::Intersection, left, right)
515 }
516
517 pub fn difference(&mut self, left: NodeId, right: NodeId) -> NodeId {
519 self.apply(ZddOp::Difference, left, right)
520 }
521
522 fn apply(&mut self, op: ZddOp, left: NodeId, right: NodeId) -> NodeId {
523 match op {
525 ZddOp::Union => {
526 if left == ZDD_EMPTY {
527 return right;
528 }
529 if right == ZDD_EMPTY {
530 return left;
531 }
532 if left == right {
533 return left;
534 }
535 }
536 ZddOp::Intersection => {
537 if left == ZDD_EMPTY || right == ZDD_EMPTY {
538 return ZDD_EMPTY;
539 }
540 if left == right {
541 return left;
542 }
543 if left == ZDD_BASE || right == ZDD_BASE {
545 return ZDD_EMPTY;
546 }
547 }
548 ZddOp::Difference => {
549 if left == ZDD_EMPTY {
550 return ZDD_EMPTY;
551 }
552 if right == ZDD_EMPTY {
553 return left;
554 }
555 if left == right {
556 return ZDD_EMPTY;
557 }
558 }
559 }
560
561 let cache_key = (op, left, right);
563 if let Some(&result) = self.op_cache.get(&cache_key) {
564 return result;
565 }
566
567 let left_node = self.nodes[left];
569 let right_node = self.nodes[right];
570
571 let result = if left_node.var == right_node.var {
572 let low = self.apply(op, left_node.low, right_node.low);
573 let high = self.apply(op, left_node.high, right_node.high);
574 self.make_node(left_node.var, low, high)
575 } else if left_node.var < right_node.var {
576 let low = self.apply(op, left_node.low, right);
577 let high = match op {
578 ZddOp::Union => left_node.high,
579 ZddOp::Intersection => self.apply(op, left_node.high, right),
580 ZddOp::Difference => left_node.high,
581 };
582 self.make_node(left_node.var, low, high)
583 } else {
584 let low = self.apply(op, left, right_node.low);
585 let high = match op {
586 ZddOp::Union => right_node.high,
587 ZddOp::Intersection => self.apply(op, left, right_node.high),
588 ZddOp::Difference => ZDD_EMPTY,
589 };
590 self.make_node(right_node.var, low, high)
591 };
592
593 self.op_cache.insert(cache_key, result);
594 result
595 }
596
597 pub fn count(&self, node: NodeId) -> u64 {
599 let mut cache = FxHashMap::default();
600 self.count_rec(node, &mut cache)
601 }
602
603 fn count_rec(&self, node: NodeId, cache: &mut FxHashMap<NodeId, u64>) -> u64 {
604 if node == ZDD_EMPTY {
605 return 0;
606 }
607 if node == ZDD_BASE {
608 return 1;
609 }
610
611 if let Some(&count) = cache.get(&node) {
612 return count;
613 }
614
615 let n = self.nodes[node];
616 let count = self.count_rec(n.low, cache) + self.count_rec(n.high, cache);
617 cache.insert(node, count);
618 count
619 }
620
621 pub fn node_count(&self) -> usize {
623 self.nodes.len()
624 }
625
626 pub fn clear_cache(&mut self) {
628 self.op_cache.clear();
629 }
630}
631
632impl Default for ZddManager {
633 fn default() -> Self {
634 Self::new()
635 }
636}
637
638impl fmt::Display for ZddManager {
639 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
640 writeln!(f, "ZDD Manager: {} nodes", self.nodes.len())?;
641 writeln!(f, " Cache size: {}", self.op_cache.len())?;
642 Ok(())
643 }
644}
645
646use num_rational::BigRational;
652use num_traits::Zero;
653
654#[derive(Debug, Clone, PartialEq, Eq, Hash)]
656enum AddNode {
657 Terminal(BigRational),
659 Internal {
661 var: VarId,
662 low: NodeId,
663 high: NodeId,
664 },
665}
666
667#[derive(Debug, Clone)]
669pub struct AddManager {
670 nodes: Vec<AddNode>,
671 unique_table: FxHashMap<AddNode, NodeId>,
672 op_cache: FxHashMap<(AddOp, NodeId, NodeId), NodeId>,
673}
674
675#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
676enum AddOp {
677 Add,
678 Mul,
679 Max,
680 Min,
681}
682
683impl AddManager {
684 pub fn new() -> Self {
686 let mut manager = Self {
687 nodes: Vec::new(),
688 unique_table: FxHashMap::default(),
689 op_cache: FxHashMap::default(),
690 };
691
692 let zero = AddNode::Terminal(BigRational::zero());
694 manager.nodes.push(zero.clone());
695 manager.unique_table.insert(zero, 0);
696
697 manager
698 }
699
700 pub fn constant(&mut self, value: BigRational) -> NodeId {
702 let node = AddNode::Terminal(value);
703
704 if let Some(&id) = self.unique_table.get(&node) {
706 return id;
707 }
708
709 let id = self.nodes.len();
710 self.nodes.push(node.clone());
711 self.unique_table.insert(node, id);
712 id
713 }
714
715 pub fn variable(&mut self, var: VarId) -> NodeId {
717 let zero = self.constant(BigRational::zero());
718 let one = self.constant(BigRational::from_integer(1.into()));
719 self.make_node(var, zero, one)
720 }
721
722 fn make_node(&mut self, var: VarId, low: NodeId, high: NodeId) -> NodeId {
724 if low == high {
726 return low;
727 }
728
729 let node = AddNode::Internal { var, low, high };
730
731 if let Some(&id) = self.unique_table.get(&node) {
733 return id;
734 }
735
736 let id = self.nodes.len();
738 self.nodes.push(node.clone());
739 self.unique_table.insert(node, id);
740 id
741 }
742
743 pub fn eval(&self, node: NodeId, assignment: &FxHashMap<VarId, bool>) -> BigRational {
745 match &self.nodes[node] {
746 AddNode::Terminal(value) => value.clone(),
747 AddNode::Internal { var, low, high } => {
748 if *assignment.get(var).unwrap_or(&false) {
749 self.eval(*high, assignment)
750 } else {
751 self.eval(*low, assignment)
752 }
753 }
754 }
755 }
756
757 pub fn add(&mut self, left: NodeId, right: NodeId) -> NodeId {
759 self.apply(AddOp::Add, left, right)
760 }
761
762 pub fn mul(&mut self, left: NodeId, right: NodeId) -> NodeId {
764 self.apply(AddOp::Mul, left, right)
765 }
766
767 pub fn max(&mut self, left: NodeId, right: NodeId) -> NodeId {
769 self.apply(AddOp::Max, left, right)
770 }
771
772 pub fn min(&mut self, left: NodeId, right: NodeId) -> NodeId {
774 self.apply(AddOp::Min, left, right)
775 }
776
777 pub fn scale(&mut self, node: NodeId, scalar: &BigRational) -> NodeId {
779 let scalar_node = self.constant(scalar.clone());
780 self.mul(node, scalar_node)
781 }
782
783 fn apply(&mut self, op: AddOp, left: NodeId, right: NodeId) -> NodeId {
785 if let (AddNode::Terminal(l), AddNode::Terminal(r)) =
787 (&self.nodes[left], &self.nodes[right])
788 {
789 let result_value = match op {
790 AddOp::Add => l + r,
791 AddOp::Mul => l * r,
792 AddOp::Max => {
793 if l > r {
794 l.clone()
795 } else {
796 r.clone()
797 }
798 }
799 AddOp::Min => {
800 if l < r {
801 l.clone()
802 } else {
803 r.clone()
804 }
805 }
806 };
807 return self.constant(result_value);
808 }
809
810 let cache_key = (op, left, right);
812 if let Some(&result) = self.op_cache.get(&cache_key) {
813 return result;
814 }
815
816 let (var, left_low, left_high, right_low, right_high) = self.split_nodes(left, right);
818
819 let low = self.apply(op, left_low, right_low);
820 let high = self.apply(op, left_high, right_high);
821
822 let result = self.make_node(var, low, high);
823 self.op_cache.insert(cache_key, result);
824 result
825 }
826
827 fn split_nodes(&self, left: NodeId, right: NodeId) -> (VarId, NodeId, NodeId, NodeId, NodeId) {
829 let (left_var, left_low, left_high) = match &self.nodes[left] {
830 AddNode::Terminal(_) => (u32::MAX, left, left),
831 AddNode::Internal { var, low, high } => (*var, *low, *high),
832 };
833
834 let (right_var, right_low, right_high) = match &self.nodes[right] {
835 AddNode::Terminal(_) => (u32::MAX, right, right),
836 AddNode::Internal { var, low, high } => (*var, *low, *high),
837 };
838
839 if left_var == u32::MAX && right_var == u32::MAX {
840 panic!("Both nodes are terminals - should have been handled earlier");
841 }
842
843 if left_var == right_var {
844 (left_var, left_low, left_high, right_low, right_high)
845 } else if left_var < right_var {
846 (left_var, left_low, left_high, right, right)
847 } else {
848 (right_var, left, left, right_low, right_high)
849 }
850 }
851
852 pub fn ite(&mut self, cond: NodeId, then_add: NodeId, else_add: NodeId) -> NodeId {
854 let one = self.constant(BigRational::from_integer(1.into()));
857 let neg_one = BigRational::from_integer((-1).into());
858 let scaled_cond = self.scale(cond, &neg_one);
859 let not_cond = self.apply(AddOp::Add, one, scaled_cond);
860
861 let then_part = self.mul(cond, then_add);
862 let else_part = self.mul(not_cond, else_add);
863 self.add(then_part, else_part)
864 }
865
866 pub fn node_count(&self) -> usize {
868 self.nodes.len()
869 }
870
871 pub fn clear_cache(&mut self) {
873 self.op_cache.clear();
874 }
875
876 pub fn get_var(&self, node: NodeId) -> Option<VarId> {
878 match &self.nodes[node] {
879 AddNode::Terminal(_) => None,
880 AddNode::Internal { var, .. } => Some(*var),
881 }
882 }
883
884 pub fn get_value(&self, node: NodeId) -> Option<&BigRational> {
886 match &self.nodes[node] {
887 AddNode::Terminal(value) => Some(value),
888 AddNode::Internal { .. } => None,
889 }
890 }
891}
892
893impl Default for AddManager {
894 fn default() -> Self {
895 Self::new()
896 }
897}
898
899impl fmt::Display for AddManager {
900 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
901 writeln!(f, "ADD Manager: {} nodes", self.nodes.len())?;
902 writeln!(f, " Cache size: {}", self.op_cache.len())?;
903 Ok(())
904 }
905}
906
907#[cfg(test)]
908mod tests {
909 use super::*;
910
911 #[test]
912 fn test_bdd_constants() {
913 let manager = BddManager::new();
914 assert_eq!(manager.constant_false(), BDD_FALSE);
915 assert_eq!(manager.constant_true(), BDD_TRUE);
916 }
917
918 #[test]
919 fn test_bdd_variable() {
920 let mut manager = BddManager::new();
921 let x = manager.variable(0);
922
923 let mut assignment = FxHashMap::default();
924 assignment.insert(0, true);
925 assert!(manager.eval(x, &assignment));
926
927 assignment.insert(0, false);
928 assert!(!manager.eval(x, &assignment));
929 }
930
931 #[test]
932 fn test_bdd_not() {
933 let mut manager = BddManager::new();
934 let x = manager.variable(0);
935 let not_x = manager.not(x);
936
937 let mut assignment = FxHashMap::default();
938 assignment.insert(0, true);
939 assert!(!manager.eval(not_x, &assignment));
940
941 assignment.insert(0, false);
942 assert!(manager.eval(not_x, &assignment));
943 }
944
945 #[test]
946 fn test_bdd_and() {
947 let mut manager = BddManager::new();
948 let x = manager.variable(0);
949 let y = manager.variable(1);
950 let x_and_y = manager.and(x, y);
951
952 let mut assignment = FxHashMap::default();
953 assignment.insert(0, true);
954 assignment.insert(1, true);
955 assert!(manager.eval(x_and_y, &assignment));
956
957 assignment.insert(0, false);
958 assert!(!manager.eval(x_and_y, &assignment));
959 }
960
961 #[test]
962 fn test_bdd_or() {
963 let mut manager = BddManager::new();
964 let x = manager.variable(0);
965 let y = manager.variable(1);
966 let x_or_y = manager.or(x, y);
967
968 let mut assignment = FxHashMap::default();
969 assignment.insert(0, false);
970 assignment.insert(1, false);
971 assert!(!manager.eval(x_or_y, &assignment));
972
973 assignment.insert(0, true);
974 assert!(manager.eval(x_or_y, &assignment));
975 }
976
977 #[test]
978 fn test_bdd_xor() {
979 let mut manager = BddManager::new();
980 let x = manager.variable(0);
981 let y = manager.variable(1);
982 let x_xor_y = manager.xor(x, y);
983
984 let mut assignment = FxHashMap::default();
985 assignment.insert(0, true);
986 assignment.insert(1, true);
987 assert!(!manager.eval(x_xor_y, &assignment));
988
989 assignment.insert(0, true);
990 assignment.insert(1, false);
991 assert!(manager.eval(x_xor_y, &assignment));
992 }
993
994 #[test]
995 fn test_bdd_ite() {
996 let mut manager = BddManager::new();
997 let x = manager.variable(0);
998 let y = manager.variable(1);
999 let z = manager.variable(2);
1000
1001 let result = manager.ite(x, y, z);
1003
1004 let mut assignment = FxHashMap::default();
1005 assignment.insert(0, true);
1006 assignment.insert(1, true);
1007 assignment.insert(2, false);
1008 assert!(manager.eval(result, &assignment)); assignment.insert(0, false);
1011 assignment.insert(1, true);
1012 assignment.insert(2, false);
1013 assert!(!manager.eval(result, &assignment)); }
1015
1016 #[test]
1017 fn test_bdd_implies() {
1018 let mut manager = BddManager::new();
1019 let x = manager.variable(0);
1020 let y = manager.variable(1);
1021 let x_implies_y = manager.implies(x, y);
1022
1023 let mut assignment = FxHashMap::default();
1024 assignment.insert(0, true);
1025 assignment.insert(1, false);
1026 assert!(!manager.eval(x_implies_y, &assignment));
1027
1028 assignment.insert(0, false);
1029 assignment.insert(1, false);
1030 assert!(manager.eval(x_implies_y, &assignment));
1031 }
1032
1033 #[test]
1034 fn test_bdd_sharing() {
1035 let mut manager = BddManager::new();
1036 let x = manager.variable(0);
1037 let y = manager.variable(0); assert_eq!(x, y); }
1040
1041 #[test]
1043 fn test_zdd_empty_and_base() {
1044 let manager = ZddManager::new();
1045 assert_eq!(manager.empty(), ZDD_EMPTY);
1046 assert_eq!(manager.base(), ZDD_BASE);
1047 assert_eq!(manager.count(ZDD_EMPTY), 0);
1048 assert_eq!(manager.count(ZDD_BASE), 1);
1049 }
1050
1051 #[test]
1052 fn test_zdd_singleton() {
1053 let mut manager = ZddManager::new();
1054 let x = manager.singleton(0);
1055 assert_eq!(manager.count(x), 1); assert_ne!(x, ZDD_EMPTY);
1057 assert_ne!(x, ZDD_BASE);
1058 }
1059
1060 #[test]
1061 fn test_zdd_union() {
1062 let mut manager = ZddManager::new();
1063 let x = manager.singleton(0);
1064 let y = manager.singleton(1);
1065 let union = manager.union(x, y);
1066
1067 assert_eq!(manager.count(union), 2);
1069 }
1070
1071 #[test]
1072 fn test_zdd_intersection() {
1073 let mut manager = ZddManager::new();
1074 let x = manager.singleton(0);
1075 let y = manager.singleton(1);
1076 let intersection = manager.intersection(x, y);
1077
1078 assert_eq!(intersection, ZDD_EMPTY);
1080 assert_eq!(manager.count(intersection), 0);
1081 }
1082
1083 #[test]
1084 fn test_zdd_difference() {
1085 let mut manager = ZddManager::new();
1086 let x = manager.singleton(0);
1087 let y = manager.singleton(1);
1088
1089 let diff1 = manager.difference(x, y);
1090 assert_eq!(manager.count(diff1), 1); let diff2 = manager.difference(x, x);
1093 assert_eq!(diff2, ZDD_EMPTY); }
1095
1096 #[test]
1097 fn test_zdd_union_associative() {
1098 let mut manager = ZddManager::new();
1099 let x = manager.singleton(0);
1100 let y = manager.singleton(1);
1101 let z = manager.singleton(2);
1102
1103 let xy = manager.union(x, y);
1104 let xyz1 = manager.union(xy, z);
1105
1106 let yz = manager.union(y, z);
1107 let xyz2 = manager.union(x, yz);
1108
1109 assert_eq!(manager.count(xyz1), manager.count(xyz2));
1110 assert_eq!(manager.count(xyz1), 3); }
1112
1113 #[test]
1115 fn test_add_constant() {
1116 use num_bigint::BigInt;
1117 let mut manager = AddManager::new();
1118 let five = manager.constant(BigRational::from_integer(BigInt::from(5)));
1119
1120 let assignment = FxHashMap::default();
1121 let result = manager.eval(five, &assignment);
1122 assert_eq!(result, BigRational::from_integer(BigInt::from(5)));
1123 }
1124
1125 #[test]
1126 fn test_add_variable() {
1127 use num_bigint::BigInt;
1128 let mut manager = AddManager::new();
1129 let x = manager.variable(0);
1130
1131 let mut assignment = FxHashMap::default();
1132 assignment.insert(0, true);
1133 let result = manager.eval(x, &assignment);
1134 assert_eq!(result, BigRational::from_integer(BigInt::from(1)));
1135
1136 assignment.insert(0, false);
1137 let result = manager.eval(x, &assignment);
1138 assert_eq!(result, BigRational::from_integer(BigInt::from(0)));
1139 }
1140
1141 #[test]
1142 fn test_add_addition() {
1143 use num_bigint::BigInt;
1144 let mut manager = AddManager::new();
1145 let three = manager.constant(BigRational::from_integer(BigInt::from(3)));
1146 let five = manager.constant(BigRational::from_integer(BigInt::from(5)));
1147 let sum = manager.add(three, five);
1148
1149 let assignment = FxHashMap::default();
1150 let result = manager.eval(sum, &assignment);
1151 assert_eq!(result, BigRational::from_integer(BigInt::from(8)));
1152 }
1153
1154 #[test]
1155 fn test_add_multiplication() {
1156 use num_bigint::BigInt;
1157 let mut manager = AddManager::new();
1158 let three = manager.constant(BigRational::from_integer(BigInt::from(3)));
1159 let five = manager.constant(BigRational::from_integer(BigInt::from(5)));
1160 let product = manager.mul(three, five);
1161
1162 let assignment = FxHashMap::default();
1163 let result = manager.eval(product, &assignment);
1164 assert_eq!(result, BigRational::from_integer(BigInt::from(15)));
1165 }
1166
1167 #[test]
1168 fn test_add_max_min() {
1169 use num_bigint::BigInt;
1170 let mut manager = AddManager::new();
1171 let three = manager.constant(BigRational::from_integer(BigInt::from(3)));
1172 let five = manager.constant(BigRational::from_integer(BigInt::from(5)));
1173
1174 let max_val = manager.max(three, five);
1175 let min_val = manager.min(three, five);
1176
1177 let assignment = FxHashMap::default();
1178 assert_eq!(
1179 manager.eval(max_val, &assignment),
1180 BigRational::from_integer(BigInt::from(5))
1181 );
1182 assert_eq!(
1183 manager.eval(min_val, &assignment),
1184 BigRational::from_integer(BigInt::from(3))
1185 );
1186 }
1187
1188 #[test]
1189 fn test_add_scale() {
1190 use num_bigint::BigInt;
1191 let mut manager = AddManager::new();
1192 let x = manager.variable(0);
1193 let scaled = manager.scale(x, &BigRational::from_integer(BigInt::from(5)));
1194
1195 let mut assignment = FxHashMap::default();
1196 assignment.insert(0, true);
1197 let result = manager.eval(scaled, &assignment);
1198 assert_eq!(result, BigRational::from_integer(BigInt::from(5)));
1199
1200 assignment.insert(0, false);
1201 let result = manager.eval(scaled, &assignment);
1202 assert_eq!(result, BigRational::from_integer(BigInt::from(0)));
1203 }
1204
1205 #[test]
1206 fn test_add_sharing() {
1207 use num_bigint::BigInt;
1208 let mut manager = AddManager::new();
1209 let x = manager.constant(BigRational::from_integer(BigInt::from(5)));
1210 let y = manager.constant(BigRational::from_integer(BigInt::from(5)));
1211 assert_eq!(x, y); }
1213}