use std::fmt;
use crate::network::gates::{BinaryType, NaryType, TernaryType};
use crate::{Gate, Network};
#[derive(Clone, Debug)]
pub struct NetworkStats {
pub nb_inputs: usize,
pub nb_outputs: usize,
pub nb_and: usize,
pub and_arity: Vec<usize>,
pub nb_xor: usize,
pub xor_arity: Vec<usize>,
pub nb_lut: usize,
pub lut_arity: Vec<usize>,
pub nb_mux: usize,
pub nb_maj: usize,
pub nb_buf: usize,
pub nb_not: usize,
pub nb_dff: usize,
pub nb_dffe: usize,
pub nb_dffr: usize,
}
impl NetworkStats {
pub fn nb_gates(&self) -> usize {
self.nb_and + self.nb_xor + self.nb_mux + self.nb_maj + self.nb_buf + self.nb_dff
}
fn add_and(&mut self, sz: usize) {
self.nb_and += 1;
while self.and_arity.len() <= sz {
self.and_arity.push(0);
}
self.and_arity[sz] += 1;
}
fn add_xor(&mut self, sz: usize) {
self.nb_xor += 1;
while self.xor_arity.len() <= sz {
self.xor_arity.push(0);
}
self.xor_arity[sz] += 1;
}
fn add_lut(&mut self, sz: usize) {
self.nb_lut += 1;
while self.lut_arity.len() <= sz {
self.lut_arity.push(0);
}
self.lut_arity[sz] += 1;
}
}
impl fmt::Display for NetworkStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Stats:")?;
writeln!(f, " Inputs: {}", self.nb_inputs)?;
writeln!(f, " Outputs: {}", self.nb_outputs)?;
writeln!(f, " Gates: {}", self.nb_gates())?;
if self.nb_dff != 0 {
writeln!(f, " Dff: {}", self.nb_dff)?;
if self.nb_dffe != 0 {
writeln!(f, " enable: {}", self.nb_dff)?;
}
if self.nb_dffr != 0 {
writeln!(f, " reset: {}", self.nb_dff)?;
}
}
if self.nb_and != 0 {
writeln!(f, " And: {}", self.nb_and)?;
for (i, nb) in self.and_arity.iter().enumerate() {
if *nb != 0 {
writeln!(f, " {}: {}", i, nb)?;
}
}
}
if self.nb_xor != 0 {
writeln!(f, " Xor: {}", self.nb_xor)?;
for (i, nb) in self.xor_arity.iter().enumerate() {
if *nb != 0 {
writeln!(f, " {}: {}", i, nb)?;
}
}
}
if self.nb_lut != 0 {
writeln!(f, " Lut: {}", self.nb_lut)?;
for (i, nb) in self.lut_arity.iter().enumerate() {
if *nb != 0 {
writeln!(f, " {}: {}", i, nb)?;
}
}
}
if self.nb_mux != 0 {
writeln!(f, " Mux: {}", self.nb_mux)?;
}
if self.nb_maj != 0 {
writeln!(f, " Maj: {}", self.nb_maj)?;
}
if self.nb_not != 0 {
writeln!(f, " Not: {}", self.nb_not)?;
}
if self.nb_buf != 0 {
writeln!(f, " Buf: {}", self.nb_buf)?;
}
fmt::Result::Ok(())
}
}
pub fn stats(a: &Network) -> NetworkStats {
use Gate::*;
let mut ret = NetworkStats {
nb_inputs: a.nb_inputs(),
nb_outputs: a.nb_outputs(),
nb_and: 0,
and_arity: Vec::new(),
nb_xor: 0,
xor_arity: Vec::new(),
nb_lut: 0,
lut_arity: Vec::new(),
nb_maj: 0,
nb_mux: 0,
nb_buf: 0,
nb_not: 0,
nb_dff: 0,
nb_dffe: 0,
nb_dffr: 0,
};
for i in 0..a.nb_nodes() {
match a.gate(i) {
Binary(_, BinaryType::And) => ret.add_and(2),
Ternary(_, TernaryType::And) => ret.add_and(3),
Binary(_, BinaryType::Xor) => ret.add_xor(2),
Ternary(_, TernaryType::Xor) => ret.add_xor(3),
Ternary(_, TernaryType::Mux) => ret.nb_mux += 1,
Ternary(_, TernaryType::Maj) => ret.nb_maj += 1,
Buf(s) => {
if !s.is_constant() {
if s.is_inverted() {
ret.nb_not += 1;
} else {
ret.nb_buf += 1;
}
}
}
Dff([_, en, res]) => {
ret.nb_dff += 1;
if !en.is_constant() {
ret.nb_dffe += 1;
}
if !res.is_constant() {
ret.nb_dffr += 1;
}
}
Nary(v, tp) => match tp {
NaryType::And | NaryType::Or | NaryType::Nand | NaryType::Nor => {
ret.add_and(v.len());
}
NaryType::Xor | NaryType::Xnor => {
ret.add_xor(v.len());
}
},
Lut(lut) => {
ret.add_lut(lut.inputs.len());
}
}
}
ret
}
pub fn count_gate_usage(aig: &Network) -> Vec<usize> {
let mut ret = vec![0; aig.nb_nodes()];
for i in 0..aig.nb_nodes() {
for j in aig.gate(i).vars() {
ret[j as usize] += 1;
}
}
for i in 0..aig.nb_outputs() {
let s = aig.output(i);
if s.is_var() {
ret[s.var() as usize] += 1;
}
}
ret
}
pub fn gate_users(aig: &Network) -> Vec<Vec<usize>> {
let mut ret = vec![vec![]; aig.nb_nodes()];
for i in 0..aig.nb_nodes() {
for j in aig.gate(i).vars() {
ret[j as usize].push(i);
}
}
ret
}
pub fn gate_is_output(aig: &Network) -> Vec<bool> {
let mut ret = vec![false; aig.nb_nodes()];
for i in 0..aig.nb_outputs() {
if aig.output(i).is_var() {
ret[aig.output(i).var() as usize] = true;
}
}
ret
}