1use std::collections::{BTreeMap, HashSet};
2
3use ontologos_core::{AxiomId, EntityId, InferenceTrace};
4use serde::Serialize;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
8#[serde(rename_all = "snake_case")]
9pub enum RlRule {
10 EqClassSub,
12 EqPropSub,
14 CharPropagate,
16 ExistentialSubProp,
18 ExistentialSubsumption,
20 TypeDomain,
22 TypeRange,
24 TypeSubclass,
26 TypeEquivalent,
28 PropSub,
30 PropInverse,
32 PropSymmetric,
34 PropTransitive,
36 SameAsClass,
38 SameAsProp,
40 PropReflexive,
42}
43
44impl RlRule {
45 #[must_use]
46 pub fn as_str(self) -> &'static str {
47 match self {
48 Self::EqClassSub => "eq_class_sub",
49 Self::EqPropSub => "eq_prop_sub",
50 Self::CharPropagate => "char_propagate",
51 Self::ExistentialSubProp => "existential_sub_prop",
52 Self::ExistentialSubsumption => "existential_subsumption",
53 Self::TypeDomain => "type_domain",
54 Self::TypeRange => "type_range",
55 Self::TypeSubclass => "type_subclass",
56 Self::TypeEquivalent => "type_equivalent",
57 Self::PropSub => "prop_sub",
58 Self::PropInverse => "prop_inverse",
59 Self::PropSymmetric => "prop_symmetric",
60 Self::PropTransitive => "prop_transitive",
61 Self::SameAsClass => "same_as_class",
62 Self::SameAsProp => "same_as_prop",
63 Self::PropReflexive => "prop_reflexive",
64 }
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
70pub struct InferenceRecord {
71 pub rule: RlRule,
72 pub premises: Vec<AxiomId>,
73 pub conclusion: AxiomId,
74}
75
76#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
78pub struct MaterializationReport {
79 pub initial_axiom_count: usize,
80 pub final_axiom_count: usize,
81 pub rdfs_inferred: usize,
82 pub inferred_by_rule: BTreeMap<RlRule, usize>,
83 #[serde(skip_serializing_if = "trace_is_empty")]
84 pub trace: InferenceTrace,
85 #[serde(skip_serializing_if = "Vec::is_empty")]
86 pub clashes: Vec<String>,
87 #[serde(skip)]
89 pub disjoint_clash_keys: HashSet<(EntityId, EntityId, EntityId)>,
90 #[serde(skip)]
92 pub same_as_clash_keys: HashSet<(EntityId, EntityId)>,
93}
94
95fn trace_is_empty(trace: &InferenceTrace) -> bool {
96 trace.steps.is_empty()
97}
98
99impl MaterializationReport {
100 #[must_use]
101 pub fn inferred_total(&self) -> usize {
102 self.final_axiom_count
103 .saturating_sub(self.initial_axiom_count)
104 }
105}