Skip to main content

concept_graph/
subsumption.rs

1//! Subsumption over the closure, in the vocabulary FHIR `$subsumes` returns.
2
3use crate::closure::Closure;
4use crate::ordinal::Ordinal;
5
6/// The outcome of testing whether A subsumes B
7/// (<https://hl7.org/fhir/R4B/codesystem-concept-subsumption-outcome.html>).
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum Outcome {
10    /// A and B are the same concept.
11    Equivalent,
12    /// A is an ancestor of B.
13    Subsumes,
14    /// A is a descendant of B.
15    SubsumedBy,
16    /// Neither is an ancestor of the other.
17    NotSubsumed,
18}
19
20impl Outcome {
21    /// The FHIR code.
22    #[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/// Tests whether `a` subsumes `b` under `closure`.
34#[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}