#![allow(unused)]
use std::{cmp::Ordering, hash::Hash};
use crate::algorithms::visit::TopologicalIter;
use crate::network::Network;
use crate::network::NetworkShortcuts;
use fnv::FnvHashMap;
use itertools::Itertools;
use smallvec::{smallvec, SmallVec};
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct Cut<NodeId> {
root_node: NodeId,
leaf_nodes: SmallVec<[NodeId; 16]>,
}
impl<NodeId> Cut<NodeId>
where
NodeId: Clone + Ord,
{
fn trivial_cut(node: NodeId) -> Self {
Self {
root_node: node.clone(),
leaf_nodes: smallvec![node],
}
}
fn new(node: NodeId, mut leaf_nodes: SmallVec<[NodeId; 16]>) -> Self {
leaf_nodes.sort();
Self {
root_node: node,
leaf_nodes,
}
}
}
fn cut_union<'a, NodeId: 'a>(
root: NodeId,
cuts: impl Iterator<Item = &'a Cut<NodeId>>,
) -> Cut<NodeId>
where
NodeId: Clone + Ord + Eq,
{
let leaf_nodes_union = cuts
.map(|cut| cut.leaf_nodes.iter().cloned())
.kmerge()
.dedup()
.collect();
Cut {
root_node: root,
leaf_nodes: leaf_nodes_union,
}
}
#[test]
fn test_cut_onion() {
let a = Cut::new("root_a", smallvec!["w", "x", "z"]);
let b = Cut::new("root_b", smallvec!["x", "y", "z"]);
let u = cut_union("root_u", [a, b].iter());
assert_eq!(u, Cut::new("root_u", smallvec!["w", "x", "y", "z"]));
}
#[derive(Clone, Copy, Debug)]
struct CutEnumerationConfig<F> {
max_cut_size: usize,
max_cuts_per_node: usize,
sort_cuts_by_fn: F,
}
#[derive(Clone, Debug)]
struct CutEnumeration<NodeId> {
cuts: FnvHashMap<NodeId, Vec<Cut<NodeId>>>,
}
impl<NodeId> CutEnumeration<NodeId>
where
NodeId: Hash + Eq,
{
pub fn get_cuts(&self, node: &NodeId) -> &Vec<Cut<NodeId>> {
&self.cuts[node]
}
}
impl<F> CutEnumerationConfig<F> {
fn compute_cuts<N>(&self, network: &N) -> CutEnumeration<N::NodeId>
where
N: Network,
N::NodeId: Ord,
F: Fn(&Cut<N::NodeId>, &Cut<N::NodeId>) -> Ordering,
{
let topo_sorted: Vec<_> = {
let top_nodes = network
.primary_outputs()
.map(|signal| network.get_source_node(&signal))
.collect();
let sorted: Vec<_> = TopologicalIter::new(network, top_nodes)
.visit_primary_inputs(true)
.visit_constants(true)
.collect();
sorted
};
let mut cuts: FnvHashMap<N::NodeId, Vec<Cut<N::NodeId>>> = Default::default();
cuts.reserve(topo_sorted.len());
for node in &topo_sorted {
let signal = network.get_node_output(node);
let mut current_cuts = if network.is_input(signal) || network.is_constant(signal) {
vec![Cut::trivial_cut(node.clone())]
} else {
let child_nodes = (0..network.num_node_inputs(node))
.map(|i| network.get_node_input(node, i))
.map(|input_signal| network.get_source_node(&input_signal));
let child_cuts: SmallVec<[&Vec<Cut<_>>; 16]> =
child_nodes.map(|child_node| &cuts[&child_node]).collect();
let cut_unions: Vec<_> = child_cuts
.into_iter()
.multi_cartesian_product()
.map(|selected_cuts| cut_union(node.clone(), selected_cuts.into_iter()))
.chain([Cut::trivial_cut(node.clone())])
.filter(|cut| cut.leaf_nodes.len() <= self.max_cut_size)
.collect();
cut_unions
};
current_cuts.sort_by(|c1, c2| (self.sort_cuts_by_fn)(c1, c2));
current_cuts.truncate(self.max_cuts_per_node);
cuts.insert(node.clone(), current_cuts);
}
CutEnumeration { cuts }
}
}
#[test]
fn test_cut_enumeration() {
use crate::network::*;
use crate::networks::aig::*;
let config = CutEnumerationConfig {
max_cut_size: 100,
max_cuts_per_node: 100,
sort_cuts_by_fn: |_a: &Cut<AigNodeId>, _b: &Cut<AigNodeId>| -> Ordering { Ordering::Equal }, };
let mut net = Aig::new();
let [a, b, c, d] = net.create_primary_inputs();
let anb = net.create_and(a, b);
let cnd = net.create_and(c, d);
let top = net.create_and(anb, cnd);
let _out = net.create_primary_output(top);
let cuts = config.compute_cuts(&net);
assert_eq!(cuts.get_cuts(&a).len(), 1);
assert_eq!(cuts.get_cuts(&b).len(), 1);
assert_eq!(cuts.get_cuts(&c).len(), 1);
assert_eq!(cuts.get_cuts(&d).len(), 1);
assert_eq!(cuts.get_cuts(&anb).len(), 2);
assert_eq!(cuts.get_cuts(&cnd).len(), 2);
assert_eq!(cuts.get_cuts(&top).len(), 5);
}