qualia_core_db/
qpu_ingress.rs1use crate::NQuin;
4
5pub const MAX_QPU_SAMPLES: usize = 64;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum QpuIngressError {
9 InvalidPayload,
10 SampleBufferFull,
11}
12
13pub fn parse_dwave_samples(
15 json: &str,
16 out_bits: &mut [u8; MAX_QPU_SAMPLES],
17 out_len: &mut usize,
18) -> Result<(), QpuIngressError> {
19 let v: serde_json::Value =
20 serde_json::from_str(json).map_err(|_| QpuIngressError::InvalidPayload)?;
21 let samples = v
22 .pointer("/solutions/0/solutions")
23 .or_else(|| v.pointer("/samples"))
24 .and_then(|s| s.as_array())
25 .ok_or(QpuIngressError::InvalidPayload)?;
26
27 *out_len = 0;
28 if let Some(first) = samples.first() {
29 if let Some(sample_str) = first.get("sample").and_then(|s| s.as_array()) {
30 for bit in sample_str {
31 if *out_len >= MAX_QPU_SAMPLES {
32 return Err(QpuIngressError::SampleBufferFull);
33 }
34 out_bits[*out_len] = bit.as_i64().unwrap_or(0) as u8;
35 *out_len += 1;
36 }
37 return Ok(());
38 }
39 if let Some(sample_obj) = first.as_object() {
40 let mut idx = 0usize;
41 while sample_obj.contains_key(&idx.to_string()) {
42 if idx >= MAX_QPU_SAMPLES {
43 return Err(QpuIngressError::SampleBufferFull);
44 }
45 out_bits[idx] = sample_obj[&idx.to_string()].as_i64().unwrap_or(0) as u8;
46 idx += 1;
47 }
48 *out_len = idx;
49 return Ok(());
50 }
51 }
52 Err(QpuIngressError::InvalidPayload)
53}
54
55pub fn parse_ibm_counts(
57 json: &str,
58 out_bits: &mut [u8; MAX_QPU_SAMPLES],
59 out_len: &mut usize,
60) -> Result<(), QpuIngressError> {
61 let v: serde_json::Value =
62 serde_json::from_str(json).map_err(|_| QpuIngressError::InvalidPayload)?;
63 let counts = v
64 .pointer("/results/0/data/counts")
65 .or_else(|| v.pointer("/counts"))
66 .and_then(|c| c.as_object())
67 .ok_or(QpuIngressError::InvalidPayload)?;
68
69 let (best_key, _) = counts
70 .iter()
71 .max_by_key(|(_, v)| v.as_i64().unwrap_or(0))
72 .ok_or(QpuIngressError::InvalidPayload)?;
73
74 *out_len = 0;
75 for ch in best_key.chars() {
76 if *out_len >= MAX_QPU_SAMPLES {
77 return Err(QpuIngressError::SampleBufferFull);
78 }
79 out_bits[*out_len] = if ch == '1' { 1 } else { 0 };
80 *out_len += 1;
81 }
82 Ok(())
83}
84
85pub fn bits_to_provenance_quins(bits: &[u8], num_vars: u8, out: &mut [NQuin]) -> usize {
87 let mut n = 0usize;
88 for (i, &b) in bits.iter().enumerate().take(num_vars as usize) {
89 if n >= out.len() {
90 break;
91 }
92 let predicate = crate::q_hash("q42:qpuBit");
93 let context = crate::q_hash("q42:qpuIngress");
94 let subject = i as u64;
95 let object = b as u64;
96 let q = NQuin {
97 subject,
98 predicate,
99 object,
100 context,
101 metadata: 0xC000_0000_0000_0001,
102 parity: subject ^ predicate ^ object ^ context,
103 };
104 out[n] = q;
105 n += 1;
106 }
107 n
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn parse_ibm_counts_bitstring() {
116 let json = r#"{"counts":{"101":42,"010":1}}"#;
117 let mut bits = [0u8; MAX_QPU_SAMPLES];
118 let mut len = 0;
119 parse_ibm_counts(json, &mut bits, &mut len).unwrap();
120 assert_eq!(len, 3);
121 assert_eq!(bits[0], 1);
122 assert_eq!(bits[1], 0);
123 assert_eq!(bits[2], 1);
124 }
125}