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