qualia_core_db/specialized_libs/qpu_bridge/
job.rs1use crate::lexicon::generate_60bit_token;
14use core::ptr;
15
16use super::*;
21
22#[repr(C)]
23pub struct QPUJobManager {
24 pub(crate) active_jobs: [QPUJob; 64],
26 pub(crate) completed_jobs: [QPUJob; 64],
28 pub(crate) job_counters: QPUJobCounters,
30 pub(crate) submission_state: QPUSubmissionState,
32}
33
34#[repr(C)]
35#[derive(Clone, Copy)]
36pub struct QPUJob {
37 pub(crate) job_id: [u8; 64],
39 pub(crate) job_type: QPUJobType,
41 pub(crate) priority: QPUJobPriority,
43 pub(crate) submitted_at: u64,
45 pub(crate) expected_completion: u64,
47 pub(crate) status: QPUJobStatus,
49 pub(crate) result_data: *const u8,
51 pub(crate) result_size: usize,
53}
54
55#[repr(u8)]
56#[derive(Clone, Copy, PartialEq)]
57pub enum QPUJobType {
58 HamiltonianMapping = 0,
59 QuantumStatePreparation = 1,
60 QuantumMeasurement = 2,
61 QuantumCircuitExecution = 3,
62 VariationalQuantumEigensolver = 4,
63 QuantumApproximateOptimization = 5,
64}
65
66#[repr(u8)]
67#[derive(Clone, Copy, PartialEq)]
68pub enum QPUJobPriority {
69 Low = 0,
70 Normal = 1,
71 High = 2,
72 Critical = 3,
73}
74
75#[repr(u8)]
76#[derive(Clone, Copy, PartialEq)]
77pub enum QPUJobStatus {
78 Queued = 0,
79 Running = 1,
80 Completed = 2,
81 Failed = 3,
82 Cancelled = 4,
83 Timeout = 5,
84}
85
86#[repr(C)]
87#[derive(Clone, Copy)]
88pub struct QPUJobCounters {
89 pub(crate) total_submitted: u64,
91 pub(crate) total_completed: u64,
93 pub(crate) total_failed: u64,
95 pub(crate) running_jobs: u32,
97 pub(crate) avg_completion_time_us: u32,
99}
100
101#[repr(u8)]
102#[derive(Clone, Copy, PartialEq)]
103pub enum QPUSubmissionState {
104 Idle = 0,
105 Submitting = 1,
106 Waiting = 2,
107 Retrieving = 3,
108}
109
110#[repr(C)]
111pub struct QPURateLimiter {
112 pub(crate) jobs_per_second: u32,
114 pub(crate) current_jobs: u32,
116 pub(crate) window_start: u64,
118 pub(crate) window_duration: u32,
120 pub(crate) quota_remaining: u32,
122}
123
124#[repr(C)]
125pub struct QPUJobSubmissionParams {
126 pub(crate) job_type: QPUJobType,
128 pub(crate) priority: QPUJobPriority,
130 pub(crate) input_data: *const u8,
132 pub(crate) input_size: usize,
134 pub(crate) expected_output_size: usize,
136 pub(crate) timeout: u32,
138}
139
140#[repr(C)]
141pub struct QPUJobResult {
142 pub(crate) job_id: [u8; 64],
144 pub(crate) success: bool,
146 pub(crate) result_data: *const u8,
148 pub(crate) result_size: usize,
150 pub(crate) execution_time_us: u64,
152 pub(crate) quantum_volume: u32,
154 pub(crate) error_code: QPUErrorCode,
156}
157
158impl QPUJobManager {
159 #[inline(always)]
160 pub const fn default() -> Self {
161 Self {
162 active_jobs: [QPUJob::default(); 64],
163 completed_jobs: [QPUJob::default(); 64],
164 job_counters: QPUJobCounters::default(),
165 submission_state: QPUSubmissionState::Idle,
166 }
167 }
168
169 pub fn allocate_job_slot(&mut self) -> Result<[u8; 64], QPUBridgeError> {
170 for i in 0..64 {
172 if self.active_jobs[i].job_id[0] == 0 {
173 let job_id = self.generate_job_id(i);
175 return Ok(job_id);
176 }
177 }
178 Err(QPUBridgeError::QueueFull)
179 }
180
181 pub fn release_job_slot(&mut self, job_id: [u8; 64]) {
182 for i in 0..64 {
184 if self.active_jobs[i].job_id == job_id {
185 self.active_jobs[i] = QPUJob::default();
186 break;
187 }
188 }
189 }
190
191 pub fn add_active_job(&mut self, job: QPUJob) {
192 for i in 0..64 {
194 if self.active_jobs[i].job_id == job.job_id {
195 self.active_jobs[i] = job;
196 self.job_counters.running_jobs += 1;
197 break;
198 }
199 }
200 }
201
202 pub fn find_active_job(&self, job_id: &[u8; 64]) -> Result<usize, QPUBridgeError> {
203 for i in 0..64 {
204 if self.active_jobs[i].job_id == *job_id {
205 return Ok(i);
206 }
207 }
208 Err(QPUBridgeError::JobNotFound)
209 }
210
211 pub fn move_to_completed(&mut self, active_index: usize) {
212 let job = self.active_jobs[active_index];
214
215 for i in 0..64 {
217 if self.completed_jobs[i].job_id[0] == 0 {
218 self.completed_jobs[i] = job;
219 break;
220 }
221 }
222
223 self.active_jobs[active_index] = QPUJob::default();
225 self.job_counters.running_jobs -= 1;
226 }
227
228 fn generate_job_id(&self, slot_index: usize) -> [u8; 64] {
229 let mut job_id = [0u8; 64];
230
231 let timestamp: u64 = 0; let hash = generate_60bit_token(×tamp.to_le_bytes()) as u64;
234
235 for i in 0..8 {
237 job_id[i] = (hash >> (i * 8)) as u8;
238 }
239
240 job_id[8] = slot_index as u8;
242
243 job_id
244 }
245}
246
247impl QPUJob {
248 #[inline(always)]
249 pub const fn default() -> Self {
250 Self {
251 job_id: [0u8; 64],
252 job_type: QPUJobType::HamiltonianMapping,
253 priority: QPUJobPriority::Normal,
254 submitted_at: 0,
255 expected_completion: 0,
256 status: QPUJobStatus::Queued,
257 result_data: ptr::null(),
258 result_size: 0,
259 }
260 }
261}
262
263impl QPUJobCounters {
264 #[inline(always)]
265 pub const fn default() -> Self {
266 Self {
267 total_submitted: 0,
268 total_completed: 0,
269 total_failed: 0,
270 running_jobs: 0,
271 avg_completion_time_us: 0,
272 }
273 }
274}
275
276impl QPURateLimiter {
277 #[inline(always)]
278 pub const fn default() -> Self {
279 Self {
280 jobs_per_second: 10,
281 current_jobs: 0,
282 window_start: 0,
283 window_duration: 1,
284 quota_remaining: 1000,
285 }
286 }
287
288 pub fn can_submit_job(&mut self, current_time: u64) -> bool {
289 if current_time - self.window_start > (self.window_duration as u64 * 1_000_000) {
291 self.window_start = current_time;
293 self.current_jobs = 0;
294 }
295
296 self.current_jobs < self.jobs_per_second && self.quota_remaining > 0
298 }
299
300 pub fn record_job_submission(&mut self, _current_time: u64) {
301 self.current_jobs += 1;
302 self.quota_remaining -= 1;
303 }
304}