///|
/// A prime-implicant chart. Each entry in `coverers` corresponds to the
/// minterm at the same index and contains indexes into `primes`.
pub struct CoverageChart {
minterms : Array[Int32]
primes : Array[Cube]
coverers : Array[Array[Int32]]
}
///|
fn compare_cubes(left : Cube, right : Cube) -> Int32 {
for bit in 0..> shift) & 1) == 1 {
0
} else if ((left.value >> shift) & 1) == 0 {
1
} else {
2
}
let right_rank = if ((right.wildcard >> shift) & 1) == 1 {
0
} else if ((right.value >> shift) & 1) == 0 {
1
} else {
2
}
if left_rank < right_rank {
return -1
}
if left_rank > right_rank {
return 1
}
}
0
}
///|
/// Build a row-to-prime coverage chart from a validated table and its
/// refinement result.
pub fn make_coverage_chart(
spec : TruthSpec,
refinement : Refinement,
) -> CoverageChart {
let primes = refinement.primes.copy()
primes.sort_by(compare_cubes)
let coverers : Array[Array[Int32]] = []
for row in spec.on_set {
let row_coverers : Array[Int32] = []
for i in 0.. Array[Int32] {
let essential : Array[Int32] = []
for coverers in self.coverers {
if coverers.length() == 1 {
let index = coverers[0]
if !essential.contains(index) {
essential.push(index)
}
}
}
essential
}
///|
/// Return every prime implicant that uniquely covers at least one required
/// minterm, in the chart's deterministic pattern order.
pub fn CoverageChart::essential_implicants(self : CoverageChart) -> Array[Cube] {
self.essential_indices().map(index => self.primes[index])
}
///|
test "coverage chart maps each required row to its prime implicants" {
let spec = match TruthSpec::new(3, [7, 1, 5, 3], []) {
Some(spec) => spec
None => fail("valid truth table was rejected")
}
let chart = make_coverage_chart(spec, refine(spec))
assert_eq(chart.minterms, [7, 1, 5, 3])
assert_eq(chart.primes.length(), 1)
assert_eq(chart.primes[0].pattern(), "--1")
assert_eq(chart.coverers, [[0], [0], [0], [0]])
}
///|
test "coverage chart omits don't-care-only rows" {
let spec = match TruthSpec::new(3, [1], [3]) {
Some(spec) => spec
None => fail("valid truth table was rejected")
}
let chart = make_coverage_chart(spec, refine(spec))
assert_eq(chart.minterms, [1])
assert_eq(chart.coverers, [[0]])
}
///|
test "essential implicants are the unique coverers of required rows" {
let spec = match TruthSpec::new(3, [0, 1, 6, 7], []) {
Some(spec) => spec
None => fail("valid truth table was rejected")
}
let chart = make_coverage_chart(spec, refine(spec))
let essential = chart.essential_implicants()
assert_eq(essential.length(), 2)
assert_eq(essential[0].pattern(), "00-")
assert_eq(essential[1].pattern(), "11-")
}