#[macro_use]
extern crate variant_count;
use num_traits::Zero;
use rand::distributions::{Distribution, Standard};
use rand::Rng;
use serde::{Deserialize, Serialize};
pub use eval::{dump_vcd, evaluate_composite_program, largest_wires, smallest_wires, VcdDumper};
pub use has_const::HasConst;
pub use has_io::HasIO;
pub use identity::Identity;
pub use parsers::Parse;
pub use translatable::Translatable;
mod analysis;
mod eval;
pub mod exporters;
mod has_const;
mod has_io;
mod identity;
mod io_extractors;
pub mod parsers;
mod tests;
mod translatable;
pub trait WireValue: Copy + PartialEq + std::fmt::Debug + Serialize {
fn is_zero(&self) -> bool;
fn to_le_bytes(&self) -> [u8; 8];
}
impl WireValue for bool {
fn is_zero(&self) -> bool {
!*self
}
fn to_le_bytes(&self) -> [u8; 8] {
[if *self { 1u8 } else { 0u8 }, 0, 0, 0, 0, 0, 0, 0]
}
}
impl WireValue for u64 {
fn is_zero(&self) -> bool {
Zero::is_zero(self)
}
fn to_le_bytes(&self) -> [u8; 8] {
u64::to_le_bytes(*self)
}
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, VariantCount)]
pub enum Operation<T: WireValue> {
Input(usize),
Random(usize),
Add(usize, usize, usize),
AddConst(usize, usize, T),
Sub(usize, usize, usize),
SubConst(usize, usize, T),
Mul(usize, usize, usize),
MulConst(usize, usize, T),
AssertZero(usize),
Const(usize, T),
}
#[derive(Clone, Copy)]
enum OpType<T: WireValue> {
Input(fn(usize) -> Operation<T>),
InputConst(fn(usize, T) -> Operation<T>),
Output(fn(usize) -> Operation<T>),
Binary(fn(usize, usize, usize) -> Operation<T>),
BinaryConst(fn(usize, usize, T) -> Operation<T>),
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)]
pub enum CombineOperation {
GF2(Operation<bool>),
Z64(Operation<u64>),
B2A(usize, usize),
SizeHint(usize, usize),
}
impl<T: WireValue> Operation<T> {
fn random_variant<R: Rng + ?Sized>(rng: &mut R) -> OpType<T> {
match rng.gen_range(0..Operation::<T>::VARIANT_COUNT) {
0 => OpType::Input(Operation::Input),
1 => OpType::Input(Operation::Random),
2 => OpType::Binary(Operation::Add),
3 => OpType::BinaryConst(Operation::AddConst),
4 => OpType::Binary(Operation::Sub),
5 => OpType::BinaryConst(Operation::SubConst),
6 => OpType::Binary(Operation::Mul),
7 => OpType::BinaryConst(Operation::MulConst),
8 => OpType::Output(Operation::AssertZero),
9 => OpType::InputConst(Operation::Const),
_ => {
unimplemented!("Operation.random_variant is missing some variants")
}
}
}
fn construct<I1, I2>(
ty: OpType<T>,
mut inputs: I1,
mut outputs: I2,
constant: Option<T>,
) -> Operation<T>
where
I1: Iterator<Item = usize>,
I2: Iterator<Item = usize>,
{
match ty {
OpType::Input(op) => op(outputs.next().expect("Input op requires an output wire")),
OpType::InputConst(op) => op(
outputs
.next()
.expect("InputConst op requires an output wire"),
constant.expect("InputConst op requires a constant operand"),
),
OpType::Output(op) => op(inputs.next().expect("Output op requires an input wire")),
OpType::Binary(op) => op(
outputs.next().expect("Binary op requires an output wire"),
inputs.next().expect("Binary op requires two input wires"),
inputs.next().expect("Binary op requires two input wires"),
),
OpType::BinaryConst(op) => op(
outputs
.next()
.expect("BinaryConst op requires an output wire"),
inputs
.next()
.expect("BinaryConst op requires an input wire"),
constant.expect("BinaryConst op requires a constant operand"),
),
}
}
}
impl From<Operation<bool>> for CombineOperation {
fn from(op: Operation<bool>) -> Self {
CombineOperation::GF2(op)
}
}
impl From<Operation<u64>> for CombineOperation {
fn from(op: Operation<u64>) -> Self {
CombineOperation::Z64(op)
}
}
impl<T: WireValue> Distribution<Operation<T>> for Standard
where
Standard: Distribution<(usize, usize, usize, T)>,
{
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Operation<T> {
let (out, i0, i1, c): (usize, usize, usize, T) = rand::random();
Operation::<T>::construct(
Operation::<T>::random_variant(rng),
[i0, i1].iter().copied(),
[out].iter().copied(),
Some(c),
)
}
}
pub trait Gate<T>: HasIO + HasConst<T> + Translatable + Identity<T> {}
impl Gate<u64> for Operation<u64> {}
impl Gate<bool> for Operation<bool> {}
impl<T: WireValue> Gate<T> for CombineOperation where CombineOperation: HasConst<T> + Identity<T> {}