use heyting::{answer_query_topk, FuzzyKg, Godel, Lukasiewicz, Product, Query, QueryConfig, Truth};
const ANIMAL: usize = 0;
const MAMMAL: usize = 1;
const BIRD: usize = 2;
const FISH: usize = 3;
const DOG: usize = 4;
const CAT: usize = 5;
const SPARROW: usize = 6;
const SHARK: usize = 7;
const MEAT: usize = 8;
const PLANT: usize = 9;
const NAMES: [&str; 10] = [
"animal", "mammal", "bird", "fish", "dog", "cat", "sparrow", "shark", "meat", "plant",
];
const IS_A: usize = 0;
const EATS: usize = 1;
fn build() -> FuzzyKg {
let mut kg = FuzzyKg::new(10);
for (c, p) in [
(DOG, MAMMAL),
(CAT, MAMMAL),
(SPARROW, BIRD),
(SHARK, FISH),
(MAMMAL, ANIMAL),
(BIRD, ANIMAL),
(FISH, ANIMAL),
] {
kg.add_edge(c, IS_A, p, 1.0);
}
kg.add_edge(DOG, EATS, MEAT, 1.0);
kg.add_edge(DOG, EATS, PLANT, 0.3); kg.add_edge(CAT, EATS, MEAT, 1.0);
kg.add_edge(SHARK, EATS, FISH, 0.9);
kg
}
fn show<T: Truth>(kg: &FuzzyKg, label: &str, algebra: &str, q: &Query) {
let cfg = QueryConfig::default();
let top = answer_query_topk::<T>(kg, q, &cfg, 3);
let answers: Vec<String> = top
.iter()
.filter(|(_, s)| *s > 1e-3)
.map(|(e, s)| format!("{} ({s:.2})", NAMES[*e]))
.collect();
println!("{label:<36} [{algebra:<11}] -> {}", answers.join(", "));
}
fn main() {
let kg = build();
println!(
"taxonomy: {} entities, {} edges\n",
kg.num_entities(),
kg.num_edges()
);
show::<Godel>(&kg, "1p dog is_a ?", "Godel", &Query::anchor(DOG, IS_A));
show::<Product>(
&kg,
"2p dog is_a ? is_a ?",
"Product",
&Query::anchor(DOG, IS_A).then(IS_A),
);
show::<Godel>(
&kg,
"2i (dog is_a ?) AND (cat is_a ?)",
"Godel",
&Query::intersection(vec![Query::anchor(DOG, IS_A), Query::anchor(CAT, IS_A)]),
);
show::<Godel>(
&kg,
"2u (dog is_a ?) OR (sparrow is_a ?)",
"Godel",
&Query::union(vec![Query::anchor(DOG, IS_A), Query::anchor(SPARROW, IS_A)]),
);
show::<Lukasiewicz>(
&kg,
"not (dog eats ?) AND NOT (cat eats ?)",
"Lukasiewicz",
&Query::intersection(vec![
Query::anchor(DOG, EATS),
Query::anchor(CAT, EATS).negate(),
]),
);
}