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)]
20pub struct DistributedExecutor {
21 pub backends: Vec<ExecutionBackend>,
23 pub load_balancer: LoadBalancer,
25 pub fault_tolerance: FaultToleranceConfig,
27 pub scheduler: ExecutionScheduler,
29 pub resource_manager: ResourceManager,
31}
32
33#[derive(Debug, Clone)]
35pub struct ExecutionBackend {
36 pub id: String,
38 pub backend_type: BackendType,
40 pub status: BackendStatus,
42 pub performance: BackendPerformance,
44 pub queue_info: QueueInfo,
46 pub capabilities: BackendCapabilities,
48 pub network_config: NetworkConfig,
50}
51
52#[derive(Debug, Clone, PartialEq)]
54pub enum BackendType {
55 Hardware {
57 vendor: String,
58 model: String,
59 location: String,
60 },
61 Simulator {
63 simulator_type: SimulatorType,
64 host: String,
65 },
66 CloudService {
68 provider: String,
69 service_name: String,
70 region: String,
71 },
72 Hybrid {
74 quantum_backend: Box<Self>,
75 classical_resources: ClassicalResources,
76 },
77}
78
79#[derive(Debug, Clone, PartialEq, Eq)]
81pub enum SimulatorType {
82 StateVector,
83 DensityMatrix,
84 TensorNetwork,
85 StabilunerformCode,
86 MatrixProductState,
87 Custom(String),
88}
89
90#[derive(Debug, Clone, PartialEq)]
92pub struct ClassicalResources {
93 pub cpu_cores: usize,
95 pub memory_gb: f64,
97 pub gpus: Vec<GPUInfo>,
99 pub storage_gb: f64,
101}
102
103#[derive(Debug, Clone, PartialEq)]
105pub struct GPUInfo {
106 pub model: String,
108 pub memory_gb: f64,
110 pub compute_capability: String,
112}
113
114#[derive(Debug, Clone, PartialEq, Eq)]
116pub enum BackendStatus {
117 Available,
119 Busy,
121 Unavailable,
123 Maintenance,
125 Offline,
127 Error(String),
129}
130
131#[derive(Debug, Clone)]
133pub struct BackendPerformance {
134 pub max_qubits: usize,
136 pub max_depth: usize,
138 pub gate_fidelities: HashMap<String, f64>,
140 pub coherence_times: HashMap<String, f64>,
142 pub execution_time_model: ExecutionTimeModel,
144 pub throughput: f64,
146}
147
148#[derive(Debug, Clone)]
150pub struct ExecutionTimeModel {
151 pub base_time: f64,
153 pub time_per_gate: f64,
155 pub time_per_qubit: f64,
157 pub time_per_measurement: f64,
159 pub network_latency: f64,
161}
162
163#[derive(Debug, Clone)]
165pub struct QueueInfo {
166 pub queue_length: usize,
168 pub estimated_wait_time: f64,
170 pub max_queue_size: usize,
172 pub priority_levels: Vec<Priority>,
174}
175
176#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
178pub enum Priority {
179 Low,
180 Normal,
181 High,
182 Critical,
183}
184
185#[derive(Debug, Clone)]
187pub struct BackendCapabilities {
188 pub supported_gates: Vec<String>,
190 pub mid_circuit_measurements: bool,
192 pub classical_control: bool,
194 pub reset_operations: bool,
196 pub connectivity: ConnectivityGraph,
198 pub noise_model: Option<NoiseCharacteristics>,
200}
201
202#[derive(Debug, Clone)]
204pub struct ConnectivityGraph {
205 pub num_qubits: usize,
207 pub edges: Vec<(usize, usize)>,
209 pub topology: TopologyType,
211}
212
213#[derive(Debug, Clone, PartialEq)]
215pub enum TopologyType {
216 Linear,
218 Grid2D { rows: usize, cols: usize },
220 AllToAll,
222 Random { density: f64 },
224 Custom,
226}
227
228#[derive(Debug, Clone)]
230pub struct NoiseCharacteristics {
231 pub single_qubit_errors: HashMap<String, f64>,
233 pub two_qubit_errors: HashMap<String, f64>,
235 pub measurement_errors: Vec<f64>,
237 pub decoherence_times: Vec<f64>,
239}
240
241#[derive(Debug, Clone)]
243pub struct NetworkConfig {
244 pub endpoint: String,
246 pub credentials: Credentials,
248 pub timeouts: TimeoutConfig,
250 pub retry_policy: RetryPolicy,
252}
253
254#[derive(Debug, Clone)]
256pub struct Credentials {
257 pub auth_type: AuthenticationType,
259 pub api_key: Option<String>,
261 pub token: Option<String>,
263 pub username_password: Option<(String, String)>,
265}
266
267#[derive(Debug, Clone, PartialEq, Eq)]
269pub enum AuthenticationType {
270 ApiKey,
271 Token,
272 UsernamePassword,
273 Certificate,
274 None,
275}
276
277#[derive(Debug, Clone)]
279pub struct TimeoutConfig {
280 pub connection_timeout: f64,
282 pub request_timeout: f64,
284 pub total_timeout: f64,
286}
287
288#[derive(Debug, Clone)]
290pub struct RetryPolicy {
291 pub max_retries: usize,
293 pub base_delay: f64,
295 pub backoff_strategy: BackoffStrategy,
297 pub retryable_errors: Vec<ErrorType>,
299}
300
301#[derive(Debug, Clone, PartialEq)]
303pub enum BackoffStrategy {
304 Fixed,
306 Linear,
308 Exponential { multiplier: f64 },
310 Jitter { max_jitter: f64 },
312}
313
314#[derive(Debug, Clone, PartialEq, Eq)]
316pub enum ErrorType {
317 NetworkError,
318 TimeoutError,
319 ServiceUnavailable,
320 RateLimited,
321 InternalServerError,
322}
323
324#[derive(Debug, Clone)]
326pub struct LoadBalancer {
327 pub strategy: LoadBalancingStrategy,
329 pub health_check: HealthCheckConfig,
331 pub metrics: MetricsConfig,
333}
334
335#[derive(Debug, Clone, PartialEq)]
337pub enum LoadBalancingStrategy {
338 RoundRobin,
340 LeastConnections,
342 LeastQueueTime,
344 BestPerformance,
346 WeightedRoundRobin(HashMap<String, f64>),
348 Custom(String),
350}
351
352#[derive(Debug, Clone)]
354pub struct HealthCheckConfig {
355 pub interval: f64,
357 pub timeout: f64,
359 pub failure_threshold: usize,
361 pub success_threshold: usize,
363}
364
365#[derive(Debug, Clone)]
367pub struct MetricsConfig {
368 pub enabled: bool,
370 pub collection_interval: f64,
372 pub retention_period: f64,
374 pub storage_backend: MetricsStorage,
376}
377
378#[derive(Debug, Clone, PartialEq, Eq)]
380pub enum MetricsStorage {
381 InMemory,
382 File(String),
383 Database(String),
384 CloudStorage(String),
385}
386
387#[derive(Debug, Clone)]
389pub struct FaultToleranceConfig {
390 pub enable_failover: bool,
392 pub redundancy_level: usize,
394 pub error_correction: ErrorCorrectionStrategy,
396 pub failure_detection: FailureDetectionConfig,
398}
399
400#[derive(Debug, Clone, PartialEq, Eq)]
402pub enum ErrorCorrectionStrategy {
403 None,
405 MajorityVoting,
407 QuantumErrorCorrection,
409 ClassicalPostProcessing,
411 Custom(String),
413}
414
415#[derive(Debug, Clone)]
417pub struct FailureDetectionConfig {
418 pub detection_methods: Vec<FailureDetectionMethod>,
420 pub detection_threshold: f64,
422 pub detection_window: f64,
424}
425
426#[derive(Debug, Clone, PartialEq, Eq)]
428pub enum FailureDetectionMethod {
429 ErrorRateMonitoring,
431 LatencyMonitoring,
433 ResultValidation,
435 HealthCheckFailures,
437}
438
439#[derive(Debug, Clone)]
441pub struct ExecutionScheduler {
442 pub policy: SchedulingPolicy,
444 pub priority_queue: PriorityQueueConfig,
446 pub resource_allocation: ResourceAllocationStrategy,
448}
449
450#[derive(Debug, Clone, PartialEq, Eq)]
452pub enum SchedulingPolicy {
453 FCFS,
455 SJF,
457 Priority,
459 FairShare,
461 DeadlineAware,
463 Custom(String),
465}
466
467#[derive(Debug, Clone)]
469pub struct PriorityQueueConfig {
470 pub max_size_per_priority: HashMap<Priority, usize>,
472 pub aging_factor: f64,
474 pub priority_boost_interval: f64,
476}
477
478#[derive(Debug, Clone, PartialEq, Eq)]
480pub enum ResourceAllocationStrategy {
481 BestFit,
483 FirstFit,
485 WorstFit,
487 NextFit,
489 Custom(String),
491}
492
493#[derive(Debug, Clone)]
495pub struct ResourceManager {
496 pub resource_pool: ResourcePool,
498 pub allocation_policies: AllocationPolicies,
500 pub usage_tracking: UsageTracking,
502}
503
504#[derive(Debug, Clone)]
506pub struct ResourcePool {
507 pub total_qubits: usize,
509 pub available_slots: usize,
511 pub memory_pool: f64,
513 pub compute_pool: f64,
515}
516
517#[derive(Debug, Clone)]
519pub struct AllocationPolicies {
520 pub max_qubits_per_user: Option<usize>,
522 pub max_execution_time: Option<f64>,
524 pub fair_share: bool,
526 pub reserved_resources: f64,
528}
529
530#[derive(Debug, Clone)]
532pub struct UsageTracking {
533 pub per_user_tracking: bool,
535 pub per_project_tracking: bool,
537 pub reporting_interval: f64,
539 pub retention_period: f64,
541}
542
543#[derive(Debug, Clone)]
545pub struct DistributedJob<const N: usize> {
546 pub id: String,
548 pub circuit: Circuit<N>,
550 pub parameters: ExecutionParameters,
552 pub priority: Priority,
554 pub target_backends: Option<Vec<String>>,
556 pub submitted_at: Instant,
558 pub deadline: Option<Instant>,
560}
561
562#[derive(Debug, Clone)]
564pub struct ExecutionParameters {
565 pub shots: usize,
567 pub optimization_level: usize,
569 pub error_mitigation: Vec<ErrorMitigation>,
571 pub result_format: ResultFormat,
573 pub memory_requirement: Option<f64>,
575}
576
577#[derive(Debug, Clone, PartialEq, Eq)]
579pub enum ErrorMitigation {
580 ReadoutErrorMitigation,
582 ZeroNoiseExtrapolation,
584 CliffordDataRegression,
586 SymmetryVerification,
588 Custom(String),
590}
591
592#[derive(Debug, Clone, PartialEq, Eq)]
594pub enum ResultFormat {
595 Counts,
597 Probabilities,
599 Statevector,
601 ExpectationValues,
603 Custom(String),
605}
606
607#[derive(Debug, Clone)]
609pub struct DistributedResult {
610 pub job_id: String,
612 pub status: ExecutionStatus,
614 pub backend_results: HashMap<String, BackendResult>,
616 pub final_result: Option<AggregatedResult>,
618 pub metadata: ExecutionMetadata,
620}
621
622#[derive(Debug, Clone, PartialEq, Eq)]
624pub enum ExecutionStatus {
625 Queued,
627 Running,
629 Completed,
631 Failed(String),
633 Cancelled,
635 TimedOut,
637}
638
639#[derive(Debug, Clone)]
641pub struct BackendResult {
642 pub backend_id: String,
644 pub status: ExecutionStatus,
646 pub measurements: Option<Vec<Vec<bool>>>,
648 pub probabilities: Option<HashMap<String, f64>>,
650 pub execution_time: Duration,
652 pub error: Option<String>,
654}
655
656#[derive(Debug, Clone)]
658pub struct AggregatedResult {
659 pub combined_measurements: HashMap<String, f64>,
661 pub error_estimates: HashMap<String, f64>,
663 pub confidence_intervals: HashMap<String, (f64, f64)>,
665 pub quality_metrics: QualityMetrics,
667}
668
669#[derive(Debug, Clone)]
671pub struct QualityMetrics {
672 pub statistical_significance: f64,
674 pub consistency_score: f64,
676 pub estimated_fidelity: f64,
678 pub mitigation_effectiveness: f64,
680}
681
682#[derive(Debug, Clone)]
684pub struct ExecutionMetadata {
685 pub total_time: Duration,
687 pub queue_time: Duration,
689 pub backends_used: Vec<String>,
691 pub resource_usage: ResourceUsage,
693 pub cost_info: Option<CostInfo>,
695}
696
697#[derive(Debug, Clone)]
699pub struct ResourceUsage {
700 pub cpu_hours: f64,
702 pub memory_hours: f64,
704 pub qubit_hours: f64,
706 pub network_usage: f64,
708}
709
710#[derive(Debug, Clone)]
712pub struct CostInfo {
713 pub total_cost: f64,
715 pub cost_breakdown: HashMap<String, f64>,
717 pub currency: String,
719}
720
721impl DistributedExecutor {
722 #[must_use]
724 pub fn new() -> Self {
725 Self {
726 backends: Vec::new(),
727 load_balancer: LoadBalancer {
728 strategy: LoadBalancingStrategy::RoundRobin,
729 health_check: HealthCheckConfig {
730 interval: 30.0,
731 timeout: 5.0,
732 failure_threshold: 3,
733 success_threshold: 2,
734 },
735 metrics: MetricsConfig {
736 enabled: true,
737 collection_interval: 60.0,
738 retention_period: 3600.0 * 24.0, storage_backend: MetricsStorage::InMemory,
740 },
741 },
742 fault_tolerance: FaultToleranceConfig {
743 enable_failover: true,
744 redundancy_level: 1,
745 error_correction: ErrorCorrectionStrategy::MajorityVoting,
746 failure_detection: FailureDetectionConfig {
747 detection_methods: vec![
748 FailureDetectionMethod::ErrorRateMonitoring,
749 FailureDetectionMethod::LatencyMonitoring,
750 ],
751 detection_threshold: 0.1,
752 detection_window: 300.0,
753 },
754 },
755 scheduler: ExecutionScheduler {
756 policy: SchedulingPolicy::Priority,
757 priority_queue: PriorityQueueConfig {
758 max_size_per_priority: {
759 let mut map = HashMap::new();
760 map.insert(Priority::Critical, 10);
761 map.insert(Priority::High, 50);
762 map.insert(Priority::Normal, 200);
763 map.insert(Priority::Low, 1000);
764 map
765 },
766 aging_factor: 0.1,
767 priority_boost_interval: 3600.0, },
769 resource_allocation: ResourceAllocationStrategy::BestFit,
770 },
771 resource_manager: ResourceManager {
772 resource_pool: ResourcePool {
773 total_qubits: 0,
774 available_slots: 0,
775 memory_pool: 0.0,
776 compute_pool: 0.0,
777 },
778 allocation_policies: AllocationPolicies {
779 max_qubits_per_user: Some(100),
780 max_execution_time: Some(3600.0), fair_share: true,
782 reserved_resources: 0.1, },
784 usage_tracking: UsageTracking {
785 per_user_tracking: true,
786 per_project_tracking: true,
787 reporting_interval: 3600.0, retention_period: 3600.0 * 24.0 * 30.0, },
790 },
791 }
792 }
793
794 pub fn add_backend(&mut self, backend: ExecutionBackend) -> QuantRS2Result<()> {
796 if backend.id.is_empty() {
798 return Err(QuantRS2Error::InvalidInput(
799 "Backend ID cannot be empty".to_string(),
800 ));
801 }
802
803 if self.backends.iter().any(|b| b.id == backend.id) {
805 return Err(QuantRS2Error::InvalidInput(format!(
806 "Backend with ID '{}' already exists",
807 backend.id
808 )));
809 }
810
811 self.resource_manager.resource_pool.total_qubits += backend.performance.max_qubits;
813 self.resource_manager.resource_pool.available_slots += 1;
814
815 self.backends.push(backend);
816 Ok(())
817 }
818
819 pub fn submit_job<const N: usize>(&mut self, job: DistributedJob<N>) -> QuantRS2Result<String> {
821 if job.circuit.num_gates() == 0 {
823 return Err(QuantRS2Error::InvalidInput(
824 "Cannot submit empty circuit".to_string(),
825 ));
826 }
827
828 let required_qubits = job.circuit.num_qubits();
830 if required_qubits > self.resource_manager.resource_pool.total_qubits {
831 return Err(QuantRS2Error::UnsupportedQubits(
832 required_qubits,
833 format!(
834 "Maximum available qubits: {}",
835 self.resource_manager.resource_pool.total_qubits
836 ),
837 ));
838 }
839
840 let selected_backends = self.select_backends(&job)?;
842 if selected_backends.is_empty() {
843 return Err(QuantRS2Error::BackendExecutionFailed(
844 "No suitable backends available".to_string(),
845 ));
846 }
847
848 Ok(job.id)
856 }
857
858 fn select_backends<const N: usize>(
860 &self,
861 job: &DistributedJob<N>,
862 ) -> QuantRS2Result<Vec<String>> {
863 let mut suitable_backends = Vec::new();
864
865 for backend in &self.backends {
866 if self.is_backend_suitable(backend, job) {
867 suitable_backends.push(backend.id.clone());
868 }
869 }
870
871 match self.load_balancer.strategy {
873 LoadBalancingStrategy::RoundRobin => {
874 suitable_backends.truncate(self.fault_tolerance.redundancy_level.max(1));
876 }
877 LoadBalancingStrategy::LeastQueueTime => {
878 suitable_backends.sort_by(|a, b| {
880 let backend_a = self
881 .backends
882 .iter()
883 .find(|backend| backend.id == *a)
884 .expect("Backend ID in suitable_backends must exist in backends list");
885 let backend_b = self
886 .backends
887 .iter()
888 .find(|backend| backend.id == *b)
889 .expect("Backend ID in suitable_backends must exist in backends list");
890 backend_a
891 .queue_info
892 .estimated_wait_time
893 .partial_cmp(&backend_b.queue_info.estimated_wait_time)
894 .unwrap_or(std::cmp::Ordering::Equal)
895 });
896 suitable_backends.truncate(self.fault_tolerance.redundancy_level.max(1));
897 }
898 _ => {
899 suitable_backends.truncate(1);
901 }
902 }
903
904 Ok(suitable_backends)
905 }
906
907 fn is_backend_suitable<const N: usize>(
909 &self,
910 backend: &ExecutionBackend,
911 job: &DistributedJob<N>,
912 ) -> bool {
913 if backend.status != BackendStatus::Available {
915 return false;
916 }
917
918 if job.circuit.num_qubits() > backend.performance.max_qubits {
920 return false;
921 }
922
923 if job.circuit.num_gates() > backend.performance.max_depth {
925 return false;
926 }
927
928 if let Some(ref targets) = job.target_backends {
930 if !targets.contains(&backend.id) {
931 return false;
932 }
933 }
934
935 if backend.queue_info.queue_length >= backend.queue_info.max_queue_size {
937 return false;
938 }
939
940 true
941 }
942
943 pub const fn get_job_status(&self, job_id: &str) -> QuantRS2Result<ExecutionStatus> {
945 Ok(ExecutionStatus::Queued)
947 }
948
949 pub const fn cancel_job(&mut self, job_id: &str) -> QuantRS2Result<()> {
951 Ok(())
954 }
955
956 pub fn get_results(&self, job_id: &str) -> QuantRS2Result<DistributedResult> {
958 Ok(DistributedResult {
961 job_id: job_id.to_string(),
962 status: ExecutionStatus::Completed,
963 backend_results: HashMap::new(),
964 final_result: None,
965 metadata: ExecutionMetadata {
966 total_time: Duration::from_secs(1),
967 queue_time: Duration::from_secs(0),
968 backends_used: vec!["backend_1".to_string()],
969 resource_usage: ResourceUsage {
970 cpu_hours: 0.1,
971 memory_hours: 0.1,
972 qubit_hours: 0.1,
973 network_usage: 0.01,
974 },
975 cost_info: None,
976 },
977 })
978 }
979
980 #[must_use]
982 pub fn get_health_status(&self) -> SystemHealthStatus {
983 let available_backends = self
984 .backends
985 .iter()
986 .filter(|b| b.status == BackendStatus::Available)
987 .count();
988
989 let total_qubits = self
990 .backends
991 .iter()
992 .filter(|b| b.status == BackendStatus::Available)
993 .map(|b| b.performance.max_qubits)
994 .sum();
995
996 SystemHealthStatus {
997 total_backends: self.backends.len(),
998 available_backends,
999 total_qubits,
1000 average_queue_time: self
1001 .backends
1002 .iter()
1003 .map(|b| b.queue_info.estimated_wait_time)
1004 .sum::<f64>()
1005 / self.backends.len() as f64,
1006 system_load: self.calculate_system_load(),
1007 }
1008 }
1009
1010 fn calculate_system_load(&self) -> f64 {
1012 if self.backends.is_empty() {
1013 return 0.0;
1014 }
1015
1016 let total_capacity: f64 = self
1017 .backends
1018 .iter()
1019 .map(|b| b.queue_info.max_queue_size as f64)
1020 .sum();
1021
1022 let current_load: f64 = self
1023 .backends
1024 .iter()
1025 .map(|b| b.queue_info.queue_length as f64)
1026 .sum();
1027
1028 if total_capacity > 0.0 {
1029 current_load / total_capacity
1030 } else {
1031 0.0
1032 }
1033 }
1034}
1035
1036#[derive(Debug, Clone)]
1038pub struct SystemHealthStatus {
1039 pub total_backends: usize,
1041 pub available_backends: usize,
1043 pub total_qubits: usize,
1045 pub average_queue_time: f64,
1047 pub system_load: f64,
1049}
1050
1051impl Default for DistributedExecutor {
1052 fn default() -> Self {
1053 Self::new()
1054 }
1055}
1056
1057#[cfg(test)]
1058mod tests {
1059 use super::*;
1060
1061 #[test]
1062 fn test_distributed_executor_creation() {
1063 let executor = DistributedExecutor::new();
1064 assert_eq!(executor.backends.len(), 0);
1065 assert_eq!(executor.resource_manager.resource_pool.total_qubits, 0);
1066 }
1067
1068 #[test]
1069 fn test_backend_addition() {
1070 let mut executor = DistributedExecutor::new();
1071
1072 let backend = ExecutionBackend {
1073 id: "test_backend".to_string(),
1074 backend_type: BackendType::Simulator {
1075 simulator_type: SimulatorType::StateVector,
1076 host: "localhost".to_string(),
1077 },
1078 status: BackendStatus::Available,
1079 performance: BackendPerformance {
1080 max_qubits: 10,
1081 max_depth: 1000,
1082 gate_fidelities: HashMap::new(),
1083 coherence_times: HashMap::new(),
1084 execution_time_model: ExecutionTimeModel {
1085 base_time: 0.1,
1086 time_per_gate: 0.001,
1087 time_per_qubit: 0.01,
1088 time_per_measurement: 0.005,
1089 network_latency: 0.05,
1090 },
1091 throughput: 10.0,
1092 },
1093 queue_info: QueueInfo {
1094 queue_length: 0,
1095 estimated_wait_time: 0.0,
1096 max_queue_size: 100,
1097 priority_levels: vec![Priority::Normal, Priority::High],
1098 },
1099 capabilities: BackendCapabilities {
1100 supported_gates: vec!["h".to_string(), "cnot".to_string()],
1101 mid_circuit_measurements: false,
1102 classical_control: false,
1103 reset_operations: false,
1104 connectivity: ConnectivityGraph {
1105 num_qubits: 10,
1106 edges: vec![(0, 1), (1, 2)],
1107 topology: TopologyType::Linear,
1108 },
1109 noise_model: None,
1110 },
1111 network_config: NetworkConfig {
1112 endpoint: "http://localhost:8080".to_string(),
1113 credentials: Credentials {
1114 auth_type: AuthenticationType::None,
1115 api_key: None,
1116 token: None,
1117 username_password: None,
1118 },
1119 timeouts: TimeoutConfig {
1120 connection_timeout: 5.0,
1121 request_timeout: 30.0,
1122 total_timeout: 60.0,
1123 },
1124 retry_policy: RetryPolicy {
1125 max_retries: 3,
1126 base_delay: 1.0,
1127 backoff_strategy: BackoffStrategy::Exponential { multiplier: 2.0 },
1128 retryable_errors: vec![ErrorType::NetworkError, ErrorType::TimeoutError],
1129 },
1130 },
1131 };
1132
1133 executor
1134 .add_backend(backend)
1135 .expect("Failed to add backend to executor");
1136 assert_eq!(executor.backends.len(), 1);
1137 assert_eq!(executor.resource_manager.resource_pool.total_qubits, 10);
1138 }
1139
1140 #[test]
1141 fn test_job_submission() {
1142 let mut executor = DistributedExecutor::new();
1143
1144 let backend = create_test_backend();
1146 executor
1147 .add_backend(backend)
1148 .expect("Failed to add backend to executor");
1149
1150 let mut circuit = Circuit::<2>::new();
1152 circuit.h(QubitId(0)).expect("Failed to add Hadamard gate"); let job = DistributedJob {
1154 id: "test_job".to_string(),
1155 circuit,
1156 parameters: ExecutionParameters {
1157 shots: 1000,
1158 optimization_level: 1,
1159 error_mitigation: vec![],
1160 result_format: ResultFormat::Counts,
1161 memory_requirement: None,
1162 },
1163 priority: Priority::Normal,
1164 target_backends: None,
1165 submitted_at: Instant::now(),
1166 deadline: None,
1167 };
1168
1169 let job_id = executor
1170 .submit_job(job)
1171 .expect("Failed to submit job to executor");
1172 assert_eq!(job_id, "test_job");
1173 }
1174
1175 fn create_test_backend() -> ExecutionBackend {
1176 ExecutionBackend {
1177 id: "test_backend".to_string(),
1178 backend_type: BackendType::Simulator {
1179 simulator_type: SimulatorType::StateVector,
1180 host: "localhost".to_string(),
1181 },
1182 status: BackendStatus::Available,
1183 performance: BackendPerformance {
1184 max_qubits: 10,
1185 max_depth: 1000,
1186 gate_fidelities: HashMap::new(),
1187 coherence_times: HashMap::new(),
1188 execution_time_model: ExecutionTimeModel {
1189 base_time: 0.1,
1190 time_per_gate: 0.001,
1191 time_per_qubit: 0.01,
1192 time_per_measurement: 0.005,
1193 network_latency: 0.05,
1194 },
1195 throughput: 10.0,
1196 },
1197 queue_info: QueueInfo {
1198 queue_length: 0,
1199 estimated_wait_time: 0.0,
1200 max_queue_size: 100,
1201 priority_levels: vec![Priority::Normal, Priority::High],
1202 },
1203 capabilities: BackendCapabilities {
1204 supported_gates: vec!["h".to_string(), "cnot".to_string()],
1205 mid_circuit_measurements: false,
1206 classical_control: false,
1207 reset_operations: false,
1208 connectivity: ConnectivityGraph {
1209 num_qubits: 10,
1210 edges: vec![(0, 1), (1, 2)],
1211 topology: TopologyType::Linear,
1212 },
1213 noise_model: None,
1214 },
1215 network_config: NetworkConfig {
1216 endpoint: "http://localhost:8080".to_string(),
1217 credentials: Credentials {
1218 auth_type: AuthenticationType::None,
1219 api_key: None,
1220 token: None,
1221 username_password: None,
1222 },
1223 timeouts: TimeoutConfig {
1224 connection_timeout: 5.0,
1225 request_timeout: 30.0,
1226 total_timeout: 60.0,
1227 },
1228 retry_policy: RetryPolicy {
1229 max_retries: 3,
1230 base_delay: 1.0,
1231 backoff_strategy: BackoffStrategy::Exponential { multiplier: 2.0 },
1232 retryable_errors: vec![ErrorType::NetworkError, ErrorType::TimeoutError],
1233 },
1234 },
1235 }
1236 }
1237}