use std::collections::HashSet;
use bit_set::BitSet;
use crate::FormalContext;
pub trait ImplicationEngine<T> {
fn compute_basis(&self, context: &FormalContext<T>) -> Vec<(BitSet, BitSet)>;
fn compute_named_basis(&self, context: &FormalContext<T>) -> Vec<(HashSet<T>, HashSet<T>)>
where
T: Eq + std::hash::Hash + Clone,
{
self.compute_basis(context)
.into_iter()
.map(|(premise_bits, conclusion_bits)| {
let premise = premise_bits.iter().map(|i| context.attributes[i].clone()).collect();
let conclusion = conclusion_bits.iter().map(|i| context.attributes[i].clone()).collect();
(premise, conclusion)
})
.collect()
}
}
#[cfg(test)]
mod tests {
use std::{collections::HashSet, fs};
use crate::{algorithms::CanonicalBasis, traits::ImplicationEngine, FormalContext};
#[test]
fn test_compute_named_basis_matches_context_canonical_basis() {
let ctx = FormalContext::<String>::from(
&fs::read("test_data/living_beings_and_water.cxt").unwrap(),
)
.unwrap();
let via_trait: Vec<(HashSet<String>, HashSet<String>)> =
CanonicalBasis.compute_named_basis(&ctx);
let via_method: Vec<(HashSet<String>, HashSet<String>)> = ctx.canonical_basis();
assert_eq!(via_trait.len(), via_method.len());
for pair in &via_trait {
assert!(
via_method.contains(pair),
"implication {:?} missing from context.canonical_basis()",
pair
);
}
}
}