1use rustc_hash::FxHashMap as HashMap;
2
3use crate::{expr::Expr, varint::make_mask};
4
5fn distribute<F>(
7 v: &mut [Expr],
8 self_cst: fn(Vec<Expr>) -> Expr,
9 child_cst: fn(Vec<Expr>) -> Expr,
10 extractor: F,
11) -> Option<Expr>
12where
13 F: Fn(&mut [Expr]) -> Option<(usize, Vec<Expr>)>,
14{
15 if let Some((idx, terms)) = extractor(v) {
16 let mut distributed_terms: Vec<Expr> = Vec::with_capacity(terms.len());
17
18 for term in terms {
19 let mut copy = v.to_vec();
20 copy[idx] = term;
21 distributed_terms.push(self_cst(copy));
22 }
23
24 return Some(child_cst(distributed_terms));
25 }
26
27 None
28}
29
30macro_rules! distribute {
31 ($self:ident, $child:ident, $v:expr) => {
32 distribute($v, Expr::$self, Expr::$child, distribute!(@extractor $child))
33 };
34
35 (@extractor $variant:ident) => {
36 |v: &mut [Expr]| {
37 v.iter_mut().enumerate().find_map(|(i, e)| match e {
38 Expr::$variant(v) => Some((i, std::mem::take(v))),
39 _ => None,
40 })
41 }
42 };
43}
44
45fn remove_pairs(v: Vec<Expr>) -> Vec<Expr> {
47 let mut reduced = Vec::with_capacity(v.len());
48 let mut iter = v.into_iter().peekable();
49
50 while let Some(current) = iter.next() {
51 let mut count = 1;
52
53 while let Some(next) = iter.peek() {
54 if *next == current {
55 count += 1;
56 iter.next();
57 continue;
58 }
59
60 break;
61 }
62
63 if (count & 1) == 1 {
64 reduced.push(current);
65 }
66 }
67
68 reduced
69}
70
71fn dedupe(mut v: Vec<Expr>) -> Vec<Expr> {
73 v.sort();
76 v.dedup();
77 v
78}
79
80struct Reducer {
81 mask: u64,
82}
83
84#[must_use]
86enum FlattenResult {
87 Expr(Expr),
88 Vec(Vec<Expr>),
89 None,
90}
91
92impl Reducer {
93 fn flatten<F>(&self, v: Vec<Expr>, mut handler: F) -> Vec<Expr>
95 where
96 F: FnMut(Expr) -> FlattenResult,
97 {
98 let mut flat = Vec::with_capacity(v.len());
99
100 let mut stack: Vec<_> = v.into_iter().map(|e| self.reduce_masked(e)).collect();
101
102 while let Some(e) = stack.pop() {
103 match handler(e) {
104 FlattenResult::Vec(mut v) => {
105 stack.append(&mut v);
106 }
107
108 FlattenResult::Expr(e) => flat.push(e),
109
110 FlattenResult::None => {}
111 }
112 }
113
114 flat
115 }
116
117 pub fn group_terms(&self, exprs: Vec<Expr>) -> Expr {
118 let initial_len = exprs.len();
119
120 let mut map =
121 HashMap::<Expr, u64>::with_capacity_and_hasher(initial_len, Default::default());
122
123 for e in exprs.into_iter() {
124 if let Expr::Scale(c, e) = e {
125 let count = map.entry(*e).or_insert(0);
126 *count = count.wrapping_add(c);
127 } else {
128 let count = map.entry(e).or_insert(0);
129 *count = count.wrapping_add(1);
130 }
131 }
132
133 let mut out = Vec::with_capacity(map.len());
134
135 for (e, mut count) in map {
136 count &= self.mask;
137
138 if count == 0 {
139 continue;
140 }
141
142 out.push(Expr::scale(count, e));
143 }
144
145 out.sort();
146
147 if initial_len > out.len() {
148 self.reduce_masked(Expr::Add(out))
149 } else {
150 Expr::Add(out)
151 }
152 }
153
154 fn reduce_not(&self, expr: Expr) -> Expr {
156 match expr {
157 Expr::Not(x) => self.reduce_masked(*x),
159
160 Expr::Const(v) => Expr::Const(!v),
161
162 Expr::And(exprs) => {
164 Expr::Or(exprs.into_iter().map(|e| self.reduce_masked(!e)).collect())
165 }
166
167 Expr::Or(exprs) => {
169 Expr::And(exprs.into_iter().map(|e| self.reduce_masked(!e)).collect())
170 }
171
172 _ => !self.reduce_masked(expr),
173 }
174 }
175
176 fn reduce_scale(&self, scale: u64, expr: Expr) -> Expr {
178 let scale = scale & self.mask;
179
180 match scale {
181 0 => Expr::zero(),
182
183 1 => self.reduce_masked(expr),
184
185 _ => match self.reduce_masked(expr) {
186 Expr::Const(c2) => Expr::Const(scale.wrapping_mul(c2) & self.mask),
187
188 Expr::Scale(c2, e) => {
189 let c = scale.wrapping_mul(c2) & self.mask;
190 match c {
191 0 => Expr::zero(),
192 1 => *e,
193 c => c * *e,
194 }
195 }
196
197 Expr::Add(sum) => {
198 self.reduce_masked(Expr::Add(sum.into_iter().map(|e| scale * e).collect()))
200 }
201
202 other => scale * other,
203 },
204 }
205 }
206
207 fn reduce_and(&self, exprs: Vec<Expr>) -> Expr {
209 let mut c: u64 = self.mask;
210
211 let mut flat = self.flatten(exprs, |e| match e {
212 Expr::And(v) => FlattenResult::Vec(v),
213 Expr::Const(v) => {
214 c &= v;
215 FlattenResult::None
216 }
217 _ => FlattenResult::Expr(e),
218 });
219
220 c &= self.mask;
221
222 if c == 0 {
223 return Expr::zero();
224 }
225
226 if c != self.mask {
227 flat.push(Expr::Const(c));
228 }
229
230 if let Some(distributed) = distribute!(And, Xor, &mut flat) {
231 return self.reduce_masked(distributed);
232 }
233
234 flat = dedupe(flat);
235
236 match flat.len() {
237 0 => Expr::Const(u64::MAX),
238 1 => flat.remove(0),
239 _ => Expr::And(flat),
240 }
241 }
242
243 fn reduce_or(&self, exprs: Vec<Expr>) -> Expr {
244 let mut c: u64 = 0;
245
246 let mut flat = self.flatten(exprs, |e| match e {
247 Expr::Or(v) => FlattenResult::Vec(v),
248 Expr::Const(v) => {
249 c |= v;
250 FlattenResult::None
251 }
252 _ => FlattenResult::Expr(e),
253 });
254
255 c &= self.mask;
256
257 if c != 0 {
258 flat.push(Expr::Const(c));
259 }
260
261 if let Some(distributed) = distribute!(Or, And, &mut flat) {
262 return self.reduce_masked(distributed);
263 }
264
265 flat = dedupe(flat);
266
267 match flat.len() {
268 0 => Expr::zero(),
269 1 => flat.remove(0),
270 _ => Expr::Or(flat),
271 }
272 }
273
274 fn reduce_xor(&self, exprs: Vec<Expr>) -> Expr {
275 let mut c: u64 = 0;
276
277 let mut flat = self.flatten(exprs, |e| match e {
278 Expr::Xor(v) => FlattenResult::Vec(v),
279 Expr::Const(v) => {
280 c ^= v;
281 FlattenResult::None
282 }
283 _ => FlattenResult::Expr(e),
284 });
285
286 c &= self.mask;
287
288 if c != 0 {
289 flat.push(Expr::Const(c));
290 }
291
292 flat = remove_pairs(flat);
293
294 match flat.len() {
295 0 => Expr::zero(),
296 1 => flat.remove(0),
297 _ => Expr::Xor(flat),
298 }
299 }
300
301 fn reduce_add(&self, exprs: Vec<Expr>) -> Expr {
302 if self.mask == 1 {
304 return self.reduce_xor(exprs);
305 }
306
307 let mut c: u64 = 0;
308
309 let mut flat = self.flatten(exprs, |e| match e {
310 Expr::Add(v) => FlattenResult::Vec(v),
311 Expr::Const(v) => {
312 c = c.wrapping_add(v);
313 FlattenResult::None
314 }
315 _ => FlattenResult::Expr(e),
316 });
317
318 c &= self.mask;
319
320 if c != 0 {
321 flat.push(Expr::Const(c));
322 }
323
324 match flat.len() {
325 0 => Expr::zero(),
326 1 => flat.remove(0),
327 _ => self.group_terms(flat),
328 }
329 }
330
331 fn reduce_mul(&self, exprs: Vec<Expr>) -> Expr {
332 if self.mask == 1 {
334 return self.reduce_and(exprs);
335 }
336
337 let mut c: u64 = 1;
338
339 let mut flat = self.flatten(exprs, |e| match e {
340 Expr::Mul(v) => FlattenResult::Vec(v),
341 Expr::Const(v) => {
342 c = c.wrapping_mul(v);
343 FlattenResult::None
344 }
345 Expr::Scale(s, v) => {
346 c = c.wrapping_mul(s);
347 FlattenResult::Expr(*v)
348 }
349 _ => FlattenResult::Expr(e),
350 });
351
352 c &= self.mask;
353
354 if c == 0 {
355 return Expr::zero();
356 }
357
358 if let Some(distributed) = distribute!(Mul, Add, &mut flat) {
359 return self.reduce_masked(Expr::scale(c, distributed));
360 }
361
362 flat.sort();
363
364 match flat.len() {
365 0 => Expr::Const(c),
366 1 => Expr::scale(c, flat.remove(0)),
367 _ => Expr::scale(c, Expr::Mul(flat)),
368 }
369 }
370
371 fn reduce_masked(&self, expr: Expr) -> Expr {
372 match expr {
373 Expr::Var(_) => expr,
374
375 Expr::Const(c) => Expr::Const(c & self.mask),
376
377 Expr::Not(expr) => self.reduce_not(*expr),
378
379 Expr::Scale(c, e) => self.reduce_scale(c, *e),
380
381 Expr::And(exprs) => self.reduce_and(exprs),
382
383 Expr::Or(exprs) => self.reduce_or(exprs),
384
385 Expr::Xor(exprs) => self.reduce_xor(exprs),
386
387 Expr::Add(exprs) => self.reduce_add(exprs),
388
389 Expr::Mul(exprs) => self.reduce_mul(exprs),
390 }
391 }
392
393 }
405
406impl Expr {
407 pub(crate) fn reduce_masked(self, mask: u64) -> Self {
408 Reducer { mask }.reduce_masked(self)
409 }
410
411 pub fn reduce(self, n: u8) -> Self {
414 self.reduce_masked(make_mask(n))
415 }
416}