1use itertools::{Itertools, fold};
2use std::collections::{HashMap, HashSet};
3
4pub fn hamming(x: u16, y: u16, mask: Option<u16>) -> u32 {
22 if let Some(mask) = mask {
23 return (mask & (x ^ y)).count_ones();
24 }
25 return (x ^ y).count_ones();
26}
27
28pub fn find_first_difference(x: u16, y: u16, mask: Option<u16>) -> usize {
47 debug_assert!(hamming(x, y, mask) >= 1, "Make sure that there is at least one different bit between mask & (x ^ y), otherwise this function will panic in optimized builds");
48
49 let to_check = match mask {
50 Some(m) => m & (x ^ y),
51 None => (x ^ y),
52 };
53
54 for i in 0..u16::BITS as usize {
55 if to_check & (1 << i) != 0 {
56 return i;
57 }
58 }
59 panic!("There is no bit set in {:0b}", to_check);
60}
61
62type MinTerm = u16;
63type GroupTable = HashMap<usize, Vec<(Vec<MinTerm>, MinTerm, MinTerm)>>;
64type VariableNumber = u16;
65
66
67pub fn simplify_bool_term(minterms: &Vec<MinTerm>, n_variables: Option<u16>) -> Vec<(u32, u32)> {
114 let (prime_implicants, n_variable_cnd) = compute_prime_implicants(minterms).unwrap();
116
117 let n_variables = match n_variables {
118 Some(n) => n,
119 None => n_variable_cnd,
120 };
121
122
123 let simplification = compute_simplified_term(&prime_implicants, n_variables);
125
126 let mut result = Vec::new();
128 for idx in simplification {
129 let (_, assignment, mask) = &prime_implicants[idx];
130 let mut set_states: u32 = 0;
131 let mut unset_states: u32 = 0;
132
133 for var in 0..n_variables {
134 if (mask >> var) & 0b1 == 1 {
135 if (assignment >> var) &0b1 == 1 {
136 set_states |= 0b1 << var
137 } else {
138 unset_states |= 0b1 << var
139 }
140 }
141 }
142 result.push((set_states, unset_states))
143 }
144
145 return result;
146}
147
148fn compute_prime_implicants(minterms: &Vec<MinTerm>) -> Result<(Vec<(Vec<MinTerm>, MinTerm, MinTerm)>, VariableNumber), &'static str> {
149 let mut group_table: GroupTable = HashMap::new();
151 let mut max_minterm = 0;
152
153 for minterm in minterms {
155 if *minterm > max_minterm {
156 max_minterm = *minterm;
157 }
158 let number_of_ones = hamming(*minterm, 0, None);
159 let group = group_table.entry(number_of_ones as usize).or_insert(vec![]);
160
161 group.push((vec![*minterm], *minterm, MinTerm::MAX));
163 }
164
165 let mut original_table: GroupTable = group_table;
166
167 loop {
170 let mut next_table: GroupTable = HashMap::new();
171 let mut group: usize = 0;
172
173 for (g1, g2) in original_table.keys().sorted().tuple_windows() {
174 let g1_entry = &original_table[g1];
175 let g2_entry = &original_table[g2];
176
177 let mut temp_hm: HashMap<Vec<MinTerm>, (usize, MinTerm, MinTerm)> = HashMap::new();
178
179 for (cnd1, minterm1, mask1) in g1_entry {
180 for (cnd2, minterm2, mask2) in g2_entry {
181 if mask1 == mask2 {
183 let mask = mask1 & mask2;
184 if hamming(*minterm1, *minterm2, Some(mask)) == 1 {
185 let different_bit_pos =
187 find_first_difference(*minterm1, *minterm2, Some(mask));
188
189 let new_mask = mask & !(1 << different_bit_pos);
190 let new_assignment = *minterm1;
191 let mut new_descriptors = vec![];
192
193 new_descriptors.extend(cnd1);
194 new_descriptors.extend(cnd2);
195 new_descriptors.sort();
196
197 temp_hm.insert(new_descriptors, (group, new_assignment, new_mask));
199 }
200 }
201 }
202 }
203 if !temp_hm.is_empty() {
204 group += 1;
205 }
206
207 for (descriptor, (group, assignment, mask)) in temp_hm.drain() {
208 let entry = next_table.entry(group).or_insert(vec![]);
209 entry.push((descriptor, assignment, mask));
210 }
211 }
212 if group == 0 {
213 break;
215 }
216 original_table = next_table;
217 }
218
219 let mut prime_implicants = Vec::new();
220 for (_, prime) in original_table.drain() {
221 prime_implicants.extend(prime);
222 }
223
224 return Ok((prime_implicants, (max_minterm as f32 + 1.).log2().floor() as u16));
225}
226
227fn needed_variables(n_variables: u16, assignment: u16, mask: u16) -> Vec<String> {
228 let mut variables: Vec<String> = vec!();
229
230 for cnd in 0..n_variables {
231 if mask >> cnd & 0b1 == 1 {
232 let offset = n_variables - cnd -1;
233 let current_char: char = char::from_u32(('A' as u16 + offset) as u32).expect("Not a char");
234
235 if assignment >> cnd & 0b1 == 1 {
236 variables.push(format!("{}", current_char));
237 } else {
238 variables.push(format!("{}'", current_char));
239 }
240 }
241 }
242 return variables;
243}
244
245fn compute_simplified_term(prime_implicants: &Vec<(Vec<MinTerm>, u16, u16)>, n_variables: u16) -> Vec<usize> {
246 let mut bool_matrix: HashMap<MinTerm, (u16, Vec<usize>)> = HashMap::new();
250 let mut prime_terms: HashSet<usize> = HashSet::new();
251
252 for (i, (descriptors, _, _)) in prime_implicants.iter().enumerate() {
253 for desc in descriptors {
254 let (counter, idx) = bool_matrix.entry(*desc).or_insert((0, Vec::new()));
255 *counter += 1;
256 idx.push(i);
257 prime_terms.insert(i);
258 }
259 }
260
261 let mut essential_prime_terms = HashSet::new();
262 for (counter, term_idx) in bool_matrix.values() {
263 if *counter == 1 {
264 essential_prime_terms.insert(term_idx[0]);
267 prime_terms.remove(&term_idx[0]);
268 }
269 }
270
271 if prime_terms.len() == 0 {
274 return essential_prime_terms.into_iter().collect();
275 }
276
277 let mut bool_matrix: HashMap<MinTerm, Vec<usize>> = HashMap::new();
279 for i in prime_terms {
280 let (descriptors, _, _) = &prime_implicants[i];
281 for desc in descriptors {
282 let idx = bool_matrix.entry(*desc).or_insert(Vec::new());
283 idx.push(i);
284 }
285 }
286
287 let mut distributives: Vec<Vec<Vec<usize>>> = bool_matrix
288 .drain()
289 .map(|(_, b)|
290 b
291 .iter()
292 .map(|&a| vec!(a))
293 .collect()
294 )
295 .collect::<Vec<Vec<Vec<usize>>>>();
296
297
298 let first = distributives.swap_remove(0);
299 let mut distributed = fold(distributives, first, |a, b| distribute(a,b));
300
301
302 let short_len = distributed[0].len();
304 let candidates = distributed.drain(..).take_while(|cnd| cnd.len() <= short_len).collect::<Vec<Vec<usize>>>();
305
306 if candidates.len() == 0 {
307 for term in &candidates[0] {
309 essential_prime_terms.insert(*term);
310 }
311 return essential_prime_terms.drain().collect();
312 }
314
315 let mut best_entry = 0;
317 let mut best_literal_count = usize::MAX;
318
319 for (i, cnd) in candidates.iter().enumerate() {
320 let count = cnd
321 .iter()
322 .map(|&idx| &prime_implicants[idx])
323 .map(|(_, a, b)| needed_variables(n_variables, *a, *b).len())
324 .sum::<usize>();
325
326 if count < best_literal_count {
327 best_literal_count = count;
328 best_entry = i;
329 }
330 }
331
332 for term in &candidates[best_entry] {
333 essential_prime_terms.insert(*term);
334 }
335 return essential_prime_terms.drain().collect();
336}
337
338fn distribute<T>(mut left: Vec<Vec<T>>, right: Vec<Vec<T>>) -> Vec<Vec<T>>
341 where T:std::clone::Clone + std::cmp::PartialEq + std::cmp::Ord + std::fmt::Debug
342{
343 let product: Vec<Vec<T>> = left
345 .drain(..)
346 .cartesian_product(right)
347 .map(|(mut a, b)| {a.extend(b); a})
348 .dedup() .map(|mut a | {
350 a.sort();
351 a.dedup(); a
353 })
354 .sorted_by(|a, b| Ord::cmp(&a.len(), &b.len()))
355 .collect();
356
357 let mut del = Vec::new();
359 for (i, term1) in product.iter().enumerate() {
360 for (j, term2) in product[i+1..].iter().enumerate() {
361 debug_assert!(term1.len() <= term2.len(), "The length of term1 is greater than of term2");
367 debug_assert!(term1.iter().tuple_windows().map(|(a,b)| a < b).all(|a| a == true), "Term1 is not sorted");
368 debug_assert!(term2.iter().tuple_windows().map(|(a,b)| a < b).all(|a| a == true), "Term2 is not sorted");
369
370 let term1_in_term2 = term1.iter().map(|a| binary_contains(&term2, &a)).all(|a| a.is_ok());
372 if term1_in_term2 {
373 del.push(i+j+1)
375 }
376 }
377 }
378 del.sort();
379 del.dedup();
380
381 let mut product = product;
382 for entry in del.into_iter().rev() {
383 product.swap_remove(entry);
384 }
385 return product;
386}
387
388fn binary_contains<T>(xs: &Vec<T>, x: &T) -> Result<usize, usize>
389where T: std::cmp::PartialOrd
390{
391 let mut size = xs.len();
392 if size == 0 {
393 return Err(0);
394 }
395
396 let mut base: usize = 0;
397 while size > 1 {
398 let half = size / 2;
399 let mid = base + half;
400 if xs[mid] <= *x {
401 base = mid;
402 }
403 size = size >> 1; }
405
406 if xs[base] == *x {
407 return Ok(base);
408 }
409 Err(base + (xs[base] < *x) as usize)
410}
411
412
413
414#[cfg(test)]
415mod tests {
416 use super::*;
417 #[test]
418 fn simplifies_if_all_one() {
419 let minterms = (0..8).collect::<Vec<u16>>();
420 assert_eq!(simplify_bool_term(&minterms, None), [(0,0)]);
421 }
422 #[test]
423 fn simplifies_if_all_zero() {
424 let minterms = vec!();
425 assert_eq!(simplify_bool_term(&minterms, None), []);
426 }
427 #[test]
428 fn simplify_1() {
429 let minterms = vec!(0, 1);
435 assert_eq!(simplify_bool_term(&minterms, Some(2)), [(0, 2)]);
436 }
437 #[test]
438 fn simplify_2() {
439 let minterms = vec!(0, 2);
445 assert_eq!(simplify_bool_term(&minterms, Some(2)), [(0, 1)]);
446 }
447 #[test]
448 fn simplify_3() {
449 let minterms = vec!(1, 2);
455 let test_solution = simplify_bool_term(&minterms, Some(2));
456 let solution = [(1, 2), (2, 1)];
457 assert!(test_solution.iter().all(|x| solution.contains(x)) && solution.iter().all(|x| test_solution.contains(x)));
458 }
459 #[test]
460 fn test_order() {
461 let minterms = vec!(1, 2, 10, 30, 16, 24, 30);
462 let solution1 = simplify_bool_term(&minterms, None);
463 let solution2 = simplify_bool_term(&minterms.into_iter().rev().collect(), None);
464
465 assert!(solution1.iter().all(|x| solution2.contains(x)) && solution2.iter().all(|x| solution1.contains(x)));
466 }
467
468 #[test]
469 fn test_doubles() {
470 let minterms = vec!(1, 2, 3, 3, 2, 1, 2, 3);
471 let test_solution = simplify_bool_term(&minterms, Some(2));
472 let solution = [(1,0), (2,0)];
473
474 assert!(solution.iter().all(|x| test_solution.contains(x)) && test_solution.iter().all(|x| solution.contains(x)));
475 }
476}