1use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
14use std::sync::{Arc, Mutex, RwLock};
15use std::time::{Duration, SystemTime};
16
17use crate::{translation::HardwareBackend, CircuitResult};
18use quantrs2_circuit::prelude::Circuit;
19
20use serde::{Deserialize, Serialize};
21use tokio::sync::mpsc;
22use uuid::Uuid;
23
24#[derive(
26 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Default,
27)]
28pub enum JobPriority {
29 Critical = 0,
31 High = 1,
33 #[default]
35 Normal = 2,
36 Low = 3,
38 BestEffort = 4,
40}
41
42#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
44pub enum JobStatus {
45 Pending,
47 Validating,
49 Scheduled,
51 Running,
53 Completed,
55 Failed,
57 Cancelled,
59 TimedOut,
61 Retrying,
63 Paused,
65}
66
67#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
69pub enum SchedulingStrategy {
70 PriorityFIFO,
72 ShortestJobFirst,
74 ShortestRemainingTimeFirst,
76 FairShare,
78 PriorityRoundRobin,
80 Backfill,
82 EarliestDeadlineFirst,
84 RateMonotonic,
86 MLOptimized,
88 MultiObjectiveOptimized,
90 ReinforcementLearning,
92 GeneticAlgorithm,
94 GameTheoreticFair,
96 EnergyAware,
98 DeadlineAwareSLA,
100 Custom(String),
102}
103
104#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
106pub enum AllocationStrategy {
107 FirstFit,
109 BestFit,
111 WorstFit,
113 LeastLoaded,
115 MostLoaded,
117 RoundRobin,
119 WeightedRoundRobin,
121 CostOptimized,
123 PerformanceOptimized,
125 EnergyEfficient,
127 SciRS2Optimized,
129 MultiObjectiveOptimized,
131 LocalityAware,
133 FaultTolerant,
135 PredictiveAllocation,
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct JobConfig {
142 pub priority: JobPriority,
144 pub max_execution_time: Duration,
146 pub max_queue_time: Option<Duration>,
148 pub retry_attempts: u32,
150 pub retry_delay: Duration,
152 pub resource_requirements: ResourceRequirements,
154 pub preferred_backends: Vec<HardwareBackend>,
156 pub tags: HashMap<String, String>,
158 pub dependencies: Vec<JobId>,
160 pub deadline: Option<SystemTime>,
162 pub cost_limit: Option<f64>,
164}
165
166impl Default for JobConfig {
167 fn default() -> Self {
168 Self {
169 priority: JobPriority::Normal,
170 max_execution_time: Duration::from_secs(3600), max_queue_time: Some(Duration::from_secs(86400)), retry_attempts: 3,
173 retry_delay: Duration::from_secs(60),
174 resource_requirements: ResourceRequirements::default(),
175 preferred_backends: vec![],
176 tags: HashMap::new(),
177 dependencies: vec![],
178 deadline: None,
179 cost_limit: None,
180 }
181 }
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize)]
186pub struct ResourceRequirements {
187 pub min_qubits: usize,
189 pub max_depth: Option<usize>,
191 pub min_fidelity: Option<f64>,
193 pub required_connectivity: Option<String>,
195 pub memory_mb: Option<u64>,
197 pub cpu_cores: Option<u32>,
199 pub required_features: Vec<String>,
201}
202
203impl Default for ResourceRequirements {
204 fn default() -> Self {
205 Self {
206 min_qubits: 1,
207 max_depth: None,
208 min_fidelity: None,
209 required_connectivity: None,
210 memory_mb: None,
211 cpu_cores: None,
212 required_features: vec![],
213 }
214 }
215}
216
217#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
219pub struct JobId(pub String);
220
221impl Default for JobId {
222 fn default() -> Self {
223 Self::new()
224 }
225}
226
227impl JobId {
228 pub fn new() -> Self {
229 Self(Uuid::new_v4().to_string())
230 }
231
232 pub const fn from_string(s: String) -> Self {
233 Self(s)
234 }
235}
236
237impl std::fmt::Display for JobId {
238 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
239 write!(f, "{}", self.0)
240 }
241}
242
243#[derive(Debug, Clone)]
245pub struct QuantumJob<const N: usize> {
246 pub id: JobId,
248 pub config: JobConfig,
250 pub circuit: Circuit<N>,
252 pub shots: usize,
254 pub submitted_at: SystemTime,
256 pub status: JobStatus,
258 pub execution_history: Vec<JobExecution>,
260 pub metadata: HashMap<String, String>,
262 pub user_id: String,
264 pub group_id: Option<String>,
266 pub estimated_duration: Option<Duration>,
268 pub assigned_backend: Option<HardwareBackend>,
270 pub estimated_cost: Option<f64>,
272 pub actual_cost: Option<f64>,
273}
274
275#[derive(Debug, Clone, Serialize, Deserialize)]
277pub struct JobExecution {
278 pub attempt: u32,
280 pub backend: HardwareBackend,
282 pub started_at: SystemTime,
284 pub ended_at: Option<SystemTime>,
286 pub result: Option<CircuitResult>,
288 pub error: Option<String>,
290 pub metrics: ExecutionMetrics,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize)]
296pub struct ExecutionMetrics {
297 pub queue_time: Duration,
299 pub execution_time: Option<Duration>,
301 pub resource_utilization: f64,
303 pub cost: Option<f64>,
305 pub quality_metrics: HashMap<String, f64>,
307}
308
309impl Default for ExecutionMetrics {
310 fn default() -> Self {
311 Self {
312 queue_time: Duration::from_secs(0),
313 execution_time: None,
314 resource_utilization: 0.0,
315 cost: None,
316 quality_metrics: HashMap::new(),
317 }
318 }
319}
320
321#[derive(Debug, Clone)]
323pub struct BackendPerformance {
324 pub backend: HardwareBackend,
326 pub queue_length: usize,
328 pub avg_queue_time: Duration,
330 pub avg_execution_time: Duration,
332 pub success_rate: f64,
334 pub utilization: f64,
336 pub avg_cost: Option<f64>,
338 pub last_updated: SystemTime,
340 pub history: VecDeque<PerformanceSnapshot>,
342}
343
344#[derive(Debug, Clone, Serialize, Deserialize)]
346pub struct PerformanceSnapshot {
347 pub timestamp: SystemTime,
348 pub queue_length: usize,
349 pub utilization: f64,
350 pub avg_queue_time_secs: f64,
351 pub success_rate: f64,
352}
353
354#[derive(Debug, Clone)]
356pub struct QueueAnalytics {
357 pub total_queue_length: usize,
359 pub queue_by_priority: HashMap<JobPriority, usize>,
361 pub queue_by_backend: HashMap<HardwareBackend, usize>,
363 pub predicted_queue_times: HashMap<HardwareBackend, Duration>,
365 pub system_load: f64,
367 pub throughput: f64,
369 pub avg_wait_time: Duration,
371}
372
373#[derive(Debug, Clone)]
375pub struct SchedulingParams {
376 pub strategy: SchedulingStrategy,
378 pub allocation_strategy: AllocationStrategy,
380 pub time_slice: Duration,
382 pub max_jobs_per_user: Option<usize>,
384 pub fair_share_weights: HashMap<String, f64>,
386 pub backfill_threshold: Duration,
388 pub load_balance_factor: f64,
390 pub scirs2_params: SciRS2SchedulingParams,
392}
393
394#[derive(Debug, Clone)]
396pub struct SciRS2SchedulingParams {
397 pub enabled: bool,
399 pub objective_weights: HashMap<String, f64>,
401 pub learning_window: Duration,
403 pub optimization_frequency: Duration,
405 pub model_params: HashMap<String, f64>,
407 pub ml_algorithm: MLAlgorithm,
409 pub multi_objective_weights: MultiObjectiveWeights,
411 pub rl_params: RLParameters,
413 pub ga_params: GAParameters,
415 pub enable_prediction: bool,
417 pub retrain_frequency: Duration,
419 pub feature_params: FeatureParams,
421}
422
423impl Default for SciRS2SchedulingParams {
424 fn default() -> Self {
425 Self {
426 enabled: true,
427 objective_weights: [
428 ("throughput".to_string(), 0.25),
429 ("fairness".to_string(), 0.25),
430 ("utilization".to_string(), 0.2),
431 ("cost".to_string(), 0.15),
432 ("energy".to_string(), 0.1),
433 ("sla_compliance".to_string(), 0.05),
434 ]
435 .into_iter()
436 .collect(),
437 learning_window: Duration::from_secs(86400), optimization_frequency: Duration::from_secs(180), model_params: HashMap::new(),
440 ml_algorithm: MLAlgorithm::EnsembleMethod,
441 multi_objective_weights: MultiObjectiveWeights::default(),
442 rl_params: RLParameters::default(),
443 ga_params: GAParameters::default(),
444 enable_prediction: true,
445 retrain_frequency: Duration::from_secs(3600), feature_params: FeatureParams::default(),
447 }
448 }
449}
450
451impl Default for SchedulingParams {
452 fn default() -> Self {
453 Self {
454 strategy: SchedulingStrategy::MLOptimized,
455 allocation_strategy: AllocationStrategy::SciRS2Optimized,
456 time_slice: Duration::from_secs(60),
457 max_jobs_per_user: Some(100),
458 fair_share_weights: HashMap::new(),
459 backfill_threshold: Duration::from_secs(300),
460 load_balance_factor: 0.8,
461 scirs2_params: SciRS2SchedulingParams::default(),
462 }
463 }
464}
465
466pub struct QuantumJobScheduler {
468 pub(super) params: Arc<RwLock<SchedulingParams>>,
470 pub(super) job_queues: Arc<Mutex<BTreeMap<JobPriority, VecDeque<JobId>>>>,
472 pub(super) jobs: Arc<RwLock<HashMap<JobId, Box<dyn std::any::Any + Send + Sync>>>>,
474 pub(super) backend_performance: Arc<RwLock<HashMap<HardwareBackend, BackendPerformance>>>,
476 pub(super) backends: Arc<RwLock<HashSet<HardwareBackend>>>,
478 pub(super) running_jobs: Arc<RwLock<HashMap<JobId, (HardwareBackend, SystemTime)>>>,
480 pub(super) execution_history: Arc<RwLock<Vec<JobExecution>>>,
482 pub(super) user_shares: Arc<RwLock<HashMap<String, UserShare>>>,
484 pub(super) scheduler_running: Arc<Mutex<bool>>,
486 pub(super) event_sender: mpsc::UnboundedSender<SchedulerEvent>,
488 pub(super) performance_predictor: Arc<Mutex<PerformancePredictor>>,
490 pub(super) resource_manager: Arc<Mutex<ResourceManager>>,
492 pub(super) job_status_map: Arc<RwLock<HashMap<JobId, JobStatus>>>,
494 pub(super) job_config_map: Arc<RwLock<HashMap<JobId, JobConfig>>>,
496 pub(super) job_metrics_map: Arc<RwLock<HashMap<JobId, ExecutionMetrics>>>,
498}
499
500#[derive(Debug, Clone)]
502pub(super) struct UserShare {
503 pub(super) user_id: String,
504 pub(super) allocated_share: f64,
505 pub(super) used_share: f64,
506 pub(super) jobs_running: usize,
507 pub(super) jobs_queued: usize,
508 pub(super) last_updated: SystemTime,
509}
510
511#[derive(Debug, Clone)]
513pub enum SchedulerEvent {
514 JobSubmitted(JobId),
515 JobScheduled(JobId, HardwareBackend),
516 JobStarted(JobId),
517 JobCompleted(JobId, CircuitResult),
518 JobFailed(JobId, String),
519 JobCancelled(JobId),
520 BackendStatusChanged(HardwareBackend, BackendStatus),
521 QueueAnalyticsUpdated(QueueAnalytics),
522}
523
524#[derive(Debug, Clone)]
526pub enum BackendStatus {
527 Available,
528 Busy,
529 Maintenance,
530 Offline,
531 Error(String),
532}
533
534pub(super) struct PerformancePredictor {
536 pub(super) history: VecDeque<PredictionDataPoint>,
538 pub(super) model_params: HashMap<String, f64>,
540 pub(super) accuracy_metrics: HashMap<String, f64>,
542}
543
544#[derive(Debug, Clone)]
546pub(super) struct PredictionDataPoint {
547 pub(super) timestamp: SystemTime,
548 pub(super) backend: HardwareBackend,
549 pub(super) queue_length: usize,
550 pub(super) job_complexity: f64,
551 pub(super) execution_time: Duration,
552 pub(super) success: bool,
553}
554
555pub(super) struct ResourceManager {
557 pub(super) available_resources: HashMap<HardwareBackend, ResourceCapacity>,
559 pub(super) reservations: HashMap<JobId, ResourceReservation>,
561 pub(super) utilization_history: VecDeque<ResourceSnapshot>,
563}
564
565#[derive(Debug, Clone)]
567pub(super) struct ResourceCapacity {
568 pub(super) qubits: usize,
569 pub(super) max_circuit_depth: Option<usize>,
570 pub(super) memory_mb: u64,
571 pub(super) cpu_cores: u32,
572 pub(super) concurrent_jobs: usize,
573 pub(super) features: HashSet<String>,
574}
575
576#[derive(Debug, Clone)]
578pub(super) struct ResourceReservation {
579 pub(super) job_id: JobId,
580 pub(super) backend: HardwareBackend,
581 pub(super) resources: ResourceRequirements,
582 pub(super) reserved_at: SystemTime,
583 pub(super) expires_at: SystemTime,
584}
585
586#[derive(Debug, Clone)]
588pub(super) struct ResourceSnapshot {
589 pub(super) timestamp: SystemTime,
590 pub(super) backend: HardwareBackend,
591 pub(super) utilization: f64,
592 pub(super) active_jobs: usize,
593}
594
595#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
597pub enum MLAlgorithm {
598 LinearRegression,
600 SVM,
602 RandomForest,
604 GradientBoosting,
606 NeuralNetwork,
608 EnsembleMethod,
610 DeepRL,
612 GraphNN,
614}
615
616#[derive(Debug, Clone, Serialize, Deserialize)]
618pub struct MultiObjectiveWeights {
619 pub throughput: f64,
621 pub cost: f64,
623 pub energy: f64,
625 pub fairness: f64,
627 pub sla_compliance: f64,
629 pub qos: f64,
631}
632
633#[derive(Debug, Clone, Serialize, Deserialize)]
635pub struct RLParameters {
636 pub learning_rate: f64,
638 pub discount_factor: f64,
640 pub exploration_rate: f64,
642 pub episode_length: usize,
644 pub reward_weights: HashMap<String, f64>,
646 pub state_dimension: usize,
648 pub action_space_size: usize,
650}
651
652#[derive(Debug, Clone, Serialize, Deserialize)]
654pub struct GAParameters {
655 pub population_size: usize,
657 pub generations: usize,
659 pub crossover_prob: f64,
661 pub mutation_prob: f64,
663 pub selection_strategy: String,
665 pub elite_size: usize,
667}
668
669#[derive(Debug, Clone, Serialize, Deserialize)]
671pub struct FeatureParams {
672 pub enable_temporal_features: bool,
674 pub enable_complexity_features: bool,
676 pub enable_user_features: bool,
678 pub enable_platform_features: bool,
680 pub enable_historical_features: bool,
682 pub normalization_method: String,
684 pub selection_threshold: f64,
686}
687
688#[derive(Debug, Clone, Serialize, Deserialize)]
690pub struct SLAConfig {
691 pub max_queue_time: Duration,
693 pub max_execution_time: Duration,
695 pub min_availability: f64,
697 pub violation_penalty: f64,
699 pub tier: SLATier,
701}
702
703#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
705pub enum SLATier {
706 Gold,
707 Silver,
708 Bronze,
709 Basic,
710}
711
712impl Default for MultiObjectiveWeights {
714 fn default() -> Self {
715 Self {
716 throughput: 0.3,
717 cost: 0.2,
718 energy: 0.15,
719 fairness: 0.15,
720 sla_compliance: 0.1,
721 qos: 0.1,
722 }
723 }
724}
725
726impl Default for RLParameters {
727 fn default() -> Self {
728 Self {
729 learning_rate: 0.001,
730 discount_factor: 0.95,
731 exploration_rate: 0.1,
732 episode_length: 1000,
733 reward_weights: [
734 ("throughput".to_string(), 1.0),
735 ("fairness".to_string(), 0.5),
736 ("cost".to_string(), -0.3),
737 ]
738 .into_iter()
739 .collect(),
740 state_dimension: 64,
741 action_space_size: 16,
742 }
743 }
744}
745
746impl Default for GAParameters {
747 fn default() -> Self {
748 Self {
749 population_size: 50,
750 generations: 100,
751 crossover_prob: 0.8,
752 mutation_prob: 0.1,
753 selection_strategy: "tournament".to_string(),
754 elite_size: 5,
755 }
756 }
757}
758
759impl Default for FeatureParams {
760 fn default() -> Self {
761 Self {
762 enable_temporal_features: true,
763 enable_complexity_features: true,
764 enable_user_features: true,
765 enable_platform_features: true,
766 enable_historical_features: true,
767 normalization_method: "z_score".to_string(),
768 selection_threshold: 0.1,
769 }
770 }
771}