Full solution calculation

This commit is contained in:
Arne Keller 2021-03-15 15:33:17 +01:00
parent 388ac6c412
commit d5e3da78f9
2 changed files with 120 additions and 14 deletions

View File

@ -1,6 +1,8 @@
use itertools::Itertools;
pub type Variable = usize;
pub type Block = Vec<(Variable, Output)>;
pub type BlockRef<'a> = &'a [(Variable, Output)];
pub const A: Variable = 1 << 0;
pub const B: Variable = 1 << 1;
@ -66,7 +68,7 @@ pub fn find_groups(func: &FunctionSpec, vars: &[Variable], typ: Output) -> Vec<V
}
let mut fits = true;
for input in 0..func.len() {
if input | mask == input && input & inv_mask == input {
if check_mask(input, mask, inv_mask) {
if func[input] == typ.invert() {
fits = false;
break;
@ -82,10 +84,10 @@ pub fn find_groups(func: &FunctionSpec, vars: &[Variable], typ: Output) -> Vec<V
groups
}
pub fn find_prime<'a>(func: &FunctionSpec, vars: &[Variable], typ: Output, blocks: &'a [Vec<(Variable, Output)>]) -> Vec<&'a [(Variable, Output)]> {
pub fn find_prime<'a>(func: &FunctionSpec, vars: &[Variable], typ: Output, blocks: &'a [Block]) -> Vec<&'a [(Variable, Output)]> {
assert_eq!(func.len(), 2usize.pow(vars.len() as u32));
let block_masks = blocks.iter().map(|x| &**x)
let block_masks = blocks.iter()
.map(block_to_mask)
.collect::<Vec<_>>();
@ -95,8 +97,8 @@ pub fn find_prime<'a>(func: &FunctionSpec, vars: &[Variable], typ: Output, block
continue;
}
let mut matched = None;
for (i, (mask, inv_mask)) in block_masks.iter().enumerate() {
if input | mask == input && input & inv_mask == input {
for (i, &(mask, inv_mask)) in block_masks.iter().enumerate() {
if check_mask(input, mask, inv_mask) {
if matched.is_none() {
matched = Some(i);
} else {
@ -111,21 +113,83 @@ pub fn find_prime<'a>(func: &FunctionSpec, vars: &[Variable], typ: Output, block
prime.into_iter().enumerate().filter(|&(_, prime)| prime).map(|(i, _)| &*blocks[i]).collect()
}
pub fn all_solutions(mut func: FunctionSpec, vars: &[Variable], typ: Output, prime: &[BlockRef], other: &[Block]) -> Vec<Vec<Block>> {
assert_eq!(func.len(), 2usize.pow(vars.len() as u32));
// first mark all inputs covered by prime blocks as Any
let prime_masks = prime.iter()
.map(block_to_mask)
.collect::<Vec<_>>();
'input: for input in 0..func.len() {
if func[input] != typ {
continue;
}
for &(mask, inv_mask) in prime_masks.iter() {
if check_mask(input, mask, inv_mask) {
func[input] = Any;
continue 'input;
}
}
}
// then start recursive search
let other_masks = other.iter()
.map(block_to_mask)
.collect::<Vec<_>>();
all_recursive(func, vars, typ, other, &other_masks)
}
fn all_recursive(func: FunctionSpec, vars: &[Variable], typ: Output, other: &[Block], other_masks: &[(Variable, Variable)]) -> Vec<Vec<Block>> {
let mut all = Vec::new();
for i in 0..other.len() {
let block = &other[i];
let (mask, inv_mask) = other_masks[i];
for input in 0..func.len() {
if func[input] != typ {
continue;
}
if check_mask(input, mask, inv_mask) {
// this block is useful
// mark inputs as done
let mut func = func.clone();
for input in 0..func.len() {
if check_mask(input, mask, inv_mask) {
func[input] = Any;
}
}
let extensions = all_recursive(func, vars, typ, other, other_masks);
if extensions.is_empty() {
all.push(vec![block.clone()]);
}
for mut extension in extensions {
extension.push(block.clone());
all.push(extension);
}
}
}
}
all
}
/// a ⊆ b
fn subset_of<T: Eq>(a: &[T], b: &[T]) -> bool {
a.iter().all(|x| b.contains(x))
}
fn block_to_mask(block: &[(Variable, Output)]) -> (Variable, Variable) {
fn block_to_mask<T: AsRef<[(Variable, Output)]>>(block: T) -> (Variable, Variable) {
let mut mask = 0;
let mut inv_mask = !0;
for &(var, out) in block {
for &(var, out) in block.as_ref() {
mask |= if out == One { var } else { 0 };
inv_mask ^= if out == Zero { var } else { 0 };
}
(mask, inv_mask)
}
#[inline(always)]
fn check_mask(input: usize, mask: usize, inv_mask: usize) -> bool {
input | mask == input && input & inv_mask == input
}
pub fn print_implicate(vars: &[(Variable, Output)]) -> String {
let mut s = String::new();
for i in 0..vars.len() {
@ -141,6 +205,21 @@ pub fn print_implicate(vars: &[(Variable, Output)]) -> String {
s
}
pub fn print_implicant(vars: &[(Variable, Output)]) -> String {
let mut s = String::new();
for i in 0..vars.len() {
let (var, out) = vars[i];
if out == Zero {
s += "~";
}
s += print_var(var);
if i != vars.len() - 1 {
s += " ";
}
}
s
}
fn print_var(var: Variable) -> &'static str {
match var {
A => "a",
@ -148,4 +227,20 @@ fn print_var(var: Variable) -> &'static str {
C => "c",
_ => "?"
}
}
}
#[test]
fn test_3var() {
let fun: FunctionSpec = vec![0, 0, 1, 0, 0, 1, 1, 1].into_iter().map(Into::into).collect();
let groups = find_groups(&fun, &mut [A, B, C], Zero);
assert_eq!(groups, vec![
vec![(A, Zero), (B, Zero)],
vec![(A, One), (C, Zero)],
vec![(B, Zero), (C, Zero)],
]);
let prime = find_prime(&fun, &mut [A, B, C], Zero, &groups);
assert_eq!(prime, vec![
vec![(A, Zero), (B, Zero)],
vec![(A, One), (C, Zero)],
]);
}

View File

@ -2,15 +2,26 @@ use kv::*;
use kv::Output::*;
fn main() {
let function = vec![0, 0, 1, 0, 0, 1, 1, 1].into_iter().map(Into::into).collect();
let groups = find_groups(&function, &mut [A, B, C], Zero);
let function = vec![0, 0, 1, 1, 1, 1, 1, 0].into_iter().map(Into::into).collect();
let groups = find_groups(&function, &[A, B, C], One);
println!("all:");
for x in &groups {
println!("{}", print_implicate(x));
println!("{}", print_implicant(x));
}
println!("prime:");
let prime = find_prime(&function, &mut [A, B, C], Zero, &groups);
for x in prime {
println!("{}", print_implicate(&x));
let prime = find_prime(&function, &[A, B, C], One, &groups);
for x in &prime {
println!("{}", print_implicant(x));
}
println!("solutions:");
let solutions = all_solutions(function, &[A, B, C], One, &prime, &groups);
for sol in solutions {
for x in &prime {
print!("{} | ", print_implicant(x));
}
for x in &sol {
print!("{} | ", print_implicant(x));
}
println!();
}
}