cnfgen/dynintexpr/
extra_arith.rs1#![cfg_attr(docsrs, feature(doc_cfg))]
4use std::fmt::Debug;
7
8use crate::dynintexpr::DynIntExprNode;
9
10use super::*;
11use crate::VarLit;
12
13impl<T, const SIGN: bool> ExtraOps for DynIntExprNode<T, SIGN>
14where
15 T: VarLit + Neg<Output = T> + Debug,
16 isize: TryFrom<T>,
17 <T as TryInto<usize>>::Error: Debug,
18 <T as TryFrom<usize>>::Error: Debug,
19 <isize as TryFrom<T>>::Error: Debug,
20{
21 type Output = Self;
22 type BoolOutput = BoolExprNode<T>;
23
24 fn count_zeros(self) -> Self::Output {
25 (!self).count_ones()
26 }
27
28 fn count_ones(self) -> Self::Output {
29 let n = self.indexes.len();
30 let mut elems = (0..n)
31 .map(|x| DynIntExprNode::filled_expr(1, self.bit(x)))
32 .collect::<Vec<_>>();
33 let mut bits = 1;
34 let creator = self.creator.clone();
35 while bits < (n << 1) {
36 let elem_len = elems.len();
37 let mut new_elems = vec![];
38 for i in 0..(elem_len >> 1) {
39 let a =
41 elems[i << 1]
42 .clone()
43 .concat(DynIntExprNode::filled(creator.clone(), 1, false));
44 let b = elems[(i << 1) + 1].clone().concat(DynIntExprNode::filled(
45 creator.clone(),
46 1,
47 false,
48 ));
49 new_elems.push(a.addc(b, BoolExprNode::single_value(creator.clone(), false)));
51 }
52 if (elem_len & 1) != 0 {
53 new_elems.push(elems.last().unwrap().clone().concat(DynIntExprNode::filled(
55 creator.clone(),
56 1,
57 false,
58 )));
59 }
60 elems = new_elems;
61 bits <<= 1;
62 }
63 DynIntExprNode::from_boolexprs((0..n).map(|x| {
65 if x < elems[0].bitnum() {
66 elems[0].bit(x)
67 } else {
68 BoolExprNode::single_value(creator.clone(), false)
69 }
70 }))
71 }
72
73 fn leading_zeros(self) -> Self::Output {
74 let n = self.indexes.len();
75 let creator = self.creator.clone();
76 let mut out_bits = vec![];
77 let mut enable = BoolExprNode::single_value(creator.clone(), true);
78 for i in 0..n {
79 let b = !self.bit(n - i - 1) & enable;
80 out_bits.push(b.clone());
81 enable = b;
82 }
83 DynIntExprNode::from_boolexprs(out_bits).count_ones()
84 }
85
86 fn leading_ones(self) -> Self::Output {
87 (!self).leading_zeros()
88 }
89
90 fn trailing_zeros(self) -> Self::Output {
91 let n = self.indexes.len();
92 let creator = self.creator.clone();
93 let mut out_bits = vec![];
94 let mut enable = BoolExprNode::single_value(creator.clone(), true);
95 for i in 0..n {
96 let b = !self.bit(i) & enable;
97 out_bits.push(b.clone());
98 enable = b;
99 }
100 DynIntExprNode::from_boolexprs(out_bits).count_ones()
101 }
102
103 fn trailing_ones(self) -> Self::Output {
104 (!self).trailing_zeros()
105 }
106
107 fn is_power_of_two(self) -> Self::BoolOutput {
108 let n = self.indexes.len();
109 let creator = self.creator.clone();
110 let mut s = BoolExprNode::single_value(creator.clone(), false);
111 let mut c = BoolExprNode::single_value(creator.clone(), false);
112 for i in 0..n {
113 let (s1, c1) = half_adder(s.clone(), self.bit(i));
114 s = s1;
115 c |= c1;
116 }
117 s & !c
118 }
119
120 fn reverse_bits(self) -> Self::Output {
121 let n = self.indexes.len();
122 DynIntExprNode::from_boolexprs((0..n).map(|x| self.bit(n - x - 1)))
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129 use crate::intexpr::IntExprNode;
130 use generic_array::typenum::*;
131
132 macro_rules! test_expr_node_op {
133 ($sign:expr, $op:ident) => {
134 let ec = ExprCreator::new();
135 let x1 = DynIntExprNode::<isize, $sign>::variable(ec.clone(), 12);
136 let res = x1.$op();
137
138 let exp_ec = ExprCreator::new();
139 let x1 = IntExprNode::<isize, U12, $sign>::variable(exp_ec.clone());
140 let exp = x1.$op();
141
142 assert_eq!(exp.indexes.as_slice(), res.indexes.as_slice());
143 assert_eq!(*exp_ec.borrow(), *ec.borrow());
144
145 let ec = ExprCreator::new();
146 let x1 = DynIntExprNode::<isize, $sign>::variable(ec.clone(), 10);
147 let res = x1.$op();
148
149 let exp_ec = ExprCreator::new();
150 let x1 = IntExprNode::<isize, U10, $sign>::variable(exp_ec.clone());
151 let exp = x1.$op();
152
153 assert_eq!(exp.indexes.as_slice(), res.indexes.as_slice());
154 assert_eq!(*exp_ec.borrow(), *ec.borrow());
155
156 let ec = ExprCreator::new();
157 let x1 = DynIntExprNode::<isize, $sign>::variable(ec.clone(), 8);
158 let res = x1.$op();
159
160 let exp_ec = ExprCreator::new();
161 let x1 = IntExprNode::<isize, U8, $sign>::variable(exp_ec.clone());
162 let exp = x1.$op();
163
164 assert_eq!(exp.indexes.as_slice(), res.indexes.as_slice());
165 assert_eq!(*exp_ec.borrow(), *ec.borrow());
166 };
167 }
168
169 macro_rules! test_expr_node_bitop {
170 ($sign:expr, $op:ident) => {
171 let ec = ExprCreator::new();
172 let x1 = DynIntExprNode::<isize, $sign>::variable(ec.clone(), 12);
173 let res = x1.$op();
174
175 let exp_ec = ExprCreator::new();
176 let x1 = IntExprNode::<isize, U12, $sign>::variable(exp_ec.clone());
177 let exp = x1.$op();
178
179 assert_eq!(exp.index, res.index);
180 assert_eq!(*exp_ec.borrow(), *ec.borrow());
181
182 let ec = ExprCreator::new();
183 let x1 = DynIntExprNode::<isize, $sign>::variable(ec.clone(), 10);
184 let res = x1.$op();
185
186 let exp_ec = ExprCreator::new();
187 let x1 = IntExprNode::<isize, U10, $sign>::variable(exp_ec.clone());
188 let exp = x1.$op();
189
190 assert_eq!(exp.index, res.index);
191 assert_eq!(*exp_ec.borrow(), *ec.borrow());
192
193 let ec = ExprCreator::new();
194 let x1 = DynIntExprNode::<isize, $sign>::variable(ec.clone(), 8);
195 let res = x1.$op();
196
197 let exp_ec = ExprCreator::new();
198 let x1 = IntExprNode::<isize, U8, $sign>::variable(exp_ec.clone());
199 let exp = x1.$op();
200
201 assert_eq!(exp.index, res.index);
202 assert_eq!(*exp_ec.borrow(), *ec.borrow());
203 };
204 }
205
206 #[test]
207 fn test_expr_node_ops() {
208 test_expr_node_op!(false, count_ones);
209 test_expr_node_op!(true, count_ones);
210 test_expr_node_op!(false, count_zeros);
211 test_expr_node_op!(true, count_zeros);
212 test_expr_node_op!(false, leading_zeros);
213 test_expr_node_op!(true, leading_zeros);
214 test_expr_node_op!(false, leading_ones);
215 test_expr_node_op!(true, leading_ones);
216 test_expr_node_op!(false, trailing_zeros);
217 test_expr_node_op!(true, trailing_zeros);
218 test_expr_node_op!(false, trailing_ones);
219 test_expr_node_op!(true, trailing_ones);
220 test_expr_node_op!(false, reverse_bits);
221 test_expr_node_op!(true, reverse_bits);
222 test_expr_node_bitop!(false, is_power_of_two);
223 test_expr_node_bitop!(true, is_power_of_two);
224 }
225}