use fnv::FnvHashMap;
use smallvec::{smallvec, SmallVec};
use crate::{
network::{EdgeWithInversion, Network},
traits::{
BooleanFunction, BooleanSystem, LogicValue, NumInputs, NumOutputs, PartialBooleanSystem,
},
};
pub struct RecursiveSim<'a, N> {
network: &'a N,
}
impl<'a, N> RecursiveSim<'a, N> {
pub fn new(network: &'a N) -> Self {
Self { network }
}
}
impl<'a, N> RecursiveSim<'a, N>
where
N: Network<LogicValue = bool>,
N::Signal: EdgeWithInversion,
{
pub fn simulate(
&self,
outputs: &'a [N::Signal],
inputs: &[N::LogicValue],
) -> impl Iterator<Item = N::LogicValue> + 'a {
assert_eq!(
self.network.num_primary_inputs(),
inputs.len(),
"input value vector must match the number of primary inputs"
);
let mut cache: FnvHashMap<N::Signal, N::LogicValue> = Default::default();
let mut stack = outputs.to_vec();
let net = self.network;
cache.extend(
(0..net.num_primary_inputs())
.map(|i| net.get_primary_input(i).non_inverted())
.zip(inputs.iter().copied()),
);
while let Some(signal) = stack.pop() {
let node = net.get_source_node(&signal);
if cache.contains_key(&signal.non_inverted()) {
continue;
} else {
let operands =
(0..net.num_node_inputs(&node)).map(|i| net.get_node_input(&node, i));
let mut buf: SmallVec<[N::LogicValue; 16]> = smallvec![];
let mut values_complete = true;
for in_sig in operands {
if let Some(value) = net.get_constant_value(in_sig) {
buf.push(value);
} else if let Some(value) = cache.get(&in_sig.non_inverted()) {
let v = *value ^ in_sig.is_inverted();
buf.push(v);
} else {
buf.push(N::LogicValue::zero());
debug_assert!(
!net.is_input(in_sig),
"primary inputs must be added to the cache already"
);
if values_complete {
stack.push(signal);
}
values_complete = false;
stack.push(in_sig);
}
}
if values_complete {
let node = net.get_source_node(&signal);
let operator = net.node_function(node);
let value = operator.eval(&buf);
cache.insert(signal.non_inverted(), value);
}
}
}
outputs
.iter()
.map(move |o| cache[&o.non_inverted()] ^ o.is_inverted())
}
}
impl<'a, N: Network> NumInputs for RecursiveSim<'a, N> {
fn num_inputs(&self) -> usize {
self.network.num_primary_inputs()
}
}
impl<'a, N: Network> NumOutputs for RecursiveSim<'a, N> {
fn num_outputs(&self) -> usize {
self.network.num_primary_outputs()
}
}
impl<'a, N> PartialBooleanSystem for RecursiveSim<'a, N>
where
N: Network<LogicValue = bool>,
N::Signal: EdgeWithInversion + Ord,
{
type LiteralId = usize;
type TermId = N::Signal;
fn evaluate_term_partial(&self, term: &Self::TermId, input_values: &[bool]) -> Option<bool> {
Some(self.evaluate_term(term, input_values))
}
}
impl<'a, N> BooleanSystem for RecursiveSim<'a, N>
where
N: Network<LogicValue = bool>,
N::Signal: EdgeWithInversion + Ord,
{
fn evaluate_term(&self, term: &Self::TermId, input_values: &[bool]) -> bool {
self.simulate(&[*term], input_values).next().unwrap()
}
}
#[test]
fn test_recursive_simulator() {
use crate::network::*;
use crate::networks::mig::*;
let mut mig = Mig::new();
let [a, b, c, d] = mig.create_primary_inputs();
let maj = mig.create_maj3(a, b, c);
let maj_or_d = mig.create_or(maj, d);
mig.create_primary_output(maj);
mig.create_primary_output(maj_or_d);
let simulator = RecursiveSim::new(&mig);
let output_values: Vec<_> = simulator
.simulate(&[maj, maj_or_d], &[true, false, false, true])
.collect();
assert_eq!(output_values, vec![false, true]);
let output_values: Vec<_> = simulator
.simulate(&[maj, maj_or_d], &[true, true, false, false])
.collect();
assert_eq!(output_values, vec![true, true]);
}