#![cfg_attr(docsrs, feature(doc_cfg))]
use std::cell::RefCell;
use std::cmp;
use std::fmt::Debug;
use std::iter;
use std::ops::{Add, BitAnd, BitOr, Neg, Not, Sub};
use std::rc::Rc;
use generic_array::typenum::*;
use generic_array::*;
use crate::boolexpr::{bool_ite, bool_opt_ite, half_adder, BoolExprNode};
pub use crate::boolexpr_creator::{ExprCreator, ExprCreator32, ExprCreatorSys};
use crate::dynintexpr::DynIntExprNode;
use crate::int_utils::*;
use crate::writer::{Literal, VarLit};
use crate::{impl_int_bitop_assign, impl_int_ty1_lt_ty2};
#[derive(thiserror::Error, Debug)]
pub enum IntError {
#[error("Bit overflow")]
BitOverflow,
#[error("Value can be negative")]
CanBeNegative,
#[error("Bit number mismatch")]
BitsMismatch,
}
pub mod traits;
pub use traits::*;
pub mod bin_arith;
pub use bin_arith::*;
pub mod int_arith;
pub use int_arith::*;
pub mod extra_arith;
pub use extra_arith::*;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct IntExprNode<T: VarLit + Debug, N: ArrayLength<usize>, const SIGN: bool> {
pub(super) creator: Rc<RefCell<ExprCreator<T>>>,
pub(super) indexes: GenericArray<usize, N>,
}
impl<T, N: ArrayLength<usize>, const SIGN: bool> IntExprNode<T, N, SIGN>
where
T: VarLit + Neg<Output = T> + Debug,
isize: TryFrom<T>,
<T as TryInto<usize>>::Error: Debug,
<T as TryFrom<usize>>::Error: Debug,
<isize as TryFrom<T>>::Error: Debug,
{
pub const BITS: usize = N::USIZE;
pub const SIGN: bool = SIGN;
pub const LOG_BITS: usize = calc_log_bits(Self::BITS);
pub fn variable(creator: Rc<RefCell<ExprCreator<T>>>) -> Self {
let mut indexes = GenericArray::<usize, N>::default();
{
let mut creator = creator.borrow_mut();
indexes.iter_mut().for_each(|x| {
let l = creator.new_variable();
*x = creator.single(l);
});
}
IntExprNode { creator, indexes }
}
pub fn from_boolexprs(iter: impl IntoIterator<Item = BoolExprNode<T>>) -> Option<Self> {
let mut creator = None;
GenericArray::from_exact_iter(iter.into_iter().map(|x| {
if let Some(c) = creator.clone() {
assert_eq!(Rc::as_ptr(&c), Rc::as_ptr(&x.creator));
} else {
creator = Some(x.creator.clone());
}
x.index
}))
.map(|indexes| IntExprNode {
creator: creator.unwrap(),
indexes,
})
}
pub fn filled(creator: Rc<RefCell<ExprCreator<T>>>, v: impl Into<Literal<T>>) -> Self {
IntExprNode {
creator: creator.clone(),
indexes: GenericArray::from_exact_iter(
iter::repeat(creator.borrow_mut().single(v)).take(N::USIZE),
)
.unwrap(),
}
}
pub fn filled_expr(v: BoolExprNode<T>) -> Self {
IntExprNode {
creator: v.creator.clone(),
indexes: GenericArray::from_exact_iter(iter::repeat(v.index).take(N::USIZE)).unwrap(),
}
}
pub fn as_unsigned(self) -> IntExprNode<T, N, false> {
IntExprNode {
creator: self.creator,
indexes: self.indexes,
}
}
pub fn as_signed(self) -> IntExprNode<T, N, true> {
IntExprNode {
creator: self.creator,
indexes: self.indexes,
}
}
}
impl<T, N: ArrayLength<usize>> IntExprNode<T, N, false>
where
T: VarLit + Neg<Output = T> + Debug,
isize: TryFrom<T>,
<T as TryInto<usize>>::Error: Debug,
<T as TryFrom<usize>>::Error: Debug,
<isize as TryFrom<T>>::Error: Debug,
{
pub fn subvalue<N2>(&self, start: usize) -> IntExprNode<T, N2, false>
where
N2: ArrayLength<usize>,
{
IntExprNode {
creator: self.creator.clone(),
indexes: GenericArray::clone_from_slice(&self.indexes[start..start + N2::USIZE]),
}
}
pub fn select_bits<N2, I>(&self, iter: I) -> Option<IntExprNode<T, N2, false>>
where
N2: ArrayLength<usize>,
I: IntoIterator<Item = usize>,
{
GenericArray::from_exact_iter(iter.into_iter().map(|x| self.indexes[x])).map(|indexes| {
IntExprNode {
creator: self.creator.clone(),
indexes,
}
})
}
pub fn concat<N2>(self, rest: IntExprNode<T, N2, false>) -> IntExprNode<T, Sum<N, N2>, false>
where
N: Add<N2>,
N2: ArrayLength<usize>,
Sum<N, N2>: ArrayLength<usize>,
{
use generic_array::sequence::*;
assert_eq!(Rc::as_ptr(&self.creator), Rc::as_ptr(&rest.creator));
IntExprNode {
creator: self.creator,
indexes: self.indexes.concat(rest.indexes),
}
}
pub fn split<K>(
self,
) -> (
IntExprNode<T, K, false>,
IntExprNode<T, operator_aliases::Diff<N, K>, false>,
)
where
N: Sub<K>,
K: ArrayLength<usize>,
operator_aliases::Diff<N, K>: ArrayLength<usize>,
{
use generic_array::sequence::*;
let (indexes1, indexes2) = self.indexes.split();
(
IntExprNode {
creator: self.creator.clone(),
indexes: indexes1,
},
IntExprNode {
creator: self.creator,
indexes: indexes2,
},
)
}
}
macro_rules! impl_int_try_from {
($ty1:ty, $ty2: ty, $($gparams:ident),*) => {
impl<T: VarLit, const SIGN2: bool, $( $gparams ),* >
TryFrom<IntExprNode<T, $ty2, SIGN2>> for IntExprNode<T, $ty1, false>
where
$ty1: ArrayLength<usize>,
$ty2: ArrayLength<usize>,
{
type Error = IntError;
fn try_from(v: IntExprNode<T, $ty2, SIGN2>) -> Result<Self, Self::Error> {
let len1 = <$ty1>::USIZE;
if !v.indexes.iter().skip(len1).all(|x| *x==0) {
return Err(IntError::BitOverflow);
}
Ok(IntExprNode::<T, $ty1, false>{ creator: v.creator.clone(),
indexes: GenericArray::clone_from_slice(&v.indexes[0..len1]) })
}
}
impl<T: VarLit, $( $gparams ),* >
TryFrom<IntExprNode<T, $ty2, false>> for IntExprNode<T, $ty1, true>
where
$ty1: ArrayLength<usize>,
$ty2: ArrayLength<usize>,
{
type Error = IntError;
fn try_from(v: IntExprNode<T, $ty2, false>) -> Result<Self, Self::Error> {
let len1 = <$ty1>::USIZE;
if !v.indexes.iter().skip(len1-1).all(|x| *x==0) {
return Err(IntError::BitOverflow);
}
Ok(IntExprNode::<T, $ty1, true>{ creator: v.creator.clone(),
indexes: GenericArray::clone_from_slice(&v.indexes[0..len1]) })
}
}
impl<T: VarLit, $( $gparams ),* >
TryFrom<IntExprNode<T, $ty2, true>> for IntExprNode<T, $ty1, true>
where
$ty1: ArrayLength<usize>,
$ty2: ArrayLength<usize>,
{
type Error = IntError;
fn try_from(v: IntExprNode<T, $ty2, true>) -> Result<Self, Self::Error> {
let len1 = <$ty1>::USIZE;
let last_idx = v.indexes[len1-1];
if !v.indexes.iter().skip(len1).all(|x| last_idx==*x) {
return Err(IntError::BitOverflow);
}
Ok(IntExprNode::<T, $ty1, true>{ creator: v.creator.clone(),
indexes: GenericArray::clone_from_slice(&v.indexes[0..len1]) })
}
}
impl<T: VarLit, $( $gparams ),* >
TryFrom<IntExprNode<T, $ty1, true>> for IntExprNode<T, $ty2, false>
where
$ty1: ArrayLength<usize>,
$ty2: ArrayLength<usize>,
{
type Error = IntError;
fn try_from(v: IntExprNode<T, $ty1, true>) -> Result<Self, Self::Error> {
if *v.indexes.last().unwrap() != 0 {
return Err(IntError::CanBeNegative); }
let mut new_v = IntExprNode::<T, $ty2, false>{ creator: v.creator.clone(),
indexes: GenericArray::default() };
new_v.indexes[0..v.indexes.len()].copy_from_slice(v.indexes.as_slice());
Ok(new_v)
}
}
}
}
impl_int_ty1_lt_ty2!(impl_int_try_from);
impl<T: VarLit, N: ArrayLength<usize>> TryFrom<IntExprNode<T, N, false>>
for IntExprNode<T, N, true>
{
type Error = IntError;
fn try_from(v: IntExprNode<T, N, false>) -> Result<Self, Self::Error> {
if *v.indexes.last().unwrap() != 0 {
return Err(IntError::BitOverflow);
}
Ok(IntExprNode {
creator: v.creator,
indexes: v.indexes,
})
}
}
impl<T: VarLit, N: ArrayLength<usize>> TryFrom<IntExprNode<T, N, true>>
for IntExprNode<T, N, false>
{
type Error = IntError;
fn try_from(v: IntExprNode<T, N, true>) -> Result<Self, Self::Error> {
if *v.indexes.last().unwrap() != 0 {
return Err(IntError::CanBeNegative);
}
Ok(IntExprNode {
creator: v.creator,
indexes: v.indexes,
})
}
}
impl<T: VarLit, N: ArrayLength<usize>, const SIGN: bool> TryFrom<DynIntExprNode<T, SIGN>>
for IntExprNode<T, N, SIGN>
{
type Error = IntError;
fn try_from(v: DynIntExprNode<T, SIGN>) -> Result<Self, Self::Error> {
if N::USIZE != v.indexes.len() {
return Err(IntError::BitsMismatch);
}
Ok(IntExprNode {
creator: v.creator,
indexes: GenericArray::clone_from_slice(&v.indexes),
})
}
}
macro_rules! impl_int_from {
($ty1:ty, $ty2: ty, $($gparams:ident),*) => {
impl<T: VarLit, const SIGN2: bool, $( $gparams ),* >
From<IntExprNode<T, $ty1, false>> for IntExprNode<T, $ty2, SIGN2>
where
$ty1: ArrayLength<usize>,
$ty2: ArrayLength<usize>, {
fn from(v: IntExprNode<T, $ty1, false>) -> Self {
let mut new_v = IntExprNode::<T, $ty2, SIGN2>{ creator: v.creator.clone(),
indexes: GenericArray::default() };
new_v.indexes[0..v.indexes.len()].copy_from_slice(v.indexes.as_slice());
new_v
}
}
impl<T: VarLit, $( $gparams ),* >
From<IntExprNode<T, $ty1, true>> for IntExprNode<T, $ty2, true>
where
$ty1: ArrayLength<usize>,
$ty2: ArrayLength<usize>, {
fn from(v: IntExprNode<T, $ty1, true>) -> Self {
let len = <$ty1>::USIZE;
let mut new_v = IntExprNode::<T, $ty2, true>{ creator: v.creator.clone(),
indexes: GenericArray::default() };
new_v.indexes[0..len].copy_from_slice(v.indexes.as_slice());
let last = *v.indexes.last().unwrap();
new_v.indexes[len..].iter_mut().for_each(|x| *x = last);
new_v
}
}
}
}
impl_int_ty1_lt_ty2!(impl_int_from);
impl<T: VarLit, N, const SIGN: bool> From<BoolExprNode<T>> for IntExprNode<T, N, SIGN>
where
N: ArrayLength<usize>,
T: VarLit + Neg<Output = T> + Debug,
isize: TryFrom<T>,
<T as TryInto<usize>>::Error: Debug,
<T as TryFrom<usize>>::Error: Debug,
<isize as TryFrom<T>>::Error: Debug,
{
fn from(v: BoolExprNode<T>) -> Self {
assert_ne!(N::USIZE, 0);
let ec = v.creator.clone();
Self::from_boolexprs(
std::iter::once(v)
.chain((0..N::USIZE - 1).map(|_| BoolExprNode::single_value(ec.clone(), false))),
)
.unwrap()
}
}
pub type U8ExprNode<T> = IntExprNode<T, U8, false>;
pub type U16ExprNode<T> = IntExprNode<T, U16, false>;
pub type U32ExprNode<T> = IntExprNode<T, U32, false>;
pub type U64ExprNode<T> = IntExprNode<T, U64, false>;
pub type U128ExprNode<T> = IntExprNode<T, U128, false>;
pub type UExprNode<T, N> = IntExprNode<T, N, false>;
pub type IExprNode<T, N> = IntExprNode<T, N, true>;
pub type I8ExprNode<T> = IntExprNode<T, U8, true>;
pub type I16ExprNode<T> = IntExprNode<T, U16, true>;
pub type I32ExprNode<T> = IntExprNode<T, U32, true>;
pub type I64ExprNode<T> = IntExprNode<T, U64, true>;
pub type I128ExprNode<T> = IntExprNode<T, U128, true>;
pub fn int_ite<C, T, E>(
c: C,
t: T,
e: E,
) -> <<T as BitAnd>::Output as BitOr<<E as BitAnd>::Output>>::Output
where
C: Not + Clone,
T: BitAnd + BitMask<C>,
E: BitAnd + BitMask<<C as Not>::Output>,
<T as BitAnd<T>>::Output: BitOr<<E as BitAnd<E>>::Output>,
{
(<T as BitMask<C>>::bitmask(c.clone()) & t)
| (<E as BitMask<<C as Not>::Output>>::bitmask(!c) & e)
}
pub fn int_opt_ite<T, N, const SIGN: bool>(
c: BoolExprNode<T>,
t: IntExprNode<T, N, SIGN>,
e: IntExprNode<T, N, SIGN>,
) -> IntExprNode<T, N, SIGN>
where
N: ArrayLength<usize>,
T: VarLit + Neg<Output = T> + Debug,
isize: TryFrom<T>,
<T as TryInto<usize>>::Error: Debug,
<T as TryFrom<usize>>::Error: Debug,
<isize as TryFrom<T>>::Error: Debug,
{
IntExprNode::from_boolexprs(
t.iter()
.zip(e.iter())
.map(|(tb, eb)| bool_opt_ite(c.clone(), tb, eb)),
)
.unwrap()
}
pub fn int_min<T, E>(t: T, e: E) -> <<T as BitAnd>::Output as BitOr<<E as BitAnd>::Output>>::Output
where
<T as traits::IntOrd<E>>::Output: Clone + Not,
T: Clone + BitAnd + BitMask<<T as IntOrd<E>>::Output> + IntOrd<E>,
E: Clone + BitAnd + BitMask<<<T as IntOrd<E>>::Output as Not>::Output>,
<T as BitAnd<T>>::Output: BitOr<<E as BitAnd<E>>::Output>,
{
int_ite(t.clone().less_than(e.clone()), t, e)
}
pub fn int_max<T, E>(t: T, e: E) -> <<T as BitAnd>::Output as BitOr<<E as BitAnd>::Output>>::Output
where
<T as traits::IntOrd<E>>::Output: Clone + Not,
T: Clone + BitAnd + BitMask<<T as IntOrd<E>>::Output> + IntOrd<E>,
E: Clone + BitAnd + BitMask<<<T as IntOrd<E>>::Output as Not>::Output>,
<T as BitAnd<T>>::Output: BitOr<<E as BitAnd<E>>::Output>,
{
int_ite(t.clone().greater_than(e.clone()), t, e)
}
pub fn int_table<T, N, K, I, const SIGN: bool>(
index: IntExprNode<T, K, SIGN>,
table_iter: I,
) -> IntExprNode<T, N, SIGN>
where
T: VarLit + Neg<Output = T> + Debug,
isize: TryFrom<T>,
<T as TryInto<usize>>::Error: Debug,
<T as TryFrom<usize>>::Error: Debug,
<isize as TryFrom<T>>::Error: Debug,
N: ArrayLength<usize>,
K: ArrayLength<usize>,
I: IntoIterator<Item = IntExprNode<T, N, SIGN>>,
{
let mut ites = vec![];
let mut iter = table_iter.into_iter();
while let Some(v) = iter.next() {
if let Some(v2) = iter.next() {
ites.push(int_ite(index.bit(0), v2, v));
} else {
panic!("Odd number of elements");
}
}
for step in 1..K::USIZE {
if (ites.len() & 1) != 0 {
panic!("Odd number of elements");
}
for i in 0..(ites.len() >> 1) {
ites[i] = int_ite(
index.bit(step),
ites[(i << 1) + 1].clone(),
ites[i << 1].clone(),
);
}
ites.resize(
ites.len() >> 1,
IntExprNode::filled(index.creator.clone(), false),
);
}
ites.pop().unwrap()
}
pub fn int_booltable<T, K, I, const SIGN: bool>(
index: IntExprNode<T, K, SIGN>,
table_iter: I,
) -> BoolExprNode<T>
where
T: VarLit + Neg<Output = T> + Debug,
isize: TryFrom<T>,
<T as TryInto<usize>>::Error: Debug,
<T as TryFrom<usize>>::Error: Debug,
<isize as TryFrom<T>>::Error: Debug,
K: ArrayLength<usize>,
I: IntoIterator<Item = BoolExprNode<T>>,
{
let mut ites = vec![];
let mut iter = table_iter.into_iter();
while let Some(v) = iter.next() {
if let Some(v2) = iter.next() {
ites.push(bool_ite(index.bit(0), v2, v));
} else {
panic!("Odd number of elements");
}
}
for step in 1..K::USIZE {
if (ites.len() & 1) != 0 {
panic!("Odd number of elements");
}
for i in 0..(ites.len() >> 1) {
ites[i] = bool_ite(
index.bit(step),
ites[(i << 1) + 1].clone(),
ites[i << 1].clone(),
);
}
ites.resize(
ites.len() >> 1,
BoolExprNode::single_value(index.creator.clone(), false),
);
}
ites.pop().unwrap()
}
pub fn int_opt_table<T, N, K, I, const SIGN: bool>(
index: IntExprNode<T, K, SIGN>,
table_iter: I,
) -> IntExprNode<T, N, SIGN>
where
T: VarLit + Neg<Output = T> + Debug,
isize: TryFrom<T>,
<T as TryInto<usize>>::Error: Debug,
<T as TryFrom<usize>>::Error: Debug,
<isize as TryFrom<T>>::Error: Debug,
N: ArrayLength<usize>,
K: ArrayLength<usize>,
I: IntoIterator<Item = IntExprNode<T, N, SIGN>>,
{
let tbl = Vec::from_iter(table_iter);
IntExprNode::from_boolexprs(
(0..N::USIZE).map(|bit| int_opt_booltable(index.clone(), tbl.iter().map(|t| t.bit(bit)))),
)
.unwrap()
}
pub fn int_opt_booltable<T, K, I, const SIGN: bool>(
index: IntExprNode<T, K, SIGN>,
table_iter: I,
) -> BoolExprNode<T>
where
T: VarLit + Neg<Output = T> + Debug,
isize: TryFrom<T>,
<T as TryInto<usize>>::Error: Debug,
<T as TryFrom<usize>>::Error: Debug,
<isize as TryFrom<T>>::Error: Debug,
K: ArrayLength<usize>,
I: IntoIterator<Item = BoolExprNode<T>>,
{
use crate::boolexpr::{boolexpr_are_negated, boolexpr_are_same};
let mut ites: Vec<BoolExprNode<T>> = vec![];
let tbl = Vec::from_iter(table_iter);
let mut iter = tbl.iter();
while let Some(v) = iter.next() {
if let Some(v2) = iter.next() {
let count = ites.len() << 1;
let mut already_added = false;
for k in 1..K::USIZE {
let kbit = 1 << k;
if (count & kbit) != 0 {
if boolexpr_are_same(&tbl[count], &tbl[count - kbit])
&& boolexpr_are_same(&tbl[count + 1], &tbl[count + 1 - kbit])
{
ites.push(ites[(count - kbit) >> 1].clone());
already_added = true;
break;
} else if boolexpr_are_negated(&tbl[count], &tbl[count - kbit])
&& boolexpr_are_negated(&tbl[count + 1], &tbl[count + 1 - kbit])
{
ites.push(!ites[(count - kbit) >> 1].clone());
already_added = true;
break;
}
}
}
if !already_added {
ites.push(bool_opt_ite(index.bit(0), v2.clone(), v.clone()));
}
} else {
panic!("Odd number of elements");
}
}
for step in 1..K::USIZE {
if (ites.len() & 1) != 0 {
panic!("Odd number of elements");
}
for i in 0..(ites.len() >> 1) {
let count = i << (step + 1);
let mut already_added = false;
for k in step + 1..K::USIZE {
let kbit = 1 << k;
if (count & kbit) != 0 {
if (0..(1 << (step + 1)))
.all(|x| boolexpr_are_same(&tbl[count + x], &tbl[count + x - kbit]))
{
ites[i] = ites[(count - kbit) >> (step + 1)].clone();
already_added = true;
break;
} else if (0..(1 << (step + 1)))
.all(|x| boolexpr_are_negated(&tbl[count + x], &tbl[count + x - kbit]))
{
ites[i] = !ites[(count - kbit) >> (step + 1)].clone();
already_added = true;
break;
}
}
}
if !already_added {
ites[i] = bool_opt_ite(
index.bit(step),
ites[(i << 1) + 1].clone(),
ites[i << 1].clone(),
);
}
}
ites.resize(
ites.len() >> 1,
BoolExprNode::single_value(index.creator.clone(), false),
);
}
ites.pop().unwrap()
}
pub fn int_demux<T, N, K, const SIGN: bool>(
index: IntExprNode<T, K, SIGN>,
value: IntExprNode<T, N, SIGN>,
) -> Vec<IntExprNode<T, N, SIGN>>
where
T: VarLit + Neg<Output = T> + Debug,
isize: TryFrom<T>,
<T as TryInto<usize>>::Error: Debug,
<T as TryFrom<usize>>::Error: Debug,
<isize as TryFrom<T>>::Error: Debug,
N: ArrayLength<usize>,
K: ArrayLength<usize>,
{
assert_ne!(K::USIZE, 0);
let mut chooser_table = vec![];
chooser_table.push(!index.bit(K::USIZE - 1));
chooser_table.push(index.bit(K::USIZE - 1));
for l in 1..K::USIZE {
let mut new_chooser_table = Vec::with_capacity(1 << l);
for i in 0..1 << l {
new_chooser_table.push(chooser_table[i].clone() & !index.bit(K::USIZE - l - 1));
new_chooser_table.push(chooser_table[i].clone() & index.bit(K::USIZE - l - 1));
}
chooser_table = new_chooser_table;
}
(0..1 << K::USIZE)
.map(|i| value.clone() & BitMask::bitmask(chooser_table[i].clone()))
.collect::<Vec<_>>()
}
pub fn int_booldemux<T, K, const SIGN: bool>(
index: IntExprNode<T, K, SIGN>,
value: BoolExprNode<T>,
) -> Vec<BoolExprNode<T>>
where
T: VarLit + Neg<Output = T> + Debug,
isize: TryFrom<T>,
<T as TryInto<usize>>::Error: Debug,
<T as TryFrom<usize>>::Error: Debug,
<isize as TryFrom<T>>::Error: Debug,
K: ArrayLength<usize>,
{
assert_ne!(K::USIZE, 0);
let mut chooser_table = vec![];
chooser_table.push(!index.bit(K::USIZE - 1));
chooser_table.push(index.bit(K::USIZE - 1));
for l in 1..K::USIZE {
let mut new_chooser_table = Vec::with_capacity(1 << l);
for i in 0..1 << l {
new_chooser_table.push(chooser_table[i].clone() & !index.bit(K::USIZE - l - 1));
new_chooser_table.push(chooser_table[i].clone() & index.bit(K::USIZE - l - 1));
}
chooser_table = new_chooser_table;
}
(0..1 << K::USIZE)
.map(|i| value.clone() & chooser_table[i].clone())
.collect::<Vec<_>>()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::boolexpr::BoolExprNode;
#[test]
fn test_expr_node() {
let ec = ExprCreator::new();
let x1 = IntExprNode::<isize, U8, false>::variable(ec.clone());
assert_eq!([2, 3, 4, 5, 6, 7, 8, 9], *x1.indexes);
assert_eq!([2, 3, 4, 5, 6, 7, 8, 9], *(x1.clone().as_signed()).indexes);
assert_eq!([2, 3, 4, 5, 6, 7, 8, 9], *(x1.as_unsigned()).indexes);
let x2 = IntExprNode::<isize, U8, true>::variable(ec.clone());
assert_eq!([10, 11, 12, 13, 14, 15, 16, 17], *x2.indexes);
assert_eq!(
[10, 11, 12, 13, 14, 15, 16, 17],
*(x2.clone().as_unsigned()).indexes
);
assert_eq!([10, 11, 12, 13, 14, 15, 16, 17], *(x2.as_signed()).indexes);
let b1 = BoolExprNode::variable(ec.clone());
let x3 = IntExprNode::<isize, U4, false>::filled(ec.clone(), b1.varlit().unwrap());
assert_eq!([18, 18, 18, 18], *x3.indexes);
let b1 = BoolExprNode::variable(ec.clone());
let b2 = BoolExprNode::variable(ec.clone());
let bxp = b1.clone() ^ b2.clone();
let x4 = IntExprNode::<isize, U4, false>::filled_expr(bxp.clone());
assert_eq!(
iter::repeat(bxp.index)
.take(4)
.collect::<Vec<_>>()
.as_slice(),
x4.indexes.as_slice()
);
let b3 = BoolExprNode::variable(ec.clone());
let b4 = BoolExprNode::variable(ec.clone());
let bxps = [
b1.clone() & b2.clone(),
b1.clone() | b2.clone(),
b1.clone() ^ b2.clone(),
b1 | b2.clone() | b3.clone(),
b3.clone() & b4.clone(),
b3.clone() | b4.clone(),
b3.clone() ^ b4.clone(),
b2 | b3 | b4,
];
let x5 = IntExprNode::<isize, U8, false>::from_boolexprs(bxps.clone()).unwrap();
assert_eq!(
bxps.iter().map(|x| x.index).collect::<Vec<_>>().as_slice(),
x5.indexes.as_slice()
);
}
#[test]
fn test_expr_node_manip() {
let ec = ExprCreator::new();
let x1 = IntExprNode::<isize, U16, false>::variable(ec.clone());
let x2 = x1.subvalue::<U6>(7);
assert_eq!([9, 10, 11, 12, 13, 14], *x2.indexes);
let x3 = x1
.select_bits::<U9, _>([3, 8, 9, 0, 3, 4, 12, 14, 15])
.unwrap();
assert_eq!([5, 10, 11, 2, 5, 6, 14, 16, 17], *x3.indexes);
assert_eq!(None, x1.select_bits::<U9, _>([3, 8, 9, 0, 3, 4, 12, 14]));
assert_eq!(
None,
x1.select_bits::<U9, _>([3, 8, 9, 0, 3, 4, 12, 14, 15, 0])
);
let y1 = IntExprNode::<isize, U8, false>::variable(ec.clone());
let z1 = x1.clone().concat(y1.clone());
assert_eq!(
(2..(2 + 24)).into_iter().collect::<Vec<usize>>().as_slice(),
z1.indexes.as_slice()
);
let z1 = y1.concat(x1);
assert_eq!(
((2 + 16)..(2 + 24))
.into_iter()
.chain((2..18).into_iter())
.collect::<Vec<usize>>()
.as_slice(),
z1.indexes.as_slice()
);
let (xt1, xt2) = z1.split::<U5>();
assert_eq!([18, 19, 20, 21, 22], *xt1.indexes);
assert_eq!(
((2 + 16 + 5)..(2 + 24))
.into_iter()
.chain((2..18).into_iter())
.collect::<Vec<usize>>()
.as_slice(),
xt2.indexes.as_slice()
);
}
#[test]
fn test_expr_node_from() {
let ec = ExprCreator::new();
let x1 = IntExprNode::<isize, U8, false>::variable(ec.clone());
let x2 = IntExprNode::<isize, U14, false>::from(x1.clone());
assert_eq!([2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0], *x2.indexes);
let ix2 = IntExprNode::<isize, U14, true>::from(x1.clone());
assert_eq!([2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0], *ix2.indexes);
let ix1 = IntExprNode::<isize, U8, true>::variable(ec.clone());
let ix2 = IntExprNode::<isize, U12, true>::from(ix1.clone());
assert_eq!(
[10, 11, 12, 13, 14, 15, 16, 17, 17, 17, 17, 17],
*ix2.indexes
);
}
#[test]
fn test_expr_node_try_from_dynint_expr_node() {
use crate::dynintexpr::DynIntExprNode;
let ec = ExprCreator::new();
let dix1 = DynIntExprNode::<isize, false>::variable(ec.clone(), 10);
let ix1 = IntExprNode::<isize, U10, false>::try_from(dix1.clone()).unwrap();
assert_eq!(ix1.indexes.as_slice(), dix1.indexes.as_slice());
}
#[test]
fn test_expr_node_try_from() {
let ec = ExprCreator::new();
let ix1 = IntExprNode::<isize, U8, true>::from(IntExprNode::<isize, U7, false>::variable(
ec.clone(),
));
let x1 = IntExprNode::<isize, U8, false>::try_from(ix1.clone()).unwrap();
assert_eq!([2, 3, 4, 5, 6, 7, 8, 0], *x1.indexes);
let x2 = IntExprNode::<isize, U9, false>::try_from(ix1.clone()).unwrap();
assert_eq!([2, 3, 4, 5, 6, 7, 8, 0, 0], *x2.indexes);
let x2 = IntExprNode::<isize, U10, false>::try_from(ix1).unwrap();
assert_eq!([2, 3, 4, 5, 6, 7, 8, 0, 0, 0], *x2.indexes);
let ix1 = IntExprNode::<isize, U8, true>::from(IntExprNode::<isize, U7, true>::variable(
ec.clone(),
));
assert_eq!(
Err("Value can be negative".to_string()),
IntExprNode::<isize, U8, false>::try_from(ix1.clone()).map_err(|x| x.to_string())
);
assert_eq!(
Err("Value can be negative".to_string()),
IntExprNode::<isize, U9, false>::try_from(ix1.clone()).map_err(|x| x.to_string())
);
assert_eq!(
Err("Value can be negative".to_string()),
IntExprNode::<isize, U10, false>::try_from(ix1).map_err(|x| x.to_string())
);
let x1 = IntExprNode::<isize, U8, false>::from(IntExprNode::<isize, U7, false>::variable(
ec.clone(),
));
let ix2 = IntExprNode::<isize, U8, true>::try_from(x1.clone()).unwrap();
assert_eq!([16, 17, 18, 19, 20, 21, 22, 0], *ix2.indexes);
let ix2 = IntExprNode::<isize, U9, true>::try_from(x1.clone()).unwrap();
assert_eq!([16, 17, 18, 19, 20, 21, 22, 0, 0], *ix2.indexes);
let x1 = IntExprNode::<isize, U8, false>::variable(ec.clone());
let ix2 = IntExprNode::<isize, U9, true>::try_from(x1.clone()).unwrap();
assert_eq!([23, 24, 25, 26, 27, 28, 29, 30, 0], *ix2.indexes);
assert_eq!(
Err("Bit overflow".to_string()),
IntExprNode::<isize, U8, true>::try_from(x1.clone()).map_err(|x| x.to_string())
);
let ux1 = IntExprNode::<isize, U8, false>::from(IntExprNode::<isize, U6, false>::variable(
ec.clone(),
));
let x2 = IntExprNode::<isize, U6, false>::try_from(ux1.clone()).unwrap();
assert_eq!([31, 32, 33, 34, 35, 36], *x2.indexes);
assert_eq!(
Err("Bit overflow".to_string()),
IntExprNode::<isize, U5, false>::try_from(ux1.clone()).map_err(|x| x.to_string())
);
assert_eq!(
Err("Bit overflow".to_string()),
IntExprNode::<isize, U4, false>::try_from(ux1.clone()).map_err(|x| x.to_string())
);
let ix2 = IntExprNode::<isize, U7, true>::try_from(ux1.clone()).unwrap();
assert_eq!([31, 32, 33, 34, 35, 36, 0], *ix2.indexes);
assert_eq!(
Err("Bit overflow".to_string()),
IntExprNode::<isize, U6, true>::try_from(ux1.clone()).map_err(|x| x.to_string())
);
assert_eq!(
Err("Bit overflow".to_string()),
IntExprNode::<isize, U5, true>::try_from(ux1.clone()).map_err(|x| x.to_string())
);
let ix1 = IntExprNode::<isize, U8, true>::from(IntExprNode::<isize, U6, false>::variable(
ec.clone(),
));
let x2 = IntExprNode::<isize, U6, false>::try_from(ix1.clone()).unwrap();
assert_eq!([37, 38, 39, 40, 41, 42], *x2.indexes);
assert_eq!(
Err("Bit overflow".to_string()),
IntExprNode::<isize, U5, false>::try_from(ix1.clone()).map_err(|x| x.to_string())
);
let ix2 = IntExprNode::<isize, U7, true>::try_from(ix1.clone()).unwrap();
assert_eq!([37, 38, 39, 40, 41, 42, 0], *ix2.indexes);
assert_eq!(
Err("Bit overflow".to_string()),
IntExprNode::<isize, U6, true>::try_from(ix1.clone()).map_err(|x| x.to_string())
);
assert_eq!(
Err("Bit overflow".to_string()),
IntExprNode::<isize, U5, true>::try_from(ix1.clone()).map_err(|x| x.to_string())
);
let ix1 = IntExprNode::<isize, U8, true>::from(IntExprNode::<isize, U6, true>::variable(
ec.clone(),
));
assert_eq!(
Err("Bit overflow".to_string()),
IntExprNode::<isize, U6, false>::try_from(ix1.clone()).map_err(|x| x.to_string())
);
assert_eq!(
Err("Bit overflow".to_string()),
IntExprNode::<isize, U5, false>::try_from(ix1.clone()).map_err(|x| x.to_string())
);
assert_eq!(
Err("Bit overflow".to_string()),
IntExprNode::<isize, U7, false>::try_from(ix1.clone()).map_err(|x| x.to_string())
);
let ix2 = IntExprNode::<isize, U6, true>::try_from(ix1.clone()).unwrap();
assert_eq!([43, 44, 45, 46, 47, 48], *ix2.indexes);
assert_eq!(
Err("Bit overflow".to_string()),
IntExprNode::<isize, U5, true>::try_from(ix1.clone()).map_err(|x| x.to_string())
);
assert_eq!(
Err("Bit overflow".to_string()),
IntExprNode::<isize, U4, true>::try_from(ix1.clone()).map_err(|x| x.to_string())
);
}
#[test]
fn test_int_ite() {
let ec = ExprCreator::new();
let c1 = BoolExprNode::<isize>::variable(ec.clone());
let x1 = IntExprNode::<isize, U7, false>::variable(ec.clone());
let x2 = IntExprNode::<isize, U7, false>::variable(ec.clone());
let res = int_ite(c1, x1, x2);
let exp_ec = ExprCreator::new();
let c1 = BoolExprNode::<isize>::variable(exp_ec.clone());
let x1 = IntExprNode::<isize, U7, false>::variable(exp_ec.clone());
let x2 = IntExprNode::<isize, U7, false>::variable(exp_ec.clone());
let exp =
(IntExprNode::filled_expr(c1.clone()) & x1) | (IntExprNode::filled_expr(!c1) & x2);
assert_eq!(exp.indexes.as_slice(), res.indexes.as_slice());
assert_eq!(*exp_ec.borrow(), *ec.borrow());
}
#[test]
fn test_int_table() {
let ec = ExprCreator::new();
let idx = IntExprNode::<isize, U5, false>::variable(ec.clone());
let values = (0..(1 << 5))
.into_iter()
.map(|_| IntExprNode::<isize, U10, false>::variable(ec.clone()))
.collect::<Vec<_>>();
let res = int_table(idx, values);
let exp_ec = ExprCreator::new();
let idx = IntExprNode::<isize, U5, false>::variable(exp_ec.clone());
let values = (0..(1 << 5))
.into_iter()
.map(|_| IntExprNode::<isize, U10, false>::variable(exp_ec.clone()))
.collect::<Vec<_>>();
let mut selects0 = vec![];
for i in 0..16 {
selects0.push(int_ite(
idx.bit(0),
values[(i << 1) + 1].clone(),
values[i << 1].clone(),
));
}
let mut selects1 = vec![];
for i in 0..8 {
selects1.push(int_ite(
idx.bit(1),
selects0[(i << 1) + 1].clone(),
selects0[i << 1].clone(),
));
}
let mut selects2 = vec![];
for i in 0..4 {
selects2.push(int_ite(
idx.bit(2),
selects1[(i << 1) + 1].clone(),
selects1[i << 1].clone(),
));
}
let mut selects3 = vec![];
for i in 0..2 {
selects3.push(int_ite(
idx.bit(3),
selects2[(i << 1) + 1].clone(),
selects2[i << 1].clone(),
));
}
let exp = int_ite(idx.bit(4), selects3[1].clone(), selects3[0].clone());
assert_eq!(exp.indexes.as_slice(), res.indexes.as_slice());
assert_eq!(*exp_ec.borrow(), *ec.borrow());
}
#[test]
fn test_int_booltable() {
let ec = ExprCreator::new();
let idx = IntExprNode::<isize, U5, false>::variable(ec.clone());
let values = (0..(1 << 5))
.into_iter()
.map(|_| BoolExprNode::<isize>::variable(ec.clone()))
.collect::<Vec<_>>();
let res = int_booltable(idx, values);
let exp_ec = ExprCreator::new();
let idx = IntExprNode::<isize, U5, false>::variable(exp_ec.clone());
let values = (0..(1 << 5))
.into_iter()
.map(|_| BoolExprNode::<isize>::variable(exp_ec.clone()))
.collect::<Vec<_>>();
let mut selects0 = vec![];
for i in 0..16 {
selects0.push(bool_ite(
idx.bit(0),
values[(i << 1) + 1].clone(),
values[i << 1].clone(),
));
}
let mut selects1 = vec![];
for i in 0..8 {
selects1.push(bool_ite(
idx.bit(1),
selects0[(i << 1) + 1].clone(),
selects0[i << 1].clone(),
));
}
let mut selects2 = vec![];
for i in 0..4 {
selects2.push(bool_ite(
idx.bit(2),
selects1[(i << 1) + 1].clone(),
selects1[i << 1].clone(),
));
}
let mut selects3 = vec![];
for i in 0..2 {
selects3.push(bool_ite(
idx.bit(3),
selects2[(i << 1) + 1].clone(),
selects2[i << 1].clone(),
));
}
let exp = bool_ite(idx.bit(4), selects3[1].clone(), selects3[0].clone());
assert_eq!(exp.index, res.index);
assert_eq!(*exp_ec.borrow(), *ec.borrow());
}
#[test]
fn test_int_demux() {
let ec = ExprCreator::new();
let idx = IntExprNode::<isize, U1, false>::variable(ec.clone());
let value = IntExprNode::<isize, U10, false>::variable(ec.clone());
let res = int_demux(idx, value);
let exp_ec = ExprCreator::new();
let idx = IntExprNode::<isize, U1, false>::variable(exp_ec.clone());
let value = IntExprNode::<isize, U10, false>::variable(exp_ec.clone());
let exp = vec![
value.clone() & IntExprNode::filled_expr(!idx.bit(0)),
value.clone() & IntExprNode::filled_expr(idx.bit(0)),
];
assert_eq!(
exp.into_iter().map(|x| x.indexes).collect::<Vec<_>>(),
res.into_iter().map(|x| x.indexes).collect::<Vec<_>>()
);
assert_eq!(*exp_ec.borrow(), *ec.borrow());
let ec = ExprCreator::new();
let idx = IntExprNode::<isize, U4, false>::variable(ec.clone());
let value = IntExprNode::<isize, U10, false>::variable(ec.clone());
let res = int_demux(idx, value);
let exp_ec = ExprCreator::new();
let idx = IntExprNode::<isize, U4, false>::variable(exp_ec.clone());
let value = IntExprNode::<isize, U10, false>::variable(exp_ec.clone());
let stage0 = vec![!idx.bit(3), idx.bit(3)];
let stage1 = stage0
.iter()
.map(|x| [x.clone() & !idx.bit(2), x.clone() & idx.bit(2)])
.flatten()
.collect::<Vec<_>>();
let stage2 = stage1
.iter()
.map(|x| [x.clone() & !idx.bit(1), x.clone() & idx.bit(1)])
.flatten()
.collect::<Vec<_>>();
let stage3 = stage2
.iter()
.map(|x| [x.clone() & !idx.bit(0), x.clone() & idx.bit(0)])
.flatten()
.collect::<Vec<_>>();
let exp = stage3
.into_iter()
.map(|x| value.clone() & IntExprNode::filled_expr(x.clone()))
.collect::<Vec<_>>();
assert_eq!(
exp.into_iter().map(|x| x.indexes).collect::<Vec<_>>(),
res.into_iter().map(|x| x.indexes).collect::<Vec<_>>()
);
assert_eq!(*exp_ec.borrow(), *ec.borrow());
}
#[test]
fn test_int_booldemux() {
let ec = ExprCreator::new();
let idx = IntExprNode::<isize, U1, false>::variable(ec.clone());
let value = BoolExprNode::<isize>::variable(ec.clone());
let res = int_booldemux(idx, value);
let exp_ec = ExprCreator::new();
let idx = IntExprNode::<isize, U1, false>::variable(exp_ec.clone());
let value = BoolExprNode::<isize>::variable(exp_ec.clone());
let exp = vec![value.clone() & !idx.bit(0), value.clone() & idx.bit(0)];
assert_eq!(
exp.into_iter().map(|x| x.index).collect::<Vec<_>>(),
res.into_iter().map(|x| x.index).collect::<Vec<_>>()
);
assert_eq!(*exp_ec.borrow(), *ec.borrow());
let ec = ExprCreator::new();
let idx = IntExprNode::<isize, U4, false>::variable(ec.clone());
let value = BoolExprNode::<isize>::variable(ec.clone());
let res = int_booldemux(idx, value);
let exp_ec = ExprCreator::new();
let idx = IntExprNode::<isize, U4, false>::variable(exp_ec.clone());
let value = BoolExprNode::<isize>::variable(exp_ec.clone());
let stage0 = vec![!idx.bit(3), idx.bit(3)];
let stage1 = stage0
.iter()
.map(|x| [x.clone() & !idx.bit(2), x.clone() & idx.bit(2)])
.flatten()
.collect::<Vec<_>>();
let stage2 = stage1
.iter()
.map(|x| [x.clone() & !idx.bit(1), x.clone() & idx.bit(1)])
.flatten()
.collect::<Vec<_>>();
let stage3 = stage2
.iter()
.map(|x| [x.clone() & !idx.bit(0), x.clone() & idx.bit(0)])
.flatten()
.collect::<Vec<_>>();
let exp = stage3
.into_iter()
.map(|x| value.clone() & x.clone())
.collect::<Vec<_>>();
assert_eq!(
exp.into_iter().map(|x| x.index).collect::<Vec<_>>(),
res.into_iter().map(|x| x.index).collect::<Vec<_>>()
);
assert_eq!(*exp_ec.borrow(), *ec.borrow());
}
}