use std::collections::HashSet;
use crate::{Aig, AigNodeRef, NodeId};
pub struct Dfs {
stack: Vec<NodeId>,
seen: HashSet<NodeId>,
starts: Vec<NodeId>,
}
impl Dfs {
pub fn from_node(start: AigNodeRef) -> Self {
let start_id = start.borrow().get_id();
Dfs {
stack: vec![start_id],
seen: HashSet::from([start_id]),
starts: Vec::new(),
}
}
pub fn from_outputs(aig: &Aig) -> Self {
let mut ids: Vec<NodeId> = aig
.get_outputs()
.iter()
.map(|fanin| fanin.node.borrow().get_id())
.collect();
if let Some(start_id) = ids.pop() {
let stack = vec![start_id];
let seen = HashSet::from([start_id]);
Dfs {
stack,
seen,
starts: ids,
}
} else {
Dfs {
stack: Vec::new(),
seen: HashSet::new(),
starts: Vec::new(),
}
}
}
fn new_start(&mut self) -> bool {
assert!(self.stack.is_empty());
while let Some(id) = self.starts.pop() {
if !self.seen.contains(&id) {
self.seen.insert(id);
self.stack.push(id);
return true;
}
}
false
}
pub fn next(&mut self, aig: &Aig) -> Option<AigNodeRef> {
while let Some(id) = self.stack.pop() {
let node = aig.get_node(id).unwrap();
for child in node.borrow().get_fanins() {
let child_id = child.get_node().borrow().get_id();
if !self.seen.contains(&child_id) {
self.seen.insert(child_id);
self.stack.push(child_id);
}
}
return Some(node);
}
if self.new_start() {
return self.next(aig);
}
None
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{Aig, AigEdge, AigNode};
#[test]
fn from_node_test() {
let mut aig = Aig::new();
let n0 = aig.add_node(AigNode::False).unwrap();
let n1 = aig.add_node(AigNode::Input(1)).unwrap();
let n2 = aig
.add_node(AigNode::and(
2,
AigEdge::new(n0.clone(), false),
AigEdge::new(n1.clone(), false),
))
.unwrap();
let mut dfs = Dfs::from_node(n2.clone());
assert_eq!(dfs.next(&aig).unwrap(), n2.clone()); let n = dfs.next(&aig).unwrap(); if n == n0.clone() {
assert_eq!(dfs.next(&aig).unwrap(), n1.clone());
} else if n == n1.clone() {
assert_eq!(dfs.next(&aig).unwrap(), n0.clone());
} else {
panic!("Test failed.");
}
assert!(dfs.next(&aig).is_none());
assert!(dfs.next(&aig).is_none());
assert!(dfs.next(&aig).is_none());
}
#[test]
fn from_outputs_test() {
let mut aig = Aig::new();
let n0 = aig.add_node(AigNode::False).unwrap();
let n1 = aig.add_node(AigNode::Input(1)).unwrap();
let n2 = aig
.add_node(AigNode::and(
2,
AigEdge::new(n0.clone(), false),
AigEdge::new(n1.clone(), false),
))
.unwrap();
let n3 = aig.add_node(AigNode::Input(3)).unwrap();
let n4 = aig
.add_node(AigNode::and(
4,
AigEdge::new(n2.clone(), false),
AigEdge::new(n3.clone(), false),
))
.unwrap();
aig.add_output(2, false).unwrap();
aig.add_output(4, true).unwrap();
let mut dfs = Dfs::from_outputs(&aig);
let n = dfs.next(&aig).unwrap();
if n == n2.clone() {
let n = dfs.next(&aig).unwrap();
if n == n0.clone() {
assert_eq!(dfs.next(&aig).unwrap(), n1.clone());
} else if n == n1.clone() {
assert_eq!(dfs.next(&aig).unwrap(), n0.clone());
} else {
panic!("Test failed.");
}
assert_eq!(dfs.next(&aig).unwrap(), n4.clone());
assert_eq!(dfs.next(&aig).unwrap(), n3.clone());
}
else if n == n4.clone() {
let n = dfs.next(&aig).unwrap();
if n == n2.clone() {
let n = dfs.next(&aig).unwrap();
if n == n0.clone() {
assert_eq!(dfs.next(&aig).unwrap(), n1.clone());
} else if n == n1.clone() {
assert_eq!(dfs.next(&aig).unwrap(), n0.clone());
} else {
panic!("Test failed.");
}
assert_eq!(dfs.next(&aig).unwrap(), n3.clone());
}
else if n == n3.clone() {
assert_eq!(dfs.next(&aig).unwrap(), n2.clone());
let n = dfs.next(&aig).unwrap();
if n == n0.clone() {
assert_eq!(dfs.next(&aig).unwrap(), n1.clone());
} else if n == n1.clone() {
assert_eq!(dfs.next(&aig).unwrap(), n0.clone());
} else {
panic!("Test failed.");
}
} else {
panic!("Test failed.");
}
} else {
panic!("Test failed.")
}
assert!(dfs.next(&aig).is_none());
assert!(dfs.next(&aig).is_none());
assert!(dfs.next(&aig).is_none());
}
#[test]
fn repeated_node() {
let mut aig = Aig::new();
let n0 = aig.add_node(AigNode::Input(1)).unwrap();
let n1 = aig.add_node(AigNode::Input(1)).unwrap();
let n2 = aig
.add_node(AigNode::and(
2,
AigEdge::new(n0.clone(), false),
AigEdge::new(n1.clone(), true),
))
.unwrap();
let mut dfs = Dfs::from_node(n2.clone());
assert_eq!(dfs.next(&aig).unwrap(), n2.clone());
assert_eq!(dfs.next(&aig).unwrap(), n1.clone());
assert!(dfs.next(&aig).is_none());
}
}