qualia_core_db/
qubo_compiler.rs1use crate::NQuin;
4
5pub const MAX_QUBO_VARS: usize = 128;
6
7#[derive(Debug, Clone)]
9pub struct QuboMatrix {
10 pub linear: Vec<f64>,
12 pub quadratic: Vec<(usize, usize, f64)>,
14 pub num_vars: usize,
16 pub coupler_count: usize,
18 pub couplers: Vec<Coupler>,
20 pub index_map: Vec<(u64, u64)>,
22 pub index_count: usize,
24}
25
26#[derive(Debug, Clone)]
28pub struct Coupler {
29 pub var_a: usize,
30 pub var_b: usize,
31 pub weight: f64,
32}
33
34impl Default for QuboMatrix {
35 fn default() -> Self {
36 Self::new(MAX_QUBO_VARS)
37 }
38}
39
40impl QuboMatrix {
41 pub fn new(num_vars: usize) -> Self {
43 Self {
44 linear: vec![0.0; num_vars],
45 quadratic: Vec::new(),
46 num_vars,
47 coupler_count: 0,
48 couplers: Vec::new(),
49 index_map: vec![(0, 0); num_vars],
50 index_count: 0,
51 }
52 }
53
54 pub fn set_linear(&mut self, var: usize, value: f64) {
56 if var < self.linear.len() {
57 self.linear[var] = value;
58 }
59 }
60
61 pub fn set_quadratic(&mut self, var1: usize, var2: usize, value: f64) {
63 if var1 < self.linear.len() && var2 < self.linear.len() {
64 self.coupler_count += 1;
65 self.couplers.push(Coupler {
66 var_a: var1,
67 var_b: var2,
68 weight: value,
69 });
70 self.quadratic.push((var1, var2, value));
71 }
72 }
73
74 pub fn emit_coupler(&mut self, var_a: usize, var_b: usize, weight: f64) {
76 self.couplers.push(Coupler {
77 var_a,
78 var_b,
79 weight,
80 });
81 self.coupler_count += 1;
82 }
83}
84
85pub fn solve_classical(matrix: &QuboMatrix, assignment: &mut [u8]) -> f32 {
87 let mut energy = 0.0f32;
89 for i in 0..matrix.num_vars.min(assignment.len()) {
90 assignment[i] = if matrix.linear[i] > 0.0 { 0 } else { 1 };
91 energy += matrix.linear[i] as f32 * assignment[i] as f32;
92 }
93 energy
94}
95
96pub fn compile_quins_to_qubo(quins: &[NQuin], matrix: &mut QuboMatrix) -> Result<(), String> {
98 for quin in quins.iter().take(MAX_QUBO_VARS) {
100 let var = quin.object as usize % MAX_QUBO_VARS;
101 matrix.set_linear(var, quin.predicate as f64);
102 }
103 Ok(())
104}
105
106pub fn rehydrate_solution(matrix: &mut QuboMatrix, assignment: &[u8], out: &mut [NQuin]) -> usize {
108 let mut count = 0;
110 for (i, &val) in assignment.iter().enumerate().take(out.len()) {
111 if i < matrix.num_vars {
112 out[count] = NQuin {
113 subject: i as u64,
114 predicate: val as u64,
115 object: 0,
116 context: 0,
117 metadata: 0,
118 parity: 0,
119 };
120 count += 1;
121 }
122 }
123 count
124}
125
126pub fn scrub_metadata(matrix: &mut QuboMatrix) {
128 matrix.index_map.clear();
129 matrix.index_count = 0;
130}
131
132pub fn serialize_matrix(matrix: &QuboMatrix) -> Vec<u8> {
134 let mut bytes = Vec::new();
135 bytes.extend_from_slice(b"HDF5_Q42_MAGIC");
136 bytes.extend_from_slice(&(matrix.num_vars as u64).to_le_bytes());
137 bytes.extend_from_slice(&(matrix.coupler_count as u64).to_le_bytes());
138 for &val in &matrix.linear {
139 bytes.extend_from_slice(&val.to_le_bytes());
140 }
141 for coupler in &matrix.couplers {
142 bytes.extend_from_slice(&(coupler.var_a as u64).to_le_bytes());
143 bytes.extend_from_slice(&(coupler.var_b as u64).to_le_bytes());
144 bytes.extend_from_slice(&coupler.weight.to_le_bytes());
145 }
146 bytes
147}
148
149#[cfg(not(target_arch = "wasm32"))]
151pub fn publish_to_commons(
152 matrix: &mut QuboMatrix,
153 storage_path: &std::path::Path,
154) -> Result<String, String> {
155 scrub_metadata(matrix);
156 let bytes = serialize_matrix(matrix);
157
158 let commons_dir = storage_path.join("commons");
159 std::fs::create_dir_all(&commons_dir).map_err(|e| e.to_string())?;
160
161 let file_path = commons_dir.join("quantum_cache.q42");
162 std::fs::write(&file_path, bytes).map_err(|e| e.to_string())?;
163
164 let info_hash = crate::webtorrent_seeder::sha1_file(&file_path)?;
165 let req = crate::webtorrent_seeder::RegisterSeedRequest {
166 info_hash: info_hash.clone(),
167 file_path: file_path.to_str().unwrap().to_string(),
168 display_name: "quantum_cache.q42".to_string(),
169 ontology_id: "quantum_commons".to_string(),
170 bandwidth_limit_kbps: 1024,
171 commons_asserted: true,
172 };
173
174 if let Some(_existing) = crate::webtorrent_seeder::lookup_seed(&info_hash) {
176 crate::webtorrent_seeder::deprecate_seed(&info_hash);
177 }
178
179 crate::webtorrent_seeder::register_seed(req)?;
180 Ok(crate::webtorrent_seeder::build_magnet_uri(
181 &info_hash,
182 "quantum_cache.q42",
183 4242,
184 ))
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn test_rigorous_metadata_scrubbing() {
193 let mut matrix = QuboMatrix::new(2);
194 matrix.index_map.push((12345, 67890));
196 matrix.index_count = 1;
197
198 scrub_metadata(&mut matrix);
200
201 assert_eq!(matrix.index_count, 0);
203 assert!(
204 matrix.index_map.is_empty(),
205 "Index map was not fully scrubbed!"
206 );
207 }
208}