1use crate::NQuin;
2
3const DL_MAX_CLASSES: usize = 256;
5
6pub fn check_subsumption_quin(
14 sub_class_hash: u64,
15 super_class_hash: u64,
16 tbox: &[NQuin], ) -> bool {
18 if sub_class_hash == super_class_hash {
19 return true;
20 }
21 let mut frontier = [0u64; DL_MAX_CLASSES];
22 let mut visited = [0u64; DL_MAX_CLASSES];
23 let mut fl = 1usize; let mut vl = 0usize; frontier[0] = sub_class_hash;
26
27 while fl > 0 {
28 fl -= 1;
29 let current = frontier[fl];
30 if visited[..vl].contains(¤t) {
31 continue;
32 }
33 if vl < DL_MAX_CLASSES {
34 visited[vl] = current;
35 vl += 1;
36 } else {
37 break; }
39 for quin in tbox {
40 if quin.subject == current {
41 let parent = quin.object;
42 if parent == super_class_hash {
43 return true;
44 }
45 if fl < DL_MAX_CLASSES && !visited[..vl].contains(&parent) {
46 frontier[fl] = parent;
47 fl += 1;
48 }
49 }
50 }
51 }
52 false
53}
54
55pub fn concepts_disjoint(a: u64, b: u64, disjoint: &[(u64, u64)]) -> bool {
66 disjoint
67 .iter()
68 .any(|&(c1, c2)| (c1 == a && c2 == b) || (c1 == b && c2 == a))
69}
70
71pub fn abox_clash(types: &[u64], disjoint: &[(u64, u64)], tbox: &[NQuin]) -> bool {
75 for (i, &t1) in types.iter().enumerate() {
76 for &t2 in &types[i + 1..] {
77 if concepts_disjoint(t1, t2, disjoint) {
78 return true;
79 }
80 for &(d1, d2) in disjoint {
81 if (check_subsumption_quin(t1, d1, tbox) && check_subsumption_quin(t2, d2, tbox))
82 || (check_subsumption_quin(t1, d2, tbox)
83 && check_subsumption_quin(t2, d1, tbox))
84 {
85 return true;
86 }
87 }
88 }
89 }
90 false
91}
92
93#[inline]
96pub fn role_subsumes(sub_role: u64, super_role: u64, rbox: &[NQuin]) -> bool {
97 check_subsumption_quin(sub_role, super_role, rbox)
98}
99
100#[inline]
102pub fn is_transitive_role(role: u64, transitive_roles: &[u64]) -> bool {
103 transitive_roles.contains(&role)
104}
105
106pub fn count_qualified_fillers(
110 individual: u64,
111 role: u64,
112 filler_class: u64,
113 abox: &[NQuin],
114 type_assertions: &[(u64, u64)],
115 tbox: &[NQuin],
116) -> usize {
117 let mut count = 0usize;
118 for e in abox {
119 if e.subject == individual && e.predicate == role {
120 let succ = e.object;
121 if type_assertions
122 .iter()
123 .any(|&(s, c)| s == succ && check_subsumption_quin(c, filler_class, tbox))
124 {
125 count += 1;
126 }
127 }
128 }
129 count
130}
131
132#[inline]
134pub fn min_cardinality_met(actual: usize, n: usize) -> bool {
135 actual >= n
136}
137
138#[inline]
140pub fn max_cardinality_met(actual: usize, n: usize) -> bool {
141 actual <= n
142}
143
144#[inline]
147pub fn is_nominal_instance(individual: u64, nominal_individual: u64) -> bool {
148 individual == nominal_individual
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn test_check_subsumption_quin() {
157 let tbox = vec![
158 NQuin {
159 subject: 10,
160 predicate: 0,
161 object: 20,
162 context: 0,
163 metadata: 0,
164 parity: 0,
165 },
166 NQuin {
167 subject: 20,
168 predicate: 0,
169 object: 30,
170 context: 0,
171 metadata: 0,
172 parity: 0,
173 },
174 ];
175
176 assert_eq!(check_subsumption_quin(10, 10, &tbox), true);
177 assert_eq!(check_subsumption_quin(10, 20, &tbox), true);
178 assert_eq!(check_subsumption_quin(10, 30, &tbox), true);
179 assert_eq!(check_subsumption_quin(10, 40, &tbox), false);
180 assert_eq!(check_subsumption_quin(20, 10, &tbox), false);
181 }
182
183 #[test]
185 fn multiple_inheritance_dag() {
186 let e = |s: u64, o: u64| NQuin {
187 subject: s,
188 predicate: 1,
189 object: o,
190 context: 0,
191 metadata: 0,
192 parity: 0,
193 };
194 let (np, agent, human, moral) = (1u64, 2u64, 3u64, 4u64);
195 let tbox = [
196 e(np, agent), e(np, human), e(human, moral), e(agent, moral), ];
201 assert!(check_subsumption_quin(np, agent, &tbox), "via first parent");
202 assert!(
203 check_subsumption_quin(np, human, &tbox),
204 "via SECOND parent (multiple inheritance)"
205 );
206 assert!(
207 check_subsumption_quin(np, moral, &tbox),
208 "transitively via either diamond path"
209 );
210 assert!(
211 !check_subsumption_quin(agent, human, &tbox),
212 "Agent is not a HumanBeing"
213 );
214 }
215
216 #[test]
217 fn disjointness_clash_detection() {
218 let sub = 1u64; let e = |s: u64, o: u64| NQuin {
220 subject: s,
221 predicate: sub,
222 object: o,
223 context: 0,
224 metadata: 0,
225 parity: 0,
226 };
227 let (human, robot, agent, machine) = (10u64, 20u64, 30u64, 40u64);
228 let tbox = [e(human, agent), e(robot, machine)]; let disjoint = [(agent, machine)]; assert!(concepts_disjoint(agent, machine, &disjoint));
232 assert!(abox_clash(&[human, robot], &disjoint, &tbox));
234 assert!(!abox_clash(&[human, agent], &disjoint, &tbox));
236 }
237
238 #[test]
239 fn roles_cardinality_nominals() {
240 let sp = 7u64;
241 let e = |s: u64, o: u64| NQuin {
242 subject: s,
243 predicate: sp,
244 object: o,
245 context: 0,
246 metadata: 0,
247 parity: 0,
248 };
249 let (has_mother, has_parent) = (100u64, 200u64);
250 let rbox = [e(has_mother, has_parent)]; assert!(role_subsumes(has_mother, has_parent, &rbox));
252 assert!(!role_subsumes(has_parent, has_mother, &rbox));
253 assert!(is_transitive_role(
254 crate::q_hash("role:ancestorOf"),
255 &[crate::q_hash("role:ancestorOf")]
256 ));
257
258 let role = crate::q_hash("role:hasChild");
260 let student = crate::q_hash("class:Student");
261 let (alice, bob, cara) = (
262 crate::q_hash("ind:alice"),
263 crate::q_hash("ind:bob"),
264 crate::q_hash("ind:cara"),
265 );
266 let mut a1 = NQuin {
267 subject: alice,
268 predicate: role,
269 object: bob,
270 context: 0,
271 metadata: 0,
272 parity: 0,
273 };
274 a1.parity = a1.subject ^ a1.predicate ^ a1.object;
275 let mut a2 = a1;
276 a2.object = cara;
277 a2.parity = a2.subject ^ a2.predicate ^ a2.object;
278 let abox = [a1, a2];
279 let types = [(bob, student), (cara, student)];
280 let n = count_qualified_fillers(alice, role, student, &abox, &types, &[]);
281 assert_eq!(n, 2);
282 assert!(min_cardinality_met(n, 2) && !min_cardinality_met(n, 3));
283 assert!(max_cardinality_met(n, 2) && !max_cardinality_met(n, 1));
284
285 assert!(is_nominal_instance(alice, alice));
287 assert!(!is_nominal_instance(bob, alice));
288 }
289}