use std::cmp::Reverse;
use std::collections::BinaryHeap;
use crate::network::stats;
use crate::Network;
use super::simple_sim::SimpleSimulator;
use super::Fault;
pub struct IncrementalSimulator<'a> {
is_output: Vec<bool>,
gate_users: Vec<Vec<usize>>,
sim: SimpleSimulator<'a>,
incr_sim: SimpleSimulator<'a>,
update_queue: BinaryHeap<Reverse<usize>>,
touched_gates: Vec<usize>,
is_touched: Vec<bool>,
}
impl<'a> IncrementalSimulator<'a> {
pub fn from_aig(aig: &'a Network) -> IncrementalSimulator<'a> {
assert!(aig.is_topo_sorted());
let sim = SimpleSimulator::from_aig(aig);
let incr_sim = sim.clone();
IncrementalSimulator {
is_output: stats::gate_is_output(aig),
gate_users: stats::gate_users(aig),
sim,
incr_sim,
update_queue: BinaryHeap::new(),
touched_gates: Vec::new(),
is_touched: vec![false; aig.nb_nodes()],
}
}
fn reset(&mut self) {
for v in &self.touched_gates {
self.incr_sim.node_values[*v] = self.sim.node_values[*v];
self.is_touched[*v] = false;
}
assert!(self.update_queue.is_empty());
self.touched_gates.clear();
}
pub fn run_initial(&mut self, input_values: &Vec<u64>) {
self.sim.reset();
self.sim.copy_inputs(input_values);
self.sim.run_comb();
self.incr_sim = self.sim.clone();
}
fn update_gate(&mut self, i: usize, value: u64) {
let old_val = self.incr_sim.node_values[i];
if old_val == value {
return;
}
if !self.is_touched[i] {
self.is_touched[i] = true;
self.touched_gates.push(i);
}
self.incr_sim.node_values[i] = value;
for &j in &self.gate_users[i] {
if !self.is_touched[j] {
self.is_touched[j] = true;
self.update_queue.push(Reverse(j));
self.touched_gates.push(j);
}
}
}
fn run_incremental(&mut self, fault: Fault) {
match fault {
Fault::OutputStuckAtFault { gate, value } => {
self.update_gate(gate, if value { !0 } else { 0 });
}
Fault::InputStuckAtFault { gate, input, value } => {
let value = self.incr_sim.run_gate_with_input_stuck(gate, input, value);
self.update_gate(gate, value);
}
}
while let Some(Reverse(i)) = self.update_queue.pop() {
let v = self.incr_sim.run_gate(i);
self.update_gate(i, v);
}
}
fn output_modified(&self) -> u64 {
let mut ret = 0;
for i in &self.touched_gates {
if self.is_output[*i] {
ret |= self.incr_sim.node_values[*i] ^ self.sim.node_values[*i];
}
}
ret
}
pub fn detects_fault(&mut self, fault: Fault) -> u64 {
self.run_incremental(fault);
let ret = self.output_modified();
self.reset();
ret
}
}