use crate::{
helpers::sort2,
network::*,
networks::generic_network::*,
truth_table::small_lut::{truth_table_library, SmallTruthTable},
};
use super::SimplifyResult;
pub type Aig = LogicNetwork<AigNode>;
pub type AigNodeId = NodeId;
#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Eq, Ord)]
pub struct AigNode {
pub(super) a: AigNodeId,
pub(super) b: AigNodeId,
num_references: usize,
}
impl AigNode {
fn new([a, b]: [AigNodeId; 2]) -> Self {
Self {
a,
b,
num_references: 0,
}
}
fn to_array(self) -> [AigNodeId; 2] {
[self.a, self.b]
}
fn to_array_mut(&mut self) -> [&mut AigNodeId; 2] {
[&mut self.a, &mut self.b]
}
}
impl NetworkNode for AigNode {
type NodeId = AigNodeId;
fn num_inputs(&self) -> usize {
2
}
fn get_input(&self, i: usize) -> Self::NodeId {
match i {
0 => self.a,
1 => self.b,
_ => panic!("index out of bounds"),
}
}
fn function(&self) -> SmallTruthTable {
truth_table_library::and2()
}
fn normalized(self) -> SimplifyResult<Self, Self::NodeId> {
Aig::simplify_node(self)
}
}
impl MutNetworkNode for AigNode {
fn set_input(&mut self, i: usize, signal: Self::NodeId) {
let input = match i {
0 => &mut self.a,
1 => &mut self.b,
_ => panic!("index out of bounds"),
};
*input = signal;
}
}
impl NetworkNodeWithReferenceCount for AigNode {
fn num_references(&self) -> usize {
self.num_references
}
}
impl MutNetworkNodeWithReferenceCount for AigNode {
fn reference(&mut self) {
self.num_references += 1;
}
fn dereference(&mut self) {
self.num_references -= 1;
}
}
impl IntoIterator for AigNode {
type Item = AigNodeId;
type IntoIter = std::array::IntoIter<AigNodeId, 2>;
fn into_iter(self) -> Self::IntoIter {
debug_assert_eq!(
self.to_array(),
sort2(self.to_array()),
"inputs must be sorted"
);
self.to_array().into_iter()
}
}
impl Aig {
fn simplify_node(node: AigNode) -> SimplifyResult<AigNode, NodeId> {
SimplifyResult::new_node(node)
.and_then(Self::simplify_node_by_majority)
.and_then(Self::simplify_constants)
.map_unsimplified(Self::normalize_node_by_commutativity) }
fn normalize_node_by_commutativity(node: AigNode) -> AigNode {
let [a, b] = sort2(node.to_array());
AigNode { a, b, ..node }
}
fn simplify_node_by_majority(node: AigNode) -> SimplifyResult<AigNode, NodeId> {
let [a, b] = [node.a, node.b];
match [a, b] {
[x, y] if x == y => SimplifyResult::new_id(x),
[x, y] if x == y.invert() => SimplifyResult::new_id(AigNodeId::zero()),
_ => SimplifyResult::new_node(node),
}
}
fn simplify_constants(node: AigNode) -> SimplifyResult<AigNode, NodeId> {
let [a, b] = node.to_array();
match [a, b] {
[x, _] | [_, x] if x.is_zero() => SimplifyResult::new_id(AigNodeId::zero()),
[x, y] | [y, x] if x.is_one() => SimplifyResult::new_id(y),
_ => SimplifyResult::new_node(node),
}
}
}
impl HomogeneousNetwork for Aig {
const NUM_NODE_INPUTS: usize = 2;
fn function(&self) -> Self::NodeFunction {
crate::truth_table::small_lut::truth_table_library::and2()
}
}
impl SubstituteInNode for Aig {
fn substitute_in_node(
&mut self,
node: Self::NodeId,
old_signal: Self::Signal,
new_signal: Self::Signal,
) {
if let Some(n) = self.get_logic_node_mut(node) {
n.to_array_mut()
.into_iter()
.filter(|input| **input == old_signal)
.for_each(|input| *input = new_signal);
}
}
}
impl UnaryOp for Aig {
fn create_not(&mut self, signal: Self::Signal) -> Self::Signal {
signal.invert()
}
}
impl BinaryOp for Aig {
fn create_and(&mut self, a: Self::Signal, b: Self::Signal) -> Self::Signal {
let node = AigNode::new([a, b]);
match Self::simplify_node(node) {
SimplifyResult::Node(n, invert) => self.create_node(n).invert_if(invert),
SimplifyResult::Simplified(s, invert) => s.invert_if(invert),
}
}
fn create_or(&mut self, a: Self::Signal, b: Self::Signal) -> Self::Signal {
self.create_and(a.invert(), b.invert()).invert()
}
fn create_nand(&mut self, a: Self::Signal, b: Self::Signal) -> Self::Signal {
self.create_and(a, b).invert()
}
fn create_nor(&mut self, a: Self::Signal, b: Self::Signal) -> Self::Signal {
self.create_or(a, b).invert()
}
fn create_xor(&mut self, a: Self::Signal, b: Self::Signal) -> Self::Signal {
let x = self.create_and(a, b.invert());
let y = self.create_and(a.invert(), b);
self.create_or(x, y)
}
}
impl TernaryOp for Aig {}
#[test]
fn test_aig_create_constants() {
let aig = Aig::new();
let zero = aig.get_constant(false);
let one = aig.get_constant(true);
assert!(zero.is_constant());
assert!(one.is_constant());
assert!(zero.is_zero());
assert_ne!(zero, one);
assert_eq!(zero.invert(), one);
}
#[test]
fn test_aig_create_primary_inputs() {
let mut aig = Aig::new();
let a = aig.create_primary_input();
let b = aig.create_primary_input();
let c = aig.create_primary_input();
assert_ne!(a, b);
assert_ne!(b, c);
assert!(aig.is_input(a));
assert!(aig.is_input(b));
assert!(aig.is_input(c));
assert!(!aig.is_constant(a));
}
#[test]
fn test_aig_node_deduplication() {
let mut aig = Aig::new();
let a = aig.create_primary_input();
let b = aig.create_primary_input();
let a_and_b_1 = aig.create_and(a, b);
let a_and_b_2 = aig.create_and(a, b);
assert_eq!(a_and_b_1, a_and_b_2);
}
#[test]
fn test_aig_node_simplification_by_commutativity() {
let mut aig = Aig::new();
let a = aig.create_primary_input();
let b = aig.create_primary_input();
let a_and_b_1 = aig.create_and(a, b);
let a_and_b_2 = aig.create_and(b, a);
assert_eq!(a_and_b_1, a_and_b_2);
}
#[test]
fn test_aig_node_simplification_by_majority() {
let mut aig = Aig::new();
let a = aig.create_primary_input();
let a_and_a = aig.create_and(a, a);
assert_eq!(a_and_a, a);
}
#[test]
fn test_aig_node_simplification_with_constants() {
let mut aig = Aig::new();
let a = aig.create_primary_input();
let zero = aig.get_constant(false);
let a_and_zero = aig.create_and(a, zero);
assert_eq!(a_and_zero, zero);
}
#[test]
fn test_aig_simulation() {
use crate::native_boolean_functions::NativeBooleanFunction;
use crate::traits::BooleanSystem;
let mut aig = Aig::new();
let [in1, in2, carry_in] = aig.create_primary_inputs();
let sum = aig.create_xor3(in1, in2, carry_in);
let carry = aig.create_maj3(in1, in2, carry_in);
let output_sum = aig.create_primary_output(sum);
let output_carry = aig.create_primary_output(carry);
let simulator = crate::network_simulator::RecursiveSim::new(&aig);
fn full_adder([a, b, c]: [bool; 3]) -> [bool; 2] {
let sum = (a as usize) + (b as usize) + (c as usize);
[
sum & 0b1 == 1,
sum & 0b10 == 0b10, ]
}
let reference = NativeBooleanFunction::new(full_adder);
for i in 0..(1 << 3) {
let inputs = [0, 1, 2].map(|idx| (i >> idx) & 1 == 1);
let exptected_output = [0, 1].map(|out| reference.evaluate_term(&out, &inputs));
let actual_output: Vec<_> = simulator
.simulate(&[output_sum, output_carry], &inputs)
.collect();
dbg!(inputs);
assert_eq!(exptected_output.as_slice(), actual_output.as_slice());
}
}