qualia_core_db/inference/
agent.rs1use crate::indexing::QuinIndex;
13use crate::q_hash;
14
15pub const P_RDF_TYPE: u64 = q_hash("http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
16pub const P_OPERATED_BY: u64 = q_hash("https://ns.webcivics.net/values/operatedBy");
18
19pub const A_NATURAL_PERSON: u64 = q_hash("https://ns.webcivics.net/values/NaturalPerson");
21pub const A_LEGAL_PERSON: u64 = q_hash("https://ns.webcivics.net/values/LegalPerson");
22pub const A_PUBLIC_AUTHORITY: u64 = q_hash("https://ns.webcivics.net/values/PublicAuthority");
23pub const A_ARTIFICIAL_AGENT: u64 = q_hash("https://ns.webcivics.net/values/ArtificialAgent");
24pub const A_PLATFORM_AGENT: u64 = q_hash("https://ns.webcivics.net/values/PlatformAgent");
25
26pub fn agent_type(index: &QuinIndex, agent: u64) -> Option<u64> {
28 index.object_of(agent, P_RDF_TYPE)
29}
30
31pub fn principal_of(index: &QuinIndex, agent: u64) -> Option<u64> {
33 index.object_of(agent, P_OPERATED_BY)
34}
35
36#[inline]
38pub fn is_artificial(agent_class: u64) -> bool {
39 agent_class == A_ARTIFICIAL_AGENT || agent_class == A_PLATFORM_AGENT
40}
41
42pub fn is_ungrounded_agency(index: &QuinIndex, agent: u64) -> bool {
45 match agent_type(index, agent) {
46 Some(class) if is_artificial(class) => principal_of(index, agent).is_none(),
47 _ => false,
48 }
49}
50
51pub fn agent_type_name(class: u64) -> Option<&'static str> {
53 match class {
54 A_NATURAL_PERSON => Some("NaturalPerson"),
55 A_LEGAL_PERSON => Some("LegalPerson"),
56 A_PUBLIC_AUTHORITY => Some("PublicAuthority"),
57 A_ARTIFICIAL_AGENT => Some("ArtificialAgent"),
58 A_PLATFORM_AGENT => Some("PlatformAgent"),
59 _ => None,
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66 use crate::NQuin;
67
68 fn t(s: u64, p: u64, o: u64) -> NQuin {
69 NQuin {
70 subject: s,
71 predicate: p,
72 object: o,
73 context: 0,
74 metadata: 0,
75 parity: 0,
76 }
77 }
78
79 #[test]
80 fn resolves_agent_type() {
81 let alice = q_hash("https://example.org/alice");
82 let idx = QuinIndex::from_slice(&[t(alice, P_RDF_TYPE, A_NATURAL_PERSON)]);
83 assert_eq!(agent_type(&idx, alice), Some(A_NATURAL_PERSON));
84 assert_eq!(
85 agent_type_name(agent_type(&idx, alice).unwrap()),
86 Some("NaturalPerson")
87 );
88 }
89
90 #[test]
91 fn natural_person_is_never_ungrounded() {
92 let alice = q_hash("https://example.org/alice");
93 let idx = QuinIndex::from_slice(&[t(alice, P_RDF_TYPE, A_NATURAL_PERSON)]);
94 assert!(!is_ungrounded_agency(&idx, alice));
95 }
96
97 #[test]
98 fn artificial_agent_without_principal_is_ungrounded() {
99 let bot = q_hash("https://example.org/bot");
100 let idx = QuinIndex::from_slice(&[t(bot, P_RDF_TYPE, A_ARTIFICIAL_AGENT)]);
101 assert!(is_ungrounded_agency(&idx, bot));
103 }
104
105 #[test]
106 fn artificial_agent_with_principal_is_grounded() {
107 let bot = q_hash("https://example.org/bot");
108 let human = q_hash("https://example.org/alice");
109 let idx = QuinIndex::from_slice(&[
110 t(bot, P_RDF_TYPE, A_ARTIFICIAL_AGENT),
111 t(bot, P_OPERATED_BY, human), ]);
113 assert!(!is_ungrounded_agency(&idx, bot));
114 assert_eq!(principal_of(&idx, bot), Some(human));
115 }
116}