use std::iter::zip;
use crate::{Gate, Network, Signal};
pub struct Matcher<'a> {
matches: Vec<Signal>,
pattern: &'a Network,
}
impl<'a> Matcher<'a> {
pub fn from_pattern(pattern: &Network) -> Matcher {
let matches = vec![Signal::placeholder(); pattern.nb_inputs() + pattern.nb_nodes()];
assert!(pattern.nb_outputs() == 1);
assert!(!pattern.output(0).is_inverted());
assert!(!pattern.nb_nodes() >= 1);
Matcher { matches, pattern }
}
pub fn matches(&mut self, aig: &Network, i: usize) -> Option<Vec<Signal>> {
let matched = self.try_match(self.pattern.output(0), aig, Signal::from_var(i as u32));
let ret = if matched {
let v = (0..self.pattern.nb_inputs())
.map(|i| self.get_match(Signal::from_input(i as u32)))
.collect();
Some(v)
} else {
None
};
self.reset();
ret
}
fn try_match(&mut self, repr: Signal, aig: &Network, s: Signal) -> bool {
let existing_match = self.get_match(repr);
if existing_match != Signal::placeholder() {
return existing_match == s;
}
self.set_match(repr, s);
if repr.is_var() {
if !s.is_var() {
return false;
}
if s.is_inverted() != repr.is_inverted() {
return false;
}
let g_repr = self.pattern.gate(repr.var() as usize);
let g = aig.gate(s.var() as usize);
if !Matcher::gate_type_matches(g_repr, g) {
return false;
}
for (&repr_r, &s_r) in zip(g_repr.dependencies(), g.dependencies()) {
if !self.try_match(repr_r, aig, s_r) {
return false;
}
}
true
} else if repr.is_input() {
true
} else {
repr == s
}
}
fn gate_type_matches(g_repr: &Gate, g: &Gate) -> bool {
use Gate::*;
match (g_repr, g) {
(Binary(_, t1), Binary(_, t2)) => t1 == t2,
(Ternary(_, t1), Ternary(_, t2)) => t1 == t2,
(Nary(v1, t1), Nary(v2, t2)) => t1 == t2 && v1.len() == v2.len(),
(Buf(_), Buf(_)) => true,
(Dff(_), Dff(_)) => true,
_ => false,
}
}
fn get_match(&self, repr: Signal) -> Signal {
if repr.is_constant() {
return repr;
}
let ind = if repr.is_input() {
repr.input() as usize
} else {
self.pattern.nb_inputs() + repr.var() as usize
};
let m = self.matches[ind];
if m == Signal::placeholder() {
m
} else {
m ^ repr.is_inverted()
}
}
fn set_match(&mut self, repr: Signal, val: Signal) {
assert!(!repr.is_constant());
let ind = if repr.is_input() {
repr.input() as usize
} else {
self.pattern.nb_inputs() + repr.var() as usize
};
self.matches[ind] = val ^ repr.is_inverted();
}
fn reset(&mut self) {
for m in &mut self.matches {
*m = Signal::placeholder();
}
}
}
#[cfg(test)]
mod test {
use crate::{Gate, Network, Signal};
use super::Matcher;
#[test]
fn test_and() {
let mut aig = Network::new();
aig.add_inputs(3);
let i0 = Signal::from_input(0);
let i1 = Signal::from_input(1);
let i2 = Signal::from_input(2);
aig.add(Gate::and(i0, i1));
aig.add(Gate::and(i0, i2));
aig.add(Gate::and(i2, i1));
aig.add(Gate::and(i0, !i1));
aig.add(Gate::and(!i0, i1));
aig.add(Gate::xor(i0, i1));
aig.add(Gate::xor(!i0, i1));
let mut pattern = Network::new();
pattern.add_inputs(2);
let o = pattern.add(Gate::and(i0, i1));
pattern.add_output(o);
let mut matcher = Matcher::from_pattern(&pattern);
for i in 0..5 {
assert!(matcher.matches(&aig, i).is_some());
}
for i in 5..7 {
assert!(matcher.matches(&aig, i).is_none());
}
assert_eq!(matcher.matches(&aig, 0), Some(vec![i0, i1]));
assert_eq!(matcher.matches(&aig, 1), Some(vec![i0, i2]));
assert_eq!(matcher.matches(&aig, 2), Some(vec![i2, i1]));
assert_eq!(matcher.matches(&aig, 3), Some(vec![i0, !i1]));
assert_eq!(matcher.matches(&aig, 4), Some(vec![!i0, i1]));
}
#[test]
fn test_complex_xor() {
let mut aig = Network::new();
aig.add_inputs(2);
let i0 = Signal::from_input(0);
let i1 = Signal::from_input(1);
let x0 = aig.add(Gate::and(i0, !i1));
let x1 = aig.add(Gate::and(!i0, i1));
aig.add(Gate::and(!x0, !x1));
aig.add(Gate::and(x0, x1));
aig.add(Gate::and(!x0, x1));
aig.add(Gate::and(!x1, !x0));
let x2 = aig.add(Gate::and(i0, i1));
let x3 = aig.add(Gate::and(!i0, !i1));
aig.add(Gate::and(!x2, !x3));
let mut pattern = Network::new();
pattern.add_inputs(2);
let p0 = pattern.add(Gate::and(i0, !i1));
let p1 = pattern.add(Gate::and(!i0, i1));
let o = pattern.add(Gate::and(!p0, !p1));
pattern.add_output(o);
let mut matcher = Matcher::from_pattern(&pattern);
assert_eq!(matcher.matches(&aig, 2), Some(vec![i0, i1]));
assert_eq!(matcher.matches(&aig, 3), None);
assert_eq!(matcher.matches(&aig, 4), None);
assert_eq!(matcher.matches(&aig, 5), Some(vec![!i0, !i1]));
assert_eq!(matcher.matches(&aig, 8), Some(vec![i0, !i1]));
}
#[test]
fn test_complex_mux() {
let mut aig = Network::new();
aig.add_inputs(3);
let i0 = Signal::from_input(0);
let i1 = Signal::from_input(1);
let i2 = Signal::from_input(2);
let x0 = aig.add(Gate::and(i0, i1));
let x1 = aig.add(Gate::and(!i0, i2));
aig.add(Gate::and(!x0, !x1));
let x2 = aig.add(Gate::and(i0, i1));
let x3 = aig.add(Gate::and(!i0, !i1));
aig.add(Gate::and(!x2, !x3));
let mut pattern = Network::new();
pattern.add_inputs(3);
let p0 = pattern.add(Gate::and(i0, !i1));
let p1 = pattern.add(Gate::and(!i0, !i2));
let o = pattern.add(Gate::and(!p0, !p1));
pattern.add_output(o);
let mut matcher = Matcher::from_pattern(&pattern);
assert_eq!(matcher.matches(&aig, 2), Some(vec![i0, !i1, !i2]));
assert_eq!(matcher.matches(&aig, 5), Some(vec![i0, !i1, i1]));
}
#[test]
fn test_constants() {
let mut aig = Network::new();
aig.add_inputs(3);
let i0 = Signal::from_input(0);
let i1 = Signal::from_input(1);
let i2 = Signal::from_input(2);
aig.add(Gate::and(i0, Signal::zero()));
aig.add(Gate::and(i0, Signal::one()));
aig.add(Gate::and(!i0, Signal::zero()));
aig.add(Gate::and(i1, Signal::zero()));
aig.add(Gate::and(i1, Signal::one()));
aig.add(Gate::and(!i1, Signal::zero()));
aig.add(Gate::and(i2, Signal::zero()));
aig.add(Gate::and(i2, Signal::one()));
aig.add(Gate::and(!i2, Signal::zero()));
let mut pattern = Network::new();
pattern.add_inputs(1);
let o = pattern.add(Gate::and(i0, Signal::zero()));
pattern.add_output(o);
let mut matcher = Matcher::from_pattern(&pattern);
assert_eq!(matcher.matches(&aig, 0), Some(vec![i0]));
assert_eq!(matcher.matches(&aig, 1), None);
assert_eq!(matcher.matches(&aig, 2), Some(vec![!i0]));
assert_eq!(matcher.matches(&aig, 3), Some(vec![i1]));
assert_eq!(matcher.matches(&aig, 4), None);
assert_eq!(matcher.matches(&aig, 5), Some(vec![!i1]));
assert_eq!(matcher.matches(&aig, 6), Some(vec![i2]));
assert_eq!(matcher.matches(&aig, 7), None);
assert_eq!(matcher.matches(&aig, 8), Some(vec![!i2]));
}
#[test]
fn test_loop() {
let mut aig = Network::new();
aig.add_inputs(3);
let d = Signal::from_input(0);
let en = Signal::from_input(1);
aig.add(Gate::mux(en, d, Signal::from_var(1)));
aig.add(Gate::dff(
Signal::from_var(0),
Signal::one(),
Signal::zero(),
));
aig.add(Gate::mux(en, d, Signal::from_input(2)));
aig.add(Gate::dff(
Signal::from_var(2),
Signal::one(),
Signal::zero(),
));
aig.add(Gate::mux(!en, d, Signal::from_var(5)));
aig.add(Gate::dff(
Signal::from_var(4),
Signal::one(),
Signal::zero(),
));
aig.add(Gate::mux(en, d, !Signal::from_var(7)));
aig.add(Gate::dff(
Signal::from_var(6),
Signal::one(),
Signal::zero(),
));
aig.add(Gate::mux(en, d, Signal::from_var(9)));
aig.add(Gate::dff(
!Signal::from_var(8),
Signal::one(),
Signal::zero(),
));
let mut pattern = Network::new();
pattern.add_inputs(2);
pattern.add(Gate::mux(en, d, Signal::from_var(1)));
pattern.add(Gate::dff(
Signal::from_var(0),
Signal::one(),
Signal::zero(),
));
pattern.add_output(Signal::from_var(1));
let mut matcher = Matcher::from_pattern(&pattern);
assert_eq!(matcher.matches(&aig, 1), Some(vec![d, en]));
assert_eq!(matcher.matches(&aig, 3), None);
assert_eq!(matcher.matches(&aig, 5), Some(vec![d, !en]));
assert_eq!(matcher.matches(&aig, 7), None);
assert_eq!(matcher.matches(&aig, 9), None);
}
}