1use crate::builder::Circuit;
7use quantrs2_core::{
8 error::{QuantRS2Error, QuantRS2Result},
9 qubit::QubitId,
10};
11use scirs2_core::Complex64;
12use std::collections::HashMap;
13use std::time::{Duration, Instant};
14
15#[derive(Debug, Clone)]
17struct JobRecord {
18 status: ExecutionStatus,
20 backends: Vec<String>,
22 submitted_at: std::time::Instant,
24}
25
26#[derive(Debug)]
31pub struct DistributedExecutor {
32 pub backends: Vec<ExecutionBackend>,
34 pub load_balancer: LoadBalancer,
36 pub fault_tolerance: FaultToleranceConfig,
38 pub scheduler: ExecutionScheduler,
40 pub resource_manager: ResourceManager,
42 job_registry: HashMap<String, JobRecord>,
44}
45
46#[derive(Debug, Clone)]
48pub struct ExecutionBackend {
49 pub id: String,
51 pub backend_type: BackendType,
53 pub status: BackendStatus,
55 pub performance: BackendPerformance,
57 pub queue_info: QueueInfo,
59 pub capabilities: BackendCapabilities,
61 pub network_config: NetworkConfig,
63}
64
65#[derive(Debug, Clone, PartialEq)]
67pub enum BackendType {
68 Hardware {
70 vendor: String,
71 model: String,
72 location: String,
73 },
74 Simulator {
76 simulator_type: SimulatorType,
77 host: String,
78 },
79 CloudService {
81 provider: String,
82 service_name: String,
83 region: String,
84 },
85 Hybrid {
87 quantum_backend: Box<Self>,
88 classical_resources: ClassicalResources,
89 },
90}
91
92#[derive(Debug, Clone, PartialEq, Eq)]
94pub enum SimulatorType {
95 StateVector,
96 DensityMatrix,
97 TensorNetwork,
98 StabilunerformCode,
99 MatrixProductState,
100 Custom(String),
101}
102
103#[derive(Debug, Clone, PartialEq)]
105pub struct ClassicalResources {
106 pub cpu_cores: usize,
108 pub memory_gb: f64,
110 pub gpus: Vec<GPUInfo>,
112 pub storage_gb: f64,
114}
115
116#[derive(Debug, Clone, PartialEq)]
118pub struct GPUInfo {
119 pub model: String,
121 pub memory_gb: f64,
123 pub compute_capability: String,
125}
126
127#[derive(Debug, Clone, PartialEq, Eq)]
129pub enum BackendStatus {
130 Available,
132 Busy,
134 Unavailable,
136 Maintenance,
138 Offline,
140 Error(String),
142}
143
144#[derive(Debug, Clone)]
146pub struct BackendPerformance {
147 pub max_qubits: usize,
149 pub max_depth: usize,
151 pub gate_fidelities: HashMap<String, f64>,
153 pub coherence_times: HashMap<String, f64>,
155 pub execution_time_model: ExecutionTimeModel,
157 pub throughput: f64,
159}
160
161#[derive(Debug, Clone)]
163pub struct ExecutionTimeModel {
164 pub base_time: f64,
166 pub time_per_gate: f64,
168 pub time_per_qubit: f64,
170 pub time_per_measurement: f64,
172 pub network_latency: f64,
174}
175
176#[derive(Debug, Clone)]
178pub struct QueueInfo {
179 pub queue_length: usize,
181 pub estimated_wait_time: f64,
183 pub max_queue_size: usize,
185 pub priority_levels: Vec<Priority>,
187}
188
189#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
191pub enum Priority {
192 Low,
193 Normal,
194 High,
195 Critical,
196}
197
198#[derive(Debug, Clone)]
200pub struct BackendCapabilities {
201 pub supported_gates: Vec<String>,
203 pub mid_circuit_measurements: bool,
205 pub classical_control: bool,
207 pub reset_operations: bool,
209 pub connectivity: ConnectivityGraph,
211 pub noise_model: Option<NoiseCharacteristics>,
213}
214
215#[derive(Debug, Clone)]
217pub struct ConnectivityGraph {
218 pub num_qubits: usize,
220 pub edges: Vec<(usize, usize)>,
222 pub topology: TopologyType,
224}
225
226#[derive(Debug, Clone, PartialEq)]
228pub enum TopologyType {
229 Linear,
231 Grid2D { rows: usize, cols: usize },
233 AllToAll,
235 Random { density: f64 },
237 Custom,
239}
240
241#[derive(Debug, Clone)]
243pub struct NoiseCharacteristics {
244 pub single_qubit_errors: HashMap<String, f64>,
246 pub two_qubit_errors: HashMap<String, f64>,
248 pub measurement_errors: Vec<f64>,
250 pub decoherence_times: Vec<f64>,
252}
253
254#[derive(Debug, Clone)]
256pub struct NetworkConfig {
257 pub endpoint: String,
259 pub credentials: Credentials,
261 pub timeouts: TimeoutConfig,
263 pub retry_policy: RetryPolicy,
265}
266
267#[derive(Debug, Clone)]
269pub struct Credentials {
270 pub auth_type: AuthenticationType,
272 pub api_key: Option<String>,
274 pub token: Option<String>,
276 pub username_password: Option<(String, String)>,
278}
279
280#[derive(Debug, Clone, PartialEq, Eq)]
282pub enum AuthenticationType {
283 ApiKey,
284 Token,
285 UsernamePassword,
286 Certificate,
287 None,
288}
289
290#[derive(Debug, Clone)]
292pub struct TimeoutConfig {
293 pub connection_timeout: f64,
295 pub request_timeout: f64,
297 pub total_timeout: f64,
299}
300
301#[derive(Debug, Clone)]
303pub struct RetryPolicy {
304 pub max_retries: usize,
306 pub base_delay: f64,
308 pub backoff_strategy: BackoffStrategy,
310 pub retryable_errors: Vec<ErrorType>,
312}
313
314#[derive(Debug, Clone, PartialEq)]
316pub enum BackoffStrategy {
317 Fixed,
319 Linear,
321 Exponential { multiplier: f64 },
323 Jitter { max_jitter: f64 },
325}
326
327#[derive(Debug, Clone, PartialEq, Eq)]
329pub enum ErrorType {
330 NetworkError,
331 TimeoutError,
332 ServiceUnavailable,
333 RateLimited,
334 InternalServerError,
335}
336
337#[derive(Debug, Clone)]
339pub struct LoadBalancer {
340 pub strategy: LoadBalancingStrategy,
342 pub health_check: HealthCheckConfig,
344 pub metrics: MetricsConfig,
346}
347
348#[derive(Debug, Clone, PartialEq)]
350pub enum LoadBalancingStrategy {
351 RoundRobin,
353 LeastConnections,
355 LeastQueueTime,
357 BestPerformance,
359 WeightedRoundRobin(HashMap<String, f64>),
361 Custom(String),
363}
364
365#[derive(Debug, Clone)]
367pub struct HealthCheckConfig {
368 pub interval: f64,
370 pub timeout: f64,
372 pub failure_threshold: usize,
374 pub success_threshold: usize,
376}
377
378#[derive(Debug, Clone)]
380pub struct MetricsConfig {
381 pub enabled: bool,
383 pub collection_interval: f64,
385 pub retention_period: f64,
387 pub storage_backend: MetricsStorage,
389}
390
391#[derive(Debug, Clone, PartialEq, Eq)]
393pub enum MetricsStorage {
394 InMemory,
395 File(String),
396 Database(String),
397 CloudStorage(String),
398}
399
400#[derive(Debug, Clone)]
402pub struct FaultToleranceConfig {
403 pub enable_failover: bool,
405 pub redundancy_level: usize,
407 pub error_correction: ErrorCorrectionStrategy,
409 pub failure_detection: FailureDetectionConfig,
411}
412
413#[derive(Debug, Clone, PartialEq, Eq)]
415pub enum ErrorCorrectionStrategy {
416 None,
418 MajorityVoting,
420 QuantumErrorCorrection,
422 ClassicalPostProcessing,
424 Custom(String),
426}
427
428#[derive(Debug, Clone)]
430pub struct FailureDetectionConfig {
431 pub detection_methods: Vec<FailureDetectionMethod>,
433 pub detection_threshold: f64,
435 pub detection_window: f64,
437}
438
439#[derive(Debug, Clone, PartialEq, Eq)]
441pub enum FailureDetectionMethod {
442 ErrorRateMonitoring,
444 LatencyMonitoring,
446 ResultValidation,
448 HealthCheckFailures,
450}
451
452#[derive(Debug, Clone)]
454pub struct ExecutionScheduler {
455 pub policy: SchedulingPolicy,
457 pub priority_queue: PriorityQueueConfig,
459 pub resource_allocation: ResourceAllocationStrategy,
461}
462
463#[derive(Debug, Clone, PartialEq, Eq)]
465pub enum SchedulingPolicy {
466 FCFS,
468 SJF,
470 Priority,
472 FairShare,
474 DeadlineAware,
476 Custom(String),
478}
479
480#[derive(Debug, Clone)]
482pub struct PriorityQueueConfig {
483 pub max_size_per_priority: HashMap<Priority, usize>,
485 pub aging_factor: f64,
487 pub priority_boost_interval: f64,
489}
490
491#[derive(Debug, Clone, PartialEq, Eq)]
493pub enum ResourceAllocationStrategy {
494 BestFit,
496 FirstFit,
498 WorstFit,
500 NextFit,
502 Custom(String),
504}
505
506#[derive(Debug, Clone)]
508pub struct ResourceManager {
509 pub resource_pool: ResourcePool,
511 pub allocation_policies: AllocationPolicies,
513 pub usage_tracking: UsageTracking,
515}
516
517#[derive(Debug, Clone)]
519pub struct ResourcePool {
520 pub total_qubits: usize,
522 pub available_slots: usize,
524 pub memory_pool: f64,
526 pub compute_pool: f64,
528}
529
530#[derive(Debug, Clone)]
532pub struct AllocationPolicies {
533 pub max_qubits_per_user: Option<usize>,
535 pub max_execution_time: Option<f64>,
537 pub fair_share: bool,
539 pub reserved_resources: f64,
541}
542
543#[derive(Debug, Clone)]
545pub struct UsageTracking {
546 pub per_user_tracking: bool,
548 pub per_project_tracking: bool,
550 pub reporting_interval: f64,
552 pub retention_period: f64,
554}
555
556#[derive(Debug, Clone)]
558pub struct DistributedJob<const N: usize> {
559 pub id: String,
561 pub circuit: Circuit<N>,
563 pub parameters: ExecutionParameters,
565 pub priority: Priority,
567 pub target_backends: Option<Vec<String>>,
569 pub submitted_at: Instant,
571 pub deadline: Option<Instant>,
573}
574
575#[derive(Debug, Clone)]
577pub struct ExecutionParameters {
578 pub shots: usize,
580 pub optimization_level: usize,
582 pub error_mitigation: Vec<ErrorMitigation>,
584 pub result_format: ResultFormat,
586 pub memory_requirement: Option<f64>,
588}
589
590#[derive(Debug, Clone, PartialEq, Eq)]
592pub enum ErrorMitigation {
593 ReadoutErrorMitigation,
595 ZeroNoiseExtrapolation,
597 CliffordDataRegression,
599 SymmetryVerification,
601 Custom(String),
603}
604
605#[derive(Debug, Clone, PartialEq, Eq)]
607pub enum ResultFormat {
608 Counts,
610 Probabilities,
612 Statevector,
614 ExpectationValues,
616 Custom(String),
618}
619
620#[derive(Debug, Clone)]
622pub struct DistributedResult {
623 pub job_id: String,
625 pub status: ExecutionStatus,
627 pub backend_results: HashMap<String, BackendResult>,
629 pub final_result: Option<AggregatedResult>,
631 pub metadata: ExecutionMetadata,
633}
634
635#[derive(Debug, Clone, PartialEq, Eq)]
637pub enum ExecutionStatus {
638 Queued,
640 Running,
642 Completed,
644 Failed(String),
646 Cancelled,
648 TimedOut,
650}
651
652#[derive(Debug, Clone)]
654pub struct BackendResult {
655 pub backend_id: String,
657 pub status: ExecutionStatus,
659 pub measurements: Option<Vec<Vec<bool>>>,
661 pub probabilities: Option<HashMap<String, f64>>,
663 pub execution_time: Duration,
665 pub error: Option<String>,
667}
668
669#[derive(Debug, Clone)]
671pub struct AggregatedResult {
672 pub combined_measurements: HashMap<String, f64>,
674 pub error_estimates: HashMap<String, f64>,
676 pub confidence_intervals: HashMap<String, (f64, f64)>,
678 pub quality_metrics: QualityMetrics,
680}
681
682#[derive(Debug, Clone)]
684pub struct QualityMetrics {
685 pub statistical_significance: f64,
687 pub consistency_score: f64,
689 pub estimated_fidelity: f64,
691 pub mitigation_effectiveness: f64,
693}
694
695#[derive(Debug, Clone)]
697pub struct ExecutionMetadata {
698 pub total_time: Duration,
700 pub queue_time: Duration,
702 pub backends_used: Vec<String>,
704 pub resource_usage: ResourceUsage,
706 pub cost_info: Option<CostInfo>,
708}
709
710#[derive(Debug, Clone)]
712pub struct ResourceUsage {
713 pub cpu_hours: f64,
715 pub memory_hours: f64,
717 pub qubit_hours: f64,
719 pub network_usage: f64,
721}
722
723#[derive(Debug, Clone)]
725pub struct CostInfo {
726 pub total_cost: f64,
728 pub cost_breakdown: HashMap<String, f64>,
730 pub currency: String,
732}
733
734impl DistributedExecutor {
735 #[must_use]
737 pub fn new() -> Self {
738 Self {
739 backends: Vec::new(),
740 load_balancer: LoadBalancer {
741 strategy: LoadBalancingStrategy::RoundRobin,
742 health_check: HealthCheckConfig {
743 interval: 30.0,
744 timeout: 5.0,
745 failure_threshold: 3,
746 success_threshold: 2,
747 },
748 metrics: MetricsConfig {
749 enabled: true,
750 collection_interval: 60.0,
751 retention_period: 3600.0 * 24.0, storage_backend: MetricsStorage::InMemory,
753 },
754 },
755 fault_tolerance: FaultToleranceConfig {
756 enable_failover: true,
757 redundancy_level: 1,
758 error_correction: ErrorCorrectionStrategy::MajorityVoting,
759 failure_detection: FailureDetectionConfig {
760 detection_methods: vec![
761 FailureDetectionMethod::ErrorRateMonitoring,
762 FailureDetectionMethod::LatencyMonitoring,
763 ],
764 detection_threshold: 0.1,
765 detection_window: 300.0,
766 },
767 },
768 scheduler: ExecutionScheduler {
769 policy: SchedulingPolicy::Priority,
770 priority_queue: PriorityQueueConfig {
771 max_size_per_priority: {
772 let mut map = HashMap::new();
773 map.insert(Priority::Critical, 10);
774 map.insert(Priority::High, 50);
775 map.insert(Priority::Normal, 200);
776 map.insert(Priority::Low, 1000);
777 map
778 },
779 aging_factor: 0.1,
780 priority_boost_interval: 3600.0, },
782 resource_allocation: ResourceAllocationStrategy::BestFit,
783 },
784 resource_manager: ResourceManager {
785 resource_pool: ResourcePool {
786 total_qubits: 0,
787 available_slots: 0,
788 memory_pool: 0.0,
789 compute_pool: 0.0,
790 },
791 allocation_policies: AllocationPolicies {
792 max_qubits_per_user: Some(100),
793 max_execution_time: Some(3600.0), fair_share: true,
795 reserved_resources: 0.1, },
797 usage_tracking: UsageTracking {
798 per_user_tracking: true,
799 per_project_tracking: true,
800 reporting_interval: 3600.0, retention_period: 3600.0 * 24.0 * 30.0, },
803 },
804 job_registry: HashMap::new(),
805 }
806 }
807
808 pub fn add_backend(&mut self, backend: ExecutionBackend) -> QuantRS2Result<()> {
810 if backend.id.is_empty() {
812 return Err(QuantRS2Error::InvalidInput(
813 "Backend ID cannot be empty".to_string(),
814 ));
815 }
816
817 if self.backends.iter().any(|b| b.id == backend.id) {
819 return Err(QuantRS2Error::InvalidInput(format!(
820 "Backend with ID '{}' already exists",
821 backend.id
822 )));
823 }
824
825 self.resource_manager.resource_pool.total_qubits += backend.performance.max_qubits;
827 self.resource_manager.resource_pool.available_slots += 1;
828
829 self.backends.push(backend);
830 Ok(())
831 }
832
833 pub fn submit_job<const N: usize>(&mut self, job: DistributedJob<N>) -> QuantRS2Result<String> {
835 if job.circuit.num_gates() == 0 {
837 return Err(QuantRS2Error::InvalidInput(
838 "Cannot submit empty circuit".to_string(),
839 ));
840 }
841
842 let required_qubits = job.circuit.num_qubits();
844 if required_qubits > self.resource_manager.resource_pool.total_qubits {
845 return Err(QuantRS2Error::UnsupportedQubits(
846 required_qubits,
847 format!(
848 "Maximum available qubits: {}",
849 self.resource_manager.resource_pool.total_qubits
850 ),
851 ));
852 }
853
854 let selected_backends = self.select_backends(&job)?;
856 if selected_backends.is_empty() {
857 return Err(QuantRS2Error::BackendExecutionFailed(
858 "No suitable backends available".to_string(),
859 ));
860 }
861
862 let job_id = job.id.clone();
863 let submitted_at = job.submitted_at;
864
865 self.job_registry.insert(
867 job_id.clone(),
868 JobRecord {
869 status: ExecutionStatus::Queued,
870 backends: selected_backends,
871 submitted_at,
872 },
873 );
874
875 Ok(job_id)
876 }
877
878 fn select_backends<const N: usize>(
880 &self,
881 job: &DistributedJob<N>,
882 ) -> QuantRS2Result<Vec<String>> {
883 let mut suitable_backends = Vec::new();
884
885 for backend in &self.backends {
886 if self.is_backend_suitable(backend, job) {
887 suitable_backends.push(backend.id.clone());
888 }
889 }
890
891 match self.load_balancer.strategy {
893 LoadBalancingStrategy::RoundRobin => {
894 suitable_backends.truncate(self.fault_tolerance.redundancy_level.max(1));
896 }
897 LoadBalancingStrategy::LeastQueueTime => {
898 suitable_backends.sort_by(|a, b| {
901 let wait_a = self
902 .backends
903 .iter()
904 .find(|backend| backend.id == *a)
905 .map(|backend| backend.queue_info.estimated_wait_time)
906 .unwrap_or(0.0);
907 let wait_b = self
908 .backends
909 .iter()
910 .find(|backend| backend.id == *b)
911 .map(|backend| backend.queue_info.estimated_wait_time)
912 .unwrap_or(0.0);
913 wait_a
914 .partial_cmp(&wait_b)
915 .unwrap_or(std::cmp::Ordering::Equal)
916 });
917 suitable_backends.truncate(self.fault_tolerance.redundancy_level.max(1));
918 }
919 _ => {
920 suitable_backends.truncate(1);
922 }
923 }
924
925 Ok(suitable_backends)
926 }
927
928 fn is_backend_suitable<const N: usize>(
930 &self,
931 backend: &ExecutionBackend,
932 job: &DistributedJob<N>,
933 ) -> bool {
934 if backend.status != BackendStatus::Available {
936 return false;
937 }
938
939 if job.circuit.num_qubits() > backend.performance.max_qubits {
941 return false;
942 }
943
944 if job.circuit.num_gates() > backend.performance.max_depth {
946 return false;
947 }
948
949 if let Some(ref targets) = job.target_backends {
951 if !targets.contains(&backend.id) {
952 return false;
953 }
954 }
955
956 if backend.queue_info.queue_length >= backend.queue_info.max_queue_size {
958 return false;
959 }
960
961 true
962 }
963
964 pub fn get_job_status(&self, job_id: &str) -> QuantRS2Result<ExecutionStatus> {
968 self.job_registry
969 .get(job_id)
970 .map(|record| record.status.clone())
971 .ok_or_else(|| QuantRS2Error::InvalidInput(format!("Unknown job ID: '{job_id}'")))
972 }
973
974 pub fn cancel_job(&mut self, job_id: &str) -> QuantRS2Result<()> {
980 let record = self
981 .job_registry
982 .get_mut(job_id)
983 .ok_or_else(|| QuantRS2Error::InvalidInput(format!("Unknown job ID: '{job_id}'")))?;
984
985 match record.status {
986 ExecutionStatus::Queued | ExecutionStatus::Running => {
987 record.status = ExecutionStatus::Cancelled;
988 }
989 ExecutionStatus::Completed
991 | ExecutionStatus::Failed(_)
992 | ExecutionStatus::Cancelled
993 | ExecutionStatus::TimedOut => {}
994 }
995
996 Ok(())
997 }
998
999 pub fn get_results(&self, job_id: &str) -> QuantRS2Result<DistributedResult> {
1006 let record = self
1007 .job_registry
1008 .get(job_id)
1009 .ok_or_else(|| QuantRS2Error::InvalidInput(format!("Unknown job ID: '{job_id}'")))?;
1010
1011 let elapsed = record.submitted_at.elapsed();
1012
1013 Ok(DistributedResult {
1014 job_id: job_id.to_string(),
1015 status: record.status.clone(),
1016 backend_results: HashMap::new(),
1017 final_result: None,
1018 metadata: ExecutionMetadata {
1019 total_time: elapsed,
1020 queue_time: Duration::from_secs(0),
1021 backends_used: record.backends.clone(),
1022 resource_usage: ResourceUsage {
1023 cpu_hours: elapsed.as_secs_f64() / 3600.0,
1024 memory_hours: elapsed.as_secs_f64() / 3600.0,
1025 qubit_hours: elapsed.as_secs_f64() / 3600.0,
1026 network_usage: 0.0,
1027 },
1028 cost_info: None,
1029 },
1030 })
1031 }
1032
1033 #[must_use]
1035 pub fn get_health_status(&self) -> SystemHealthStatus {
1036 let available_backends = self
1037 .backends
1038 .iter()
1039 .filter(|b| b.status == BackendStatus::Available)
1040 .count();
1041
1042 let total_qubits = self
1043 .backends
1044 .iter()
1045 .filter(|b| b.status == BackendStatus::Available)
1046 .map(|b| b.performance.max_qubits)
1047 .sum();
1048
1049 SystemHealthStatus {
1050 total_backends: self.backends.len(),
1051 available_backends,
1052 total_qubits,
1053 average_queue_time: self
1054 .backends
1055 .iter()
1056 .map(|b| b.queue_info.estimated_wait_time)
1057 .sum::<f64>()
1058 / self.backends.len() as f64,
1059 system_load: self.calculate_system_load(),
1060 }
1061 }
1062
1063 fn calculate_system_load(&self) -> f64 {
1065 if self.backends.is_empty() {
1066 return 0.0;
1067 }
1068
1069 let total_capacity: f64 = self
1070 .backends
1071 .iter()
1072 .map(|b| b.queue_info.max_queue_size as f64)
1073 .sum();
1074
1075 let current_load: f64 = self
1076 .backends
1077 .iter()
1078 .map(|b| b.queue_info.queue_length as f64)
1079 .sum();
1080
1081 if total_capacity > 0.0 {
1082 current_load / total_capacity
1083 } else {
1084 0.0
1085 }
1086 }
1087}
1088
1089#[derive(Debug, Clone)]
1091pub struct SystemHealthStatus {
1092 pub total_backends: usize,
1094 pub available_backends: usize,
1096 pub total_qubits: usize,
1098 pub average_queue_time: f64,
1100 pub system_load: f64,
1102}
1103
1104impl Default for DistributedExecutor {
1105 fn default() -> Self {
1106 Self::new()
1107 }
1108}
1109
1110#[cfg(test)]
1111mod tests {
1112 use super::*;
1113
1114 #[test]
1115 fn test_distributed_executor_creation() {
1116 let executor = DistributedExecutor::new();
1117 assert_eq!(executor.backends.len(), 0);
1118 assert_eq!(executor.resource_manager.resource_pool.total_qubits, 0);
1119 }
1120
1121 #[test]
1122 fn test_backend_addition() {
1123 let mut executor = DistributedExecutor::new();
1124
1125 let backend = ExecutionBackend {
1126 id: "test_backend".to_string(),
1127 backend_type: BackendType::Simulator {
1128 simulator_type: SimulatorType::StateVector,
1129 host: "localhost".to_string(),
1130 },
1131 status: BackendStatus::Available,
1132 performance: BackendPerformance {
1133 max_qubits: 10,
1134 max_depth: 1000,
1135 gate_fidelities: HashMap::new(),
1136 coherence_times: HashMap::new(),
1137 execution_time_model: ExecutionTimeModel {
1138 base_time: 0.1,
1139 time_per_gate: 0.001,
1140 time_per_qubit: 0.01,
1141 time_per_measurement: 0.005,
1142 network_latency: 0.05,
1143 },
1144 throughput: 10.0,
1145 },
1146 queue_info: QueueInfo {
1147 queue_length: 0,
1148 estimated_wait_time: 0.0,
1149 max_queue_size: 100,
1150 priority_levels: vec![Priority::Normal, Priority::High],
1151 },
1152 capabilities: BackendCapabilities {
1153 supported_gates: vec!["h".to_string(), "cnot".to_string()],
1154 mid_circuit_measurements: false,
1155 classical_control: false,
1156 reset_operations: false,
1157 connectivity: ConnectivityGraph {
1158 num_qubits: 10,
1159 edges: vec![(0, 1), (1, 2)],
1160 topology: TopologyType::Linear,
1161 },
1162 noise_model: None,
1163 },
1164 network_config: NetworkConfig {
1165 endpoint: "http://localhost:8080".to_string(),
1166 credentials: Credentials {
1167 auth_type: AuthenticationType::None,
1168 api_key: None,
1169 token: None,
1170 username_password: None,
1171 },
1172 timeouts: TimeoutConfig {
1173 connection_timeout: 5.0,
1174 request_timeout: 30.0,
1175 total_timeout: 60.0,
1176 },
1177 retry_policy: RetryPolicy {
1178 max_retries: 3,
1179 base_delay: 1.0,
1180 backoff_strategy: BackoffStrategy::Exponential { multiplier: 2.0 },
1181 retryable_errors: vec![ErrorType::NetworkError, ErrorType::TimeoutError],
1182 },
1183 },
1184 };
1185
1186 executor
1187 .add_backend(backend)
1188 .expect("Failed to add backend to executor");
1189 assert_eq!(executor.backends.len(), 1);
1190 assert_eq!(executor.resource_manager.resource_pool.total_qubits, 10);
1191 }
1192
1193 #[test]
1194 fn test_job_submission() {
1195 let mut executor = DistributedExecutor::new();
1196
1197 let backend = create_test_backend();
1199 executor
1200 .add_backend(backend)
1201 .expect("Failed to add backend to executor");
1202
1203 let mut circuit = Circuit::<2>::new();
1205 circuit.h(QubitId(0)).expect("Failed to add Hadamard gate"); let job = DistributedJob {
1207 id: "test_job".to_string(),
1208 circuit,
1209 parameters: ExecutionParameters {
1210 shots: 1000,
1211 optimization_level: 1,
1212 error_mitigation: vec![],
1213 result_format: ResultFormat::Counts,
1214 memory_requirement: None,
1215 },
1216 priority: Priority::Normal,
1217 target_backends: None,
1218 submitted_at: Instant::now(),
1219 deadline: None,
1220 };
1221
1222 let job_id = executor
1223 .submit_job(job)
1224 .expect("Failed to submit job to executor");
1225 assert_eq!(job_id, "test_job");
1226 }
1227
1228 fn create_test_backend() -> ExecutionBackend {
1229 ExecutionBackend {
1230 id: "test_backend".to_string(),
1231 backend_type: BackendType::Simulator {
1232 simulator_type: SimulatorType::StateVector,
1233 host: "localhost".to_string(),
1234 },
1235 status: BackendStatus::Available,
1236 performance: BackendPerformance {
1237 max_qubits: 10,
1238 max_depth: 1000,
1239 gate_fidelities: HashMap::new(),
1240 coherence_times: HashMap::new(),
1241 execution_time_model: ExecutionTimeModel {
1242 base_time: 0.1,
1243 time_per_gate: 0.001,
1244 time_per_qubit: 0.01,
1245 time_per_measurement: 0.005,
1246 network_latency: 0.05,
1247 },
1248 throughput: 10.0,
1249 },
1250 queue_info: QueueInfo {
1251 queue_length: 0,
1252 estimated_wait_time: 0.0,
1253 max_queue_size: 100,
1254 priority_levels: vec![Priority::Normal, Priority::High],
1255 },
1256 capabilities: BackendCapabilities {
1257 supported_gates: vec!["h".to_string(), "cnot".to_string()],
1258 mid_circuit_measurements: false,
1259 classical_control: false,
1260 reset_operations: false,
1261 connectivity: ConnectivityGraph {
1262 num_qubits: 10,
1263 edges: vec![(0, 1), (1, 2)],
1264 topology: TopologyType::Linear,
1265 },
1266 noise_model: None,
1267 },
1268 network_config: NetworkConfig {
1269 endpoint: "http://localhost:8080".to_string(),
1270 credentials: Credentials {
1271 auth_type: AuthenticationType::None,
1272 api_key: None,
1273 token: None,
1274 username_password: None,
1275 },
1276 timeouts: TimeoutConfig {
1277 connection_timeout: 5.0,
1278 request_timeout: 30.0,
1279 total_timeout: 60.0,
1280 },
1281 retry_policy: RetryPolicy {
1282 max_retries: 3,
1283 base_delay: 1.0,
1284 backoff_strategy: BackoffStrategy::Exponential { multiplier: 2.0 },
1285 retryable_errors: vec![ErrorType::NetworkError, ErrorType::TimeoutError],
1286 },
1287 },
1288 }
1289 }
1290}