use crate::{NID, Fun, nid::NidFun, vid::VID};
use std::slice::Iter;
#[derive(PartialOrd, PartialEq, Eq, Hash, Debug, Clone)]
pub enum Ops { RPN(Vec<NID>) }
impl Ops {
pub fn to_rpn(&self)->Iter<'_, NID> {
match self {
Ops::RPN(vec) => vec.iter() }}
pub fn to_app(&self)->(NID, Vec<NID>) {
match self {
Ops::RPN(vec) => {
let mut v = vec.clone();
let f = v.pop().expect("to_app() expects at least one f-nid");
assert!(f.is_fun());
(f,v) }}}
pub fn norm(&self)->Ops {
let mut rpn:Vec<NID> = self.to_rpn().cloned().collect();
let f0 = rpn.pop().expect("norm() expects at least one f-nid").to_fun().unwrap();
let ar = f0.arity();
assert_eq!(ar, rpn.len() as u8);
let mut bits:u8 = 0;
for (i,nid) in rpn.iter_mut().enumerate() { if nid.is_inv() { bits |= 1 << i; *nid = !*nid; }}
let f = f0.when_flipped(bits);
rpn.push(f.to_nid());
Ops::RPN(rpn)}}
pub fn rpn(xs:&[NID])->Ops { Ops::RPN(xs.to_vec()) }
pub mod sig {
macro_rules! signals {
($($ids:ident : $exs:expr),+ $(,)?) => { signals![@ $($ids : $exs),+]; };
(@) => {};
(@ $id:ident : $ex:expr $(, $ids:ident : $exs:expr)*) => {
pub const $id:u32 = $ex;
signals![@ $($ids : $exs),*]; };}
signals! {
K0:0b00000000000000000000000000000000,
K1:0b11111111111111111111111111111111,
A:0b01010101010101010101010101010101, RX0:A, NX0:!A,
B:0b00110011001100110011001100110011, RX1:B, NX1:!B,
C:0b00001111000011110000111100001111, RX2:C, NX2:!C,
D:0b00000000111111110000000011111111, RX3:D, NX3:!D,
E:0b00000000000000001111111111111111, RX4:E, NX4:!E,
AB: A&B, ABC: A&B&C, ABCD: A&B&C&D, ABCDE: A&B&C&D&E,
ABCE: A&B&C&E, ABD: A&B&D, ABDE: A&B&D&E, ABE: A&B&E,
AC: A&C, ACD: A&C&D, ACDE: A&C&D&E, ACE: A&C&E,
AD: A&D, ADE: A&D&E, AE: A&E, BC: B&C,
BCD: B&C&D, BCDE: B&C&D&E, BCE: B&C&E, BD: B&D,
BDE: B&D&E, BE: B&E, CD: C&D, CDE: C&D&E,
CE: C&E, DE: D&E,
BA: AB, CBA: ABC, DCBA: ABCD, EDCBA: ABCDE,
ECBA: ABCE, DBA: ABD, EDBA: ABDE, EBA: ABE,
CA: AC, DCA: ACD, EDCA: ACDE, ECA: ACE,
DA: AD, EDA: ADE, EA: AE, CB: BC,
DCB: BCD, EDCB: BCDE, ECB: BCE, DB: BD,
EDB: BDE, EB: BE, DC: CD, EDC: CDE,
EC: CE, ED: DE,
AND: A&B, NAND: !(A&B),
XOR: A^B, IFF: !XOR,
OR: A|B, NOR: !OR,
LT: !A&B, GT: A&!B,
LTE: !GT, GTE: !LT,
ITE: A&B|!A&C,
ANF: (A&B)^C,
XOR3: A^B^C,
MAJ: (A&B)|(A&C)|(B&C),
VEL:OR, IMP: LTE,
NE: XOR, EQ: IFF }}
pub const AND:NidFun = NID::fun(2,sig::AND);
pub const XOR:NidFun = NID::fun(2,sig::XOR);
pub const EQL:NidFun = NID::fun(2,sig::EQ);
pub const NXOR:NidFun = EQL;
pub const NAND:NidFun = NID::fun(2,sig::NAND);
pub const VEL:NidFun = NID::fun(2,sig::VEL);
pub const NOR:NidFun = NID::fun(2,sig::NOR);
pub const IMP:NidFun = NID::fun(2,sig::IMP);
pub const ITE:NidFun = NID::fun(3,sig::ITE);
pub const ANF:NidFun = NID::fun(3,sig::ANF);
pub trait ToNID { fn to_nid(&self)->NID; }
impl ToNID for NID { fn to_nid(&self)->NID { *self }}
impl ToNID for VID { fn to_nid(&self)->NID { NID::from_vid(*self) }}
pub fn and<X:ToNID,Y:ToNID>(x:X,y:Y)->Ops { rpn(&[x.to_nid(), y.to_nid(), AND.to_nid()]) }
pub fn xor<X:ToNID,Y:ToNID>(x:X,y:Y)->Ops { rpn(&[x.to_nid(), y.to_nid(), XOR.to_nid()]) }
pub fn vel<X:ToNID,Y:ToNID>(x:X,y:Y)->Ops { rpn(&[x.to_nid(), y.to_nid(), VEL.to_nid()]) }
pub fn imp<X:ToNID,Y:ToNID>(x:X,y:Y)->Ops { rpn(&[x.to_nid(), y.to_nid(), IMP.to_nid()]) }
#[test] fn test_flip_and() {
assert_eq!(AND.tbl() & 0b1111, 0b0001 );
assert_eq!(AND.when_flipped(1).tbl() & 0b1111, 0b0010 );
assert_eq!(AND.when_flipped(2).tbl() & 0b1111, 0b0100 );
assert_eq!(AND.when_flipped(3).tbl() & 0b1111, 0b1000 );}
#[test] fn test_flip_vel() {
assert_eq!(VEL.tbl() & 0b1111, 0b0111 );
assert_eq!(VEL.when_flipped(1).tbl() & 0b1111, 0b1011 );
assert_eq!(VEL.when_flipped(2).tbl() & 0b1111, 0b1101 );
assert_eq!(VEL.when_flipped(3).tbl() & 0b1111, 0b1110 );}
#[test] fn test_flip_xor() {
assert_eq!(XOR.tbl() & 0b1111, 0b0110 );
assert_eq!(XOR.when_flipped(1).tbl() & 0b1111, 0b1001 );
assert_eq!(XOR.when_flipped(2).tbl() & 0b1111, 0b1001 );
assert_eq!(XOR.when_flipped(3).tbl() & 0b1111, 0b0110 );}
#[test] fn test_norm() {
assert_eq!(AND.tbl() & 0b1111, 0b0001 );
let ops = Ops::RPN(vec![NID::var(0), !NID::var(1), AND.to_nid()]);
let mut rpn:Vec<NID> = ops.norm().to_rpn().cloned().collect();
let f = rpn.pop().unwrap().to_fun().unwrap();
assert_eq!(2, f.arity());
assert_eq!(f.tbl() & 0b1111, 0b0100);
assert_eq!(rpn, vec![NID::var(0), NID::var(1)]);}