1use scirs2_core::ndarray::Array1;
9use scirs2_core::Complex64;
10use scirs2_core::random::{thread_rng, Rng};
11use scirs2_core::parallel_ops::*;
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14use std::f64::consts::PI;
15
16use crate::error::{Result, SimulatorError};
17use crate::scirs2_integration::SciRS2Backend;
18use crate::statevector::StateVectorSimulator;
19use scirs2_core::random::prelude::*;
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct QMLConfig {
24 pub num_qubits: usize,
26 pub architecture_type: QMLArchitectureType,
28 pub layer_configs: Vec<QMLLayerConfig>,
30 pub training_config: QMLTrainingConfig,
32 pub hardware_optimization: HardwareOptimizationConfig,
34 pub classical_preprocessing: ClassicalPreprocessingConfig,
36 pub hybrid_training: HybridTrainingConfig,
38 pub quantum_advantage_analysis: bool,
40 pub noise_aware_training: NoiseAwareTrainingConfig,
42 pub performance_optimization: PerformanceOptimizationConfig,
44}
45
46impl Default for QMLConfig {
47 fn default() -> Self {
48 Self {
49 num_qubits: 8,
50 architecture_type: QMLArchitectureType::VariationalQuantumCircuit,
51 layer_configs: vec![QMLLayerConfig {
52 layer_type: QMLLayerType::ParameterizedQuantumCircuit,
53 num_parameters: 16,
54 ansatz_type: AnsatzType::Hardware,
55 entanglement_pattern: EntanglementPattern::Linear,
56 rotation_gates: vec![RotationGate::RY, RotationGate::RZ],
57 depth: 4,
58 enable_gradient_computation: true,
59 }],
60 training_config: QMLTrainingConfig::default(),
61 hardware_optimization: HardwareOptimizationConfig::default(),
62 classical_preprocessing: ClassicalPreprocessingConfig::default(),
63 hybrid_training: HybridTrainingConfig::default(),
64 quantum_advantage_analysis: true,
65 noise_aware_training: NoiseAwareTrainingConfig::default(),
66 performance_optimization: PerformanceOptimizationConfig::default(),
67 }
68 }
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
73pub enum QMLArchitectureType {
74 VariationalQuantumCircuit,
76 QuantumConvolutionalNN,
78 QuantumRecurrentNN,
80 QuantumGraphNN,
82 QuantumAttentionNetwork,
84 QuantumTransformer,
86 HybridClassicalQuantum,
88 QuantumBoltzmannMachine,
90 QuantumGAN,
92 QuantumAutoencoder,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct QMLLayerConfig {
99 pub layer_type: QMLLayerType,
101 pub num_parameters: usize,
103 pub ansatz_type: AnsatzType,
105 pub entanglement_pattern: EntanglementPattern,
107 pub rotation_gates: Vec<RotationGate>,
109 pub depth: usize,
111 pub enable_gradient_computation: bool,
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
117pub enum QMLLayerType {
118 ParameterizedQuantumCircuit,
120 QuantumConvolutional,
122 QuantumPooling,
124 QuantumDense,
126 QuantumLSTM,
128 QuantumGRU,
130 QuantumAttention,
132 QuantumDropout,
134 QuantumBatchNorm,
136 DataReUpload,
138}
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
142pub enum AnsatzType {
143 Hardware,
145 ProblemSpecific,
147 AllToAll,
149 Layered,
151 Alternating,
153 BrickWall,
155 Tree,
157 Custom,
159}
160
161#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
163pub enum EntanglementPattern {
164 Linear,
166 Circular,
168 AllToAll,
170 Star,
172 Grid,
174 Random,
176 Block,
178 Custom,
180}
181
182#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
184pub enum RotationGate {
185 RX,
187 RY,
189 RZ,
191 U3,
193 Phase,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
199pub struct QMLTrainingConfig {
200 pub algorithm: QMLTrainingAlgorithm,
202 pub learning_rate: f64,
204 pub epochs: usize,
206 pub batch_size: usize,
208 pub gradient_method: GradientMethod,
210 pub optimizer: OptimizerType,
212 pub regularization: RegularizationConfig,
214 pub early_stopping: EarlyStoppingConfig,
216 pub lr_schedule: LearningRateSchedule,
218}
219
220impl Default for QMLTrainingConfig {
221 fn default() -> Self {
222 Self {
223 algorithm: QMLTrainingAlgorithm::ParameterShift,
224 learning_rate: 0.01,
225 epochs: 100,
226 batch_size: 32,
227 gradient_method: GradientMethod::ParameterShift,
228 optimizer: OptimizerType::Adam,
229 regularization: RegularizationConfig::default(),
230 early_stopping: EarlyStoppingConfig::default(),
231 lr_schedule: LearningRateSchedule::Constant,
232 }
233 }
234}
235
236#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
238pub enum QMLTrainingAlgorithm {
239 ParameterShift,
241 FiniteDifference,
243 QuantumNaturalGradient,
245 SPSA,
247 QAOA,
249 VQE,
251 Rotosolve,
253 HybridTraining,
255}
256
257#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
259pub enum GradientMethod {
260 ParameterShift,
262 FiniteDifference,
264 Adjoint,
266 Backpropagation,
268 QuantumFisherInformation,
270}
271
272#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
274pub enum OptimizerType {
275 SGD,
277 Adam,
279 AdaGrad,
281 RMSprop,
283 Momentum,
285 LBFGS,
287 QuantumNaturalGradient,
289 SPSA,
291}
292
293#[derive(Debug, Clone, Serialize, Deserialize)]
295pub struct RegularizationConfig {
296 pub l1_strength: f64,
298 pub l2_strength: f64,
300 pub dropout_prob: f64,
302 pub parameter_bounds: Option<(f64, f64)>,
304 pub enable_clipping: bool,
306 pub gradient_clip_threshold: f64,
308}
309
310impl Default for RegularizationConfig {
311 fn default() -> Self {
312 Self {
313 l1_strength: 0.0,
314 l2_strength: 0.001,
315 dropout_prob: 0.1,
316 parameter_bounds: Some((-PI, PI)),
317 enable_clipping: true,
318 gradient_clip_threshold: 1.0,
319 }
320 }
321}
322
323#[derive(Debug, Clone, Serialize, Deserialize)]
325pub struct EarlyStoppingConfig {
326 pub enabled: bool,
328 pub patience: usize,
330 pub min_delta: f64,
332 pub monitor_metric: String,
334 pub mode_max: bool,
336}
337
338impl Default for EarlyStoppingConfig {
339 fn default() -> Self {
340 Self {
341 enabled: true,
342 patience: 10,
343 min_delta: 1e-6,
344 monitor_metric: "val_loss".to_string(),
345 mode_max: false,
346 }
347 }
348}
349
350#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
352pub enum LearningRateSchedule {
353 Constant,
355 ExponentialDecay,
357 StepDecay,
359 CosineAnnealing,
361 WarmRestart,
363 ReduceOnPlateau,
365}
366
367#[derive(Debug, Clone, Serialize, Deserialize)]
369pub struct HardwareOptimizationConfig {
370 pub target_hardware: QuantumHardwareTarget,
372 pub minimize_gate_count: bool,
374 pub minimize_depth: bool,
376 pub noise_aware: bool,
378 pub connectivity_constraints: ConnectivityConstraints,
380 pub gate_fidelities: HashMap<String, f64>,
382 pub enable_parallelization: bool,
384 pub optimization_level: HardwareOptimizationLevel,
386}
387
388impl Default for HardwareOptimizationConfig {
389 fn default() -> Self {
390 let mut gate_fidelities = HashMap::new();
391 gate_fidelities.insert("single_qubit".to_string(), 0.999);
392 gate_fidelities.insert("two_qubit".to_string(), 0.99);
393
394 Self {
395 target_hardware: QuantumHardwareTarget::Simulator,
396 minimize_gate_count: true,
397 minimize_depth: true,
398 noise_aware: false,
399 connectivity_constraints: ConnectivityConstraints::AllToAll,
400 gate_fidelities,
401 enable_parallelization: true,
402 optimization_level: HardwareOptimizationLevel::Medium,
403 }
404 }
405}
406
407#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
409pub enum QuantumHardwareTarget {
410 Simulator,
412 IBM,
414 Google,
416 IonQ,
418 Rigetti,
420 Quantinuum,
422 Xanadu,
424 Custom,
426}
427
428#[derive(Debug, Clone, Serialize, Deserialize)]
430pub enum ConnectivityConstraints {
431 AllToAll,
433 Linear,
435 Grid(usize, usize), Custom(Vec<(usize, usize)>), HeavyHex,
441 Square,
443}
444
445#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
447pub enum HardwareOptimizationLevel {
448 Basic,
450 Medium,
452 Aggressive,
454 Maximum,
456}
457
458#[derive(Debug, Clone, Serialize, Deserialize)]
460pub struct ClassicalPreprocessingConfig {
461 pub feature_scaling: bool,
463 pub scaling_method: ScalingMethod,
465 pub enable_pca: bool,
467 pub pca_components: Option<usize>,
469 pub encoding_method: DataEncodingMethod,
471 pub feature_selection: FeatureSelectionConfig,
473}
474
475impl Default for ClassicalPreprocessingConfig {
476 fn default() -> Self {
477 Self {
478 feature_scaling: true,
479 scaling_method: ScalingMethod::StandardScaler,
480 enable_pca: false,
481 pca_components: None,
482 encoding_method: DataEncodingMethod::Amplitude,
483 feature_selection: FeatureSelectionConfig::default(),
484 }
485 }
486}
487
488#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
490pub enum ScalingMethod {
491 StandardScaler,
493 MinMaxScaler,
495 RobustScaler,
497 QuantileUniform,
499 PowerTransformer,
501}
502
503#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
505pub enum DataEncodingMethod {
506 Amplitude,
508 Angle,
510 Basis,
512 QuantumFeatureMap,
514 IQP,
516 PauliFeatureMap,
518 DataReUpload,
520}
521
522#[derive(Debug, Clone, Serialize, Deserialize)]
524pub struct FeatureSelectionConfig {
525 pub enabled: bool,
527 pub method: FeatureSelectionMethod,
529 pub num_features: Option<usize>,
531 pub threshold: f64,
533}
534
535impl Default for FeatureSelectionConfig {
536 fn default() -> Self {
537 Self {
538 enabled: false,
539 method: FeatureSelectionMethod::VarianceThreshold,
540 num_features: None,
541 threshold: 0.0,
542 }
543 }
544}
545
546#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
548pub enum FeatureSelectionMethod {
549 VarianceThreshold,
551 UnivariateSelection,
553 RecursiveFeatureElimination,
555 L1Based,
557 TreeBased,
559 QuantumFeatureImportance,
561}
562
563#[derive(Debug, Clone, Serialize, Deserialize)]
565pub struct HybridTrainingConfig {
566 pub enabled: bool,
568 pub classical_architecture: ClassicalArchitecture,
570 pub interface_config: QuantumClassicalInterface,
572 pub alternating_schedule: AlternatingSchedule,
574 pub gradient_flow: GradientFlowConfig,
576}
577
578impl Default for HybridTrainingConfig {
579 fn default() -> Self {
580 Self {
581 enabled: false,
582 classical_architecture: ClassicalArchitecture::MLP,
583 interface_config: QuantumClassicalInterface::Expectation,
584 alternating_schedule: AlternatingSchedule::Simultaneous,
585 gradient_flow: GradientFlowConfig::default(),
586 }
587 }
588}
589
590#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
592pub enum ClassicalArchitecture {
593 MLP,
595 CNN,
597 RNN,
599 LSTM,
601 Transformer,
603 ResNet,
605 Custom,
607}
608
609#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
611pub enum QuantumClassicalInterface {
612 Expectation,
614 Sampling,
616 StateTomography,
618 ProcessTomography,
620 ShadowTomography,
622}
623
624#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
626pub enum AlternatingSchedule {
627 Simultaneous,
629 Alternating,
631 ClassicalFirst,
633 QuantumFirst,
635 Custom,
637}
638
639#[derive(Debug, Clone, Serialize, Deserialize)]
641pub struct GradientFlowConfig {
642 pub classical_to_quantum: bool,
644 pub quantum_to_classical: bool,
646 pub gradient_scaling: f64,
648 pub enable_clipping: bool,
650 pub accumulation_steps: usize,
652}
653
654impl Default for GradientFlowConfig {
655 fn default() -> Self {
656 Self {
657 classical_to_quantum: true,
658 quantum_to_classical: true,
659 gradient_scaling: 1.0,
660 enable_clipping: true,
661 accumulation_steps: 1,
662 }
663 }
664}
665
666#[derive(Debug, Clone, Serialize, Deserialize)]
668pub struct NoiseAwareTrainingConfig {
669 pub enabled: bool,
671 pub noise_parameters: NoiseParameters,
673 pub error_mitigation: ErrorMitigationConfig,
675 pub noise_characterization: NoiseCharacterizationConfig,
677 pub robust_training: RobustTrainingConfig,
679}
680
681impl Default for NoiseAwareTrainingConfig {
682 fn default() -> Self {
683 Self {
684 enabled: false,
685 noise_parameters: NoiseParameters::default(),
686 error_mitigation: ErrorMitigationConfig::default(),
687 noise_characterization: NoiseCharacterizationConfig::default(),
688 robust_training: RobustTrainingConfig::default(),
689 }
690 }
691}
692
693#[derive(Debug, Clone, Serialize, Deserialize)]
695pub struct NoiseParameters {
696 pub single_qubit_error: f64,
698 pub two_qubit_error: f64,
700 pub measurement_error: f64,
702 pub coherence_times: (f64, f64),
704 pub gate_times: HashMap<String, f64>,
706}
707
708impl Default for NoiseParameters {
709 fn default() -> Self {
710 let mut gate_times = HashMap::new();
711 gate_times.insert("single_qubit".to_string(), 50e-9); gate_times.insert("two_qubit".to_string(), 200e-9); Self {
715 single_qubit_error: 0.001,
716 two_qubit_error: 0.01,
717 measurement_error: 0.01,
718 coherence_times: (50e-6, 100e-6), gate_times,
720 }
721 }
722}
723
724#[derive(Debug, Clone, Serialize, Deserialize)]
726pub struct ErrorMitigationConfig {
727 pub zero_noise_extrapolation: bool,
729 pub readout_error_mitigation: bool,
731 pub symmetry_verification: bool,
733 pub virtual_distillation: VirtualDistillationConfig,
735 pub quantum_error_correction: bool,
737}
738
739impl Default for ErrorMitigationConfig {
740 fn default() -> Self {
741 Self {
742 zero_noise_extrapolation: false,
743 readout_error_mitigation: false,
744 symmetry_verification: false,
745 virtual_distillation: VirtualDistillationConfig::default(),
746 quantum_error_correction: false,
747 }
748 }
749}
750
751#[derive(Debug, Clone, Serialize, Deserialize)]
753pub struct VirtualDistillationConfig {
754 pub enabled: bool,
756 pub num_copies: usize,
758 pub protocol: DistillationProtocol,
760}
761
762impl Default for VirtualDistillationConfig {
763 fn default() -> Self {
764 Self {
765 enabled: false,
766 num_copies: 2,
767 protocol: DistillationProtocol::Standard,
768 }
769 }
770}
771
772#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
774pub enum DistillationProtocol {
775 Standard,
777 Improved,
779 QuantumAdvantage,
781}
782
783#[derive(Debug, Clone, Serialize, Deserialize)]
785pub struct NoiseCharacterizationConfig {
786 pub enabled: bool,
788 pub method: NoiseCharacterizationMethod,
790 pub benchmarking: BenchmarkingProtocols,
792 pub calibration_frequency: CalibrationFrequency,
794}
795
796impl Default for NoiseCharacterizationConfig {
797 fn default() -> Self {
798 Self {
799 enabled: false,
800 method: NoiseCharacterizationMethod::ProcessTomography,
801 benchmarking: BenchmarkingProtocols::default(),
802 calibration_frequency: CalibrationFrequency::Daily,
803 }
804 }
805}
806
807#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
809pub enum NoiseCharacterizationMethod {
810 ProcessTomography,
812 RandomizedBenchmarking,
814 GateSetTomography,
816 QuantumDetectorTomography,
818 CrossEntropyBenchmarking,
820}
821
822#[derive(Debug, Clone, Serialize, Deserialize)]
824pub struct BenchmarkingProtocols {
825 pub randomized_benchmarking: bool,
827 pub quantum_volume: bool,
829 pub cross_entropy_benchmarking: bool,
831 pub mirror_benchmarking: bool,
833}
834
835impl Default for BenchmarkingProtocols {
836 fn default() -> Self {
837 Self {
838 randomized_benchmarking: true,
839 quantum_volume: false,
840 cross_entropy_benchmarking: false,
841 mirror_benchmarking: false,
842 }
843 }
844}
845
846#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
848pub enum CalibrationFrequency {
849 RealTime,
851 Hourly,
853 Daily,
855 Weekly,
857 Manual,
859}
860
861#[derive(Debug, Clone, Serialize, Deserialize)]
863pub struct RobustTrainingConfig {
864 pub enabled: bool,
866 pub noise_injection: NoiseInjectionConfig,
868 pub adversarial_training: AdversarialTrainingConfig,
870 pub ensemble_methods: EnsembleMethodsConfig,
872}
873
874impl Default for RobustTrainingConfig {
875 fn default() -> Self {
876 Self {
877 enabled: false,
878 noise_injection: NoiseInjectionConfig::default(),
879 adversarial_training: AdversarialTrainingConfig::default(),
880 ensemble_methods: EnsembleMethodsConfig::default(),
881 }
882 }
883}
884
885#[derive(Debug, Clone, Serialize, Deserialize)]
887pub struct NoiseInjectionConfig {
888 pub enabled: bool,
890 pub injection_probability: f64,
892 pub noise_strength: f64,
894 pub noise_type: NoiseType,
896}
897
898impl Default for NoiseInjectionConfig {
899 fn default() -> Self {
900 Self {
901 enabled: false,
902 injection_probability: 0.1,
903 noise_strength: 0.01,
904 noise_type: NoiseType::Depolarizing,
905 }
906 }
907}
908
909#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
911pub enum NoiseType {
912 Depolarizing,
914 AmplitudeDamping,
916 PhaseDamping,
918 BitFlip,
920 PhaseFlip,
922 Pauli,
924}
925
926#[derive(Debug, Clone, Serialize, Deserialize)]
928pub struct AdversarialTrainingConfig {
929 pub enabled: bool,
931 pub attack_strength: f64,
933 pub attack_method: AdversarialAttackMethod,
935 pub defense_method: AdversarialDefenseMethod,
937}
938
939impl Default for AdversarialTrainingConfig {
940 fn default() -> Self {
941 Self {
942 enabled: false,
943 attack_strength: 0.01,
944 attack_method: AdversarialAttackMethod::FGSM,
945 defense_method: AdversarialDefenseMethod::AdversarialTraining,
946 }
947 }
948}
949
950#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
952pub enum AdversarialAttackMethod {
953 FGSM,
955 PGD,
957 CarliniWagner,
959 QuantumAdversarial,
961}
962
963#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
965pub enum AdversarialDefenseMethod {
966 AdversarialTraining,
968 DefensiveDistillation,
970 CertifiedDefenses,
972 QuantumErrorCorrection,
974}
975
976#[derive(Debug, Clone, Serialize, Deserialize)]
978pub struct EnsembleMethodsConfig {
979 pub enabled: bool,
981 pub num_ensemble: usize,
983 pub ensemble_method: EnsembleMethod,
985 pub voting_strategy: VotingStrategy,
987}
988
989impl Default for EnsembleMethodsConfig {
990 fn default() -> Self {
991 Self {
992 enabled: false,
993 num_ensemble: 5,
994 ensemble_method: EnsembleMethod::Bagging,
995 voting_strategy: VotingStrategy::MajorityVoting,
996 }
997 }
998}
999
1000#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1002pub enum EnsembleMethod {
1003 Bagging,
1005 Boosting,
1007 RandomForest,
1009 QuantumEnsemble,
1011}
1012
1013#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1015pub enum VotingStrategy {
1016 MajorityVoting,
1018 WeightedVoting,
1020 SoftVoting,
1022 QuantumVoting,
1024}
1025
1026#[derive(Debug, Clone, Serialize, Deserialize)]
1028pub struct PerformanceOptimizationConfig {
1029 pub enabled: bool,
1031 pub memory_optimization: MemoryOptimizationConfig,
1033 pub computation_optimization: ComputationOptimizationConfig,
1035 pub parallelization: ParallelizationConfig,
1037 pub caching: CachingConfig,
1039}
1040
1041impl Default for PerformanceOptimizationConfig {
1042 fn default() -> Self {
1043 Self {
1044 enabled: true,
1045 memory_optimization: MemoryOptimizationConfig::default(),
1046 computation_optimization: ComputationOptimizationConfig::default(),
1047 parallelization: ParallelizationConfig::default(),
1048 caching: CachingConfig::default(),
1049 }
1050 }
1051}
1052
1053#[derive(Debug, Clone, Serialize, Deserialize)]
1055pub struct MemoryOptimizationConfig {
1056 pub enabled: bool,
1058 pub memory_mapping: bool,
1060 pub gradient_checkpointing: bool,
1062 pub memory_pool_size: Option<usize>,
1064}
1065
1066impl Default for MemoryOptimizationConfig {
1067 fn default() -> Self {
1068 Self {
1069 enabled: true,
1070 memory_mapping: false,
1071 gradient_checkpointing: false,
1072 memory_pool_size: None,
1073 }
1074 }
1075}
1076
1077#[derive(Debug, Clone, Serialize, Deserialize)]
1079pub struct ComputationOptimizationConfig {
1080 pub enabled: bool,
1082 pub mixed_precision: bool,
1084 pub simd_optimization: bool,
1086 pub jit_compilation: bool,
1088}
1089
1090impl Default for ComputationOptimizationConfig {
1091 fn default() -> Self {
1092 Self {
1093 enabled: true,
1094 mixed_precision: false,
1095 simd_optimization: true,
1096 jit_compilation: false,
1097 }
1098 }
1099}
1100
1101#[derive(Debug, Clone, Serialize, Deserialize)]
1103pub struct ParallelizationConfig {
1104 pub enabled: bool,
1106 pub num_threads: Option<usize>,
1108 pub data_parallelism: bool,
1110 pub model_parallelism: bool,
1112 pub pipeline_parallelism: bool,
1114}
1115
1116impl Default for ParallelizationConfig {
1117 fn default() -> Self {
1118 Self {
1119 enabled: true,
1120 num_threads: None,
1121 data_parallelism: true,
1122 model_parallelism: false,
1123 pipeline_parallelism: false,
1124 }
1125 }
1126}
1127
1128#[derive(Debug, Clone, Serialize, Deserialize)]
1130pub struct CachingConfig {
1131 pub enabled: bool,
1133 pub cache_size: usize,
1135 pub cache_gradients: bool,
1137 pub cache_intermediate: bool,
1139}
1140
1141impl Default for CachingConfig {
1142 fn default() -> Self {
1143 Self {
1144 enabled: true,
1145 cache_size: 1000,
1146 cache_gradients: true,
1147 cache_intermediate: false,
1148 }
1149 }
1150}
1151
1152#[derive(Debug)]
1154pub struct QuantumMLFramework {
1155 config: QMLConfig,
1157 layers: Vec<Box<dyn QMLLayer>>,
1159 training_state: QMLTrainingState,
1161 backend: Option<SciRS2Backend>,
1163 stats: QMLStats,
1165 training_history: Vec<QMLTrainingResult>,
1167}
1168
1169impl QuantumMLFramework {
1170 pub fn new(config: QMLConfig) -> Result<Self> {
1172 let mut framework = Self {
1173 config: config.clone(),
1174 layers: Vec::new(),
1175 training_state: QMLTrainingState::new(),
1176 backend: None,
1177 stats: QMLStats::new(),
1178 training_history: Vec::new(),
1179 };
1180
1181 framework.initialize_layers()?;
1183
1184 let backend = SciRS2Backend::new();
1186 if backend.is_available() {
1187 framework.backend = Some(backend);
1188 }
1189
1190 Ok(framework)
1191 }
1192
1193 fn initialize_layers(&mut self) -> Result<()> {
1195 for layer_config in &self.config.layer_configs {
1196 let layer = self.create_layer(layer_config)?;
1197 self.layers.push(layer);
1198 }
1199 Ok(())
1200 }
1201
1202 fn create_layer(&self, config: &QMLLayerConfig) -> Result<Box<dyn QMLLayer>> {
1204 match config.layer_type {
1205 QMLLayerType::ParameterizedQuantumCircuit => Ok(Box::new(
1206 ParameterizedQuantumCircuitLayer::new(self.config.num_qubits, config.clone())?,
1207 )),
1208 QMLLayerType::QuantumConvolutional => Ok(Box::new(QuantumConvolutionalLayer::new(
1209 self.config.num_qubits,
1210 config.clone(),
1211 )?)),
1212 QMLLayerType::QuantumDense => Ok(Box::new(QuantumDenseLayer::new(
1213 self.config.num_qubits,
1214 config.clone(),
1215 )?)),
1216 QMLLayerType::QuantumLSTM => Ok(Box::new(QuantumLSTMLayer::new(
1217 self.config.num_qubits,
1218 config.clone(),
1219 )?)),
1220 QMLLayerType::QuantumAttention => Ok(Box::new(QuantumAttentionLayer::new(
1221 self.config.num_qubits,
1222 config.clone(),
1223 )?)),
1224 _ => Err(SimulatorError::InvalidConfiguration(format!(
1225 "Layer type {:?} not yet implemented",
1226 config.layer_type
1227 ))),
1228 }
1229 }
1230
1231 pub fn forward(&mut self, input: &Array1<f64>) -> Result<Array1<f64>> {
1233 let mut current_state = self.encode_input(input)?;
1234
1235 for layer in &mut self.layers {
1237 current_state = layer.forward(¤t_state)?;
1238 }
1239
1240 let output = self.decode_output(¤t_state)?;
1242
1243 self.stats.forward_passes += 1;
1245
1246 Ok(output)
1247 }
1248
1249 pub fn backward(&mut self, loss_gradient: &Array1<f64>) -> Result<Array1<f64>> {
1251 let mut grad = loss_gradient.clone();
1252
1253 for layer in self.layers.iter_mut().rev() {
1255 grad = layer.backward(&grad)?;
1256 }
1257
1258 self.stats.backward_passes += 1;
1260
1261 Ok(grad)
1262 }
1263
1264 pub fn train(
1266 &mut self,
1267 training_data: &[(Array1<f64>, Array1<f64>)],
1268 validation_data: Option<&[(Array1<f64>, Array1<f64>)]>,
1269 ) -> Result<QMLTrainingResult> {
1270 let mut best_validation_loss = f64::INFINITY;
1271 let mut patience_counter = 0;
1272 let mut training_metrics = Vec::new();
1273
1274 let training_start = std::time::Instant::now();
1275
1276 for epoch in 0..self.config.training_config.epochs {
1277 let epoch_start = std::time::Instant::now();
1278
1279 let mut epoch_loss = 0.0;
1281 let mut num_batches = 0;
1282
1283 for batch in training_data.chunks(self.config.training_config.batch_size) {
1284 let batch_loss = self.train_batch(batch)?;
1285 epoch_loss += batch_loss;
1286 num_batches += 1;
1287 }
1288
1289 epoch_loss /= num_batches as f64;
1290
1291 let validation_loss = if let Some(val_data) = validation_data {
1293 self.evaluate(val_data)?
1294 } else {
1295 epoch_loss
1296 };
1297
1298 let epoch_time = epoch_start.elapsed();
1299
1300 let metrics = QMLEpochMetrics {
1301 epoch,
1302 training_loss: epoch_loss,
1303 validation_loss,
1304 epoch_time,
1305 learning_rate: self.get_current_learning_rate(epoch),
1306 };
1307
1308 training_metrics.push(metrics.clone());
1309
1310 if self.config.training_config.early_stopping.enabled {
1312 if validation_loss
1313 < best_validation_loss - self.config.training_config.early_stopping.min_delta
1314 {
1315 best_validation_loss = validation_loss;
1316 patience_counter = 0;
1317 } else {
1318 patience_counter += 1;
1319 if patience_counter >= self.config.training_config.early_stopping.patience {
1320 println!("Early stopping triggered at epoch {}", epoch);
1321 break;
1322 }
1323 }
1324 }
1325
1326 self.update_learning_rate(epoch, validation_loss);
1328
1329 if epoch % 10 == 0 {
1331 println!(
1332 "Epoch {}: train_loss={:.6}, val_loss={:.6}, time={:.2}s",
1333 epoch,
1334 epoch_loss,
1335 validation_loss,
1336 epoch_time.as_secs_f64()
1337 );
1338 }
1339 }
1340
1341 let total_training_time = training_start.elapsed();
1342
1343 let result = QMLTrainingResult {
1344 final_training_loss: training_metrics
1345 .last()
1346 .map(|m| m.training_loss)
1347 .unwrap_or(0.0),
1348 final_validation_loss: training_metrics
1349 .last()
1350 .map(|m| m.validation_loss)
1351 .unwrap_or(0.0),
1352 best_validation_loss,
1353 epochs_trained: training_metrics.len(),
1354 total_training_time,
1355 training_metrics,
1356 quantum_advantage_metrics: self.compute_quantum_advantage_metrics()?,
1357 };
1358
1359 self.training_history.push(result.clone());
1360
1361 Ok(result)
1362 }
1363
1364 fn train_batch(&mut self, batch: &[(Array1<f64>, Array1<f64>)]) -> Result<f64> {
1366 let mut total_loss = 0.0;
1367 let mut total_gradients: Vec<Array1<f64>> =
1368 (0..self.layers.len()).map(|_| Array1::zeros(0)).collect();
1369
1370 for (input, target) in batch {
1371 let prediction = self.forward(input)?;
1373
1374 let loss = self.compute_loss(&prediction, target)?;
1376 total_loss += loss;
1377
1378 let loss_gradient = self.compute_loss_gradient(&prediction, target)?;
1380
1381 let gradients = self.compute_gradients(&loss_gradient)?;
1383
1384 for (i, grad) in gradients.iter().enumerate() {
1386 if total_gradients[i].len() == 0 {
1387 total_gradients[i] = grad.clone();
1388 } else {
1389 total_gradients[i] += grad;
1390 }
1391 }
1392 }
1393
1394 let batch_size = batch.len() as f64;
1396 for grad in &mut total_gradients {
1397 *grad /= batch_size;
1398 }
1399
1400 self.apply_gradients(&total_gradients)?;
1402
1403 Ok(total_loss / batch_size)
1404 }
1405
1406 pub fn evaluate(&mut self, data: &[(Array1<f64>, Array1<f64>)]) -> Result<f64> {
1408 let mut total_loss = 0.0;
1409
1410 for (input, target) in data {
1411 let prediction = self.forward(input)?;
1412 let loss = self.compute_loss(&prediction, target)?;
1413 total_loss += loss;
1414 }
1415
1416 Ok(total_loss / data.len() as f64)
1417 }
1418
1419 fn encode_input(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1421 match self.config.classical_preprocessing.encoding_method {
1422 DataEncodingMethod::Amplitude => self.encode_amplitude(input),
1423 DataEncodingMethod::Angle => self.encode_angle(input),
1424 DataEncodingMethod::Basis => self.encode_basis(input),
1425 DataEncodingMethod::QuantumFeatureMap => self.encode_quantum_feature_map(input),
1426 _ => Err(SimulatorError::InvalidConfiguration(
1427 "Encoding method not implemented".to_string(),
1428 )),
1429 }
1430 }
1431
1432 fn encode_amplitude(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1434 let n_qubits = self.config.num_qubits;
1435 let state_size = 1 << n_qubits;
1436 let mut state = Array1::zeros(state_size);
1437
1438 let norm = input.iter().map(|x| x * x).sum::<f64>().sqrt();
1440 if norm == 0.0 {
1441 return Err(SimulatorError::InvalidState("Zero input norm".to_string()));
1442 }
1443
1444 for (i, &val) in input.iter().enumerate() {
1446 if i < state_size {
1447 state[i] = Complex64::new(val / norm, 0.0);
1448 }
1449 }
1450
1451 Ok(state)
1452 }
1453
1454 fn encode_angle(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1456 let n_qubits = self.config.num_qubits;
1457 let state_size = 1 << n_qubits;
1458 let mut state = Array1::zeros(state_size);
1459
1460 state[0] = Complex64::new(1.0, 0.0);
1462
1463 for (i, &angle) in input.iter().enumerate() {
1465 if i < n_qubits {
1466 state = self.apply_ry_rotation(&state, i, angle)?;
1468 }
1469 }
1470
1471 Ok(state)
1472 }
1473
1474 fn encode_basis(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1476 let n_qubits = self.config.num_qubits;
1477 let state_size = 1 << n_qubits;
1478 let mut state = Array1::zeros(state_size);
1479
1480 let mut binary_index = 0;
1482 for (i, &val) in input.iter().enumerate() {
1483 if i < n_qubits && val > 0.5 {
1484 binary_index |= 1 << i;
1485 }
1486 }
1487
1488 state[binary_index] = Complex64::new(1.0, 0.0);
1489
1490 Ok(state)
1491 }
1492
1493 fn encode_quantum_feature_map(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1495 let n_qubits = self.config.num_qubits;
1496 let state_size = 1 << n_qubits;
1497 let mut state = Array1::zeros(state_size);
1498
1499 let hadamard_coeff = 1.0 / (2.0_f64.powf(n_qubits as f64 / 2.0));
1501 for i in 0..state_size {
1502 state[i] = Complex64::new(hadamard_coeff, 0.0);
1503 }
1504
1505 for (i, &feature) in input.iter().enumerate() {
1507 if i < n_qubits {
1508 state = self.apply_rz_rotation(&state, i, feature * PI)?;
1510 }
1511 }
1512
1513 for i in 0..(n_qubits - 1) {
1515 if i + 1 < input.len() {
1516 let interaction = input[i] * input[i + 1];
1517 state = self.apply_cnot_interaction(&state, i, i + 1, interaction * PI)?;
1518 }
1519 }
1520
1521 Ok(state)
1522 }
1523
1524 fn apply_ry_rotation(
1526 &self,
1527 state: &Array1<Complex64>,
1528 qubit: usize,
1529 angle: f64,
1530 ) -> Result<Array1<Complex64>> {
1531 let n_qubits = self.config.num_qubits;
1532 let state_size = 1 << n_qubits;
1533 let mut new_state = state.clone();
1534
1535 let cos_half = (angle / 2.0).cos();
1536 let sin_half = (angle / 2.0).sin();
1537
1538 for i in 0..state_size {
1539 if i & (1 << qubit) == 0 {
1540 let j = i | (1 << qubit); if j < state_size {
1543 let state_0 = state[i];
1544 let state_1 = state[j];
1545
1546 new_state[i] = Complex64::new(cos_half, 0.0) * state_0
1547 - Complex64::new(sin_half, 0.0) * state_1;
1548 new_state[j] = Complex64::new(sin_half, 0.0) * state_0
1549 + Complex64::new(cos_half, 0.0) * state_1;
1550 }
1551 }
1552 }
1553
1554 Ok(new_state)
1555 }
1556
1557 fn apply_rz_rotation(
1559 &self,
1560 state: &Array1<Complex64>,
1561 qubit: usize,
1562 angle: f64,
1563 ) -> Result<Array1<Complex64>> {
1564 let n_qubits = self.config.num_qubits;
1565 let state_size = 1 << n_qubits;
1566 let mut new_state = state.clone();
1567
1568 let phase_0 = Complex64::from_polar(1.0, -angle / 2.0);
1569 let phase_1 = Complex64::from_polar(1.0, angle / 2.0);
1570
1571 for i in 0..state_size {
1572 if i & (1 << qubit) == 0 {
1573 new_state[i] *= phase_0;
1574 } else {
1575 new_state[i] *= phase_1;
1576 }
1577 }
1578
1579 Ok(new_state)
1580 }
1581
1582 fn apply_cnot_interaction(
1584 &self,
1585 state: &Array1<Complex64>,
1586 control: usize,
1587 target: usize,
1588 interaction: f64,
1589 ) -> Result<Array1<Complex64>> {
1590 let n_qubits = self.config.num_qubits;
1591 let state_size = 1 << n_qubits;
1592 let mut new_state = state.clone();
1593
1594 let phase = Complex64::from_polar(1.0, interaction);
1596
1597 for i in 0..state_size {
1598 if (i & (1 << control)) != 0 && (i & (1 << target)) != 0 {
1599 new_state[i] *= phase;
1601 }
1602 }
1603
1604 Ok(new_state)
1605 }
1606
1607 fn decode_output(&self, state: &Array1<Complex64>) -> Result<Array1<f64>> {
1609 let n_qubits = self.config.num_qubits;
1611 let mut output = Array1::zeros(n_qubits);
1612
1613 for qubit in 0..n_qubits {
1614 let expectation = self.measure_pauli_z_expectation(state, qubit)?;
1615 output[qubit] = expectation;
1616 }
1617
1618 Ok(output)
1619 }
1620
1621 fn measure_pauli_z_expectation(&self, state: &Array1<Complex64>, qubit: usize) -> Result<f64> {
1623 let state_size = state.len();
1624 let mut expectation = 0.0;
1625
1626 for i in 0..state_size {
1627 let probability = state[i].norm_sqr();
1628 if i & (1 << qubit) == 0 {
1629 expectation += probability; } else {
1631 expectation -= probability; }
1633 }
1634
1635 Ok(expectation)
1636 }
1637
1638 fn compute_loss(&self, prediction: &Array1<f64>, target: &Array1<f64>) -> Result<f64> {
1640 if prediction.shape() != target.shape() {
1642 return Err(SimulatorError::InvalidInput(format!(
1643 "Shape mismatch: prediction shape {:?} != target shape {:?}",
1644 prediction.shape(),
1645 target.shape()
1646 )));
1647 }
1648
1649 let diff = prediction - target;
1651 let mse = diff.iter().map(|x| x * x).sum::<f64>() / diff.len() as f64;
1652 Ok(mse)
1653 }
1654
1655 fn compute_loss_gradient(
1657 &self,
1658 prediction: &Array1<f64>,
1659 target: &Array1<f64>,
1660 ) -> Result<Array1<f64>> {
1661 let diff = prediction - target;
1663 let grad = 2.0 * &diff / diff.len() as f64;
1664 Ok(grad)
1665 }
1666
1667 fn compute_gradients(&mut self, loss_gradient: &Array1<f64>) -> Result<Vec<Array1<f64>>> {
1669 let mut gradients = Vec::new();
1670
1671 for layer_idx in 0..self.layers.len() {
1672 let layer_gradient = match self.config.training_config.gradient_method {
1673 GradientMethod::ParameterShift => {
1674 self.compute_parameter_shift_gradient(layer_idx, loss_gradient)?
1675 }
1676 GradientMethod::FiniteDifference => {
1677 self.compute_finite_difference_gradient(layer_idx, loss_gradient)?
1678 }
1679 _ => {
1680 return Err(SimulatorError::InvalidConfiguration(
1681 "Gradient method not implemented".to_string(),
1682 ))
1683 }
1684 };
1685 gradients.push(layer_gradient);
1686 }
1687
1688 Ok(gradients)
1689 }
1690
1691 fn compute_parameter_shift_gradient(
1693 &mut self,
1694 layer_idx: usize,
1695 loss_gradient: &Array1<f64>,
1696 ) -> Result<Array1<f64>> {
1697 let layer = &self.layers[layer_idx];
1698 let parameters = layer.get_parameters();
1699 let mut gradient = Array1::zeros(parameters.len());
1700
1701 let shift = PI / 2.0; for (param_idx, ¶m_val) in parameters.iter().enumerate() {
1704 let mut params_plus = parameters.clone();
1706 params_plus[param_idx] = param_val + shift;
1707 self.layers[layer_idx].set_parameters(¶ms_plus);
1708 let output_plus = self.forward_layer(layer_idx, loss_gradient)?;
1709
1710 let mut params_minus = parameters.clone();
1712 params_minus[param_idx] = param_val - shift;
1713 self.layers[layer_idx].set_parameters(¶ms_minus);
1714 let output_minus = self.forward_layer(layer_idx, loss_gradient)?;
1715
1716 gradient[param_idx] = (output_plus.sum() - output_minus.sum()) / 2.0;
1718
1719 self.layers[layer_idx].set_parameters(¶meters);
1721 }
1722
1723 Ok(gradient)
1724 }
1725
1726 fn compute_finite_difference_gradient(
1728 &mut self,
1729 layer_idx: usize,
1730 loss_gradient: &Array1<f64>,
1731 ) -> Result<Array1<f64>> {
1732 let layer = &self.layers[layer_idx];
1733 let parameters = layer.get_parameters();
1734 let mut gradient = Array1::zeros(parameters.len());
1735
1736 let eps = 1e-6; for (param_idx, ¶m_val) in parameters.iter().enumerate() {
1739 let mut params_plus = parameters.clone();
1741 params_plus[param_idx] = param_val + eps;
1742 self.layers[layer_idx].set_parameters(¶ms_plus);
1743 let output_plus = self.forward_layer(layer_idx, loss_gradient)?;
1744
1745 let mut params_minus = parameters.clone();
1747 params_minus[param_idx] = param_val - eps;
1748 self.layers[layer_idx].set_parameters(¶ms_minus);
1749 let output_minus = self.forward_layer(layer_idx, loss_gradient)?;
1750
1751 gradient[param_idx] = (output_plus.sum() - output_minus.sum()) / (2.0 * eps);
1753
1754 self.layers[layer_idx].set_parameters(¶meters);
1756 }
1757
1758 Ok(gradient)
1759 }
1760
1761 fn forward_layer(&mut self, layer_idx: usize, input: &Array1<f64>) -> Result<Array1<f64>> {
1763 self.forward(input)
1765 }
1766
1767 fn apply_gradients(&mut self, gradients: &[Array1<f64>]) -> Result<()> {
1769 for (layer_idx, gradient) in gradients.iter().enumerate() {
1770 let layer = &mut self.layers[layer_idx];
1771 let mut parameters = layer.get_parameters();
1772
1773 match self.config.training_config.optimizer {
1775 OptimizerType::SGD => {
1776 for (param, grad) in parameters.iter_mut().zip(gradient.iter()) {
1777 *param -= self.config.training_config.learning_rate * grad;
1778 }
1779 }
1780 OptimizerType::Adam => {
1781 for (param, grad) in parameters.iter_mut().zip(gradient.iter()) {
1783 *param -= self.config.training_config.learning_rate * grad;
1784 }
1785 }
1786 _ => {
1787 for (param, grad) in parameters.iter_mut().zip(gradient.iter()) {
1789 *param -= self.config.training_config.learning_rate * grad;
1790 }
1791 }
1792 }
1793
1794 if let Some((min_val, max_val)) =
1796 self.config.training_config.regularization.parameter_bounds
1797 {
1798 for param in parameters.iter_mut() {
1799 *param = param.clamp(min_val, max_val);
1800 }
1801 }
1802
1803 layer.set_parameters(¶meters);
1804 }
1805
1806 Ok(())
1807 }
1808
1809 fn get_current_learning_rate(&self, epoch: usize) -> f64 {
1811 let base_lr = self.config.training_config.learning_rate;
1812
1813 match self.config.training_config.lr_schedule {
1814 LearningRateSchedule::Constant => base_lr,
1815 LearningRateSchedule::ExponentialDecay => base_lr * 0.95_f64.powi(epoch as i32),
1816 LearningRateSchedule::StepDecay => {
1817 if epoch % 50 == 0 && epoch > 0 {
1818 base_lr * 0.5_f64.powi((epoch / 50) as i32)
1819 } else {
1820 base_lr
1821 }
1822 }
1823 LearningRateSchedule::CosineAnnealing => {
1824 let progress = epoch as f64 / self.config.training_config.epochs as f64;
1825 base_lr * 0.5 * (1.0 + (PI * progress).cos())
1826 }
1827 _ => base_lr,
1828 }
1829 }
1830
1831 fn update_learning_rate(&mut self, epoch: usize, validation_loss: f64) {
1833 let current_lr = self.get_current_learning_rate(epoch);
1836 self.training_state.current_learning_rate = current_lr;
1837 }
1838
1839 fn compute_quantum_advantage_metrics(&self) -> Result<QuantumAdvantageMetrics> {
1841 Ok(QuantumAdvantageMetrics {
1843 quantum_volume: 0.0,
1844 classical_simulation_cost: 0.0,
1845 quantum_speedup_factor: 1.0,
1846 circuit_depth: self.layers.iter().map(|l| l.get_depth()).sum(),
1847 gate_count: self.layers.iter().map(|l| l.get_gate_count()).sum(),
1848 entanglement_measure: 0.0,
1849 })
1850 }
1851
1852 pub fn get_stats(&self) -> &QMLStats {
1854 &self.stats
1855 }
1856
1857 pub fn get_training_history(&self) -> &[QMLTrainingResult] {
1859 &self.training_history
1860 }
1861
1862 pub fn get_layers(&self) -> &[Box<dyn QMLLayer>] {
1864 &self.layers
1865 }
1866
1867 pub fn get_config(&self) -> &QMLConfig {
1869 &self.config
1870 }
1871
1872 pub fn encode_amplitude_public(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1874 self.encode_amplitude(input)
1875 }
1876
1877 pub fn encode_angle_public(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1879 self.encode_angle(input)
1880 }
1881
1882 pub fn encode_basis_public(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1884 self.encode_basis(input)
1885 }
1886
1887 pub fn encode_quantum_feature_map_public(
1889 &self,
1890 input: &Array1<f64>,
1891 ) -> Result<Array1<Complex64>> {
1892 self.encode_quantum_feature_map(input)
1893 }
1894
1895 pub fn measure_pauli_z_expectation_public(
1897 &self,
1898 state: &Array1<Complex64>,
1899 qubit: usize,
1900 ) -> Result<f64> {
1901 self.measure_pauli_z_expectation(state, qubit)
1902 }
1903
1904 pub fn get_current_learning_rate_public(&self, epoch: usize) -> f64 {
1906 self.get_current_learning_rate(epoch)
1907 }
1908
1909 pub fn compute_loss_public(
1911 &self,
1912 prediction: &Array1<f64>,
1913 target: &Array1<f64>,
1914 ) -> Result<f64> {
1915 self.compute_loss(prediction, target)
1916 }
1917
1918 pub fn compute_loss_gradient_public(
1920 &self,
1921 prediction: &Array1<f64>,
1922 target: &Array1<f64>,
1923 ) -> Result<Array1<f64>> {
1924 self.compute_loss_gradient(prediction, target)
1925 }
1926}
1927
1928pub trait QMLLayer: std::fmt::Debug + Send + Sync {
1930 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>>;
1932
1933 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>>;
1935
1936 fn get_parameters(&self) -> Array1<f64>;
1938
1939 fn set_parameters(&mut self, parameters: &Array1<f64>);
1941
1942 fn get_depth(&self) -> usize;
1944
1945 fn get_gate_count(&self) -> usize;
1947
1948 fn get_num_parameters(&self) -> usize;
1950}
1951
1952#[derive(Debug)]
1954pub struct ParameterizedQuantumCircuitLayer {
1955 num_qubits: usize,
1957 config: QMLLayerConfig,
1959 parameters: Array1<f64>,
1961 circuit_structure: Vec<PQCGate>,
1963 simulator: StateVectorSimulator,
1965}
1966
1967impl ParameterizedQuantumCircuitLayer {
1968 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
1970 let mut layer = Self {
1971 num_qubits,
1972 config: config.clone(),
1973 parameters: Array1::zeros(config.num_parameters),
1974 circuit_structure: Vec::new(),
1975 simulator: StateVectorSimulator::new(),
1976 };
1977
1978 layer.initialize_parameters();
1980
1981 layer.build_circuit_structure()?;
1983
1984 Ok(layer)
1985 }
1986
1987 fn initialize_parameters(&mut self) {
1989 let mut rng = thread_rng();
1990 for param in self.parameters.iter_mut() {
1991 *param = rng.gen_range(-PI..PI);
1992 }
1993 }
1994
1995 fn build_circuit_structure(&mut self) -> Result<()> {
1997 match self.config.ansatz_type {
1998 AnsatzType::Hardware => self.build_hardware_efficient_ansatz(),
1999 AnsatzType::Layered => self.build_layered_ansatz(),
2000 AnsatzType::BrickWall => self.build_brick_wall_ansatz(),
2001 _ => Err(SimulatorError::InvalidConfiguration(
2002 "Ansatz type not implemented".to_string(),
2003 )),
2004 }
2005 }
2006
2007 fn build_hardware_efficient_ansatz(&mut self) -> Result<()> {
2009 let mut param_idx = 0;
2010
2011 for layer in 0..self.config.depth {
2012 for qubit in 0..self.num_qubits {
2014 for &gate_type in &self.config.rotation_gates {
2015 if param_idx < self.parameters.len() {
2016 self.circuit_structure.push(PQCGate {
2017 gate_type: PQCGateType::SingleQubit(gate_type),
2018 qubits: vec![qubit],
2019 parameter_index: Some(param_idx),
2020 });
2021 param_idx += 1;
2022 }
2023 }
2024 }
2025
2026 self.add_entangling_gates(&mut param_idx);
2028 }
2029
2030 Ok(())
2031 }
2032
2033 fn build_layered_ansatz(&mut self) -> Result<()> {
2035 self.build_hardware_efficient_ansatz()
2037 }
2038
2039 fn build_brick_wall_ansatz(&mut self) -> Result<()> {
2041 let mut param_idx = 0;
2042
2043 for layer in 0..self.config.depth {
2044 let offset = layer % 2;
2046 for i in (offset..self.num_qubits - 1).step_by(2) {
2047 self.circuit_structure.push(PQCGate {
2048 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2049 qubits: vec![i, i + 1],
2050 parameter_index: None,
2051 });
2052 }
2053
2054 for qubit in 0..self.num_qubits {
2056 if param_idx < self.parameters.len() {
2057 self.circuit_structure.push(PQCGate {
2058 gate_type: PQCGateType::SingleQubit(RotationGate::RY),
2059 qubits: vec![qubit],
2060 parameter_index: Some(param_idx),
2061 });
2062 param_idx += 1;
2063 }
2064 }
2065 }
2066
2067 Ok(())
2068 }
2069
2070 fn add_entangling_gates(&mut self, param_idx: &mut usize) {
2072 match self.config.entanglement_pattern {
2073 EntanglementPattern::Linear => {
2074 for i in 0..(self.num_qubits - 1) {
2075 self.circuit_structure.push(PQCGate {
2076 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2077 qubits: vec![i, i + 1],
2078 parameter_index: None,
2079 });
2080 }
2081 }
2082 EntanglementPattern::Circular => {
2083 for i in 0..self.num_qubits {
2084 let next = (i + 1) % self.num_qubits;
2085 self.circuit_structure.push(PQCGate {
2086 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2087 qubits: vec![i, next],
2088 parameter_index: None,
2089 });
2090 }
2091 }
2092 EntanglementPattern::AllToAll => {
2093 for i in 0..self.num_qubits {
2094 for j in (i + 1)..self.num_qubits {
2095 self.circuit_structure.push(PQCGate {
2096 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2097 qubits: vec![i, j],
2098 parameter_index: None,
2099 });
2100 }
2101 }
2102 }
2103 _ => {
2104 for i in 0..(self.num_qubits - 1) {
2106 self.circuit_structure.push(PQCGate {
2107 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2108 qubits: vec![i, i + 1],
2109 parameter_index: None,
2110 });
2111 }
2112 }
2113 }
2114 }
2115}
2116
2117impl QMLLayer for ParameterizedQuantumCircuitLayer {
2118 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2119 let mut state = input.clone();
2120
2121 for gate in &self.circuit_structure {
2123 state = self.apply_gate(&state, gate)?;
2124 }
2125
2126 Ok(state)
2127 }
2128
2129 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2130 Ok(gradient.clone())
2132 }
2133
2134 fn get_parameters(&self) -> Array1<f64> {
2135 self.parameters.clone()
2136 }
2137
2138 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2139 self.parameters = parameters.clone();
2140 }
2141
2142 fn get_depth(&self) -> usize {
2143 self.config.depth
2144 }
2145
2146 fn get_gate_count(&self) -> usize {
2147 self.circuit_structure.len()
2148 }
2149
2150 fn get_num_parameters(&self) -> usize {
2151 self.parameters.len()
2152 }
2153}
2154
2155impl ParameterizedQuantumCircuitLayer {
2156 fn apply_gate(&self, state: &Array1<Complex64>, gate: &PQCGate) -> Result<Array1<Complex64>> {
2158 match &gate.gate_type {
2159 PQCGateType::SingleQubit(rotation_gate) => {
2160 let angle = if let Some(param_idx) = gate.parameter_index {
2161 self.parameters[param_idx]
2162 } else {
2163 0.0
2164 };
2165 self.apply_single_qubit_gate(state, gate.qubits[0], *rotation_gate, angle)
2166 }
2167 PQCGateType::TwoQubit(two_qubit_gate) => {
2168 self.apply_two_qubit_gate(state, gate.qubits[0], gate.qubits[1], *two_qubit_gate)
2169 }
2170 }
2171 }
2172
2173 fn apply_single_qubit_gate(
2175 &self,
2176 state: &Array1<Complex64>,
2177 qubit: usize,
2178 gate_type: RotationGate,
2179 angle: f64,
2180 ) -> Result<Array1<Complex64>> {
2181 let state_size = state.len();
2182 let mut new_state = Array1::zeros(state_size);
2183
2184 match gate_type {
2185 RotationGate::RX => {
2186 let cos_half = (angle / 2.0).cos();
2187 let sin_half = (angle / 2.0).sin();
2188
2189 for i in 0..state_size {
2190 if i & (1 << qubit) == 0 {
2191 let j = i | (1 << qubit);
2192 if j < state_size {
2193 new_state[i] = Complex64::new(cos_half, 0.0) * state[i]
2194 + Complex64::new(0.0, -sin_half) * state[j];
2195 new_state[j] = Complex64::new(0.0, -sin_half) * state[i]
2196 + Complex64::new(cos_half, 0.0) * state[j];
2197 }
2198 }
2199 }
2200 }
2201 RotationGate::RY => {
2202 let cos_half = (angle / 2.0).cos();
2203 let sin_half = (angle / 2.0).sin();
2204
2205 for i in 0..state_size {
2206 if i & (1 << qubit) == 0 {
2207 let j = i | (1 << qubit);
2208 if j < state_size {
2209 new_state[i] = Complex64::new(cos_half, 0.0) * state[i]
2210 - Complex64::new(sin_half, 0.0) * state[j];
2211 new_state[j] = Complex64::new(sin_half, 0.0) * state[i]
2212 + Complex64::new(cos_half, 0.0) * state[j];
2213 }
2214 }
2215 }
2216 }
2217 RotationGate::RZ => {
2218 let phase_0 = Complex64::from_polar(1.0, -angle / 2.0);
2219 let phase_1 = Complex64::from_polar(1.0, angle / 2.0);
2220
2221 for i in 0..state_size {
2222 if i & (1 << qubit) == 0 {
2223 new_state[i] = phase_0 * state[i];
2224 } else {
2225 new_state[i] = phase_1 * state[i];
2226 }
2227 }
2228 }
2229 _ => {
2230 return Err(SimulatorError::InvalidGate(
2231 "Gate type not implemented".to_string(),
2232 ))
2233 }
2234 }
2235
2236 Ok(new_state)
2237 }
2238
2239 fn apply_two_qubit_gate(
2241 &self,
2242 state: &Array1<Complex64>,
2243 control: usize,
2244 target: usize,
2245 gate_type: TwoQubitGate,
2246 ) -> Result<Array1<Complex64>> {
2247 let state_size = state.len();
2248 let mut new_state = state.clone();
2249
2250 match gate_type {
2251 TwoQubitGate::CNOT => {
2252 for i in 0..state_size {
2253 if (i & (1 << control)) != 0 {
2254 let j = i ^ (1 << target);
2256 new_state[i] = state[j];
2257 }
2258 }
2259 }
2260 TwoQubitGate::CZ => {
2261 for i in 0..state_size {
2262 if (i & (1 << control)) != 0 && (i & (1 << target)) != 0 {
2263 new_state[i] = -state[i];
2265 }
2266 }
2267 }
2268 TwoQubitGate::SWAP => {
2269 for i in 0..state_size {
2270 let ctrl_bit = (i & (1 << control)) != 0;
2271 let targ_bit = (i & (1 << target)) != 0;
2272 if ctrl_bit != targ_bit {
2273 let j = i ^ (1 << control) ^ (1 << target);
2275 new_state[i] = state[j];
2276 }
2277 }
2278 }
2279 TwoQubitGate::CPhase => {
2280 for i in 0..state_size {
2281 if (i & (1 << control)) != 0 && (i & (1 << target)) != 0 {
2282 new_state[i] = -state[i];
2284 }
2285 }
2286 }
2287 }
2288
2289 Ok(new_state)
2290 }
2291}
2292
2293#[derive(Debug)]
2295pub struct QuantumConvolutionalLayer {
2296 num_qubits: usize,
2298 config: QMLLayerConfig,
2300 parameters: Array1<f64>,
2302 conv_structure: Vec<ConvolutionalFilter>,
2304}
2305
2306impl QuantumConvolutionalLayer {
2307 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
2309 let mut layer = Self {
2310 num_qubits,
2311 config: config.clone(),
2312 parameters: Array1::zeros(config.num_parameters),
2313 conv_structure: Vec::new(),
2314 };
2315
2316 layer.initialize_parameters();
2317 layer.build_convolutional_structure()?;
2318
2319 Ok(layer)
2320 }
2321
2322 fn initialize_parameters(&mut self) {
2324 let mut rng = thread_rng();
2325 for param in self.parameters.iter_mut() {
2326 *param = rng.gen_range(-PI..PI);
2327 }
2328 }
2329
2330 fn build_convolutional_structure(&mut self) -> Result<()> {
2332 let filter_size = 2; let stride = 1;
2335
2336 let mut param_idx = 0;
2337 for start in (0..self.num_qubits - filter_size + 1).step_by(stride) {
2338 if param_idx + 2 <= self.parameters.len() {
2339 self.conv_structure.push(ConvolutionalFilter {
2340 qubits: vec![start, start + 1],
2341 parameter_indices: vec![param_idx, param_idx + 1],
2342 });
2343 param_idx += 2;
2344 }
2345 }
2346
2347 Ok(())
2348 }
2349}
2350
2351impl QMLLayer for QuantumConvolutionalLayer {
2352 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2353 let mut state = input.clone();
2354
2355 for filter in &self.conv_structure {
2357 state = self.apply_convolutional_filter(&state, filter)?;
2358 }
2359
2360 Ok(state)
2361 }
2362
2363 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2364 Ok(gradient.clone())
2365 }
2366
2367 fn get_parameters(&self) -> Array1<f64> {
2368 self.parameters.clone()
2369 }
2370
2371 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2372 self.parameters = parameters.clone();
2373 }
2374
2375 fn get_depth(&self) -> usize {
2376 self.conv_structure.len()
2377 }
2378
2379 fn get_gate_count(&self) -> usize {
2380 self.conv_structure.len() * 4 }
2382
2383 fn get_num_parameters(&self) -> usize {
2384 self.parameters.len()
2385 }
2386}
2387
2388impl QuantumConvolutionalLayer {
2389 fn apply_convolutional_filter(
2391 &self,
2392 state: &Array1<Complex64>,
2393 filter: &ConvolutionalFilter,
2394 ) -> Result<Array1<Complex64>> {
2395 let mut new_state = state.clone();
2396
2397 let param1 = self.parameters[filter.parameter_indices[0]];
2399 let param2 = self.parameters[filter.parameter_indices[1]];
2400
2401 new_state = self.apply_ry_to_state(&new_state, filter.qubits[0], param1)?;
2403 new_state = self.apply_ry_to_state(&new_state, filter.qubits[1], param2)?;
2404 new_state = self.apply_cnot_to_state(&new_state, filter.qubits[0], filter.qubits[1])?;
2405
2406 Ok(new_state)
2407 }
2408
2409 fn apply_ry_to_state(
2411 &self,
2412 state: &Array1<Complex64>,
2413 qubit: usize,
2414 angle: f64,
2415 ) -> Result<Array1<Complex64>> {
2416 let state_size = state.len();
2417 let mut new_state = Array1::zeros(state_size);
2418
2419 let cos_half = (angle / 2.0).cos();
2420 let sin_half = (angle / 2.0).sin();
2421
2422 for i in 0..state_size {
2423 if i & (1 << qubit) == 0 {
2424 let j = i | (1 << qubit);
2425 if j < state_size {
2426 new_state[i] = Complex64::new(cos_half, 0.0) * state[i]
2427 - Complex64::new(sin_half, 0.0) * state[j];
2428 new_state[j] = Complex64::new(sin_half, 0.0) * state[i]
2429 + Complex64::new(cos_half, 0.0) * state[j];
2430 }
2431 }
2432 }
2433
2434 Ok(new_state)
2435 }
2436
2437 fn apply_cnot_to_state(
2439 &self,
2440 state: &Array1<Complex64>,
2441 control: usize,
2442 target: usize,
2443 ) -> Result<Array1<Complex64>> {
2444 let state_size = state.len();
2445 let mut new_state = state.clone();
2446
2447 for i in 0..state_size {
2448 if (i & (1 << control)) != 0 {
2449 let j = i ^ (1 << target);
2450 new_state[i] = state[j];
2451 }
2452 }
2453
2454 Ok(new_state)
2455 }
2456}
2457
2458#[derive(Debug)]
2460pub struct QuantumDenseLayer {
2461 num_qubits: usize,
2463 config: QMLLayerConfig,
2465 parameters: Array1<f64>,
2467 dense_structure: Vec<DenseConnection>,
2469}
2470
2471impl QuantumDenseLayer {
2472 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
2474 let mut layer = Self {
2475 num_qubits,
2476 config: config.clone(),
2477 parameters: Array1::zeros(config.num_parameters),
2478 dense_structure: Vec::new(),
2479 };
2480
2481 layer.initialize_parameters();
2482 layer.build_dense_structure()?;
2483
2484 Ok(layer)
2485 }
2486
2487 fn initialize_parameters(&mut self) {
2489 let mut rng = thread_rng();
2490 for param in self.parameters.iter_mut() {
2491 *param = rng.gen_range(-PI..PI);
2492 }
2493 }
2494
2495 fn build_dense_structure(&mut self) -> Result<()> {
2497 let mut param_idx = 0;
2498
2499 for i in 0..self.num_qubits {
2501 for j in (i + 1)..self.num_qubits {
2502 if param_idx < self.parameters.len() {
2503 self.dense_structure.push(DenseConnection {
2504 qubit1: i,
2505 qubit2: j,
2506 parameter_index: param_idx,
2507 });
2508 param_idx += 1;
2509 }
2510 }
2511 }
2512
2513 Ok(())
2514 }
2515}
2516
2517impl QMLLayer for QuantumDenseLayer {
2518 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2519 let mut state = input.clone();
2520
2521 for connection in &self.dense_structure {
2523 state = self.apply_dense_connection(&state, connection)?;
2524 }
2525
2526 Ok(state)
2527 }
2528
2529 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2530 Ok(gradient.clone())
2531 }
2532
2533 fn get_parameters(&self) -> Array1<f64> {
2534 self.parameters.clone()
2535 }
2536
2537 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2538 self.parameters = parameters.clone();
2539 }
2540
2541 fn get_depth(&self) -> usize {
2542 1 }
2544
2545 fn get_gate_count(&self) -> usize {
2546 self.dense_structure.len() * 2 }
2548
2549 fn get_num_parameters(&self) -> usize {
2550 self.parameters.len()
2551 }
2552}
2553
2554impl QuantumDenseLayer {
2555 fn apply_dense_connection(
2557 &self,
2558 state: &Array1<Complex64>,
2559 connection: &DenseConnection,
2560 ) -> Result<Array1<Complex64>> {
2561 let angle = self.parameters[connection.parameter_index];
2562
2563 self.apply_parameterized_two_qubit_gate(state, connection.qubit1, connection.qubit2, angle)
2565 }
2566
2567 fn apply_parameterized_two_qubit_gate(
2569 &self,
2570 state: &Array1<Complex64>,
2571 qubit1: usize,
2572 qubit2: usize,
2573 angle: f64,
2574 ) -> Result<Array1<Complex64>> {
2575 let state_size = state.len();
2576 let mut new_state = state.clone();
2577
2578 let cos_val = angle.cos();
2580 let sin_val = angle.sin();
2581
2582 for i in 0..state_size {
2583 if (i & (1 << qubit1)) != 0 && (i & (1 << qubit2)) != 0 {
2584 let phase = Complex64::new(cos_val, sin_val);
2586 new_state[i] *= phase;
2587 }
2588 }
2589
2590 Ok(new_state)
2591 }
2592}
2593
2594#[derive(Debug)]
2596pub struct QuantumLSTMLayer {
2597 num_qubits: usize,
2599 config: QMLLayerConfig,
2601 parameters: Array1<f64>,
2603 lstm_gates: Vec<LSTMGate>,
2605 hidden_state: Option<Array1<Complex64>>,
2607 cell_state: Option<Array1<Complex64>>,
2609}
2610
2611impl QuantumLSTMLayer {
2612 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
2614 let mut layer = Self {
2615 num_qubits,
2616 config: config.clone(),
2617 parameters: Array1::zeros(config.num_parameters),
2618 lstm_gates: Vec::new(),
2619 hidden_state: None,
2620 cell_state: None,
2621 };
2622
2623 layer.initialize_parameters();
2624 layer.build_lstm_structure()?;
2625
2626 Ok(layer)
2627 }
2628
2629 fn initialize_parameters(&mut self) {
2631 let mut rng = thread_rng();
2632 for param in self.parameters.iter_mut() {
2633 *param = rng.gen_range(-PI..PI);
2634 }
2635 }
2636
2637 fn build_lstm_structure(&mut self) -> Result<()> {
2639 let params_per_gate = self.parameters.len() / 4; self.lstm_gates = vec![
2642 LSTMGate {
2643 gate_type: LSTMGateType::Forget,
2644 parameter_start: 0,
2645 parameter_count: params_per_gate,
2646 },
2647 LSTMGate {
2648 gate_type: LSTMGateType::Input,
2649 parameter_start: params_per_gate,
2650 parameter_count: params_per_gate,
2651 },
2652 LSTMGate {
2653 gate_type: LSTMGateType::Output,
2654 parameter_start: 2 * params_per_gate,
2655 parameter_count: params_per_gate,
2656 },
2657 LSTMGate {
2658 gate_type: LSTMGateType::Candidate,
2659 parameter_start: 3 * params_per_gate,
2660 parameter_count: params_per_gate,
2661 },
2662 ];
2663
2664 Ok(())
2665 }
2666}
2667
2668impl QMLLayer for QuantumLSTMLayer {
2669 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2670 if self.hidden_state.is_none() {
2672 let state_size = 1 << self.num_qubits;
2673 self.hidden_state = Some(Array1::zeros(state_size));
2674 self.cell_state = Some(Array1::zeros(state_size));
2675 self.hidden_state.as_mut().unwrap()[0] = Complex64::new(1.0, 0.0);
2677 self.cell_state.as_mut().unwrap()[0] = Complex64::new(1.0, 0.0);
2678 }
2679
2680 let mut current_state = input.clone();
2681
2682 for gate in &self.lstm_gates {
2684 current_state = self.apply_lstm_gate(¤t_state, gate)?;
2685 }
2686
2687 self.hidden_state = Some(current_state.clone());
2689
2690 Ok(current_state)
2691 }
2692
2693 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2694 Ok(gradient.clone())
2695 }
2696
2697 fn get_parameters(&self) -> Array1<f64> {
2698 self.parameters.clone()
2699 }
2700
2701 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2702 self.parameters = parameters.clone();
2703 }
2704
2705 fn get_depth(&self) -> usize {
2706 self.lstm_gates.len()
2707 }
2708
2709 fn get_gate_count(&self) -> usize {
2710 self.parameters.len() }
2712
2713 fn get_num_parameters(&self) -> usize {
2714 self.parameters.len()
2715 }
2716}
2717
2718impl QuantumLSTMLayer {
2719 fn apply_lstm_gate(
2721 &self,
2722 state: &Array1<Complex64>,
2723 gate: &LSTMGate,
2724 ) -> Result<Array1<Complex64>> {
2725 let mut new_state = state.clone();
2726
2727 for i in 0..gate.parameter_count {
2729 let param_idx = gate.parameter_start + i;
2730 if param_idx < self.parameters.len() {
2731 let angle = self.parameters[param_idx];
2732 let qubit = i % self.num_qubits;
2733
2734 new_state = self.apply_rotation(&new_state, qubit, angle)?;
2736 }
2737 }
2738
2739 Ok(new_state)
2740 }
2741
2742 fn apply_rotation(
2744 &self,
2745 state: &Array1<Complex64>,
2746 qubit: usize,
2747 angle: f64,
2748 ) -> Result<Array1<Complex64>> {
2749 let state_size = state.len();
2750 let mut new_state = Array1::zeros(state_size);
2751
2752 let cos_half = (angle / 2.0).cos();
2753 let sin_half = (angle / 2.0).sin();
2754
2755 for i in 0..state_size {
2756 if i & (1 << qubit) == 0 {
2757 let j = i | (1 << qubit);
2758 if j < state_size {
2759 new_state[i] = Complex64::new(cos_half, 0.0) * state[i]
2760 - Complex64::new(sin_half, 0.0) * state[j];
2761 new_state[j] = Complex64::new(sin_half, 0.0) * state[i]
2762 + Complex64::new(cos_half, 0.0) * state[j];
2763 }
2764 }
2765 }
2766
2767 Ok(new_state)
2768 }
2769
2770 pub fn get_lstm_gates(&self) -> &[LSTMGate] {
2772 &self.lstm_gates
2773 }
2774}
2775
2776#[derive(Debug)]
2778pub struct QuantumAttentionLayer {
2779 num_qubits: usize,
2781 config: QMLLayerConfig,
2783 parameters: Array1<f64>,
2785 attention_structure: Vec<AttentionHead>,
2787}
2788
2789impl QuantumAttentionLayer {
2790 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
2792 let mut layer = Self {
2793 num_qubits,
2794 config: config.clone(),
2795 parameters: Array1::zeros(config.num_parameters),
2796 attention_structure: Vec::new(),
2797 };
2798
2799 layer.initialize_parameters();
2800 layer.build_attention_structure()?;
2801
2802 Ok(layer)
2803 }
2804
2805 fn initialize_parameters(&mut self) {
2807 let mut rng = thread_rng();
2808 for param in self.parameters.iter_mut() {
2809 *param = rng.gen_range(-PI..PI);
2810 }
2811 }
2812
2813 fn build_attention_structure(&mut self) -> Result<()> {
2815 let num_heads = 2; let params_per_head = self.parameters.len() / num_heads;
2817
2818 for head in 0..num_heads {
2819 self.attention_structure.push(AttentionHead {
2820 head_id: head,
2821 parameter_start: head * params_per_head,
2822 parameter_count: params_per_head,
2823 query_qubits: (0..self.num_qubits / 2).collect(),
2824 key_qubits: (self.num_qubits / 2..self.num_qubits).collect(),
2825 });
2826 }
2827
2828 Ok(())
2829 }
2830}
2831
2832impl QMLLayer for QuantumAttentionLayer {
2833 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2834 let mut state = input.clone();
2835
2836 for head in &self.attention_structure {
2838 state = self.apply_attention_head(&state, head)?;
2839 }
2840
2841 Ok(state)
2842 }
2843
2844 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2845 Ok(gradient.clone())
2846 }
2847
2848 fn get_parameters(&self) -> Array1<f64> {
2849 self.parameters.clone()
2850 }
2851
2852 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2853 self.parameters = parameters.clone();
2854 }
2855
2856 fn get_depth(&self) -> usize {
2857 self.attention_structure.len()
2858 }
2859
2860 fn get_gate_count(&self) -> usize {
2861 self.parameters.len()
2862 }
2863
2864 fn get_num_parameters(&self) -> usize {
2865 self.parameters.len()
2866 }
2867}
2868
2869impl QuantumAttentionLayer {
2870 fn apply_attention_head(
2872 &self,
2873 state: &Array1<Complex64>,
2874 head: &AttentionHead,
2875 ) -> Result<Array1<Complex64>> {
2876 let mut new_state = state.clone();
2877
2878 for i in 0..head.parameter_count {
2880 let param_idx = head.parameter_start + i;
2881 if param_idx < self.parameters.len() {
2882 let angle = self.parameters[param_idx];
2883
2884 if i < head.query_qubits.len() && i < head.key_qubits.len() {
2886 let query_qubit = head.query_qubits[i];
2887 let key_qubit = head.key_qubits[i];
2888
2889 new_state =
2890 self.apply_attention_gate(&new_state, query_qubit, key_qubit, angle)?;
2891 }
2892 }
2893 }
2894
2895 Ok(new_state)
2896 }
2897
2898 fn apply_attention_gate(
2900 &self,
2901 state: &Array1<Complex64>,
2902 query_qubit: usize,
2903 key_qubit: usize,
2904 angle: f64,
2905 ) -> Result<Array1<Complex64>> {
2906 let state_size = state.len();
2907 let mut new_state = state.clone();
2908
2909 let cos_val = angle.cos();
2911 let sin_val = angle.sin();
2912
2913 for i in 0..state_size {
2914 if (i & (1 << query_qubit)) != 0 {
2915 let key_state = (i & (1 << key_qubit)) != 0;
2917 let attention_phase = if key_state {
2918 Complex64::new(cos_val, sin_val)
2919 } else {
2920 Complex64::new(cos_val, -sin_val)
2921 };
2922 new_state[i] *= attention_phase;
2923 }
2924 }
2925
2926 Ok(new_state)
2927 }
2928
2929 pub fn get_attention_structure(&self) -> &[AttentionHead] {
2931 &self.attention_structure
2932 }
2933}
2934
2935#[derive(Debug, Clone)]
2937pub struct QMLTrainingState {
2938 pub current_epoch: usize,
2940 pub current_learning_rate: f64,
2942 pub best_validation_loss: f64,
2944 pub patience_counter: usize,
2946 pub training_loss_history: Vec<f64>,
2948 pub validation_loss_history: Vec<f64>,
2950}
2951
2952impl QMLTrainingState {
2953 pub fn new() -> Self {
2955 Self {
2956 current_epoch: 0,
2957 current_learning_rate: 0.01,
2958 best_validation_loss: f64::INFINITY,
2959 patience_counter: 0,
2960 training_loss_history: Vec::new(),
2961 validation_loss_history: Vec::new(),
2962 }
2963 }
2964}
2965
2966#[derive(Debug, Clone)]
2968pub struct QMLTrainingResult {
2969 pub final_training_loss: f64,
2971 pub final_validation_loss: f64,
2973 pub best_validation_loss: f64,
2975 pub epochs_trained: usize,
2977 pub total_training_time: std::time::Duration,
2979 pub training_metrics: Vec<QMLEpochMetrics>,
2981 pub quantum_advantage_metrics: QuantumAdvantageMetrics,
2983}
2984
2985#[derive(Debug, Clone)]
2987pub struct QMLEpochMetrics {
2988 pub epoch: usize,
2990 pub training_loss: f64,
2992 pub validation_loss: f64,
2994 pub epoch_time: std::time::Duration,
2996 pub learning_rate: f64,
2998}
2999
3000#[derive(Debug, Clone, Serialize, Deserialize)]
3002pub struct QuantumAdvantageMetrics {
3003 pub quantum_volume: f64,
3005 pub classical_simulation_cost: f64,
3007 pub quantum_speedup_factor: f64,
3009 pub circuit_depth: usize,
3011 pub gate_count: usize,
3013 pub entanglement_measure: f64,
3015}
3016
3017#[derive(Debug, Clone)]
3019pub struct QMLStats {
3020 pub forward_passes: usize,
3022 pub backward_passes: usize,
3024 pub total_training_time: std::time::Duration,
3026 pub average_epoch_time: std::time::Duration,
3028 pub peak_memory_usage: usize,
3030 pub num_parameters: usize,
3032}
3033
3034impl QMLStats {
3035 pub fn new() -> Self {
3037 Self {
3038 forward_passes: 0,
3039 backward_passes: 0,
3040 total_training_time: std::time::Duration::from_secs(0),
3041 average_epoch_time: std::time::Duration::from_secs(0),
3042 peak_memory_usage: 0,
3043 num_parameters: 0,
3044 }
3045 }
3046}
3047
3048#[derive(Debug, Clone)]
3050pub struct PQCGate {
3051 pub gate_type: PQCGateType,
3053 pub qubits: Vec<usize>,
3055 pub parameter_index: Option<usize>,
3057}
3058
3059#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3061pub enum PQCGateType {
3062 SingleQubit(RotationGate),
3064 TwoQubit(TwoQubitGate),
3066}
3067
3068#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3070pub enum TwoQubitGate {
3071 CNOT,
3073 CZ,
3075 SWAP,
3077 CPhase,
3079}
3080
3081#[derive(Debug, Clone)]
3083pub struct ConvolutionalFilter {
3084 pub qubits: Vec<usize>,
3086 pub parameter_indices: Vec<usize>,
3088}
3089
3090#[derive(Debug, Clone)]
3092pub struct DenseConnection {
3093 pub qubit1: usize,
3095 pub qubit2: usize,
3097 pub parameter_index: usize,
3099}
3100
3101#[derive(Debug, Clone)]
3103pub struct LSTMGate {
3104 pub gate_type: LSTMGateType,
3106 pub parameter_start: usize,
3108 pub parameter_count: usize,
3110}
3111
3112#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3114pub enum LSTMGateType {
3115 Forget,
3117 Input,
3119 Output,
3121 Candidate,
3123}
3124
3125#[derive(Debug, Clone)]
3127pub struct AttentionHead {
3128 pub head_id: usize,
3130 pub parameter_start: usize,
3132 pub parameter_count: usize,
3134 pub query_qubits: Vec<usize>,
3136 pub key_qubits: Vec<usize>,
3138}
3139
3140#[derive(Debug, Clone, Serialize, Deserialize)]
3142pub struct QMLBenchmarkResults {
3143 pub training_times: HashMap<String, std::time::Duration>,
3145 pub final_accuracies: HashMap<String, f64>,
3147 pub convergence_rates: HashMap<String, f64>,
3149 pub memory_usage: HashMap<String, usize>,
3151 pub quantum_advantage: HashMap<String, QuantumAdvantageMetrics>,
3153 pub parameter_counts: HashMap<String, usize>,
3155 pub circuit_depths: HashMap<String, usize>,
3157 pub gate_counts: HashMap<String, usize>,
3159}
3160
3161pub struct QMLUtils;
3163
3164impl QMLUtils {
3165 pub fn generate_synthetic_data(
3167 num_samples: usize,
3168 input_dim: usize,
3169 output_dim: usize,
3170 ) -> (Vec<Array1<f64>>, Vec<Array1<f64>>) {
3171 let mut rng = thread_rng();
3172 let mut inputs = Vec::new();
3173 let mut outputs = Vec::new();
3174
3175 for _ in 0..num_samples {
3176 let input =
3177 Array1::from_vec((0..input_dim).map(|_| rng.gen_range(-1.0..1.0)).collect());
3178
3179 let output = Array1::from_vec(
3181 (0..output_dim)
3182 .map(|i| {
3183 if i < input_dim {
3184 (input[i] as f64).sin() } else {
3186 rng.gen_range(-1.0..1.0)
3187 }
3188 })
3189 .collect(),
3190 );
3191
3192 inputs.push(input);
3193 outputs.push(output);
3194 }
3195
3196 (inputs, outputs)
3197 }
3198
3199 pub fn train_test_split(
3201 inputs: Vec<Array1<f64>>,
3202 outputs: Vec<Array1<f64>>,
3203 test_ratio: f64,
3204 ) -> (
3205 Vec<(Array1<f64>, Array1<f64>)>,
3206 Vec<(Array1<f64>, Array1<f64>)>,
3207 ) {
3208 let total_samples = inputs.len();
3209 let test_samples = ((total_samples as f64) * test_ratio) as usize;
3210 let train_samples = total_samples - test_samples;
3211
3212 let mut combined: Vec<(Array1<f64>, Array1<f64>)> =
3213 inputs.into_iter().zip(outputs).collect();
3214
3215 let mut rng = thread_rng();
3217 for i in (1..combined.len()).rev() {
3218 let j = rng.gen_range(0..=i);
3219 combined.swap(i, j);
3220 }
3221
3222 let (train_data, test_data) = combined.split_at(train_samples);
3223 (train_data.to_vec(), test_data.to_vec())
3224 }
3225
3226 pub fn evaluate_accuracy(
3228 predictions: &[Array1<f64>],
3229 targets: &[Array1<f64>],
3230 threshold: f64,
3231 ) -> f64 {
3232 let mut correct = 0;
3233 let total = predictions.len();
3234
3235 for (pred, target) in predictions.iter().zip(targets.iter()) {
3236 let diff = pred - target;
3237 let mse = diff.iter().map(|x| x * x).sum::<f64>() / diff.len() as f64;
3238 if mse < threshold {
3239 correct += 1;
3240 }
3241 }
3242
3243 correct as f64 / total as f64
3244 }
3245
3246 pub fn compute_circuit_complexity(
3248 num_qubits: usize,
3249 depth: usize,
3250 gate_count: usize,
3251 ) -> HashMap<String, f64> {
3252 let mut metrics = HashMap::new();
3253
3254 let state_space_size = 2.0_f64.powi(num_qubits as i32);
3256 metrics.insert("state_space_size".to_string(), state_space_size);
3257
3258 let circuit_complexity = (depth * gate_count) as f64;
3260 metrics.insert("circuit_complexity".to_string(), circuit_complexity);
3261
3262 let classical_cost = state_space_size * gate_count as f64;
3264 metrics.insert("classical_simulation_cost".to_string(), classical_cost);
3265
3266 let quantum_advantage = classical_cost.log2() / circuit_complexity.log2();
3268 metrics.insert("quantum_advantage_estimate".to_string(), quantum_advantage);
3269
3270 metrics
3271 }
3272}
3273
3274pub fn benchmark_quantum_ml_layers(config: &QMLConfig) -> Result<QMLBenchmarkResults> {
3276 let mut results = QMLBenchmarkResults {
3277 training_times: HashMap::new(),
3278 final_accuracies: HashMap::new(),
3279 convergence_rates: HashMap::new(),
3280 memory_usage: HashMap::new(),
3281 quantum_advantage: HashMap::new(),
3282 parameter_counts: HashMap::new(),
3283 circuit_depths: HashMap::new(),
3284 gate_counts: HashMap::new(),
3285 };
3286
3287 let (inputs, outputs) =
3289 QMLUtils::generate_synthetic_data(100, config.num_qubits, config.num_qubits);
3290 let (train_data, val_data) = QMLUtils::train_test_split(inputs, outputs, 0.2);
3291
3292 let architectures = vec![
3294 QMLArchitectureType::VariationalQuantumCircuit,
3295 QMLArchitectureType::QuantumConvolutionalNN,
3296 ];
3298
3299 for architecture in architectures {
3300 let arch_name = format!("{:?}", architecture);
3301
3302 let mut arch_config = config.clone();
3304 arch_config.architecture_type = architecture;
3305
3306 let start_time = std::time::Instant::now();
3308 let mut framework = QuantumMLFramework::new(arch_config)?;
3309
3310 let training_result = framework.train(&train_data, Some(&val_data))?;
3311 let training_time = start_time.elapsed();
3312
3313 let final_accuracy = framework.evaluate(&val_data)?;
3315
3316 results
3318 .training_times
3319 .insert(arch_name.clone(), training_time);
3320 results
3321 .final_accuracies
3322 .insert(arch_name.clone(), 1.0 / (1.0 + final_accuracy)); results.convergence_rates.insert(
3324 arch_name.clone(),
3325 training_result.epochs_trained as f64 / config.training_config.epochs as f64,
3326 );
3327 results
3328 .memory_usage
3329 .insert(arch_name.clone(), framework.get_stats().peak_memory_usage);
3330 results
3331 .quantum_advantage
3332 .insert(arch_name.clone(), training_result.quantum_advantage_metrics);
3333 results.parameter_counts.insert(
3334 arch_name.clone(),
3335 framework
3336 .layers
3337 .iter()
3338 .map(|l| l.get_num_parameters())
3339 .sum(),
3340 );
3341 results.circuit_depths.insert(
3342 arch_name.clone(),
3343 framework.layers.iter().map(|l| l.get_depth()).sum(),
3344 );
3345 results.gate_counts.insert(
3346 arch_name.clone(),
3347 framework.layers.iter().map(|l| l.get_gate_count()).sum(),
3348 );
3349 }
3350
3351 Ok(results)
3352}