qualia_core_db/inference/runtime/graph_assist/
query.rs1use crate::NQuin;
2
3use super::identity::{derive_prefix_identity, PrefixIdentity};
4
5#[repr(C)]
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub struct GraphQuery {
8 pub context: u64,
10 pub subject: u64,
12 pub predicate: u64,
14 pub object: u64,
16}
17
18#[repr(C)]
19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub struct GraphAssistPolicy {
21 pub max_facts: u32,
22 pub sensitivity_ceiling: u8,
23 pub require_valid_parity: bool,
24 pub _pad: [u8; 2],
25}
26
27impl Default for GraphAssistPolicy {
28 fn default() -> Self {
29 Self {
30 max_facts: 64,
31 sensitivity_ceiling: 0,
32 require_valid_parity: true,
33 _pad: [0; 2],
34 }
35 }
36}
37
38#[derive(Clone, Copy, Debug, PartialEq, Eq)]
39pub enum GraphQueryError {
40 InvalidPolicy,
41 OutputBufferFull,
42}
43
44#[repr(C)]
45#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
46pub struct GraphSelectionReceipt {
47 pub scanned: u32,
48 pub matched: u32,
49 pub written: u32,
50 pub rejected_sensitivity: u32,
51 pub rejected_parity: u32,
52 pub prefix_identity: PrefixIdentity,
53}
54
55#[inline]
56fn matches(query: &GraphQuery, quin: &NQuin) -> bool {
57 (query.context == 0 || query.context == quin.context)
58 && (query.subject == 0 || query.subject == quin.subject)
59 && (query.predicate == 0 || query.predicate == quin.predicate)
60 && (query.object == 0 || query.object == quin.object)
61}
62
63pub fn query_graph_into(
68 graph: &[NQuin],
69 query: &GraphQuery,
70 policy: GraphAssistPolicy,
71 model_instance: u64,
72 tokenizer_revision: u64,
73 graph_revision: u64,
74 out: &mut [NQuin],
75) -> Result<GraphSelectionReceipt, GraphQueryError> {
76 if policy.max_facts == 0 {
77 return Err(GraphQueryError::InvalidPolicy);
78 }
79 let capacity = out.len().min(policy.max_facts as usize);
80 let mut receipt = GraphSelectionReceipt::default();
81 for quin in graph {
82 receipt.scanned = receipt.scanned.saturating_add(1);
83 if !matches(query, quin) {
84 continue;
85 }
86 let sensitivity = (quin.context >> 56) as u8;
87 if sensitivity > policy.sensitivity_ceiling {
88 receipt.rejected_sensitivity = receipt.rejected_sensitivity.saturating_add(1);
89 continue;
90 }
91 if policy.require_valid_parity
92 && quin.parity != (quin.subject ^ quin.predicate ^ quin.object ^ quin.context)
93 {
94 receipt.rejected_parity = receipt.rejected_parity.saturating_add(1);
95 continue;
96 }
97 receipt.matched = receipt.matched.saturating_add(1);
98 if receipt.written as usize >= capacity {
99 return Err(GraphQueryError::OutputBufferFull);
100 }
101 out[receipt.written as usize] = *quin;
102 receipt.written += 1;
103 }
104 receipt.prefix_identity = derive_prefix_identity(
105 model_instance,
106 tokenizer_revision,
107 query.context,
108 graph_revision,
109 &out[..receipt.written as usize],
110 );
111 Ok(receipt)
112}