concept_graph/
subsumption.rs1use crate::closure::Closure;
4use crate::ordinal::Ordinal;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum Outcome {
10 Equivalent,
12 Subsumes,
14 SubsumedBy,
16 NotSubsumed,
18}
19
20impl Outcome {
21 #[must_use]
23 pub const fn code(self) -> &'static str {
24 match self {
25 Self::Equivalent => "equivalent",
26 Self::Subsumes => "subsumes",
27 Self::SubsumedBy => "subsumed-by",
28 Self::NotSubsumed => "not-subsumed",
29 }
30 }
31}
32
33#[must_use]
35pub fn subsumes(closure: &Closure, a: Ordinal, b: Ordinal) -> Outcome {
36 if a == b {
37 Outcome::Equivalent
38 } else if closure.is_ancestor(a, b) {
39 Outcome::Subsumes
40 } else if closure.is_ancestor(b, a) {
41 Outcome::SubsumedBy
42 } else {
43 Outcome::NotSubsumed
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::{Outcome, subsumes};
50 use crate::closure::Closure;
51 use crate::csr::Csr;
52 use crate::ordinal::Ordinal;
53
54 #[test]
55 fn the_four_outcomes() {
56 let o = Ordinal::new;
57 let is_a = Csr::build(4, [(o(1), o(0)), (o(2), o(0)), (o(3), o(1))]).expect("builds");
58 let closure = Closure::compute(&is_a).expect("acyclic");
59 assert_eq!(subsumes(&closure, o(0), o(0)), Outcome::Equivalent);
60 assert_eq!(subsumes(&closure, o(0), o(3)), Outcome::Subsumes);
61 assert_eq!(subsumes(&closure, o(3), o(0)), Outcome::SubsumedBy);
62 assert_eq!(subsumes(&closure, o(2), o(3)), Outcome::NotSubsumed);
63 assert_eq!(Outcome::SubsumedBy.code(), "subsumed-by");
64 }
65}