diff --git a/Cargo.lock b/Cargo.lock index da6aa0e..08bc4ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,23 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "itertools" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" +dependencies = [ + "either", +] + [[package]] name = "kv" version = "0.0.1" +dependencies = [ + "itertools", +] diff --git a/Cargo.toml b/Cargo.toml index 581c07e..29e311c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,4 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +itertools = "0.10.0" diff --git a/src/lib.rs b/src/lib.rs index a490061..f857a88 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +use itertools::Itertools; + pub type Variable = usize; pub const A: Variable = 1 << 0; @@ -43,59 +45,43 @@ impl From for Output { pub type FunctionSpec = Vec; -pub fn find_groups(func: &FunctionSpec, vars: &mut [Variable], typ: Output) -> Vec> { - find_recursive(func, vars, typ, vec![], 0, !0) -} - -fn find_recursive(func: &FunctionSpec, vars: &mut [Variable], typ: Output, set: Vec<(Variable, Output)>, mask: Variable, inv_mask: Variable) -> Vec> { - let mut groups = Vec::new(); - for i in 0..vars.len() { - let var = vars[i]; - if var == 0 { - continue; // already set - } - let mut fits_var_1 = true; - let mut fits_var_0 = true; - for input in 0..func.len() { - if !(input & inv_mask == input && input | mask == input) { - continue; - } - if input & var != 0 { - if func[input] == typ.invert() { - fits_var_1 = false; +pub fn find_groups(func: &FunctionSpec, vars: &[Variable], typ: Output) -> Vec> { + let mut groups: Vec> = Vec::new(); + for k in 1..vars.len()+1 { + for vars in vars.iter().combinations(k) { + for var_bits in 0..(1 << k) { + let var_setting: Vec<_> = vars + .iter() + .enumerate() + .map(|(i, &&var)| (var, ((var_bits >> i) & 1).into())) + .collect(); + if groups.iter().any(|x| subset_of(x, &var_setting)) { + continue; } - } else { - if func[input] == typ.invert() { - fits_var_0 = false; + let mut mask = 0; + let mut inv_mask = !0; + for (i, &&var) in vars.iter().enumerate() { + mask |= if ((var_bits >> i) & 1) == 1 { var } else { 0 }; + inv_mask ^= if ((var_bits >> i) & 1) == 1 { 0 } else { var }; + } + let mut fits = true; + for input in 0..func.len() { + if input | mask == input && input & inv_mask == input { + if func[input] == typ.invert() { + fits = false; + break; + } + } + } + if fits { + groups.push(var_setting); } } - if !fits_var_0 && !fits_var_1 { - break; - } - } - if fits_var_1 { - let mut new_group = set.clone(); - new_group.push((var, One)); - groups.push(new_group); - } else { - let mut set2 = set.clone(); - set2.push((var, One)); - vars[i] = 0; - groups.extend(find_recursive(func, vars, typ, set2, mask | var, inv_mask)); - vars[i] = var; - } - - if fits_var_0 { - let mut new_group = set.clone(); - new_group.push((var, Zero)); - groups.push(new_group); - } else { - let mut set2 = set.clone(); - set2.push((var, Zero)); - vars[i] = 0; - groups.extend(find_recursive(func, vars, typ, set2, mask, inv_mask ^ var)); - vars[i] = var; } } groups +} + +fn subset_of(a: &[T], b: &[T]) -> bool { + a.iter().all(|x| b.contains(x)) } \ No newline at end of file