Skip to main content

cnfgen/dynintexpr/
mod.rs

1// dynintexpr.rs - dynamic integer expression structures.
2
3#![cfg_attr(docsrs, feature(doc_cfg))]
4//! The module to generate CNF clauses from dynamic integer expressions.
5//!
6//! This module contains traits and main structure to operate on integer expressions:
7//! `DynIntExprNode`. It is similar to IntExprNode, but have some specific features.
8//! Size of integer can be defined dynamically at runtime. This type can be used while
9//! writing generators which generates formula from source in higher-level language likes
10//! CVC4.
11//!
12//! Two generic parameters determine type of DynIntExprNode.
13//! The first T parameter is just variable literal type - it can be omitted.
14//! The second parameter is sign - true if signed integer or false if unsigned integer.
15//! Type of DynIntExprNode can be written in form: `DynIntExprNode<i32, false>` -
16//! DynIntExprNode for unsigned integer with 32-bit variable literals.
17//! You can use `IDynExprNode` or `UDynExprNode` to omit second parameter.
18//!
19//! Operations on this expression node are similar to operations that can be done on
20//! IntExprNode, except integer constant that can't be joined with DynIntExprNode.
21//! However, it is possible conversion from integer into DynIntExprNode thanks
22//! `TryIntConstantN` trait that provides method to that conversion.
23//!
24//! The simple example of usage:
25//! ```
26//! use cnfgen::boolexpr::*;
27//! use cnfgen::dynintexpr::*;
28//! use cnfgen::writer::{CNFError, CNFWriter};
29//! use std::io;
30//! fn write_diophantine_equation() -> Result<(), CNFError> {
31//!     // define ExprCreator.
32//!     let creator = ExprCreator32::new();
33//!     // define variables - signed 200-bit wide.
34//!     let x = IDynExprNode::variable(creator.clone(), 200);
35//!     let y = IDynExprNode::variable(creator.clone(), 200);
36//!     let z = IDynExprNode::variable(creator.clone(), 200);
37//!     // define equation: x^2 + y^2 - 77*z^2 = 0
38//!     let powx = x.clone().fullmul(x);  // x^2
39//!     let powy = y.clone().fullmul(y);  // y^2
40//!     let powz = z.clone().fullmul(z);  // z^2
41//!     let v77 = IDynExprNode::try_constant_n(creator.clone(), 400, 77).unwrap();
42//!     // We use cond_mul to get product and required condition to avoid overflow.
43//!     let (prod, cond0) = powz.cond_mul(v77);
44//!     // Similary, we use conditional addition and conditional subtraction.
45//!     let (sum1, cond1) = powx.cond_add(powy);
46//!     let (diff2, cond2) = sum1.cond_sub(prod);
47//!     // define final formula with required conditions.
48//!     let zero = IDynExprNode::try_constant_n(creator.clone(), 400, 0).unwrap();
49//!     let formula: BoolExprNode<_> = diff2.equal(zero) & cond0 & cond1 & cond2;
50//!     // write CNF to stdout.
51//!     formula.write(&mut CNFWriter::new(io::stdout()))
52//! }
53//! ```
54//!
55//! Look up module `intexpr` to figure out about possible operations.
56//!
57//! ## Conversion between types.
58//!
59//! It is possible conversion between various DynIntExprNodes that have various sizes and signs.
60//! Conversions are implemented by using `TryFromNSized` traits which define
61//! the method 'try_from_n` where argument `n` defines bits of destination.
62
63use std::cell::RefCell;
64use std::fmt::Debug;
65use std::ops::Neg;
66use std::rc::Rc;
67
68use generic_array::*;
69
70use crate::boolexpr::{bool_ite, bool_opt_ite, half_adder, BoolEqual, BoolExprNode, BoolImpl};
71pub use crate::boolexpr_creator::{ExprCreator, ExprCreator32, ExprCreatorSys};
72use crate::int_utils::*;
73pub use crate::intexpr::{
74    BitVal, DivMod, ExtraOps, FullMul, IntCondAdd, IntCondMul, IntCondNeg, IntCondShl, IntCondShr,
75    IntCondSub, IntEqual, IntError, IntExprNode, IntModAdd, IntModAddAssign, IntModMul,
76    IntModMulAssign, IntModNeg, IntModSub, IntModSubAssign, IntOrd, IntRol, IntRor,
77};
78use crate::writer::{Literal, VarLit};
79use crate::{impl_int_ipty, impl_int_upty};
80
81pub mod arith;
82pub use arith::*;
83
84pub mod extra_arith;
85pub use extra_arith::*;
86
87/// The main structure that represents dynamic integer expression, subexpression or integer value.
88///
89/// It joined with the ExprCreator that holds all expressions.
90/// Creation of new expression is naturally simple thanks operators. However, expression nodes
91/// must be cloned before using in other expressions if they will be used more than once.
92/// Simple examples:
93///
94/// * `(x1 << x2).mod_add(x3.clone()).equal(x3)`
95/// * `x1.clone().fullmul(x1).mod_add(x2.clone().fullmul(x2))`
96///
97/// The size of DynIntExprNode can be determined at runtime.
98#[derive(Clone, Debug, PartialEq, Eq)]
99pub struct DynIntExprNode<T: VarLit + Debug, const SIGN: bool> {
100    pub(super) creator: Rc<RefCell<ExprCreator<T>>>,
101    pub(super) indexes: Vec<usize>,
102}
103
104impl<T, const SIGN: bool> DynIntExprNode<T, SIGN>
105where
106    T: VarLit + Neg<Output = T> + Debug,
107    isize: TryFrom<T>,
108    <T as TryInto<usize>>::Error: Debug,
109    <T as TryFrom<usize>>::Error: Debug,
110    <isize as TryFrom<T>>::Error: Debug,
111{
112    /// SIGN of integer. It can be false - unsigned, or true - signed.
113    pub const SIGN: bool = SIGN;
114
115    /// Creates new variable as expression node. `n` is number of bits.
116    pub fn variable(creator: Rc<RefCell<ExprCreator<T>>>, n: usize) -> Self {
117        let indexes = {
118            let mut creator = creator.borrow_mut();
119            (0..n)
120                .into_iter()
121                .map(|_| {
122                    let l = creator.new_variable();
123                    creator.single(l)
124                })
125                .collect::<Vec<_>>()
126        };
127        DynIntExprNode { creator, indexes }
128    }
129
130    /// Creates integer from boolean expressions. An argument is object convertible into
131    /// iterator of `BoolExprNode`.
132    pub fn from_boolexprs(iter: impl IntoIterator<Item = BoolExprNode<T>>) -> Self {
133        let mut creator = None;
134        let indexes = iter
135            .into_iter()
136            .map(|x| {
137                // check creator - whether this same
138                if let Some(c) = creator.clone() {
139                    assert_eq!(Rc::as_ptr(&c), Rc::as_ptr(&x.creator));
140                } else {
141                    creator = Some(x.creator.clone());
142                }
143                x.index
144            })
145            .collect::<Vec<_>>();
146        DynIntExprNode {
147            creator: creator.unwrap(),
148            indexes,
149        }
150    }
151
152    /// Creates filled integer from from Literal. `n` is number of bits.
153    pub fn filled(
154        creator: Rc<RefCell<ExprCreator<T>>>,
155        n: usize,
156        v: impl Into<Literal<T>>,
157    ) -> Self {
158        DynIntExprNode {
159            creator: creator.clone(),
160            indexes: vec![creator.borrow_mut().single(v); n],
161        }
162    }
163
164    /// Creates filled integer from from a boolean value. `n` is number of bits.
165    pub fn filled_expr(n: usize, v: BoolExprNode<T>) -> Self {
166        DynIntExprNode {
167            creator: v.creator.clone(),
168            indexes: vec![v.index; n],
169        }
170    }
171
172    /// Casts integer into unsigned integer.
173    pub fn as_unsigned(self) -> DynIntExprNode<T, false> {
174        DynIntExprNode {
175            creator: self.creator,
176            indexes: self.indexes,
177        }
178    }
179
180    /// Casts integer into signed integer.
181    pub fn as_signed(self) -> DynIntExprNode<T, true> {
182        DynIntExprNode {
183            creator: self.creator,
184            indexes: self.indexes,
185        }
186    }
187
188    /// Returns length - number of bits.
189    #[inline]
190    pub fn len(&self) -> usize {
191        self.indexes.len()
192    }
193
194    /// Returns true if length is zero - number of bits is zero.
195    #[inline]
196    pub fn is_empty(&self) -> bool {
197        self.indexes.is_empty()
198    }
199}
200
201impl<T> DynIntExprNode<T, false>
202where
203    T: VarLit + Neg<Output = T> + Debug,
204    isize: TryFrom<T>,
205    <T as TryInto<usize>>::Error: Debug,
206    <T as TryFrom<usize>>::Error: Debug,
207    <isize as TryFrom<T>>::Error: Debug,
208{
209    /// Creates integer that contains `n` bits starting from `start`.
210    pub fn subvalue(&self, start: usize, n: usize) -> Self {
211        DynIntExprNode {
212            creator: self.creator.clone(),
213            indexes: Vec::from(&self.indexes[start..start + n]),
214        }
215    }
216
217    /// Creates integers that contains `n1`, `n2`, ... bits starting from `start`.
218    pub fn subvalues(&self, start: usize, ns: impl IntoIterator<Item = usize>) -> Vec<Self> {
219        let mut startx = start;
220        let mut out = vec![];
221        for n in ns.into_iter() {
222            out.push(self.subvalue(startx, n));
223            startx += n;
224        }
225        out
226    }
227
228    /// Creates integer that contains selected bits. List of bits given in
229    /// object that can be converted into iterator of indexes.
230    pub fn select_bits(&self, iter: impl IntoIterator<Item = usize>) -> Self {
231        DynIntExprNode {
232            creator: self.creator.clone(),
233            indexes: iter
234                .into_iter()
235                .map(|x| self.indexes[x])
236                .collect::<Vec<_>>(),
237        }
238    }
239
240    /// Creates integer of concatenation of self and `rest`.
241    pub fn concat(self, rest: Self) -> Self {
242        assert_eq!(Rc::as_ptr(&self.creator), Rc::as_ptr(&rest.creator));
243        DynIntExprNode {
244            creator: self.creator.clone(),
245            indexes: self
246                .indexes
247                .into_iter()
248                .chain(rest.indexes.into_iter())
249                .collect::<Vec<_>>(),
250        }
251    }
252
253    /// Splits integer into two parts: the first with `k` bits and second with rest of bits.
254    pub fn split(self, k: usize) -> (Self, Self) {
255        (
256            DynIntExprNode {
257                creator: self.creator.clone(),
258                indexes: Vec::from(&self.indexes[0..k]),
259            },
260            DynIntExprNode {
261                creator: self.creator.clone(),
262                indexes: Vec::from(&self.indexes[k..]),
263            },
264        )
265    }
266}
267
268/// Trait to convert DynDynIntExprNode to other DynDynIntExprNode with different number of bits.
269pub trait TryFromNSized<T>: Sized {
270    type Error;
271
272    /// Try to convert from input. `n` is number of bits of destination. It returns
273    /// `Ok(dest)` if conversion can be done, otherwise it returns error.
274    fn try_from_n(input: T, n: usize) -> Result<Self, Self::Error>;
275}
276
277impl<T: VarLit> TryFromNSized<DynIntExprNode<T, false>> for DynIntExprNode<T, false> {
278    type Error = IntError;
279
280    fn try_from_n(input: DynIntExprNode<T, false>, n: usize) -> Result<Self, IntError> {
281        if n < input.indexes.len() {
282            if !input.indexes.iter().skip(n).all(|x| *x == 0) {
283                return Err(IntError::BitOverflow);
284            }
285            Ok(DynIntExprNode {
286                creator: input.creator,
287                indexes: Vec::from(&input.indexes[0..n]),
288            })
289        } else {
290            let mut indexes = Vec::from(input.indexes.as_slice());
291            indexes.resize(n, 0);
292            Ok(DynIntExprNode {
293                creator: input.creator,
294                indexes,
295            })
296        }
297    }
298}
299
300impl<T: VarLit> TryFromNSized<DynIntExprNode<T, true>> for DynIntExprNode<T, false> {
301    type Error = IntError;
302
303    fn try_from_n(input: DynIntExprNode<T, true>, n: usize) -> Result<Self, IntError> {
304        if n < input.indexes.len() {
305            if !input.indexes.iter().skip(n).all(|x| *x == 0) {
306                return Err(IntError::BitOverflow);
307            }
308            Ok(DynIntExprNode {
309                creator: input.creator,
310                indexes: Vec::from(&input.indexes[0..n]),
311            })
312        } else {
313            if *input.indexes.last().unwrap() != 0 {
314                return Err(IntError::CanBeNegative);
315            }
316            let mut indexes = Vec::from(input.indexes.as_slice());
317            indexes.resize(n, 0);
318            Ok(DynIntExprNode {
319                creator: input.creator,
320                indexes,
321            })
322        }
323    }
324}
325
326impl<T: VarLit> TryFromNSized<DynIntExprNode<T, false>> for DynIntExprNode<T, true> {
327    type Error = IntError;
328
329    fn try_from_n(input: DynIntExprNode<T, false>, n: usize) -> Result<Self, IntError> {
330        if n <= input.indexes.len() {
331            if !input.indexes.iter().skip(n - 1).all(|x| *x == 0) {
332                return Err(IntError::BitOverflow);
333            }
334            Ok(DynIntExprNode {
335                creator: input.creator,
336                indexes: Vec::from(&input.indexes[0..n]),
337            })
338        } else {
339            let mut indexes = Vec::from(input.indexes.as_slice());
340            indexes.resize(n, 0);
341            Ok(DynIntExprNode {
342                creator: input.creator,
343                indexes,
344            })
345        }
346    }
347}
348
349impl<T: VarLit> TryFromNSized<DynIntExprNode<T, true>> for DynIntExprNode<T, true> {
350    type Error = IntError;
351
352    fn try_from_n(input: DynIntExprNode<T, true>, n: usize) -> Result<Self, IntError> {
353        if n < input.indexes.len() {
354            let last_idx = input.indexes[n - 1];
355            if !input.indexes.iter().skip(n).all(|x| last_idx == *x) {
356                return Err(IntError::BitOverflow);
357            }
358            Ok(DynIntExprNode {
359                creator: input.creator,
360                indexes: Vec::from(&input.indexes[0..n]),
361            })
362        } else {
363            let last = *input.indexes.last().unwrap();
364            let mut indexes = Vec::from(input.indexes.as_slice());
365            indexes.resize(n, last);
366            Ok(DynIntExprNode {
367                creator: input.creator,
368                indexes,
369            })
370        }
371    }
372}
373
374impl<T, N, const SIGN: bool> From<IntExprNode<T, N, SIGN>> for DynIntExprNode<T, SIGN>
375where
376    T: VarLit,
377    N: ArrayLength<usize>,
378{
379    fn from(v: IntExprNode<T, N, SIGN>) -> Self {
380        DynIntExprNode {
381            creator: v.creator,
382            indexes: Vec::from(v.indexes.as_slice()),
383        }
384    }
385}
386
387impl<T: VarLit, const SIGN: bool> TryFromNSized<BoolExprNode<T>> for DynIntExprNode<T, SIGN>
388where
389    T: VarLit + Neg<Output = T> + Debug,
390    isize: TryFrom<T>,
391    <T as TryInto<usize>>::Error: Debug,
392    <T as TryFrom<usize>>::Error: Debug,
393    <isize as TryFrom<T>>::Error: Debug,
394{
395    type Error = IntError;
396
397    /// Put boolean as first bit of integer.
398    fn try_from_n(v: BoolExprNode<T>, n: usize) -> Result<Self, Self::Error> {
399        let ec = v.creator.clone();
400        if n > 0 {
401            Ok(Self::from_boolexprs(std::iter::once(v).chain(
402                (0..n - 1).map(|_| BoolExprNode::single_value(ec.clone(), false)),
403            )))
404        } else {
405            Err(IntError::BitOverflow)
406        }
407    }
408}
409
410/// Trait to convert primitive integer into object (`DynIntExprNode`).
411/// It returns `Ok(result)` if integer will be match to size given in `n`.
412pub trait TryIntConstantN<T: VarLit, U>: Sized {
413    /// Try to perform conversion into expression node. `n` is number of bits of destination.
414    /// `v` is constant value to convert.
415    fn try_constant_n(
416        creator: Rc<RefCell<ExprCreator<T>>>,
417        n: usize,
418        v: U,
419    ) -> Result<Self, IntError>;
420}
421
422macro_rules! impl_int_try_uconstant_n {
423    ($pty:ty) => {
424        impl<T: VarLit> TryIntConstantN<T, $pty> for DynIntExprNode<T, false> {
425            fn try_constant_n(
426                creator: Rc<RefCell<ExprCreator<T>>>,
427                n: usize,
428                v: $pty,
429            ) -> Result<Self, IntError> {
430                let bits = <$pty>::BITS as usize;
431                // for n < bits, check whether highest bits are zero.
432                if n < bits && (v & ((((1 as $pty) << (bits - n)).overflowing_sub(1).0) << n)) != 0
433                {
434                    return Err(IntError::BitOverflow);
435                }
436                Ok(DynIntExprNode {
437                    creator,
438                    indexes: (0..n)
439                        .into_iter()
440                        .map(|x| {
441                            // return 1 - true node index, 0 - false node index
442                            if x < bits {
443                                usize::from((v & (1 << x)) != 0)
444                            } else {
445                                0
446                            }
447                        })
448                        .collect::<Vec<_>>(),
449                })
450            }
451        }
452    };
453}
454
455impl_int_upty!(impl_int_try_uconstant_n);
456
457macro_rules! impl_int_try_iconstant_n {
458    ($pty:ty) => {
459        impl<T: VarLit> TryIntConstantN<T, $pty> for DynIntExprNode<T, true> {
460            fn try_constant_n(
461                creator: Rc<RefCell<ExprCreator<T>>>,
462                n: usize,
463                v: $pty,
464            ) -> Result<Self, IntError> {
465                let bits = <$pty>::BITS as usize;
466                if n < bits {
467                    // for n < bits, check whether highest bits are zero if positive number or
468                    // if ones if negative number.
469                    let mask = ((((1 as $pty) << (bits - n)).overflowing_sub(1).0) << n);
470                    let signmask = if v < 0 { mask } else { 0 };
471                    if (v & mask) != signmask {
472                        return Err(IntError::BitOverflow);
473                    }
474                }
475                Ok(DynIntExprNode {
476                    creator,
477                    indexes: (0..n)
478                        .into_iter()
479                        .map(|x| {
480                            // return 1 - true node index, 0 - false node index
481                            if x < bits {
482                                usize::from((v & (1 << x)) != 0)
483                            } else {
484                                usize::from((v & (1 << ((<$pty>::BITS - 1) as usize))) != 0)
485                            }
486                        })
487                        .collect::<Vec<_>>(),
488                })
489            }
490        }
491    };
492}
493
494impl_int_ipty!(impl_int_try_iconstant_n);
495
496impl<'a, T, const SIGN: bool> BitVal for &'a DynIntExprNode<T, SIGN>
497where
498    T: VarLit + Neg<Output = T> + Debug,
499    isize: TryFrom<T>,
500    <T as TryInto<usize>>::Error: Debug,
501    <T as TryFrom<usize>>::Error: Debug,
502    <isize as TryFrom<T>>::Error: Debug,
503{
504    type Output = BoolExprNode<T>;
505
506    fn bitnum(self) -> usize {
507        self.indexes.len()
508    }
509
510    fn bit(self, x: usize) -> Self::Output {
511        BoolExprNode::new(self.creator.clone(), self.indexes[x])
512    }
513}
514
515// ///////////////////
516// IntEqual
517
518impl<T, const SIGN: bool> IntEqual for DynIntExprNode<T, SIGN>
519where
520    T: VarLit + Neg<Output = T> + Debug,
521    isize: TryFrom<T>,
522    <T as TryInto<usize>>::Error: Debug,
523    <T as TryFrom<usize>>::Error: Debug,
524    <isize as TryFrom<T>>::Error: Debug,
525{
526    type Output = BoolExprNode<T>;
527
528    fn equal(self, rhs: Self) -> Self::Output {
529        assert_eq!(self.indexes.len(), rhs.indexes.len());
530        let mut xp = BoolExprNode::single(self.creator.clone(), true);
531        for i in 0..self.indexes.len() {
532            xp &= self.bit(i).bequal(rhs.bit(i));
533        }
534        xp
535    }
536
537    fn nequal(self, rhs: Self) -> Self::Output {
538        assert_eq!(self.indexes.len(), rhs.indexes.len());
539        let mut xp = BoolExprNode::single(self.creator.clone(), false);
540        for i in 0..self.indexes.len() {
541            xp |= self.bit(i) ^ rhs.bit(i);
542        }
543        xp
544    }
545}
546
547impl<T> IntOrd for DynIntExprNode<T, false>
548where
549    T: VarLit + Neg<Output = T> + Debug,
550    isize: TryFrom<T>,
551    <T as TryInto<usize>>::Error: Debug,
552    <T as TryFrom<usize>>::Error: Debug,
553    <isize as TryFrom<T>>::Error: Debug,
554{
555    type Output = BoolExprNode<T>;
556
557    fn less_than(self, rhs: Self) -> Self::Output {
558        assert_eq!(self.indexes.len(), rhs.indexes.len());
559        let mut xp = (!self.bit(0)) & rhs.bit(0);
560        for i in 1..self.indexes.len() {
561            xp = (self.bit(i).bequal(rhs.bit(i)) & xp) | ((!self.bit(i)) & rhs.bit(i));
562        }
563        xp
564    }
565
566    fn less_equal(self, rhs: Self) -> Self::Output {
567        assert_eq!(self.indexes.len(), rhs.indexes.len());
568        let mut xp = self.bit(0).imp(rhs.bit(0));
569        for i in 1..self.indexes.len() {
570            xp = (self.bit(i).bequal(rhs.bit(i)) & xp) | ((!self.bit(i)) & rhs.bit(i));
571        }
572        xp
573    }
574
575    fn greater_than(self, rhs: Self) -> Self::Output {
576        rhs.less_than(self)
577    }
578
579    fn greater_equal(self, rhs: Self) -> Self::Output {
580        rhs.less_equal(self)
581    }
582}
583
584impl<T> IntOrd for DynIntExprNode<T, true>
585where
586    T: VarLit + Neg<Output = T> + Debug,
587    isize: TryFrom<T>,
588    <T as TryInto<usize>>::Error: Debug,
589    <T as TryFrom<usize>>::Error: Debug,
590    <isize as TryFrom<T>>::Error: Debug,
591{
592    type Output = BoolExprNode<T>;
593
594    fn less_than(self, rhs: Self) -> Self::Output {
595        assert_eq!(self.indexes.len(), rhs.indexes.len());
596        let lhs_sign = self.bit(self.indexes.len() - 1);
597        let rhs_sign = rhs.bit(self.indexes.len() - 1);
598        let (lhs_num, rhs_num) = {
599            let mut lhs_num = self.as_unsigned();
600            let mut rhs_num = rhs.as_unsigned();
601            *lhs_num.indexes.last_mut().unwrap() = 0;
602            *rhs_num.indexes.last_mut().unwrap() = 0;
603            (lhs_num, rhs_num)
604        };
605        (lhs_sign.clone() & (!rhs_sign.clone()))
606            | (lhs_sign.bequal(rhs_sign) & lhs_num.less_than(rhs_num))
607    }
608
609    fn less_equal(self, rhs: Self) -> Self::Output {
610        assert_eq!(self.indexes.len(), rhs.indexes.len());
611        let lhs_sign = self.bit(self.indexes.len() - 1);
612        let rhs_sign = rhs.bit(self.indexes.len() - 1);
613        let (lhs_num, rhs_num) = {
614            let mut lhs_num = self.as_unsigned();
615            let mut rhs_num = rhs.as_unsigned();
616            *lhs_num.indexes.last_mut().unwrap() = 0;
617            *rhs_num.indexes.last_mut().unwrap() = 0;
618            (lhs_num, rhs_num)
619        };
620        (lhs_sign.clone() & (!rhs_sign.clone()))
621            | (lhs_sign.bequal(rhs_sign) & lhs_num.less_equal(rhs_num))
622    }
623
624    fn greater_than(self, rhs: Self) -> Self::Output {
625        rhs.less_than(self)
626    }
627
628    fn greater_equal(self, rhs: Self) -> Self::Output {
629        rhs.less_equal(self)
630    }
631}
632
633// types
634
635/// DynIntExprNode for unsinged integer.
636pub type UDynExprNode<T> = DynIntExprNode<T, false>;
637/// DynIntExprNode for singed integer.
638pub type IDynExprNode<T> = DynIntExprNode<T, true>;
639
640#[cfg(test)]
641mod tests {
642    use super::*;
643    use crate::intexpr::IntExprNode;
644    use generic_array::typenum::*;
645    use std::iter;
646
647    #[test]
648    fn test_expr_node() {
649        let ec = ExprCreator::new();
650        let x1 = DynIntExprNode::<isize, false>::variable(ec.clone(), 7);
651        assert_eq!([2, 3, 4, 5, 6, 7, 8], *x1.indexes);
652        assert_eq!([2, 3, 4, 5, 6, 7, 8], *(x1.clone().as_signed()).indexes);
653        assert_eq!([2, 3, 4, 5, 6, 7, 8], *(x1.as_unsigned()).indexes);
654        let x2 = DynIntExprNode::<isize, true>::variable(ec.clone(), 7);
655        assert_eq!([9, 10, 11, 12, 13, 14, 15], *x2.indexes);
656        assert_eq!(
657            [9, 10, 11, 12, 13, 14, 15],
658            *(x2.clone().as_unsigned()).indexes
659        );
660        assert_eq!([9, 10, 11, 12, 13, 14, 15], *(x2.as_signed()).indexes);
661
662        let b1 = BoolExprNode::variable(ec.clone());
663        let x3 = DynIntExprNode::<isize, false>::filled(ec.clone(), 4, b1.varlit().unwrap());
664        assert_eq!([16, 16, 16, 16], *x3.indexes);
665        let b1 = BoolExprNode::variable(ec.clone());
666        let b2 = BoolExprNode::variable(ec.clone());
667        let bxp = b1.clone() ^ b2.clone();
668        let x4 = DynIntExprNode::<isize, false>::filled_expr(4, bxp.clone());
669        assert_eq!(
670            iter::repeat(bxp.index)
671                .take(4)
672                .collect::<Vec<_>>()
673                .as_slice(),
674            x4.indexes.as_slice()
675        );
676
677        //
678        let b3 = BoolExprNode::variable(ec.clone());
679        let b4 = BoolExprNode::variable(ec.clone());
680        let bxps = [
681            b1.clone() & b2.clone(),
682            b1.clone() | b2.clone(),
683            b1.clone() ^ b2.clone(),
684            b1 | b2.clone() | b3.clone(),
685            b3.clone() & b4.clone(),
686            b3.clone() | b4.clone(),
687            b3.clone() ^ b4.clone(),
688            b2 | b3 | b4,
689        ];
690
691        let x5 = DynIntExprNode::<isize, false>::from_boolexprs(bxps.clone());
692        assert_eq!(
693            bxps.iter().map(|x| x.index).collect::<Vec<_>>().as_slice(),
694            x5.indexes.as_slice()
695        );
696    }
697
698    #[test]
699    fn test_expr_node_manip() {
700        let ec = ExprCreator::new();
701        let x1 = DynIntExprNode::<isize, false>::variable(ec.clone(), 16);
702        let x2 = x1.subvalue(7, 6);
703        assert_eq!([9, 10, 11, 12, 13, 14], *x2.indexes);
704        let x3 = x1.select_bits([3, 8, 9, 0, 3, 4, 12, 14, 15]);
705        assert_eq!([5, 10, 11, 2, 5, 6, 14, 16, 17], *x3.indexes);
706
707        let y1 = DynIntExprNode::<isize, false>::variable(ec.clone(), 8);
708        let z1 = x1.clone().concat(y1.clone());
709        assert_eq!(
710            (2..(2 + 24)).into_iter().collect::<Vec<usize>>().as_slice(),
711            z1.indexes.as_slice()
712        );
713        let z1 = y1.concat(x1);
714        assert_eq!(
715            ((2 + 16)..(2 + 24))
716                .into_iter()
717                .chain((2..18).into_iter())
718                .collect::<Vec<usize>>()
719                .as_slice(),
720            z1.indexes.as_slice()
721        );
722        let (xt1, xt2) = z1.split(5);
723        assert_eq!([18, 19, 20, 21, 22], *xt1.indexes);
724        assert_eq!(
725            ((2 + 16 + 5)..(2 + 24))
726                .into_iter()
727                .chain((2..18).into_iter())
728                .collect::<Vec<usize>>()
729                .as_slice(),
730            xt2.indexes.as_slice()
731        );
732    }
733
734    #[test]
735    fn test_expr_node_from_int_expr_node() {
736        let ec = ExprCreator::new();
737        let ix1 = IntExprNode::<isize, U10, false>::variable(ec.clone());
738        let dix1 = DynIntExprNode::<isize, false>::from(ix1.clone());
739        assert_eq!(ix1.indexes.as_slice(), dix1.indexes.as_slice());
740    }
741
742    #[test]
743    fn test_expr_node_try_from_n_uncond() {
744        let ec = ExprCreator::new();
745        // Unsigned N -> Unsigned N+X
746        let x1 = DynIntExprNode::<isize, false>::variable(ec.clone(), 8);
747        let x2 = DynIntExprNode::<isize, false>::try_from_n(x1.clone(), 14).unwrap();
748        assert_eq!([2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0], *x2.indexes);
749        // Unsigned N -> Signed N+X
750        let ix2 = DynIntExprNode::<isize, true>::try_from_n(x1.clone(), 14).unwrap();
751        assert_eq!([2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0], *ix2.indexes);
752        let ix1 = DynIntExprNode::<isize, true>::variable(ec.clone(), 8);
753        // Signed N, where SIGN=var -> Signed N+X
754        let ix2 = DynIntExprNode::<isize, true>::try_from_n(ix1.clone(), 12).unwrap();
755        assert_eq!(
756            [10, 11, 12, 13, 14, 15, 16, 17, 17, 17, 17, 17],
757            *ix2.indexes
758        );
759    }
760
761    #[test]
762    fn test_expr_node_try_from_n() {
763        let ec = ExprCreator::new();
764        let ix1 = DynIntExprNode::<isize, true>::try_from_n(
765            DynIntExprNode::<isize, false>::variable(ec.clone(), 7),
766            8,
767        )
768        .unwrap();
769        // Signed N, SIGN=0 -> Unsigned N
770        let x1 = DynIntExprNode::<isize, false>::try_from_n(ix1.clone(), 8).unwrap();
771        assert_eq!([2, 3, 4, 5, 6, 7, 8, 0], *x1.indexes);
772        // Signed N, SIGN=0 -> Unsigned N+X
773        let x2 = DynIntExprNode::<isize, false>::try_from_n(ix1.clone(), 9).unwrap();
774        assert_eq!([2, 3, 4, 5, 6, 7, 8, 0, 0], *x2.indexes);
775        let x2 = DynIntExprNode::<isize, false>::try_from_n(ix1, 10).unwrap();
776        assert_eq!([2, 3, 4, 5, 6, 7, 8, 0, 0, 0], *x2.indexes);
777
778        let ix1 = DynIntExprNode::<isize, true>::try_from_n(
779            DynIntExprNode::<isize, true>::variable(ec.clone(), 7),
780            8,
781        )
782        .unwrap();
783        // Signed N, SIGN=var -> Unsigned N
784        assert_eq!(
785            Err("Value can be negative".to_string()),
786            DynIntExprNode::<isize, false>::try_from_n(ix1.clone(), 8).map_err(|x| x.to_string())
787        );
788        // Signed N, SIGN=var -> Unsigned N+X
789        assert_eq!(
790            Err("Value can be negative".to_string()),
791            DynIntExprNode::<isize, false>::try_from_n(ix1.clone(), 9).map_err(|x| x.to_string())
792        );
793        assert_eq!(
794            Err("Value can be negative".to_string()),
795            DynIntExprNode::<isize, false>::try_from_n(ix1, 10).map_err(|x| x.to_string())
796        );
797
798        let x1 = DynIntExprNode::<isize, false>::try_from_n(
799            DynIntExprNode::<isize, false>::variable(ec.clone(), 7),
800            8,
801        )
802        .unwrap();
803        // Unsigned N, LAST=0 -> Signed N
804        let ix2 = DynIntExprNode::<isize, true>::try_from_n(x1.clone(), 8).unwrap();
805        assert_eq!([16, 17, 18, 19, 20, 21, 22, 0], *ix2.indexes);
806        // Unsigned N, LAST=0 -> Signed N+X
807        let ix2 = DynIntExprNode::<isize, true>::try_from_n(x1.clone(), 9).unwrap();
808        assert_eq!([16, 17, 18, 19, 20, 21, 22, 0, 0], *ix2.indexes);
809
810        let x1 = DynIntExprNode::<isize, false>::variable(ec.clone(), 8);
811        // Unsinged N, LAST=var -> Signed N+X
812        let ix2 = DynIntExprNode::<isize, true>::try_from_n(x1.clone(), 9).unwrap();
813        assert_eq!([23, 24, 25, 26, 27, 28, 29, 30, 0], *ix2.indexes);
814        // Unsinged N, LAST=var -> Signed N
815        assert_eq!(
816            Err("Bit overflow".to_string()),
817            DynIntExprNode::<isize, true>::try_from_n(x1.clone(), 8).map_err(|x| x.to_string())
818        );
819
820        //
821        // V[N-X..] = 0, LASTS = 0
822        let ux1 = DynIntExprNode::<isize, false>::try_from_n(
823            DynIntExprNode::<isize, false>::variable(ec.clone(), 6),
824            8,
825        )
826        .unwrap();
827        // Unsigned N, LASTS=0 -> Unsigned N-X
828        let x2 = DynIntExprNode::<isize, false>::try_from_n(ux1.clone(), 6).unwrap();
829        assert_eq!([31, 32, 33, 34, 35, 36], *x2.indexes);
830        // Unsigned N, LASTS=0, V[N-X-1]=var -> Unsigned N-X
831        assert_eq!(
832            Err("Bit overflow".to_string()),
833            DynIntExprNode::<isize, false>::try_from_n(ux1.clone(), 5).map_err(|x| x.to_string())
834        );
835        assert_eq!(
836            Err("Bit overflow".to_string()),
837            DynIntExprNode::<isize, false>::try_from_n(ux1.clone(), 4).map_err(|x| x.to_string())
838        );
839        let ix2 = DynIntExprNode::<isize, true>::try_from_n(ux1.clone(), 7).unwrap();
840        // Unsigned N, LASTS=0 -> Signed N-X+1
841        assert_eq!([31, 32, 33, 34, 35, 36, 0], *ix2.indexes);
842        // Unsigned N, LASTS=0 -> Signed N-X
843        assert_eq!(
844            Err("Bit overflow".to_string()),
845            DynIntExprNode::<isize, true>::try_from_n(ux1.clone(), 6).map_err(|x| x.to_string())
846        );
847        assert_eq!(
848            Err("Bit overflow".to_string()),
849            DynIntExprNode::<isize, true>::try_from_n(ux1.clone(), 5).map_err(|x| x.to_string())
850        );
851
852        let ix1 = DynIntExprNode::<isize, true>::try_from_n(
853            DynIntExprNode::<isize, false>::variable(ec.clone(), 6),
854            8,
855        )
856        .unwrap();
857        // Signed N, LASTS=0 -> Unsigned N-X
858        let x2 = DynIntExprNode::<isize, false>::try_from_n(ix1.clone(), 6).unwrap();
859        assert_eq!([37, 38, 39, 40, 41, 42], *x2.indexes);
860        // Signed N, LASTS=0 -> Unsigned N-X-1
861        assert_eq!(
862            Err("Bit overflow".to_string()),
863            DynIntExprNode::<isize, false>::try_from_n(ix1.clone(), 5).map_err(|x| x.to_string())
864        );
865        // Signed N, LASTS=0 -> Signed N-X+1
866        let ix2 = DynIntExprNode::<isize, true>::try_from_n(ix1.clone(), 7).unwrap();
867        assert_eq!([37, 38, 39, 40, 41, 42, 0], *ix2.indexes);
868        // Signed N, LASTS=0 -> Signed N-X
869        assert_eq!(
870            Err("Bit overflow".to_string()),
871            DynIntExprNode::<isize, true>::try_from_n(ix1.clone(), 6).map_err(|x| x.to_string())
872        );
873        assert_eq!(
874            Err("Bit overflow".to_string()),
875            DynIntExprNode::<isize, true>::try_from_n(ix1.clone(), 5).map_err(|x| x.to_string())
876        );
877
878        // constvar - this same var for all LASTS bits
879        let ix1 = DynIntExprNode::<isize, true>::try_from_n(
880            DynIntExprNode::<isize, true>::variable(ec.clone(), 6),
881            8,
882        )
883        .unwrap();
884        // Signed N, LASTS=constvar -> Unsigned N-X
885        assert_eq!(
886            Err("Bit overflow".to_string()),
887            DynIntExprNode::<isize, false>::try_from_n(ix1.clone(), 6).map_err(|x| x.to_string())
888        );
889        assert_eq!(
890            Err("Bit overflow".to_string()),
891            DynIntExprNode::<isize, false>::try_from_n(ix1.clone(), 5).map_err(|x| x.to_string())
892        );
893        // Signed N, LASTS=constvar -> Unsigned N-X+1
894        assert_eq!(
895            Err("Bit overflow".to_string()),
896            DynIntExprNode::<isize, false>::try_from_n(ix1.clone(), 7).map_err(|x| x.to_string())
897        );
898        let ix2 = DynIntExprNode::<isize, true>::try_from_n(ix1.clone(), 6).unwrap();
899        // Signed N, LASTS=constvar -> Signed N-X
900        assert_eq!([43, 44, 45, 46, 47, 48], *ix2.indexes);
901        // Signed N, LASTS=constvar -> Signed N-X-1
902        assert_eq!(
903            Err("Bit overflow".to_string()),
904            DynIntExprNode::<isize, true>::try_from_n(ix1.clone(), 5).map_err(|x| x.to_string())
905        );
906        assert_eq!(
907            Err("Bit overflow".to_string()),
908            DynIntExprNode::<isize, true>::try_from_n(ix1.clone(), 5).map_err(|x| x.to_string())
909        );
910    }
911
912    #[test]
913    fn test_expr_node_try_int_constant_n() {
914        let ec = ExprCreator::new();
915        let x1 =
916            DynIntExprNode::<isize, false>::try_constant_n(ec.clone(), 9, 0b11011001u16).unwrap();
917        assert_eq!([1, 0, 0, 1, 1, 0, 1, 1, 0], *x1.indexes);
918        let x1 =
919            DynIntExprNode::<isize, true>::try_constant_n(ec.clone(), 8, 0b00111001i16).unwrap();
920        assert_eq!([1, 0, 0, 1, 1, 1, 0, 0], *x1.indexes);
921        let x1 = DynIntExprNode::<isize, true>::try_constant_n(ec.clone(), 10, -15i8).unwrap();
922        assert_eq!([1, 0, 0, 0, 1, 1, 1, 1, 1, 1], *x1.indexes);
923        let x1 =
924            DynIntExprNode::<isize, false>::try_constant_n(ec.clone(), 64, 1848549293434211u64)
925                .unwrap();
926        assert_eq!(
927            (0..64)
928                .into_iter()
929                .map(|x| ((1848549293434211u64 >> x) & 1) as usize)
930                .collect::<Vec<_>>()
931                .as_slice(),
932            x1.indexes.as_slice()
933        );
934        let x1 = DynIntExprNode::<isize, true>::try_constant_n(ec.clone(), 1, 0i64).unwrap();
935        assert_eq!([0], *x1.indexes);
936        for i in 4..16 {
937            assert_eq!(
938                Err("Bit overflow".to_string()),
939                DynIntExprNode::<isize, false>::try_constant_n(ec.clone(), 4, 14u16 | (1u16 << i))
940                    .map_err(|x| x.to_string())
941            );
942        }
943        for i in 4..16 {
944            assert_eq!(
945                Err("Bit overflow".to_string()),
946                DynIntExprNode::<isize, true>::try_constant_n(ec.clone(), 4, 6i16 | (1i16 << i))
947                    .map_err(|x| x.to_string())
948            );
949        }
950        for i in 4..16 {
951            assert_eq!(
952                Err("Bit overflow".to_string()),
953                DynIntExprNode::<isize, true>::try_constant_n(ec.clone(), 4, (-6i16) ^ (1i16 << i))
954                    .map_err(|x| x.to_string())
955            );
956        }
957    }
958
959    #[test]
960    fn test_expr_node_bitval() {
961        let ec = ExprCreator::new();
962        let x1 = DynIntExprNode::<isize, false>::variable(ec.clone(), 7);
963        assert_eq!(x1.bit(2), BoolExprNode::single(ec.clone(), 3));
964        assert_eq!(x1.bit(6), BoolExprNode::single(ec.clone(), 7));
965        let x1 = DynIntExprNode::<isize, true>::variable(ec.clone(), 7);
966        assert_eq!(x1.bit(3), BoolExprNode::single(ec.clone(), 11));
967    }
968
969    #[test]
970    fn test_expr_node_int_equal() {
971        let ec = ExprCreator::new();
972        let x1 = DynIntExprNode::<isize, false>::variable(ec.clone(), 5);
973        let x2 = DynIntExprNode::<isize, false>::variable(ec.clone(), 5);
974        let x3 = DynIntExprNode::<isize, false>::variable(ec.clone(), 5);
975        let x4 = DynIntExprNode::<isize, false>::variable(ec.clone(), 5);
976        let reseq = x1.equal(x2);
977        let resne = x3.nequal(x4);
978
979        let exp_ec = ExprCreator::new();
980        let x1 = IntExprNode::<isize, U5, false>::variable(exp_ec.clone());
981        let x2 = IntExprNode::<isize, U5, false>::variable(exp_ec.clone());
982        let x3 = IntExprNode::<isize, U5, false>::variable(exp_ec.clone());
983        let x4 = IntExprNode::<isize, U5, false>::variable(exp_ec.clone());
984        let expeq = x1.equal(x2);
985        let expne = x3.nequal(x4);
986
987        assert_eq!(expeq, reseq);
988        assert_eq!(expne, resne);
989        assert_eq!(*exp_ec.borrow(), *ec.borrow());
990    }
991
992    macro_rules! test_int_ord_macro {
993        ($sign:expr) => {
994            let ec = ExprCreator::new();
995            let xv = (0..8)
996                .into_iter()
997                .map(|_| DynIntExprNode::<isize, $sign>::variable(ec.clone(), 5))
998                .collect::<Vec<_>>();
999            let reslt = xv[0].clone().less_than(xv[1].clone());
1000            let resle = xv[2].clone().less_equal(xv[3].clone());
1001            let resgt = xv[4].clone().greater_than(xv[5].clone());
1002            let resge = xv[6].clone().greater_equal(xv[7].clone());
1003
1004            let exp_ec = ExprCreator::new();
1005            let xv = (0..8)
1006                .into_iter()
1007                .map(|_| IntExprNode::<isize, U5, $sign>::variable(exp_ec.clone()))
1008                .collect::<Vec<_>>();
1009            let explt = xv[0].clone().less_than(xv[1].clone());
1010            let exple = xv[2].clone().less_equal(xv[3].clone());
1011            let expgt = xv[4].clone().greater_than(xv[5].clone());
1012            let expge = xv[6].clone().greater_equal(xv[7].clone());
1013
1014            assert_eq!(explt, reslt);
1015            assert_eq!(exple, resle);
1016            assert_eq!(expgt, resgt);
1017            assert_eq!(expge, resge);
1018            assert_eq!(*exp_ec.borrow(), *ec.borrow());
1019        };
1020    }
1021
1022    #[test]
1023    fn test_expr_node_int_ord() {
1024        test_int_ord_macro!(false);
1025        test_int_ord_macro!(true);
1026    }
1027}