use std::collections::HashSet;
use bit_set::BitSet;
use crate::FormalContext;
pub trait ConceptEnumerator<T> {
fn enumerate_concepts<'ctx>(
&self,
context: &'ctx FormalContext<T>,
) -> impl Iterator<Item = (BitSet, BitSet)> + 'ctx;
fn enumerate_named_concepts(&self, context: &FormalContext<T>) -> Vec<(HashSet<T>, HashSet<T>)>
where
T: Eq + std::hash::Hash + Clone,
{
self.enumerate_concepts(context)
.map(|(g_bits, m_bits)| {
let extent = g_bits.iter().map(|i| context.objects[i].clone()).collect();
let intent = m_bits.iter().map(|i| context.attributes[i].clone()).collect();
(extent, intent)
})
.collect()
}
}
#[cfg(test)]
mod tests {
use std::{collections::HashSet, fs};
use crate::{
algorithms::next_closure::NextClosure,
traits::ConceptEnumerator,
FormalContext,
};
#[test]
fn test_enumerate_named_concepts_matches_context_concepts() {
let ctx = FormalContext::<String>::from(
&fs::read("test_data/living_beings_and_water.cxt").unwrap(),
)
.unwrap();
let via_trait: Vec<(HashSet<String>, HashSet<String>)> =
NextClosure.enumerate_named_concepts(&ctx);
let via_method: Vec<(HashSet<String>, HashSet<String>)> = ctx.next_closure_concepts().collect();
assert_eq!(via_trait.len(), via_method.len());
for pair in &via_trait {
assert!(via_method.contains(pair), "concept {:?} missing from context.concepts()", pair);
}
}
}