#[derive(Eq, Clone)] pub enum Bool { True, False, /// can be any number in `0..32`, anything else will cause panics or wrong results Term(u8), /// needs to contain at least two elements And(Vec), /// needs to contain at least two elements Or(Vec), Not(Box), } #[cfg(feature="quickcheck")] extern crate quickcheck; #[cfg(feature="quickcheck")] impl quickcheck::Arbitrary for Bool { fn arbitrary(g: &mut G) -> Self { let mut terms = 0; arbitrary_bool(g, 10, &mut terms) } fn shrink(&self) -> Box> { match *self { Bool::And(ref v) => Box::new(v.shrink().filter(|v| v.len() > 2).map(Bool::And)), Bool::Or(ref v) => Box::new(v.shrink().filter(|v| v.len() > 2).map(Bool::Or)), Bool::Not(ref inner) => Box::new(inner.shrink().map(|b| Bool::Not(Box::new(b)))), _ => quickcheck::empty_shrinker(), } } } #[cfg(feature="quickcheck")] fn arbitrary_bool(g: &mut G, depth: usize, terms: &mut u8) -> Bool { if depth == 0 { match g.gen_range(0, 3) { 0 => Bool::True, 1 => Bool::False, 2 => arbitrary_term(g, terms), _ => unreachable!(), } } else { match g.gen_range(0, 6) { 0 => Bool::True, 1 => Bool::False, 2 => arbitrary_term(g, terms), 3 => Bool::And(arbitrary_vec(g, depth - 1, terms)), 4 => Bool::Or(arbitrary_vec(g, depth - 1, terms)), 5 => Bool::Not(Box::new(arbitrary_bool(g, depth - 1, terms))), _ => unreachable!(), } } } #[cfg(feature="quickcheck")] fn arbitrary_term(g: &mut G, terms: &mut u8) -> Bool { if *terms == 0 { Bool::Term(*terms) } else if *terms < 32 && g.gen_weighted_bool(3) { *terms += 1; // every term needs to show up at least once Bool::Term(*terms - 1) } else { Bool::Term(g.gen_range(0, *terms)) } } #[cfg(feature="quickcheck")] fn arbitrary_vec(g: &mut G, depth: usize, terms: &mut u8) -> Vec { (0..g.gen_range(2, 20)).map(|_| arbitrary_bool(g, depth, terms)).collect() } impl PartialEq for Bool { fn eq(&self, other: &Self) -> bool { use self::Bool::*; match (self, other) { (&True, &True) | (&False, &False) => true, (&Term(a), &Term(b)) => a == b, (&Not(ref a), &Not(ref b)) => a == b, (&And(ref a), &And(ref b)) | (&Or(ref a), &Or(ref b)) => { if a.len() != b.len() { return false; } for a in a { if !b.iter().any(|b| b == a) { return false; } } true }, _ => false, } } } impl std::ops::Not for Bool { type Output = Bool; fn not(self) -> Bool { use self::Bool::*; match self { True => False, False => True, t @ Term(_) => Not(Box::new(t)), And(mut v) => { for el in &mut v { *el = !std::mem::replace(el, False); } Or(v) }, Or(mut v) => { for el in &mut v { *el = !std::mem::replace(el, False); } And(v) }, Not(inner) => *inner, } } } impl std::ops::BitAnd for Bool { type Output = Self; fn bitand(self, rhs: Bool) -> Bool { use self::Bool::*; match (self, rhs) { (And(mut v), And(rhs)) => { v.extend(rhs); And(v) }, (False, _) | (_, False) => False, (b, True) | (True, b) => b, (other, And(mut v)) | (And(mut v), other) => { v.push(other); And(v) }, (a, b) => And(vec![a, b]), } } } impl std::ops::BitOr for Bool { type Output = Self; fn bitor(self, rhs: Bool) -> Bool { use self::Bool::*; match (self, rhs) { (Or(mut v), Or(rhs)) => { v.extend(rhs); Or(v) }, (False, b) | (b, False) => b, (_, True) | (True, _) => True, (other, Or(mut v)) | (Or(mut v), other) => { v.push(other); Or(v) }, (a, b) => Or(vec![a, b]), } } } impl Bool { pub fn terms(&self) -> u32 { use self::Bool::*; match *self { Term(u) => 1 << u, Or(ref a) | And(ref a) => a.iter().fold(0, |state, item| { state | item.terms() }), Not(ref a) => a.terms(), True | False => 0, } } pub fn eval(&self, terms: u32) -> bool { use self::Bool::*; match *self { True => true, False => false, Term(i) => (terms & (1 << i)) != 0, And(ref a) => a.iter().all(|item| item.eval(terms)), Or(ref a) => a.iter().any(|item| item.eval(terms)), Not(ref a) => !a.eval(terms), } } pub fn minterms(&self) -> Vec { let terms = self.terms(); let number_of_terms = terms.count_ones(); assert!((0..number_of_terms).all(|i| (terms & (1 << i)) != 0), "non-continuous naming scheme"); (0..(1 << number_of_terms)).filter(|&i| self.eval(i)).map(Term::new).collect() } pub fn simplify(&self) -> Vec { let minterms = self.minterms(); if minterms.is_empty() { return vec![Bool::False]; } let variables = self.terms().count_ones(); if variables == 0 { return vec![Bool::True]; } let essentials = essential_minterms(minterms); let expr = essentials.prime_implicant_expr(); let simple = simplify_prime_implicant_expr(expr); let shortest = simple.iter().map(Vec::len).min().unwrap(); simple.into_iter() .filter(|v| v.len() == shortest) .map(|v| { let mut v = v.into_iter() .map(|i| essentials.essentials[i as usize] .to_bool_expr(variables)); if v.len() == 1 { v.next().unwrap() } else { Bool::Or(v.collect()) } }).collect() } } impl std::fmt::Debug for Bool { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { use self::Bool::*; match *self { True => write!(fmt, "T"), False => write!(fmt, "F"), Term(i) if i > 32 => write!(fmt, "", i), Term(i) => write!(fmt, "{}", "abcdefghijklmnopqrstuvwxyzαβγδεζη".chars().nth(i as usize).unwrap()), Not(ref a) => match **a { And(_) | Or(_) => write!(fmt, "({:?})'", a), _ => write!(fmt, "{:?}'", a), }, And(ref a) => { for a in a { match *a { And(_) | Or(_) => try!(write!(fmt, "({:?})", a)), _ => try!(write!(fmt, "{:?}", a)), } } Ok(()) }, Or(ref a) => { try!(write!(fmt, "{:?}", a[0])); for a in &a[1..] { match *a { Or(_) => try!(write!(fmt, " + ({:?})", a)), _ => try!(write!(fmt, " + {:?}", a)), } } Ok(()) } } } } #[derive(Debug)] pub struct Essentials { pub minterms: Vec, pub essentials: Vec, } pub fn simplify_prime_implicant_expr(mut e: Vec>>) -> Vec> { loop { let a = e.pop().unwrap(); if let Some(b) = e.pop() { let distributed = distribute(&a, &b); let simplified = simplify(distributed); e.push(simplified); } else { return a; } } } // AA -> A // A + AB -> A // A + A -> A fn simplify(mut e: Vec>) -> Vec> { for e in &mut e { e.sort(); e.dedup(); } e.sort(); e.dedup(); let mut del = Vec::new(); for (i, a) in e.iter().enumerate() { for (j, b) in e[i..].iter().enumerate() { if a.len() < b.len() { // A + AB -> delete AB if a.iter().all(|x| b.iter().any(|y| y == x)) { del.push(j + i); } } else if b.len() < a.len() && b.iter().all(|x| a.iter().any(|y| y == x)) { // AB + A -> delete AB del.push(i); } } } del.sort(); del.dedup(); for del in del.into_iter().rev() { e.swap_remove(del); } e } // (AB + CD)(EF + GH) -> ABEF + ABGH + CDEF + CDGH fn distribute(l: &[Vec], r: &[Vec]) -> Vec> { let mut ret = Vec::new(); assert!(!l.is_empty()); assert!(!r.is_empty()); for l in l { for r in r { ret.push(l.iter().chain(r).cloned().collect()); } } ret } impl Essentials { pub fn prime_implicant_expr(&self) -> Vec>> { let mut v = Vec::new(); for t in &self.minterms { let mut w = Vec::new(); for (i, e) in self.essentials.iter().enumerate() { if e.contains(t) { assert_eq!(i as u32 as usize, i); w.push(vec![i as u32]); } } v.push(w); } v } } #[derive(Clone, Eq, Ord)] pub struct Term { dontcare: u32, term: u32, } #[cfg(feature="quickcheck")] impl quickcheck::Arbitrary for Term { fn arbitrary(g: &mut G) -> Self { Term { dontcare: u32::arbitrary(g), term: u32::arbitrary(g), } } } impl std::cmp::PartialOrd for Term { fn partial_cmp(&self, rhs: &Self) -> Option { use std::cmp::Ordering::*; match self.dontcare.partial_cmp(&rhs.dontcare) { Some(Equal) => {}, other => return other, } let l = self.term & !self.dontcare; let r = rhs.term & !rhs.dontcare; l.partial_cmp(&r) } } impl std::fmt::Debug for Term { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { for i in (0..32).rev() { if (self.dontcare & (1 << i)) == 0 { if (self.term & (1 << i)) == 0 { try!(write!(fmt, "0")); } else { try!(write!(fmt, "1")); } } else { try!(write!(fmt, "-")); } } Ok(()) } } impl std::cmp::PartialEq for Term { fn eq(&self, other: &Self) -> bool { (self.dontcare == other.dontcare) && ((self.term & !self.dontcare) == (other.term & !other.dontcare)) } } #[derive(Debug, Eq, PartialEq)] pub enum TermFromStrError { Only32TermsSupported, UnsupportedCharacter(char), } impl std::str::FromStr for Term { type Err = TermFromStrError; fn from_str(s: &str) -> Result { if s.len() > 32 { return Err(TermFromStrError::Only32TermsSupported); } let mut term = Term::new(0); for (i, c) in s.chars().rev().enumerate() { match c { '-' => term.dontcare |= 1 << i, '1' => term.term |= 1 << i, '0' => {}, c => return Err(TermFromStrError::UnsupportedCharacter(c)), } } Ok(term) } } impl Term { pub fn new(i: u32) -> Self { Term { dontcare: 0, term: i, } } pub fn with_dontcare(term: u32, dontcare: u32) -> Self { Term { dontcare: dontcare, term: term, } } pub fn combine(&self, other: &Term) -> Option { let dc = self.dontcare ^ other.dontcare; let term = self.term ^ other.term; let dc_mask = self.dontcare | other.dontcare; match (dc.count_ones(), (!dc_mask & term).count_ones()) { (0, 1) | (1, 0) => Some(Term { dontcare: dc_mask | term, term: self.term, }), _ => None, } } pub fn contains(&self, other: &Self) -> bool { ((self.dontcare | other.dontcare) == self.dontcare) && (((self.term ^ other.term) & !self.dontcare) == 0) } pub fn to_bool_expr(&self, n_variables: u32) -> Bool { assert!(self.dontcare < (1 << n_variables)); assert!(self.term < (1 << n_variables)); let mut v = Vec::new(); for bit in 0..n_variables { if (self.dontcare & (1 << bit)) == 0 { if (self.term & (1 << bit)) == 0 { v.push(Bool::Not(Box::new(Bool::Term(bit as u8)))) } else { v.push(Bool::Term(bit as u8)) } } } match v.len() { 0 => Bool::True, 1 => v.into_iter().next().unwrap(), _ => Bool::And(v), } } } pub fn essential_minterms(mut minterms: Vec) -> Essentials { minterms.sort(); let minterms = minterms; let mut terms = minterms.clone(); let mut essentials: Vec = Vec::new(); while !terms.is_empty() { let old = std::mem::replace(&mut terms, Vec::new()); let mut combined_terms = std::collections::BTreeSet::new(); for (i, term) in old.iter().enumerate() { for (other_i, other) in old[i..].iter().enumerate() { if let Some(new_term) = term.combine(other) { terms.push(new_term); combined_terms.insert(other_i + i); combined_terms.insert(i); } } if !combined_terms.contains(&i) { essentials.push(term.clone()); } } terms.sort(); terms.dedup(); } Essentials { minterms: minterms, essentials: essentials, } }