1use crate::bdd_node::{BddNode16, BddNode32, BddNode64, BddNodeAny, BddNodeImpl};
2use crate::conversion::{UncheckedFrom, UncheckedInto};
3use crate::node_id::{AsNodeId, NodeId, NodeId16, NodeId64};
4use crate::node_id::{NodeId32, NodeIdAny};
5use crate::variable_id::{
6 AsVarId, VarIdPacked16, VarIdPacked32, VarIdPacked64, VarIdPackedAny, VariableId,
7 variables_between,
8};
9use std::fmt::Debug;
10use std::io::{self, Write};
11
12pub(crate) trait BddAny: Debug + Clone {
32 type Id: NodeIdAny;
34 type VarId: VarIdPackedAny;
36 type Node: BddNodeAny<Id = Self::Id, VarId = Self::VarId>;
38
39 fn new_true() -> Self;
41 fn new_false() -> Self;
43 fn new_literal(var: Self::VarId, value: bool) -> Self;
45
46 fn is_true(&self) -> bool;
48
49 fn is_false(&self) -> bool;
51
52 unsafe fn new_unchecked(root: Self::Id, nodes: Vec<Self::Node>) -> Self;
61
62 fn root(&self) -> Self::Id;
64 #[allow(dead_code)]
66 fn get(&self, id: Self::Id) -> Option<&Self::Node>;
67
68 unsafe fn get_node_unchecked(&self, id: Self::Id) -> &Self::Node;
74}
75
76#[derive(Debug, Clone)]
80pub(crate) struct BddImpl<TNodeId: NodeIdAny, TVarId: VarIdPackedAny> {
81 pub(crate) root: TNodeId,
82 pub(crate) nodes: Vec<BddNodeImpl<TNodeId, TVarId>>,
83}
84
85impl<TNodeId: NodeIdAny, TVarId: VarIdPackedAny> BddImpl<TNodeId, TVarId> {
86 pub fn node_count(&self) -> usize {
88 self.nodes.len()
89 }
90
91 fn not(&self) -> Self {
93 if self.is_true() {
94 return Self::new_false();
95 }
96 if self.is_false() {
97 return Self::new_true();
98 }
99
100 let mut nodes = self.nodes.clone();
101 for node in nodes.iter_mut().skip(2) {
102 node.low = node.low.flipped_if_terminal();
103 node.high = node.high.flipped_if_terminal();
104 }
105
106 Self {
107 root: self.root,
108 nodes,
109 }
110 }
111
112 pub fn structural_eq(&self, other: &Self) -> bool {
119 self.root == other.root && self.nodes == other.nodes
120 }
121
122 pub(crate) fn get_largest_variable(&self) -> VariableId {
125 self.nodes
126 .iter()
127 .map(|node| node.variable())
128 .reduce(TVarId::max_defined)
129 .expect("BDD is not constant")
130 .unchecked_into()
131 }
132
133 fn count_satisfying_paths(&self) -> f64 {
135 if self.is_false() {
136 return 0.0;
137 }
138
139 let mut counts = vec![-1.0f64; self.node_count()];
141 counts[0] = 0.0;
142 counts[1] = 1.0;
143
144 let root = self.root;
145
146 let mut stack = vec![root];
147
148 while let Some(id) = stack.pop() {
149 if counts[id.as_usize()] >= 0.0 {
150 continue;
151 }
152
153 let node = unsafe { self.get_node_unchecked(id) };
154 let low = node.low;
155 let high = node.high;
156 let low_count = counts[low.as_usize()];
157 let high_count = counts[high.as_usize()];
158 let low_is_done = low_count >= 0.0;
159 let high_is_done = high_count >= 0.0;
160
161 if low_is_done && high_is_done {
162 counts[id.as_usize()] = low_count + high_count;
163 continue;
164 }
165
166 stack.push(id);
167
168 if !low_is_done {
169 stack.push(low);
170 }
171
172 if !high_is_done {
173 stack.push(high);
174 }
175 }
176 let result: f64 = counts[root.as_usize()];
177 debug_assert!(result >= 0.0);
178 debug_assert!(!result.is_nan());
179 result
180 }
181
182 fn count_satisfying_valuations(&self, largest_variable: Option<VariableId>) -> f64 {
190 if self.is_false() {
191 return 0.0;
192 }
193
194 if self.is_true() {
195 if let Some(largest_variable) = largest_variable {
196 let exponent = (Into::<u64>::into(largest_variable) + 1)
197 .try_into()
198 .unwrap_or(f64::MAX_EXP);
199 return 2.0f64.powi(exponent);
200 }
201 return 1.0f64;
202 }
203
204 let largest_variable = largest_variable.unwrap_or_else(|| self.get_largest_variable());
205
206 let mut counts = vec![-1.0f64; self.node_count()];
208 counts[0] = 0.0;
209 counts[1] = 1.0;
210
211 let root = self.root;
212
213 let mut stack = vec![root];
214
215 while let Some(id) = stack.pop() {
216 if counts[id.as_usize()] >= 0.0 {
217 continue;
218 }
219
220 let node = unsafe { self.get_node_unchecked(id) };
221 let low = node.low();
222 let high = node.high();
223 let low_count = counts[low.as_usize()];
224 let high_count = counts[high.as_usize()];
225 let low_is_done = low_count >= 0.0;
226 let high_is_done = high_count >= 0.0;
227
228 let low_node = unsafe { self.get_node_unchecked(low) };
229 let high_node = unsafe { self.get_node_unchecked(high) };
230
231 let variable = node.variable();
232 let low_variable = low_node.variable();
233 let high_variable = high_node.variable();
234
235 if low_is_done && high_is_done {
236 let skipped = variables_between(low_variable, variable, largest_variable)
237 .try_into()
238 .unwrap_or(f64::MAX_EXP);
239 let low_count = low_count * 2.0f64.powi(skipped);
240
241 let skipped = variables_between(high_variable, variable, largest_variable)
242 .try_into()
243 .unwrap_or(f64::MAX_EXP);
244 let high_count = high_count * 2.0f64.powi(skipped);
245
246 counts[id.as_usize()] = low_count + high_count;
247
248 continue;
249 }
250
251 stack.push(id);
252
253 if !low_is_done {
254 stack.push(low);
255 }
256
257 if !high_is_done {
258 stack.push(high);
259 }
260 }
261
262 debug_assert!(counts[root.as_usize()] >= 0.0);
263
264 let root_variable = unsafe { self.get_node_unchecked(root) }.variable();
265 let result = counts[root.as_usize()]
266 * 2.0f64.powi(
267 root_variable
268 .unpack_u64()
269 .try_into()
270 .unwrap_or(f64::MAX_EXP),
271 );
272
273 if result.is_nan() {
274 f64::INFINITY
275 } else {
276 result
277 }
278 }
279}
280
281impl<TNodeId: NodeIdAny, TVarId: VarIdPackedAny> BddAny for BddImpl<TNodeId, TVarId> {
282 type Id = TNodeId;
283 type VarId = TVarId;
284 type Node = BddNodeImpl<TNodeId, TVarId>;
285
286 fn new_true() -> Self {
287 Self {
288 root: TNodeId::one(),
289 nodes: vec![BddNodeImpl::zero(), BddNodeImpl::one()],
290 }
291 }
292
293 fn new_false() -> Self {
294 Self {
295 root: TNodeId::zero(),
296 nodes: vec![BddNodeImpl::zero()],
297 }
298 }
299
300 fn new_literal(var: Self::VarId, value: bool) -> Self {
301 let node = if value {
302 Self::Node::new(var, TNodeId::zero(), TNodeId::one())
303 } else {
304 Self::Node::new(var, TNodeId::one(), TNodeId::zero())
305 };
306 Self {
307 root: 2usize.unchecked_into(),
308 nodes: vec![Self::Node::zero(), Self::Node::one(), node],
309 }
310 }
311
312 fn is_true(&self) -> bool {
313 debug_assert!(self.root.is_one() == (self.nodes.len() == 2));
314 self.root.is_one()
315 }
316
317 fn is_false(&self) -> bool {
318 debug_assert!(self.root.is_zero() == (self.nodes.len() == 1));
319 self.root.is_zero()
320 }
321
322 unsafe fn new_unchecked(root: Self::Id, nodes: Vec<Self::Node>) -> Self {
323 Self { root, nodes }
324 }
325
326 fn root(&self) -> Self::Id {
327 self.root
328 }
329
330 fn get(&self, id: Self::Id) -> Option<&Self::Node> {
331 self.nodes.get(id.as_usize())
332 }
333
334 unsafe fn get_node_unchecked(&self, id: Self::Id) -> &Self::Node {
335 unsafe { self.nodes.get_unchecked(id.as_usize()) }
336 }
337}
338
339pub(crate) type Bdd16 = BddImpl<NodeId16, VarIdPacked16>;
342
343pub(crate) type Bdd32 = BddImpl<NodeId32, VarIdPacked32>;
346
347pub(crate) type Bdd64 = BddImpl<NodeId64, VarIdPacked64>;
350
351pub(crate) trait AsBdd<TBdd: BddAny>:
354 BddAny<Id: AsNodeId<TBdd::Id>, VarId: AsVarId<TBdd::VarId>>
355{
356}
357
358impl AsBdd<Bdd16> for Bdd16 {}
359impl AsBdd<Bdd32> for Bdd16 {}
360impl AsBdd<Bdd64> for Bdd16 {}
361impl AsBdd<Bdd32> for Bdd32 {}
362impl AsBdd<Bdd64> for Bdd32 {}
363impl AsBdd<Bdd64> for Bdd64 {}
364
365macro_rules! impl_unchecked_from {
366 ($Large:ident => $Small:ident) => {
367 impl UncheckedFrom<$Large> for $Small {
368 fn unchecked_from(large: $Large) -> Self {
369 Self {
370 root: large.root.unchecked_into(),
371 nodes: large
372 .nodes
373 .into_iter()
374 .map(UncheckedInto::unchecked_into)
375 .collect(),
376 }
377 }
378 }
379 };
380}
381
382impl_unchecked_from!(Bdd32 => Bdd16);
383impl_unchecked_from!(Bdd64 => Bdd16);
384impl_unchecked_from!(Bdd64 => Bdd32);
385
386impl<TNodeId: NodeIdAny, TVarId: VarIdPackedAny> BddImpl<TNodeId, TVarId> {
387 fn write_as_dot(&self, output: &mut dyn Write) -> io::Result<()> {
389 writeln!(output, "digraph BDD {{")?;
390 writeln!(
391 output,
392 " __ruddy_root [label=\"\", style=invis, height=0, width=0];"
393 )?;
394
395 writeln!(output, " __ruddy_root -> {};", self.root)?;
396 writeln!(output)?;
397 writeln!(output, " edge [dir=none];")?;
398 writeln!(output)?;
399
400 writeln!(
401 output,
402 " 0 [label=\"0\", shape=box, width=0.3, height=0.3];"
403 )?;
404 writeln!(
405 output,
406 " 1 [label=\"1\", shape=box, width=0.3, height=0.3];"
407 )?;
408
409 for (id, node) in self.nodes.iter().enumerate().skip(2) {
410 let low = node.low();
411 let high = node.high();
412 writeln!(
413 output,
414 " {} [label=\"{}\", shape=box, width=0.3, height=0.3];",
415 id,
416 node.variable()
417 )?;
418 writeln!(output, " {id} -> {low} [style=dashed];")?;
419 writeln!(output, " {id} -> {high};")?;
420 }
421
422 writeln!(output, "}}")?;
423
424 Ok(())
425 }
426}
427
428#[derive(Clone, Debug)]
429pub(crate) enum BddInner {
430 Size16(Bdd16),
431 Size32(Bdd32),
432 Size64(Bdd64),
433}
434
435#[derive(Clone, Debug)]
449pub struct Bdd(pub(crate) BddInner);
450
451impl From<Bdd16> for Bdd {
452 fn from(bdd: Bdd16) -> Self {
453 Self(BddInner::Size16(bdd))
454 }
455}
456
457impl From<Bdd32> for Bdd {
458 fn from(bdd: Bdd32) -> Self {
459 Self(BddInner::Size32(bdd))
460 }
461}
462
463impl From<Bdd64> for Bdd {
464 fn from(bdd: Bdd64) -> Self {
465 Self(BddInner::Size64(bdd))
466 }
467}
468
469impl Bdd {
470 pub fn new_true() -> Self {
472 Bdd16::new_true().into()
473 }
474
475 pub fn new_false() -> Self {
477 Bdd16::new_false().into()
478 }
479
480 pub fn new_literal(var: VariableId, value: bool) -> Self {
482 if var.fits_in_packed16() {
483 Bdd16::new_literal(var.unchecked_into(), value).into()
484 } else if var.fits_in_packed32() {
485 Bdd32::new_literal(var.unchecked_into(), value).into()
486 } else if var.fits_in_packed64() {
487 Bdd64::new_literal(var.unchecked_into(), value).into()
488 } else {
489 unreachable!("Maximum representable variable identifier exceeded.");
490 }
491 }
492
493 pub fn node_count(&self) -> usize {
495 match &self.0 {
496 BddInner::Size16(bdd) => bdd.node_count(),
497 BddInner::Size32(bdd) => bdd.node_count(),
498 BddInner::Size64(bdd) => bdd.node_count(),
499 }
500 }
501
502 pub fn not(&self) -> Self {
504 match &self.0 {
505 BddInner::Size16(bdd) => bdd.not().into(),
506 BddInner::Size32(bdd) => bdd.not().into(),
507 BddInner::Size64(bdd) => bdd.not().into(),
508 }
509 }
510
511 pub fn is_true(&self) -> bool {
513 match &self.0 {
514 BddInner::Size16(bdd) => bdd.is_true(),
515 BddInner::Size32(bdd) => bdd.is_true(),
516 BddInner::Size64(bdd) => bdd.is_true(),
517 }
518 }
519
520 pub fn is_false(&self) -> bool {
522 match &self.0 {
523 BddInner::Size16(bdd) => bdd.is_false(),
524 BddInner::Size32(bdd) => bdd.is_false(),
525 BddInner::Size64(bdd) => bdd.is_false(),
526 }
527 }
528
529 pub(crate) fn shrink(self) -> Self {
537 match self.0 {
538 BddInner::Size64(bdd) if bdd.node_count() < 1 << 32 => {
539 let (mut vars_fit_in_16, mut vars_fit_in_32) = (true, true);
540 for node in bdd.nodes.iter() {
541 vars_fit_in_16 &= node.variable().fits_in_packed16();
542 vars_fit_in_32 &= node.variable().fits_in_packed32();
543
544 if !vars_fit_in_16 && !vars_fit_in_32 {
545 break;
546 }
547 }
548
549 if (bdd.node_count() < 1 << 16) && vars_fit_in_16 {
550 let bdd16: Bdd16 = bdd.unchecked_into();
551 return bdd16.into();
552 }
553
554 if vars_fit_in_32 {
555 let bdd32: Bdd32 = bdd.unchecked_into();
556 return bdd32.into();
557 }
558 bdd.into()
559 }
560 BddInner::Size32(bdd)
561 if (bdd.node_count() < 1 << 16)
562 && bdd
563 .nodes
564 .iter()
565 .all(|node| node.variable().fits_in_packed16()) =>
566 {
567 let bdd16: Bdd16 = bdd.unchecked_into();
568 bdd16.into()
569 }
570 _ => self,
571 }
572 }
573
574 pub fn structural_eq(&self, other: &Self) -> bool {
581 match (&self.0, &other.0) {
582 (BddInner::Size16(a), BddInner::Size16(b)) => a.structural_eq(b),
583 (BddInner::Size32(a), BddInner::Size32(b)) => a.structural_eq(b),
584 (BddInner::Size64(a), BddInner::Size64(b)) => a.structural_eq(b),
585 _ => false,
586 }
587 }
588
589 pub fn root(&self) -> NodeId {
591 match &self.0 {
592 BddInner::Size16(bdd) => bdd.root().unchecked_into(),
593 BddInner::Size32(bdd) => bdd.root().unchecked_into(),
594 BddInner::Size64(bdd) => bdd.root().unchecked_into(),
595 }
596 }
597
598 pub fn get_variable(&self, node: NodeId) -> VariableId {
600 let index: usize = node.unchecked_into();
601 match &self.0 {
602 BddInner::Size16(bdd) => bdd.nodes[index].variable.unpack().into(),
603 BddInner::Size32(bdd) => bdd.nodes[index].variable.unpack().into(),
604 BddInner::Size64(bdd) => VariableId::new_long(bdd.nodes[index].variable.unpack())
605 .unwrap_or_else(|| {
606 unreachable!("Variable stored in BDD table does not fit into standard range.")
607 }),
608 }
609 }
610
611 pub fn get_links(&self, node: NodeId) -> (NodeId, NodeId) {
613 let index: usize = node.unchecked_into();
615 match &self.0 {
616 BddInner::Size16(bdd) => {
617 let BddNode16 { low, high, .. } = bdd.nodes[index];
618 (low.unchecked_into(), high.unchecked_into())
619 }
620 BddInner::Size32(bdd) => {
621 let BddNode32 { low, high, .. } = bdd.nodes[index];
622 (low.unchecked_into(), high.unchecked_into())
623 }
624 BddInner::Size64(bdd) => {
625 let BddNode64 { low, high, .. } = bdd.nodes[index];
626 (low.unchecked_into(), high.unchecked_into())
627 }
628 }
629 }
630
631 pub fn count_satisfying_valuations(&self, largest_variable: Option<VariableId>) -> f64 {
641 match &self.0 {
642 BddInner::Size16(bdd) => bdd.count_satisfying_valuations(largest_variable),
643 BddInner::Size32(bdd) => bdd.count_satisfying_valuations(largest_variable),
644 BddInner::Size64(bdd) => bdd.count_satisfying_valuations(largest_variable),
645 }
646 }
647
648 pub fn count_satisfying_paths(&self) -> f64 {
650 match &self.0 {
651 BddInner::Size16(bdd) => bdd.count_satisfying_paths(),
652 BddInner::Size32(bdd) => bdd.count_satisfying_paths(),
653 BddInner::Size64(bdd) => bdd.count_satisfying_paths(),
654 }
655 }
656
657 pub fn write_bdd_as_dot(&self, output: &mut dyn Write) -> io::Result<()> {
659 match &self.0 {
660 BddInner::Size16(bdd) => bdd.write_as_dot(output),
661 BddInner::Size32(bdd) => bdd.write_as_dot(output),
662 BddInner::Size64(bdd) => bdd.write_as_dot(output),
663 }
664 }
665
666 pub fn to_dot_string(&self) -> String {
668 let mut output = Vec::new();
669 self.write_bdd_as_dot(&mut output).unwrap();
670 String::from_utf8(output).unwrap()
671 }
672}
673
674#[cfg(test)]
675pub(crate) mod tests {
676 use crate::bdd_node::BddNodeAny;
677 use crate::conversion::UncheckedInto;
678 use crate::node_id::{NodeId, NodeId16, NodeId32, NodeId64, NodeIdAny};
679 use crate::split::bdd::{Bdd, Bdd16, Bdd32, Bdd64, BddAny};
680 use crate::variable_id::{VarIdPacked16, VarIdPacked32, VarIdPacked64, VariableId};
681
682 use super::BddInner;
683
684 macro_rules! test_bdd_not_invariants {
685 ($func:ident, $Bdd:ident, $VarId:ident) => {
686 #[test]
687 pub fn $func() {
688 assert!($Bdd::new_true().not().structural_eq(&$Bdd::new_false()));
689 assert!($Bdd::new_false().not().structural_eq(&$Bdd::new_true()));
690
691 let v = $VarId::new(1);
692 let bdd = $Bdd::new_literal(v, true);
693 assert!(bdd.not().not().structural_eq(&bdd));
694 }
695 };
696 }
697
698 test_bdd_not_invariants!(bdd16_not_invariants, Bdd16, VarIdPacked16);
699 test_bdd_not_invariants!(bdd32_not_invariants, Bdd32, VarIdPacked32);
700 test_bdd_not_invariants!(bdd64_not_invariants, Bdd64, VarIdPacked64);
701
702 macro_rules! test_bdd_invariants {
703 ($func:ident, $Bdd:ident, $VarId:ident, $NodeId:ident) => {
704 #[test]
705 pub fn $func() {
706 assert!($Bdd::new_true().root().is_one());
707 assert!($Bdd::new_true().is_true());
708 assert!($Bdd::new_false().root().is_zero());
709 assert!($Bdd::new_false().is_false());
710
711 let v = $VarId::new(1);
712 let x = $Bdd::new_literal(v, true);
713 assert!(!x.root().is_terminal());
714 assert!(x.get($NodeId::new(3)).is_none());
715 assert_eq!(v, x.get(x.root()).unwrap().variable());
716 assert_eq!(x.node_count(), 3);
717 unsafe {
718 assert_eq!(v, x.get_node_unchecked(x.root()).variable());
719 let x_p = $Bdd::new_unchecked(x.root(), x.nodes.clone());
720 assert!(x.structural_eq(&x_p));
721 }
722 }
723 };
724 }
725
726 test_bdd_invariants!(bdd16_invariants, Bdd16, VarIdPacked16, NodeId16);
727 test_bdd_invariants!(bdd32_invariants, Bdd32, VarIdPacked32, NodeId32);
728 test_bdd_invariants!(bdd64_invariants, Bdd64, VarIdPacked64, NodeId64);
729
730 #[test]
731 fn bdd_expands_to_32_and_shrinks_to_16() {
732 let n: u16 = 16;
733 let low_vars: Vec<_> = (1..n).map(VariableId::from).collect();
738 let high_vars: Vec<_> = (n + 1..2 * n).map(VariableId::from).collect();
739
740 let mut bdd = Bdd::new_false();
741 let mut bdd32 = Bdd32::new_false();
742
743 for i in 0..high_vars.len() {
744 let prod =
745 Bdd::new_literal(low_vars[i], true).and(&Bdd::new_literal(high_vars[i], true));
746
747 let prod32 = Bdd32::new_literal(low_vars[i].unchecked_into(), true)
748 .and(&Bdd32::new_literal(high_vars[i].unchecked_into(), true))
749 .unwrap();
750
751 bdd = bdd.or(&prod);
752 bdd32 = bdd32.or(&prod32).unwrap();
753 }
754
755 assert_eq!(bdd.node_count(), 1 << n);
756 assert_eq!(bdd32.node_count(), 1 << n);
757
758 match &bdd.0 {
760 BddInner::Size32(b) => {
761 assert!(b.iff(&bdd32).unwrap().is_true());
763 assert!(b.structural_eq(&bdd32));
764 }
765 _ => panic!("expected 32-bit BDD"),
766 }
767
768 let mut bdd16_ands = Bdd16::new_true();
773
774 for i in 0..high_vars.len() {
775 let prod =
776 Bdd::new_literal(low_vars[i], true).and(&Bdd::new_literal(high_vars[i], true));
777
778 let prod16 = Bdd16::new_literal(low_vars[i].unchecked_into(), true)
779 .and(&Bdd16::new_literal(high_vars[i].unchecked_into(), true))
780 .unwrap();
781
782 bdd = bdd.and(&prod);
783 bdd16_ands = bdd16_ands.and(&prod16).unwrap();
784 }
785
786 assert_eq!(bdd.node_count(), usize::from(2 * n));
787
788 match &bdd.0 {
790 BddInner::Size16(b) => {
791 assert!(b.iff(&bdd16_ands).unwrap().is_true());
792 assert!(b.structural_eq(&bdd16_ands));
793 }
794 _ => panic!("expected 16-bit BDD"),
795 }
796 }
797
798 #[test]
803 fn bdd_64_shrink_to_32() {
804 let n = 17;
805 let low_vars: Vec<_> = (1..n).map(VarIdPacked64::new).collect();
806 let high_vars: Vec<_> = (n + 1..2 * n).map(VarIdPacked64::new).collect();
807
808 let mut bdd64 = Bdd64::new_false();
809 let mut bdd32 = Bdd32::new_false();
810
811 for i in 0..high_vars.len() {
812 let prod = Bdd64::new_literal(low_vars[i], true)
813 .and(&Bdd64::new_literal(high_vars[i], true))
814 .unwrap();
815
816 let prod32 = Bdd32::new_literal(low_vars[i].try_into().unwrap(), true)
817 .and(&Bdd32::new_literal(high_vars[i].try_into().unwrap(), true))
818 .unwrap();
819
820 bdd64 = bdd64.or(&prod).unwrap();
821 bdd32 = bdd32.or(&prod32).unwrap();
822 }
823
824 assert_eq!(bdd64.node_count(), 1 << n);
825
826 let bdd = Into::<Bdd>::into(bdd64).shrink();
827
828 assert_eq!(bdd.node_count(), 1 << n);
829
830 match &bdd.0 {
831 BddInner::Size32(b) => {
832 assert!(b.iff(&bdd32).unwrap().is_true());
833 assert!(b.structural_eq(&bdd32));
834 }
835 _ => panic!("expected 32-bit BDD"),
836 }
837 }
838
839 #[test]
843 fn bdd_64_shrink_to_16() {
844 let n = 4;
845 let low_vars: Vec<_> = (1..n).map(VarIdPacked64::new).collect();
846 let high_vars: Vec<_> = (n + 1..2 * n).map(VarIdPacked64::new).collect();
847
848 let mut bdd16 = Bdd16::new_false();
849 let mut bdd64 = Bdd64::new_false();
850
851 for i in 0..high_vars.len() {
852 let prod = Bdd64::new_literal(low_vars[i], true)
853 .and(&Bdd64::new_literal(high_vars[i], true))
854 .unwrap();
855
856 let prod16 = Bdd16::new_literal(low_vars[i].try_into().unwrap(), true)
857 .and(&Bdd16::new_literal(high_vars[i].try_into().unwrap(), true))
858 .unwrap();
859
860 bdd64 = bdd64.or(&prod).unwrap();
861 bdd16 = bdd16.or(&prod16).unwrap();
862 }
863
864 assert_eq!(bdd64.node_count(), 1 << n);
865
866 let bdd = Into::<Bdd>::into(bdd64).shrink();
867
868 assert_eq!(bdd.node_count(), 1 << n);
869
870 match &bdd.0 {
871 BddInner::Size16(b) => {
872 assert!(b.iff(&bdd16).unwrap().is_true());
873 assert!(b.structural_eq(&bdd16));
874 }
875 _ => panic!("expected 16-bit BDD"),
876 }
877 }
878
879 #[test]
880 fn new_bdd_literal_16() {
881 let var = VariableId::from(1u32);
882 let bdd = Bdd::new_literal(var, true);
883 let bdd16 = Bdd16::new_literal(var.unchecked_into(), true);
884
885 match &bdd.0 {
886 BddInner::Size16(b) => {
887 assert!(b.iff(&bdd16).unwrap().is_true());
888 assert!(b.structural_eq(&bdd16));
889 }
890 _ => panic!("expected 16-bit BDD"),
891 }
892 }
893
894 #[test]
895 fn new_bdd_literal_32() {
896 let max_id: u32 = VariableId::MAX_16_BIT_ID.try_into().unwrap();
897 let var = VariableId::from(max_id + 1);
898 let bdd = Bdd::new_literal(var, true);
899 let bdd32 = Bdd32::new_literal(var.unchecked_into(), true);
900
901 match &bdd.0 {
902 BddInner::Size32(b) => {
903 assert!(b.iff(&bdd32).unwrap().is_true());
904 assert!(b.structural_eq(&bdd32));
905 }
906 _ => panic!("expected 32-bit BDD"),
907 }
908 }
909
910 #[test]
911 fn new_bdd_literal_64() {
912 let var = VariableId::new_long(VariableId::MAX_32_BIT_ID + 1).unwrap();
913 let bdd = Bdd::new_literal(var, true);
914 let bdd64 = Bdd64::new_literal(var.unchecked_into(), true);
915
916 match &bdd.0 {
917 BddInner::Size64(b) => {
918 assert!(b.iff(&bdd64).unwrap().is_true());
919 assert!(b.structural_eq(&bdd64));
920 }
921 _ => panic!("expected 64-bit BDD"),
922 }
923 }
924
925 #[test]
926 fn new_bdd_literal_64_but_should_be_16() {
927 let var = VariableId::from(1u32);
928 let bdd = Bdd::new_literal(var, true);
929 let bdd16 = Bdd16::new_literal(var.unchecked_into(), true);
930
931 match &bdd.0 {
932 BddInner::Size16(b) => {
933 assert!(b.iff(&bdd16).unwrap().is_true());
934 assert!(b.structural_eq(&bdd16));
935 }
936 _ => panic!("expected 16-bit BDD"),
937 }
938 }
939
940 #[test]
941 fn new_bdd_literal_32_but_should_be_16() {
942 let var = VariableId::from(1u32);
943 let bdd = Bdd::new_literal(var, true);
944 let bdd16 = Bdd16::new_literal(var.unchecked_into(), true);
945
946 match &bdd.0 {
947 BddInner::Size16(b) => {
948 assert!(b.iff(&bdd16).unwrap().is_true());
949 assert!(b.structural_eq(&bdd16));
950 }
951 _ => panic!("expected 16-bit BDD"),
952 }
953 }
954
955 #[test]
956 fn new_bdd_literal_64_but_should_be_32() {
957 let var = VariableId::new_long(VariableId::MAX_16_BIT_ID + 1).unwrap();
958 let bdd = Bdd::new_literal(var, true);
959 let bdd32 = Bdd32::new_literal(var.unchecked_into(), true);
960
961 match &bdd.0 {
962 BddInner::Size32(b) => {
963 assert!(b.iff(&bdd32).unwrap().is_true());
964 assert!(b.structural_eq(&bdd32));
965 }
966 _ => panic!("expected 32-bit BDD"),
967 }
968 }
969
970 #[test]
971 fn bdd_node_count() {
972 let bdd16 = Bdd::new_literal(VariableId::new(1u32 << 8), true);
973 let bdd32 = Bdd::new_literal(VariableId::new(1u32 << 24), true);
974 let bdd64 = Bdd::new_literal(VariableId::new_long(1u64 << 48).unwrap(), true);
975
976 assert_eq!(bdd16.node_count(), 3);
977 assert_eq!(bdd32.node_count(), 3);
978 assert_eq!(bdd64.node_count(), 3);
979 }
980
981 #[test]
982 fn bdd_simple_not() {
983 let bdd16_1 = Bdd::new_literal(VariableId::new(1u32 << 8), true);
984 let bdd32_1 = Bdd::new_literal(VariableId::new(1u32 << 24), true);
985 let bdd64_1 = Bdd::new_literal(VariableId::new_long(1u64 << 48).unwrap(), true);
986
987 let bdd16_0 = Bdd::new_literal(VariableId::new(1u32 << 8), false);
988 let bdd32_0 = Bdd::new_literal(VariableId::new(1u32 << 24), false);
989 let bdd64_0 = Bdd::new_literal(VariableId::new_long(1u64 << 48).unwrap(), false);
990
991 assert!(bdd16_1.not().structural_eq(&bdd16_0));
992 assert!(bdd32_1.not().structural_eq(&bdd32_0));
993 assert!(bdd64_1.not().structural_eq(&bdd64_0));
994 }
995
996 #[test]
997 fn bdd_structural_eq() {
998 let bdd16: Bdd = Bdd16::new_literal(VarIdPacked16::new(1234), true).into();
1000 let bdd32: Bdd = Bdd32::new_literal(VarIdPacked32::new(1234), true).into();
1001 assert!(!bdd16.structural_eq(&bdd32));
1002 }
1003
1004 #[test]
1005 fn bdd_cannot_shrink() {
1006 let bdd64 = Bdd::new_literal(VariableId::new_long(1u64 << 48).unwrap(), true);
1007 assert!(bdd64.clone().shrink().structural_eq(&bdd64));
1008 }
1009
1010 #[test]
1011 fn bdd_constants() {
1012 let bdd_true = Bdd::new_true();
1013 let bdd_false = Bdd::new_false();
1014 assert!(bdd_true.is_true() && !bdd_true.is_false());
1015 assert!(bdd_false.is_false() && !bdd_false.is_true());
1016
1017 let true_32: Bdd = Bdd32::new_true().into();
1021 let false_32: Bdd = Bdd32::new_false().into();
1022 assert!(true_32.is_true() && !true_32.is_false());
1023 assert!(false_32.is_false() && !false_32.is_true());
1024
1025 let true_64: Bdd = Bdd64::new_true().into();
1026 let false_64: Bdd = Bdd64::new_false().into();
1027 assert!(true_64.is_true() && !true_64.is_false());
1028 assert!(false_64.is_false() && !false_64.is_true());
1029 }
1030
1031 #[test]
1032 fn bdd_getters() {
1033 let var16 = VariableId::new(1u32 << 8);
1034 let var32 = VariableId::new(1u32 << 24);
1035 let var64 = VariableId::new_long(1u64 << 48).unwrap();
1036 let bdd16 = Bdd::new_literal(var16, true);
1037 let bdd32 = Bdd::new_literal(var32, true);
1038 let bdd64 = Bdd::new_literal(var64, true);
1039 let zero = NodeId::zero();
1040 let one = NodeId::one();
1041
1042 assert_eq!(bdd16.get_variable(bdd16.root()), var16);
1043 assert_eq!(bdd32.get_variable(bdd32.root()), var32);
1044 assert_eq!(bdd64.get_variable(bdd64.root()), var64);
1045
1046 assert_eq!(bdd16.get_links(bdd16.root()), (zero, one));
1047 assert_eq!(bdd32.get_links(bdd32.root()), (zero, one));
1048 assert_eq!(bdd64.get_links(bdd64.root()), (zero, one));
1049 }
1050
1051 #[allow(clippy::cast_possible_truncation)]
1052 pub(crate) fn queens(n: usize) -> Bdd {
1053 fn mk_negative_literals(n: usize) -> Vec<Bdd> {
1054 let mut bdd_literals = Vec::with_capacity(n * n);
1055 for i in 0..n {
1056 for j in 0..n {
1057 let literal = Bdd::new_literal(((i * n + j) as u32).into(), false);
1058 bdd_literals.push(literal);
1059 }
1060 }
1061 bdd_literals
1062 }
1063
1064 fn one_queen(n: usize, i: usize, j: usize, negative: &[Bdd]) -> Bdd {
1065 let mut s = Bdd::new_literal(((i * n + j) as u32).into(), true);
1066
1067 for k in 0..n {
1069 if k != j {
1070 s = s.and(&negative[i * n + k]);
1071 }
1072 }
1073
1074 for k in 0..n {
1076 if k != i {
1077 s = s.and(&negative[k * n + j]);
1078 }
1079 }
1080
1081 for row in 0..n {
1084 if let Some(col) = (row + j).checked_sub(i) {
1085 if col < n && row != i {
1086 s = s.and(&negative[row * n + col]);
1087 }
1088 }
1089 }
1090
1091 for row in 0..n {
1094 if let Some(col) = (i + j).checked_sub(row) {
1095 if col < n && row != i {
1096 s = s.and(&negative[row * n + col]);
1097 }
1098 }
1099 }
1100
1101 s
1102 }
1103
1104 fn queen_in_row(n: usize, row: usize, negative: &[Bdd]) -> Bdd {
1105 let mut r = Bdd::new_false();
1106 for col in 0..n {
1107 let one_queen = one_queen(n, row, col, negative);
1108 r = r.or(&one_queen);
1109 }
1110 r
1111 }
1112
1113 let negative = mk_negative_literals(n);
1114 let mut result = Bdd::new_true();
1115 for row in 0..n {
1116 let in_row = queen_in_row(n, row, &negative);
1117 result = result.and(&in_row);
1118 }
1119 result
1120 }
1121
1122 #[test]
1123 fn count_sat_valuations() {
1124 assert_eq!(Bdd::new_false().count_satisfying_valuations(None), 0.0,);
1125
1126 assert_eq!(Bdd::new_true().count_satisfying_valuations(None), 1.0,);
1127
1128 assert_eq!(
1129 Bdd::new_true().count_satisfying_valuations(Some(VariableId::new(0))),
1130 2.0,
1131 );
1132
1133 assert_eq!(
1134 Bdd::new_literal(VariableId::new(0u32), true)
1135 .count_satisfying_valuations(Some(VariableId::new(0u32))),
1136 1.0,
1137 );
1138
1139 assert_eq!(
1140 Bdd::new_literal(VariableId::new(0u32), true).count_satisfying_valuations(None),
1141 1.0,
1142 );
1143
1144 assert_eq!(
1145 Bdd::new_literal(VariableId::new(0u32), false).count_satisfying_valuations(None),
1146 1.0,
1147 );
1148
1149 assert_eq!(
1150 Bdd::new_literal(VariableId::new(0u32), false)
1151 .count_satisfying_valuations(Some(VariableId::new(2u32))),
1152 4.0,
1153 );
1154
1155 let bdd6 = queens(6);
1156 let bdd8 = queens(9);
1157
1158 assert_eq!(bdd6.count_satisfying_valuations(None), 4.0);
1159 assert_eq!(bdd8.count_satisfying_valuations(None), 352.0);
1160
1161 let or3 = Bdd::new_literal(VariableId::new(0u32), true)
1162 .or(&Bdd::new_literal(VariableId::new(1u32), true))
1163 .or(&Bdd::new_literal(VariableId::new(3u32), true));
1164
1165 let and3 = Bdd::new_literal(VariableId::new(0u32), true)
1166 .and(&Bdd::new_literal(VariableId::new(1u32), true))
1167 .and(&Bdd::new_literal(VariableId::new(3u32), true));
1168
1169 assert_eq!(or3.count_satisfying_valuations(None), 14.0);
1170 assert_eq!(and3.count_satisfying_valuations(None), 2.0);
1171 }
1172
1173 #[test]
1174 fn count_sat_paths() {
1175 assert_eq!(Bdd::new_false().count_satisfying_paths(), 0.0,);
1176 assert_eq!(Bdd::new_true().count_satisfying_paths(), 1.0,);
1177
1178 assert_eq!(
1179 Bdd::new_literal(VariableId::new(0u32), true).count_satisfying_paths(),
1180 1.0,
1181 );
1182
1183 assert_eq!(
1184 Bdd::new_literal(VariableId::new(0u32), false).count_satisfying_paths(),
1185 1.0,
1186 );
1187
1188 let bdd4 = queens(6);
1189 let bdd8 = queens(9);
1190
1191 assert_eq!(bdd4.count_satisfying_paths(), 4.0);
1192 assert_eq!(bdd8.count_satisfying_paths(), 352.0);
1193
1194 let or3 = Bdd::new_literal(VariableId::new(0u32), true)
1195 .or(&Bdd::new_literal(VariableId::new(1u32), true))
1196 .or(&Bdd::new_literal(VariableId::new(3u32), true));
1197
1198 let and3 = Bdd::new_literal(VariableId::new(0u32), true)
1199 .and(&Bdd::new_literal(VariableId::new(1u32), true))
1200 .and(&Bdd::new_literal(VariableId::new(3u32), true));
1201
1202 assert_eq!(or3.count_satisfying_paths(), 3.0);
1203 assert_eq!(and3.count_satisfying_paths(), 1.0);
1204 }
1205
1206 #[test]
1207 fn bdd_to_dot() {
1208 let v_1 = VariableId::new(1);
1209 let v_4 = VariableId::new(4);
1210
1211 let bdd = Bdd::new_literal(v_1, true).xor(&Bdd::new_literal(v_4, true));
1212
1213 let result = bdd.to_dot_string();
1214
1215 let expected = r#"digraph BDD {
1216 __ruddy_root [label="", style=invis, height=0, width=0];
1217 __ruddy_root -> 4;
1218
1219 edge [dir=none];
1220
1221 0 [label="0", shape=box, width=0.3, height=0.3];
1222 1 [label="1", shape=box, width=0.3, height=0.3];
1223 2 [label="4", shape=box, width=0.3, height=0.3];
1224 2 -> 0 [style=dashed];
1225 2 -> 1;
1226 3 [label="4", shape=box, width=0.3, height=0.3];
1227 3 -> 1 [style=dashed];
1228 3 -> 0;
1229 4 [label="1", shape=box, width=0.3, height=0.3];
1230 4 -> 2 [style=dashed];
1231 4 -> 3;
1232}
1233"#;
1234
1235 assert_eq!(result, expected);
1236 }
1237}