use blanket::blanket;
use std::hash::Hash;
use std::ops::*;
use crate::networks::SimplifyResult;
use crate::traits::BooleanFunction;
use crate::traits::LogicValue;
use crate::{traits::IdType, truth_table::small_lut::SmallTruthTable};
#[blanket(derive(Ref, Mut))]
pub trait Network {
type Node: NetworkNode<NodeId = Self::Signal>;
type NodeId: Clone + PartialEq + Eq + Hash + Send + Sync + std::fmt::Debug + 'static;
type Signal: Copy + Clone + PartialEq + Eq + Hash + Send + Sync + std::fmt::Debug + 'static;
type LogicValue: LogicValue;
type NodeFunction: BooleanFunction;
fn foreach_gate(&self, f: impl Fn(Self::Signal));
fn foreach_node(&self, f: impl Fn(&Self::Node));
fn get_constant(&self, value: Self::LogicValue) -> Self::Signal;
fn get_constant_value(&self, signal: Self::Signal) -> Option<Self::LogicValue>;
fn get_node_input(&self, node: &Self::NodeId, input_index: usize) -> Self::Signal;
fn get_node_output(&self, node: &Self::NodeId) -> Self::Signal;
fn get_source_node(&self, signal: &Self::Signal) -> Self::NodeId;
fn get_primary_input(&self, index: usize) -> Self::Signal;
fn get_primary_output(&self, index: usize) -> Self::Signal;
fn is_constant(&self, signal: Self::Signal) -> bool {
self.get_constant_value(signal).is_some()
}
fn is_input(&self, signal: Self::Signal) -> bool;
fn node_function(&self, node: Self::NodeId) -> Self::NodeFunction;
fn num_gates(&self) -> usize;
fn num_node_inputs(&self, node: &Self::NodeId) -> usize;
fn num_primary_inputs(&self) -> usize;
fn num_primary_outputs(&self) -> usize;
}
pub trait HomogeneousNetwork: Network {
const NUM_NODE_INPUTS: usize;
fn function(&self) -> Self::NodeFunction;
}
pub trait ImmutableNot: Network {
fn get_inverted(&self, a: Self::Signal) -> Self::Signal;
fn is_inverted(&self, a: Self::Signal) -> bool;
}
pub trait ReferenceCounted: Network {
fn num_references(&self, a: Self::Signal) -> usize;
}
#[blanket(derive(Mut))]
pub trait NetworkEdit: Network {
fn create_primary_input(&mut self) -> Self::Signal;
fn create_primary_output(&mut self, signal: Self::Signal) -> Self::Signal;
fn substitute(&mut self, old: Self::Signal, new: Self::Signal);
fn create_node(&mut self, node: Self::Node) -> Self::NodeId;
fn foreach_node_mut(&mut self, f: impl Fn(&mut Self::Node));
}
#[blanket(derive(Mut))]
pub trait SubstituteInNode: Network {
fn substitute_in_node(
&mut self,
node: Self::NodeId,
old_signal: Self::Signal,
new_signal: Self::Signal,
);
}
pub trait NetworkShortcuts: Network {
fn primary_inputs(&self) -> Box<dyn Iterator<Item = Self::NodeId> + '_> {
Box::new(
(0..self.num_primary_inputs())
.map(|i| self.get_source_node(&self.get_primary_input(i))),
)
}
fn primary_outputs(&self) -> Box<dyn Iterator<Item = Self::Signal> + '_> {
Box::new((0..self.num_primary_outputs()).map(|i| self.get_primary_output(i)))
}
}
impl<T> NetworkShortcuts for T where T: Network {}
pub trait NetworkEditShortcuts: NetworkEdit {
fn create_primary_inputs<const NUM_INPUTS: usize>(&mut self) -> [Self::Signal; NUM_INPUTS] {
[(); NUM_INPUTS].map(|_| self.create_primary_input())
}
}
impl<T> NetworkEditShortcuts for T where T: NetworkEdit {}
#[blanket(derive(Mut))]
pub trait UnaryOp: NetworkEdit {
fn create_buffer(&mut self, signal: Self::Signal) -> Self::Signal {
signal
}
fn create_not(&mut self, signal: Self::Signal) -> Self::Signal;
}
#[blanket(derive(Mut))]
pub trait BinaryOp: UnaryOp {
fn create_and(&mut self, a: Self::Signal, b: Self::Signal) -> Self::Signal;
fn create_or(&mut self, a: Self::Signal, b: Self::Signal) -> Self::Signal;
fn create_nand(&mut self, a: Self::Signal, b: Self::Signal) -> Self::Signal;
fn create_nor(&mut self, a: Self::Signal, b: Self::Signal) -> Self::Signal;
fn create_xor(&mut self, a: Self::Signal, b: Self::Signal) -> Self::Signal;
fn create_xnor(&mut self, a: Self::Signal, b: Self::Signal) -> Self::Signal {
let xor = self.create_xor(a, b);
self.create_not(xor)
}
fn create_lt(&mut self, a: Self::Signal, b: Self::Signal) -> Self::Signal {
let a_not = self.create_not(a);
self.create_and(a_not, b)
}
fn create_le(&mut self, a: Self::Signal, b: Self::Signal) -> Self::Signal {
let a_not = self.create_not(a);
self.create_or(a_not, b)
}
fn create_gt(&mut self, a: Self::Signal, b: Self::Signal) -> Self::Signal {
self.create_lt(b, a)
}
fn create_ge(&mut self, a: Self::Signal, b: Self::Signal) -> Self::Signal {
self.create_le(b, a)
}
fn create_implies(&mut self, a: Self::Signal, b: Self::Signal) -> Self::Signal {
let a_not = self.create_not(a);
self.create_or(a_not, b)
}
}
#[blanket(derive(Mut))]
pub trait TernaryOp: BinaryOp {
fn create_maj3(&mut self, a: Self::Signal, b: Self::Signal, c: Self::Signal) -> Self::Signal {
let ab = self.create_and(a, b);
let bc = self.create_and(b, c);
let ac = self.create_and(a, c);
let bc_or_ac = self.create_or(bc, ac);
self.create_or(ab, bc_or_ac)
}
fn create_ite(
&mut self,
condition: Self::Signal,
then: Self::Signal,
otherwise: Self::Signal,
) -> Self::Signal {
let condition_not = self.create_not(condition);
let a = self.create_and(condition, then);
let b = self.create_and(condition_not, otherwise);
self.create_or(a, b)
}
fn create_xor3(&mut self, a: Self::Signal, b: Self::Signal, c: Self::Signal) -> Self::Signal {
let axb = self.create_xor(a, b);
self.create_xor(axb, c)
}
}
#[blanket(derive(Mut))]
pub trait NAryOp: TernaryOp {
fn create_nary_and(&mut self, inputs: impl Iterator<Item = Self::Signal>) -> Self::Signal {
inputs
.reduce(|acc, s| self.create_and(acc, s))
.unwrap_or(self.get_constant(<Self as Network>::LogicValue::one()))
}
fn create_nary_or(&mut self, inputs: impl Iterator<Item = Self::Signal>) -> Self::Signal {
inputs
.reduce(|acc, s| self.create_or(acc, s))
.unwrap_or(self.get_constant(<Self as Network>::LogicValue::zero()))
}
}
pub trait NetworkNode: Clone + Eq + PartialEq {
type NodeId: IdType;
fn num_inputs(&self) -> usize;
fn get_input(&self, i: usize) -> Self::NodeId;
fn function(&self) -> SmallTruthTable;
fn normalized(self) -> SimplifyResult<Self, Self::NodeId>;
}
pub trait MutNetworkNode: NetworkNode {
fn set_input(&mut self, i: usize, signal: Self::NodeId);
}
pub trait NetworkNodeWithReferenceCount: NetworkNode {
fn num_references(&self) -> usize;
}
pub trait StaticFunction {
}
pub trait StaticInputDegree<const NUM_INPUTS: usize>: NetworkNode {
fn to_array(&self) -> [Self::NodeId; NUM_INPUTS];
}
pub trait MutNetworkNodeWithReferenceCount: NetworkNodeWithReferenceCount {
fn reference(&mut self);
fn dereference(&mut self);
}
pub trait Edge: Sized {}
pub trait EdgeWithInversion: Edge {
fn is_inverted(&self) -> bool;
fn invert(self) -> Self;
fn invert_if(self, condition: bool) -> Self {
if condition {
self.invert()
} else {
self
}
}
fn non_inverted(self) -> Self {
if self.is_inverted() {
self.invert()
} else {
self
}
}
}