1use scirs2_core::ndarray::Array1;
9use scirs2_core::parallel_ops::{IndexedParallelIterator, ParallelIterator};
10use scirs2_core::random::{thread_rng, Rng};
11use scirs2_core::Complex64;
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, Default)]
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
681#[derive(Debug, Clone, Serialize, Deserialize)]
683pub struct NoiseParameters {
684 pub single_qubit_error: f64,
686 pub two_qubit_error: f64,
688 pub measurement_error: f64,
690 pub coherence_times: (f64, f64),
692 pub gate_times: HashMap<String, f64>,
694}
695
696impl Default for NoiseParameters {
697 fn default() -> Self {
698 let mut gate_times = HashMap::new();
699 gate_times.insert("single_qubit".to_string(), 50e-9); gate_times.insert("two_qubit".to_string(), 200e-9); Self {
703 single_qubit_error: 0.001,
704 two_qubit_error: 0.01,
705 measurement_error: 0.01,
706 coherence_times: (50e-6, 100e-6), gate_times,
708 }
709 }
710}
711
712#[derive(Debug, Clone, Serialize, Deserialize, Default)]
714pub struct ErrorMitigationConfig {
715 pub zero_noise_extrapolation: bool,
717 pub readout_error_mitigation: bool,
719 pub symmetry_verification: bool,
721 pub virtual_distillation: VirtualDistillationConfig,
723 pub quantum_error_correction: bool,
725}
726
727#[derive(Debug, Clone, Serialize, Deserialize)]
729pub struct VirtualDistillationConfig {
730 pub enabled: bool,
732 pub num_copies: usize,
734 pub protocol: DistillationProtocol,
736}
737
738impl Default for VirtualDistillationConfig {
739 fn default() -> Self {
740 Self {
741 enabled: false,
742 num_copies: 2,
743 protocol: DistillationProtocol::Standard,
744 }
745 }
746}
747
748#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
750pub enum DistillationProtocol {
751 Standard,
753 Improved,
755 QuantumAdvantage,
757}
758
759#[derive(Debug, Clone, Serialize, Deserialize)]
761pub struct NoiseCharacterizationConfig {
762 pub enabled: bool,
764 pub method: NoiseCharacterizationMethod,
766 pub benchmarking: BenchmarkingProtocols,
768 pub calibration_frequency: CalibrationFrequency,
770}
771
772impl Default for NoiseCharacterizationConfig {
773 fn default() -> Self {
774 Self {
775 enabled: false,
776 method: NoiseCharacterizationMethod::ProcessTomography,
777 benchmarking: BenchmarkingProtocols::default(),
778 calibration_frequency: CalibrationFrequency::Daily,
779 }
780 }
781}
782
783#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
785pub enum NoiseCharacterizationMethod {
786 ProcessTomography,
788 RandomizedBenchmarking,
790 GateSetTomography,
792 QuantumDetectorTomography,
794 CrossEntropyBenchmarking,
796}
797
798#[derive(Debug, Clone, Serialize, Deserialize)]
800pub struct BenchmarkingProtocols {
801 pub randomized_benchmarking: bool,
803 pub quantum_volume: bool,
805 pub cross_entropy_benchmarking: bool,
807 pub mirror_benchmarking: bool,
809}
810
811impl Default for BenchmarkingProtocols {
812 fn default() -> Self {
813 Self {
814 randomized_benchmarking: true,
815 quantum_volume: false,
816 cross_entropy_benchmarking: false,
817 mirror_benchmarking: false,
818 }
819 }
820}
821
822#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
824pub enum CalibrationFrequency {
825 RealTime,
827 Hourly,
829 Daily,
831 Weekly,
833 Manual,
835}
836
837#[derive(Debug, Clone, Serialize, Deserialize, Default)]
839pub struct RobustTrainingConfig {
840 pub enabled: bool,
842 pub noise_injection: NoiseInjectionConfig,
844 pub adversarial_training: AdversarialTrainingConfig,
846 pub ensemble_methods: EnsembleMethodsConfig,
848}
849
850#[derive(Debug, Clone, Serialize, Deserialize)]
852pub struct NoiseInjectionConfig {
853 pub enabled: bool,
855 pub injection_probability: f64,
857 pub noise_strength: f64,
859 pub noise_type: NoiseType,
861}
862
863impl Default for NoiseInjectionConfig {
864 fn default() -> Self {
865 Self {
866 enabled: false,
867 injection_probability: 0.1,
868 noise_strength: 0.01,
869 noise_type: NoiseType::Depolarizing,
870 }
871 }
872}
873
874#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
876pub enum NoiseType {
877 Depolarizing,
879 AmplitudeDamping,
881 PhaseDamping,
883 BitFlip,
885 PhaseFlip,
887 Pauli,
889}
890
891#[derive(Debug, Clone, Serialize, Deserialize)]
893pub struct AdversarialTrainingConfig {
894 pub enabled: bool,
896 pub attack_strength: f64,
898 pub attack_method: AdversarialAttackMethod,
900 pub defense_method: AdversarialDefenseMethod,
902}
903
904impl Default for AdversarialTrainingConfig {
905 fn default() -> Self {
906 Self {
907 enabled: false,
908 attack_strength: 0.01,
909 attack_method: AdversarialAttackMethod::FGSM,
910 defense_method: AdversarialDefenseMethod::AdversarialTraining,
911 }
912 }
913}
914
915#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
917pub enum AdversarialAttackMethod {
918 FGSM,
920 PGD,
922 CarliniWagner,
924 QuantumAdversarial,
926}
927
928#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
930pub enum AdversarialDefenseMethod {
931 AdversarialTraining,
933 DefensiveDistillation,
935 CertifiedDefenses,
937 QuantumErrorCorrection,
939}
940
941#[derive(Debug, Clone, Serialize, Deserialize)]
943pub struct EnsembleMethodsConfig {
944 pub enabled: bool,
946 pub num_ensemble: usize,
948 pub ensemble_method: EnsembleMethod,
950 pub voting_strategy: VotingStrategy,
952}
953
954impl Default for EnsembleMethodsConfig {
955 fn default() -> Self {
956 Self {
957 enabled: false,
958 num_ensemble: 5,
959 ensemble_method: EnsembleMethod::Bagging,
960 voting_strategy: VotingStrategy::MajorityVoting,
961 }
962 }
963}
964
965#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
967pub enum EnsembleMethod {
968 Bagging,
970 Boosting,
972 RandomForest,
974 QuantumEnsemble,
976}
977
978#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
980pub enum VotingStrategy {
981 MajorityVoting,
983 WeightedVoting,
985 SoftVoting,
987 QuantumVoting,
989}
990
991#[derive(Debug, Clone, Serialize, Deserialize)]
993pub struct PerformanceOptimizationConfig {
994 pub enabled: bool,
996 pub memory_optimization: MemoryOptimizationConfig,
998 pub computation_optimization: ComputationOptimizationConfig,
1000 pub parallelization: ParallelizationConfig,
1002 pub caching: CachingConfig,
1004}
1005
1006impl Default for PerformanceOptimizationConfig {
1007 fn default() -> Self {
1008 Self {
1009 enabled: true,
1010 memory_optimization: MemoryOptimizationConfig::default(),
1011 computation_optimization: ComputationOptimizationConfig::default(),
1012 parallelization: ParallelizationConfig::default(),
1013 caching: CachingConfig::default(),
1014 }
1015 }
1016}
1017
1018#[derive(Debug, Clone, Serialize, Deserialize)]
1020pub struct MemoryOptimizationConfig {
1021 pub enabled: bool,
1023 pub memory_mapping: bool,
1025 pub gradient_checkpointing: bool,
1027 pub memory_pool_size: Option<usize>,
1029}
1030
1031impl Default for MemoryOptimizationConfig {
1032 fn default() -> Self {
1033 Self {
1034 enabled: true,
1035 memory_mapping: false,
1036 gradient_checkpointing: false,
1037 memory_pool_size: None,
1038 }
1039 }
1040}
1041
1042#[derive(Debug, Clone, Serialize, Deserialize)]
1044pub struct ComputationOptimizationConfig {
1045 pub enabled: bool,
1047 pub mixed_precision: bool,
1049 pub simd_optimization: bool,
1051 pub jit_compilation: bool,
1053}
1054
1055impl Default for ComputationOptimizationConfig {
1056 fn default() -> Self {
1057 Self {
1058 enabled: true,
1059 mixed_precision: false,
1060 simd_optimization: true,
1061 jit_compilation: false,
1062 }
1063 }
1064}
1065
1066#[derive(Debug, Clone, Serialize, Deserialize)]
1068pub struct ParallelizationConfig {
1069 pub enabled: bool,
1071 pub num_threads: Option<usize>,
1073 pub data_parallelism: bool,
1075 pub model_parallelism: bool,
1077 pub pipeline_parallelism: bool,
1079}
1080
1081impl Default for ParallelizationConfig {
1082 fn default() -> Self {
1083 Self {
1084 enabled: true,
1085 num_threads: None,
1086 data_parallelism: true,
1087 model_parallelism: false,
1088 pipeline_parallelism: false,
1089 }
1090 }
1091}
1092
1093#[derive(Debug, Clone, Serialize, Deserialize)]
1095pub struct CachingConfig {
1096 pub enabled: bool,
1098 pub cache_size: usize,
1100 pub cache_gradients: bool,
1102 pub cache_intermediate: bool,
1104}
1105
1106impl Default for CachingConfig {
1107 fn default() -> Self {
1108 Self {
1109 enabled: true,
1110 cache_size: 1000,
1111 cache_gradients: true,
1112 cache_intermediate: false,
1113 }
1114 }
1115}
1116
1117#[derive(Debug)]
1119pub struct QuantumMLFramework {
1120 config: QMLConfig,
1122 layers: Vec<Box<dyn QMLLayer>>,
1124 training_state: QMLTrainingState,
1126 backend: Option<SciRS2Backend>,
1128 stats: QMLStats,
1130 training_history: Vec<QMLTrainingResult>,
1132}
1133
1134impl QuantumMLFramework {
1135 pub fn new(config: QMLConfig) -> Result<Self> {
1137 let mut framework = Self {
1138 config,
1139 layers: Vec::new(),
1140 training_state: QMLTrainingState::new(),
1141 backend: None,
1142 stats: QMLStats::new(),
1143 training_history: Vec::new(),
1144 };
1145
1146 framework.initialize_layers()?;
1148
1149 let backend = SciRS2Backend::new();
1151 if backend.is_available() {
1152 framework.backend = Some(backend);
1153 }
1154
1155 Ok(framework)
1156 }
1157
1158 fn initialize_layers(&mut self) -> Result<()> {
1160 for layer_config in &self.config.layer_configs {
1161 let layer = self.create_layer(layer_config)?;
1162 self.layers.push(layer);
1163 }
1164 Ok(())
1165 }
1166
1167 fn create_layer(&self, config: &QMLLayerConfig) -> Result<Box<dyn QMLLayer>> {
1169 match config.layer_type {
1170 QMLLayerType::ParameterizedQuantumCircuit => Ok(Box::new(
1171 ParameterizedQuantumCircuitLayer::new(self.config.num_qubits, config.clone())?,
1172 )),
1173 QMLLayerType::QuantumConvolutional => Ok(Box::new(QuantumConvolutionalLayer::new(
1174 self.config.num_qubits,
1175 config.clone(),
1176 )?)),
1177 QMLLayerType::QuantumDense => Ok(Box::new(QuantumDenseLayer::new(
1178 self.config.num_qubits,
1179 config.clone(),
1180 )?)),
1181 QMLLayerType::QuantumLSTM => Ok(Box::new(QuantumLSTMLayer::new(
1182 self.config.num_qubits,
1183 config.clone(),
1184 )?)),
1185 QMLLayerType::QuantumAttention => Ok(Box::new(QuantumAttentionLayer::new(
1186 self.config.num_qubits,
1187 config.clone(),
1188 )?)),
1189 _ => Err(SimulatorError::InvalidConfiguration(format!(
1190 "Layer type {:?} not yet implemented",
1191 config.layer_type
1192 ))),
1193 }
1194 }
1195
1196 pub fn forward(&mut self, input: &Array1<f64>) -> Result<Array1<f64>> {
1198 let mut current_state = self.encode_input(input)?;
1199
1200 for layer in &mut self.layers {
1202 current_state = layer.forward(¤t_state)?;
1203 }
1204
1205 let output = self.decode_output(¤t_state)?;
1207
1208 self.stats.forward_passes += 1;
1210
1211 Ok(output)
1212 }
1213
1214 pub fn backward(&mut self, loss_gradient: &Array1<f64>) -> Result<Array1<f64>> {
1216 let mut grad = loss_gradient.clone();
1217
1218 for layer in self.layers.iter_mut().rev() {
1220 grad = layer.backward(&grad)?;
1221 }
1222
1223 self.stats.backward_passes += 1;
1225
1226 Ok(grad)
1227 }
1228
1229 pub fn train(
1231 &mut self,
1232 training_data: &[(Array1<f64>, Array1<f64>)],
1233 validation_data: Option<&[(Array1<f64>, Array1<f64>)]>,
1234 ) -> Result<QMLTrainingResult> {
1235 let mut best_validation_loss = f64::INFINITY;
1236 let mut patience_counter = 0;
1237 let mut training_metrics = Vec::new();
1238
1239 let training_start = std::time::Instant::now();
1240
1241 for epoch in 0..self.config.training_config.epochs {
1242 let epoch_start = std::time::Instant::now();
1243
1244 let mut epoch_loss = 0.0;
1246 let mut num_batches = 0;
1247
1248 for batch in training_data.chunks(self.config.training_config.batch_size) {
1249 let batch_loss = self.train_batch(batch)?;
1250 epoch_loss += batch_loss;
1251 num_batches += 1;
1252 }
1253
1254 epoch_loss /= f64::from(num_batches);
1255
1256 let validation_loss = if let Some(val_data) = validation_data {
1258 self.evaluate(val_data)?
1259 } else {
1260 epoch_loss
1261 };
1262
1263 let epoch_time = epoch_start.elapsed();
1264
1265 let metrics = QMLEpochMetrics {
1266 epoch,
1267 training_loss: epoch_loss,
1268 validation_loss,
1269 epoch_time,
1270 learning_rate: self.get_current_learning_rate(epoch),
1271 };
1272
1273 training_metrics.push(metrics.clone());
1274
1275 if self.config.training_config.early_stopping.enabled {
1277 if validation_loss
1278 < best_validation_loss - self.config.training_config.early_stopping.min_delta
1279 {
1280 best_validation_loss = validation_loss;
1281 patience_counter = 0;
1282 } else {
1283 patience_counter += 1;
1284 if patience_counter >= self.config.training_config.early_stopping.patience {
1285 println!("Early stopping triggered at epoch {epoch}");
1286 break;
1287 }
1288 }
1289 }
1290
1291 self.update_learning_rate(epoch, validation_loss);
1293
1294 if epoch % 10 == 0 {
1296 println!(
1297 "Epoch {}: train_loss={:.6}, val_loss={:.6}, time={:.2}s",
1298 epoch,
1299 epoch_loss,
1300 validation_loss,
1301 epoch_time.as_secs_f64()
1302 );
1303 }
1304 }
1305
1306 let total_training_time = training_start.elapsed();
1307
1308 let result = QMLTrainingResult {
1309 final_training_loss: training_metrics.last().map_or(0.0, |m| m.training_loss),
1310 final_validation_loss: training_metrics.last().map_or(0.0, |m| m.validation_loss),
1311 best_validation_loss,
1312 epochs_trained: training_metrics.len(),
1313 total_training_time,
1314 training_metrics,
1315 quantum_advantage_metrics: self.compute_quantum_advantage_metrics()?,
1316 };
1317
1318 self.training_history.push(result.clone());
1319
1320 Ok(result)
1321 }
1322
1323 fn train_batch(&mut self, batch: &[(Array1<f64>, Array1<f64>)]) -> Result<f64> {
1325 let mut total_loss = 0.0;
1326 let mut total_gradients: Vec<Array1<f64>> =
1327 (0..self.layers.len()).map(|_| Array1::zeros(0)).collect();
1328
1329 for (input, target) in batch {
1330 let prediction = self.forward(input)?;
1332
1333 let loss = Self::compute_loss(&prediction, target)?;
1335 total_loss += loss;
1336
1337 let loss_gradient = Self::compute_loss_gradient(&prediction, target)?;
1339
1340 let gradients = self.compute_gradients(&loss_gradient)?;
1342
1343 for (i, grad) in gradients.iter().enumerate() {
1345 if total_gradients[i].is_empty() {
1346 total_gradients[i] = grad.clone();
1347 } else {
1348 total_gradients[i] += grad;
1349 }
1350 }
1351 }
1352
1353 let batch_size = batch.len() as f64;
1355 for grad in &mut total_gradients {
1356 *grad /= batch_size;
1357 }
1358
1359 self.apply_gradients(&total_gradients)?;
1361
1362 Ok(total_loss / batch_size)
1363 }
1364
1365 pub fn evaluate(&mut self, data: &[(Array1<f64>, Array1<f64>)]) -> Result<f64> {
1367 let mut total_loss = 0.0;
1368
1369 for (input, target) in data {
1370 let prediction = self.forward(input)?;
1371 let loss = Self::compute_loss(&prediction, target)?;
1372 total_loss += loss;
1373 }
1374
1375 Ok(total_loss / data.len() as f64)
1376 }
1377
1378 fn encode_input(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1380 match self.config.classical_preprocessing.encoding_method {
1381 DataEncodingMethod::Amplitude => self.encode_amplitude(input),
1382 DataEncodingMethod::Angle => self.encode_angle(input),
1383 DataEncodingMethod::Basis => self.encode_basis(input),
1384 DataEncodingMethod::QuantumFeatureMap => self.encode_quantum_feature_map(input),
1385 _ => Err(SimulatorError::InvalidConfiguration(
1386 "Encoding method not implemented".to_string(),
1387 )),
1388 }
1389 }
1390
1391 fn encode_amplitude(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1393 let n_qubits = self.config.num_qubits;
1394 let state_size = 1 << n_qubits;
1395 let mut state = Array1::zeros(state_size);
1396
1397 let norm = input.iter().map(|x| x * x).sum::<f64>().sqrt();
1399 if norm == 0.0 {
1400 return Err(SimulatorError::InvalidState("Zero input norm".to_string()));
1401 }
1402
1403 for (i, &val) in input.iter().enumerate() {
1405 if i < state_size {
1406 state[i] = Complex64::new(val / norm, 0.0);
1407 }
1408 }
1409
1410 Ok(state)
1411 }
1412
1413 fn encode_angle(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1415 let n_qubits = self.config.num_qubits;
1416 let state_size = 1 << n_qubits;
1417 let mut state = Array1::zeros(state_size);
1418
1419 state[0] = Complex64::new(1.0, 0.0);
1421
1422 for (i, &angle) in input.iter().enumerate() {
1424 if i < n_qubits {
1425 state = self.apply_ry_rotation(&state, i, angle)?;
1427 }
1428 }
1429
1430 Ok(state)
1431 }
1432
1433 fn encode_basis(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1435 let n_qubits = self.config.num_qubits;
1436 let state_size = 1 << n_qubits;
1437 let mut state = Array1::zeros(state_size);
1438
1439 let mut binary_index = 0;
1441 for (i, &val) in input.iter().enumerate() {
1442 if i < n_qubits && val > 0.5 {
1443 binary_index |= 1 << i;
1444 }
1445 }
1446
1447 state[binary_index] = Complex64::new(1.0, 0.0);
1448
1449 Ok(state)
1450 }
1451
1452 fn encode_quantum_feature_map(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1454 let n_qubits = self.config.num_qubits;
1455 let state_size = 1 << n_qubits;
1456 let mut state = Array1::zeros(state_size);
1457
1458 let hadamard_coeff = 1.0 / (n_qubits as f64 / 2.0).exp2();
1460 for i in 0..state_size {
1461 state[i] = Complex64::new(hadamard_coeff, 0.0);
1462 }
1463
1464 for (i, &feature) in input.iter().enumerate() {
1466 if i < n_qubits {
1467 state = self.apply_rz_rotation(&state, i, feature * PI)?;
1469 }
1470 }
1471
1472 for i in 0..(n_qubits - 1) {
1474 if i + 1 < input.len() {
1475 let interaction = input[i] * input[i + 1];
1476 state = self.apply_cnot_interaction(&state, i, i + 1, interaction * PI)?;
1477 }
1478 }
1479
1480 Ok(state)
1481 }
1482
1483 fn apply_ry_rotation(
1485 &self,
1486 state: &Array1<Complex64>,
1487 qubit: usize,
1488 angle: f64,
1489 ) -> Result<Array1<Complex64>> {
1490 let n_qubits = self.config.num_qubits;
1491 let state_size = 1 << n_qubits;
1492 let mut new_state = state.clone();
1493
1494 let cos_half = (angle / 2.0).cos();
1495 let sin_half = (angle / 2.0).sin();
1496
1497 for i in 0..state_size {
1498 if i & (1 << qubit) == 0 {
1499 let j = i | (1 << qubit); if j < state_size {
1502 let state_0 = state[i];
1503 let state_1 = state[j];
1504
1505 new_state[i] = Complex64::new(cos_half, 0.0) * state_0
1506 - Complex64::new(sin_half, 0.0) * state_1;
1507 new_state[j] = Complex64::new(sin_half, 0.0) * state_0
1508 + Complex64::new(cos_half, 0.0) * state_1;
1509 }
1510 }
1511 }
1512
1513 Ok(new_state)
1514 }
1515
1516 fn apply_rz_rotation(
1518 &self,
1519 state: &Array1<Complex64>,
1520 qubit: usize,
1521 angle: f64,
1522 ) -> Result<Array1<Complex64>> {
1523 let n_qubits = self.config.num_qubits;
1524 let state_size = 1 << n_qubits;
1525 let mut new_state = state.clone();
1526
1527 let phase_0 = Complex64::from_polar(1.0, -angle / 2.0);
1528 let phase_1 = Complex64::from_polar(1.0, angle / 2.0);
1529
1530 for i in 0..state_size {
1531 if i & (1 << qubit) == 0 {
1532 new_state[i] *= phase_0;
1533 } else {
1534 new_state[i] *= phase_1;
1535 }
1536 }
1537
1538 Ok(new_state)
1539 }
1540
1541 fn apply_cnot_interaction(
1543 &self,
1544 state: &Array1<Complex64>,
1545 control: usize,
1546 target: usize,
1547 interaction: f64,
1548 ) -> Result<Array1<Complex64>> {
1549 let n_qubits = self.config.num_qubits;
1550 let state_size = 1 << n_qubits;
1551 let mut new_state = state.clone();
1552
1553 let phase = Complex64::from_polar(1.0, interaction);
1555
1556 for i in 0..state_size {
1557 if (i & (1 << control)) != 0 && (i & (1 << target)) != 0 {
1558 new_state[i] *= phase;
1560 }
1561 }
1562
1563 Ok(new_state)
1564 }
1565
1566 fn decode_output(&self, state: &Array1<Complex64>) -> Result<Array1<f64>> {
1568 let n_qubits = self.config.num_qubits;
1570 let mut output = Array1::zeros(n_qubits);
1571
1572 for qubit in 0..n_qubits {
1573 let expectation = Self::measure_pauli_z_expectation(state, qubit)?;
1574 output[qubit] = expectation;
1575 }
1576
1577 Ok(output)
1578 }
1579
1580 fn measure_pauli_z_expectation(state: &Array1<Complex64>, qubit: usize) -> Result<f64> {
1582 let state_size = state.len();
1583 let mut expectation = 0.0;
1584
1585 for i in 0..state_size {
1586 let probability = state[i].norm_sqr();
1587 if i & (1 << qubit) == 0 {
1588 expectation += probability; } else {
1590 expectation -= probability; }
1592 }
1593
1594 Ok(expectation)
1595 }
1596
1597 fn compute_loss(prediction: &Array1<f64>, target: &Array1<f64>) -> Result<f64> {
1599 if prediction.shape() != target.shape() {
1601 return Err(SimulatorError::InvalidInput(format!(
1602 "Shape mismatch: prediction shape {:?} != target shape {:?}",
1603 prediction.shape(),
1604 target.shape()
1605 )));
1606 }
1607
1608 let diff = prediction - target;
1610 let mse = diff.iter().map(|x| x * x).sum::<f64>() / diff.len() as f64;
1611 Ok(mse)
1612 }
1613
1614 fn compute_loss_gradient(
1616 prediction: &Array1<f64>,
1617 target: &Array1<f64>,
1618 ) -> Result<Array1<f64>> {
1619 let diff = prediction - target;
1621 let grad = 2.0 * &diff / diff.len() as f64;
1622 Ok(grad)
1623 }
1624
1625 fn compute_gradients(&mut self, loss_gradient: &Array1<f64>) -> Result<Vec<Array1<f64>>> {
1627 let mut gradients = Vec::new();
1628
1629 for layer_idx in 0..self.layers.len() {
1630 let layer_gradient = match self.config.training_config.gradient_method {
1631 GradientMethod::ParameterShift => {
1632 self.compute_parameter_shift_gradient(layer_idx, loss_gradient)?
1633 }
1634 GradientMethod::FiniteDifference => {
1635 self.compute_finite_difference_gradient(layer_idx, loss_gradient)?
1636 }
1637 _ => {
1638 return Err(SimulatorError::InvalidConfiguration(
1639 "Gradient method not implemented".to_string(),
1640 ))
1641 }
1642 };
1643 gradients.push(layer_gradient);
1644 }
1645
1646 Ok(gradients)
1647 }
1648
1649 fn compute_parameter_shift_gradient(
1651 &mut self,
1652 layer_idx: usize,
1653 loss_gradient: &Array1<f64>,
1654 ) -> Result<Array1<f64>> {
1655 let layer = &self.layers[layer_idx];
1656 let parameters = layer.get_parameters();
1657 let mut gradient = Array1::zeros(parameters.len());
1658
1659 let shift = PI / 2.0; for (param_idx, ¶m_val) in parameters.iter().enumerate() {
1662 let mut params_plus = parameters.clone();
1664 params_plus[param_idx] = param_val + shift;
1665 self.layers[layer_idx].set_parameters(¶ms_plus);
1666 let output_plus = self.forward_layer(layer_idx, loss_gradient)?;
1667
1668 let mut params_minus = parameters.clone();
1670 params_minus[param_idx] = param_val - shift;
1671 self.layers[layer_idx].set_parameters(¶ms_minus);
1672 let output_minus = self.forward_layer(layer_idx, loss_gradient)?;
1673
1674 gradient[param_idx] = (output_plus.sum() - output_minus.sum()) / 2.0;
1676
1677 self.layers[layer_idx].set_parameters(¶meters);
1679 }
1680
1681 Ok(gradient)
1682 }
1683
1684 fn compute_finite_difference_gradient(
1686 &mut self,
1687 layer_idx: usize,
1688 loss_gradient: &Array1<f64>,
1689 ) -> Result<Array1<f64>> {
1690 let layer = &self.layers[layer_idx];
1691 let parameters = layer.get_parameters();
1692 let mut gradient = Array1::zeros(parameters.len());
1693
1694 let eps = 1e-6; for (param_idx, ¶m_val) in parameters.iter().enumerate() {
1697 let mut params_plus = parameters.clone();
1699 params_plus[param_idx] = param_val + eps;
1700 self.layers[layer_idx].set_parameters(¶ms_plus);
1701 let output_plus = self.forward_layer(layer_idx, loss_gradient)?;
1702
1703 let mut params_minus = parameters.clone();
1705 params_minus[param_idx] = param_val - eps;
1706 self.layers[layer_idx].set_parameters(¶ms_minus);
1707 let output_minus = self.forward_layer(layer_idx, loss_gradient)?;
1708
1709 gradient[param_idx] = (output_plus.sum() - output_minus.sum()) / (2.0 * eps);
1711
1712 self.layers[layer_idx].set_parameters(¶meters);
1714 }
1715
1716 Ok(gradient)
1717 }
1718
1719 fn forward_layer(&mut self, layer_idx: usize, input: &Array1<f64>) -> Result<Array1<f64>> {
1721 self.forward(input)
1723 }
1724
1725 fn apply_gradients(&mut self, gradients: &[Array1<f64>]) -> Result<()> {
1727 for (layer_idx, gradient) in gradients.iter().enumerate() {
1728 let layer = &mut self.layers[layer_idx];
1729 let mut parameters = layer.get_parameters();
1730
1731 match self.config.training_config.optimizer {
1733 OptimizerType::SGD => {
1734 for (param, grad) in parameters.iter_mut().zip(gradient.iter()) {
1735 *param -= self.config.training_config.learning_rate * grad;
1736 }
1737 }
1738 OptimizerType::Adam => {
1739 for (param, grad) in parameters.iter_mut().zip(gradient.iter()) {
1741 *param -= self.config.training_config.learning_rate * grad;
1742 }
1743 }
1744 _ => {
1745 for (param, grad) in parameters.iter_mut().zip(gradient.iter()) {
1747 *param -= self.config.training_config.learning_rate * grad;
1748 }
1749 }
1750 }
1751
1752 if let Some((min_val, max_val)) =
1754 self.config.training_config.regularization.parameter_bounds
1755 {
1756 for param in &mut parameters {
1757 *param = param.clamp(min_val, max_val);
1758 }
1759 }
1760
1761 layer.set_parameters(¶meters);
1762 }
1763
1764 Ok(())
1765 }
1766
1767 fn get_current_learning_rate(&self, epoch: usize) -> f64 {
1769 let base_lr = self.config.training_config.learning_rate;
1770
1771 match self.config.training_config.lr_schedule {
1772 LearningRateSchedule::Constant => base_lr,
1773 LearningRateSchedule::ExponentialDecay => base_lr * 0.95_f64.powi(epoch as i32),
1774 LearningRateSchedule::StepDecay => {
1775 if epoch % 50 == 0 && epoch > 0 {
1776 base_lr * 0.5_f64.powi((epoch / 50) as i32)
1777 } else {
1778 base_lr
1779 }
1780 }
1781 LearningRateSchedule::CosineAnnealing => {
1782 let progress = epoch as f64 / self.config.training_config.epochs as f64;
1783 base_lr * 0.5 * (1.0 + (PI * progress).cos())
1784 }
1785 _ => base_lr,
1786 }
1787 }
1788
1789 fn update_learning_rate(&mut self, epoch: usize, validation_loss: f64) {
1791 let current_lr = self.get_current_learning_rate(epoch);
1794 self.training_state.current_learning_rate = current_lr;
1795 }
1796
1797 fn compute_quantum_advantage_metrics(&self) -> Result<QuantumAdvantageMetrics> {
1799 Ok(QuantumAdvantageMetrics {
1801 quantum_volume: 0.0,
1802 classical_simulation_cost: 0.0,
1803 quantum_speedup_factor: 1.0,
1804 circuit_depth: self.layers.iter().map(|l| l.get_depth()).sum(),
1805 gate_count: self.layers.iter().map(|l| l.get_gate_count()).sum(),
1806 entanglement_measure: 0.0,
1807 })
1808 }
1809
1810 #[must_use]
1812 pub const fn get_stats(&self) -> &QMLStats {
1813 &self.stats
1814 }
1815
1816 #[must_use]
1818 pub fn get_training_history(&self) -> &[QMLTrainingResult] {
1819 &self.training_history
1820 }
1821
1822 #[must_use]
1824 pub fn get_layers(&self) -> &[Box<dyn QMLLayer>] {
1825 &self.layers
1826 }
1827
1828 #[must_use]
1830 pub const fn get_config(&self) -> &QMLConfig {
1831 &self.config
1832 }
1833
1834 pub fn encode_amplitude_public(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1836 self.encode_amplitude(input)
1837 }
1838
1839 pub fn encode_angle_public(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1841 self.encode_angle(input)
1842 }
1843
1844 pub fn encode_basis_public(&self, input: &Array1<f64>) -> Result<Array1<Complex64>> {
1846 self.encode_basis(input)
1847 }
1848
1849 pub fn encode_quantum_feature_map_public(
1851 &self,
1852 input: &Array1<f64>,
1853 ) -> Result<Array1<Complex64>> {
1854 self.encode_quantum_feature_map(input)
1855 }
1856
1857 pub fn measure_pauli_z_expectation_public(
1859 &self,
1860 state: &Array1<Complex64>,
1861 qubit: usize,
1862 ) -> Result<f64> {
1863 Self::measure_pauli_z_expectation(state, qubit)
1864 }
1865
1866 #[must_use]
1868 pub fn get_current_learning_rate_public(&self, epoch: usize) -> f64 {
1869 self.get_current_learning_rate(epoch)
1870 }
1871
1872 pub fn compute_loss_public(
1874 &self,
1875 prediction: &Array1<f64>,
1876 target: &Array1<f64>,
1877 ) -> Result<f64> {
1878 Self::compute_loss(prediction, target)
1879 }
1880
1881 pub fn compute_loss_gradient_public(
1883 &self,
1884 prediction: &Array1<f64>,
1885 target: &Array1<f64>,
1886 ) -> Result<Array1<f64>> {
1887 Self::compute_loss_gradient(prediction, target)
1888 }
1889}
1890
1891pub trait QMLLayer: std::fmt::Debug + Send + Sync {
1893 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>>;
1895
1896 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>>;
1898
1899 fn get_parameters(&self) -> Array1<f64>;
1901
1902 fn set_parameters(&mut self, parameters: &Array1<f64>);
1904
1905 fn get_depth(&self) -> usize;
1907
1908 fn get_gate_count(&self) -> usize;
1910
1911 fn get_num_parameters(&self) -> usize;
1913}
1914
1915#[derive(Debug)]
1917pub struct ParameterizedQuantumCircuitLayer {
1918 num_qubits: usize,
1920 config: QMLLayerConfig,
1922 parameters: Array1<f64>,
1924 circuit_structure: Vec<PQCGate>,
1926 simulator: StateVectorSimulator,
1928}
1929
1930impl ParameterizedQuantumCircuitLayer {
1931 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
1933 let mut layer = Self {
1934 num_qubits,
1935 config: config.clone(),
1936 parameters: Array1::zeros(config.num_parameters),
1937 circuit_structure: Vec::new(),
1938 simulator: StateVectorSimulator::new(),
1939 };
1940
1941 layer.initialize_parameters();
1943
1944 layer.build_circuit_structure()?;
1946
1947 Ok(layer)
1948 }
1949
1950 fn initialize_parameters(&mut self) {
1952 let mut rng = thread_rng();
1953 for param in &mut self.parameters {
1954 *param = rng.gen_range(-PI..PI);
1955 }
1956 }
1957
1958 fn build_circuit_structure(&mut self) -> Result<()> {
1960 match self.config.ansatz_type {
1961 AnsatzType::Hardware => self.build_hardware_efficient_ansatz(),
1962 AnsatzType::Layered => self.build_layered_ansatz(),
1963 AnsatzType::BrickWall => self.build_brick_wall_ansatz(),
1964 _ => Err(SimulatorError::InvalidConfiguration(
1965 "Ansatz type not implemented".to_string(),
1966 )),
1967 }
1968 }
1969
1970 fn build_hardware_efficient_ansatz(&mut self) -> Result<()> {
1972 let mut param_idx = 0;
1973
1974 for layer in 0..self.config.depth {
1975 for qubit in 0..self.num_qubits {
1977 for &gate_type in &self.config.rotation_gates {
1978 if param_idx < self.parameters.len() {
1979 self.circuit_structure.push(PQCGate {
1980 gate_type: PQCGateType::SingleQubit(gate_type),
1981 qubits: vec![qubit],
1982 parameter_index: Some(param_idx),
1983 });
1984 param_idx += 1;
1985 }
1986 }
1987 }
1988
1989 self.add_entangling_gates(¶m_idx);
1991 }
1992
1993 Ok(())
1994 }
1995
1996 fn build_layered_ansatz(&mut self) -> Result<()> {
1998 self.build_hardware_efficient_ansatz()
2000 }
2001
2002 fn build_brick_wall_ansatz(&mut self) -> Result<()> {
2004 let mut param_idx = 0;
2005
2006 for layer in 0..self.config.depth {
2007 let offset = layer % 2;
2009 for i in (offset..self.num_qubits - 1).step_by(2) {
2010 self.circuit_structure.push(PQCGate {
2011 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2012 qubits: vec![i, i + 1],
2013 parameter_index: None,
2014 });
2015 }
2016
2017 for qubit in 0..self.num_qubits {
2019 if param_idx < self.parameters.len() {
2020 self.circuit_structure.push(PQCGate {
2021 gate_type: PQCGateType::SingleQubit(RotationGate::RY),
2022 qubits: vec![qubit],
2023 parameter_index: Some(param_idx),
2024 });
2025 param_idx += 1;
2026 }
2027 }
2028 }
2029
2030 Ok(())
2031 }
2032
2033 fn add_entangling_gates(&mut self, param_idx: &usize) {
2035 match self.config.entanglement_pattern {
2036 EntanglementPattern::Linear => {
2037 for i in 0..(self.num_qubits - 1) {
2038 self.circuit_structure.push(PQCGate {
2039 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2040 qubits: vec![i, i + 1],
2041 parameter_index: None,
2042 });
2043 }
2044 }
2045 EntanglementPattern::Circular => {
2046 for i in 0..self.num_qubits {
2047 let next = (i + 1) % self.num_qubits;
2048 self.circuit_structure.push(PQCGate {
2049 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2050 qubits: vec![i, next],
2051 parameter_index: None,
2052 });
2053 }
2054 }
2055 EntanglementPattern::AllToAll => {
2056 for i in 0..self.num_qubits {
2057 for j in (i + 1)..self.num_qubits {
2058 self.circuit_structure.push(PQCGate {
2059 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2060 qubits: vec![i, j],
2061 parameter_index: None,
2062 });
2063 }
2064 }
2065 }
2066 _ => {
2067 for i in 0..(self.num_qubits - 1) {
2069 self.circuit_structure.push(PQCGate {
2070 gate_type: PQCGateType::TwoQubit(TwoQubitGate::CNOT),
2071 qubits: vec![i, i + 1],
2072 parameter_index: None,
2073 });
2074 }
2075 }
2076 }
2077 }
2078}
2079
2080impl QMLLayer for ParameterizedQuantumCircuitLayer {
2081 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2082 let mut state = input.clone();
2083
2084 for gate in &self.circuit_structure {
2086 state = self.apply_gate(&state, gate)?;
2087 }
2088
2089 Ok(state)
2090 }
2091
2092 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2093 Ok(gradient.clone())
2095 }
2096
2097 fn get_parameters(&self) -> Array1<f64> {
2098 self.parameters.clone()
2099 }
2100
2101 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2102 self.parameters = parameters.clone();
2103 }
2104
2105 fn get_depth(&self) -> usize {
2106 self.config.depth
2107 }
2108
2109 fn get_gate_count(&self) -> usize {
2110 self.circuit_structure.len()
2111 }
2112
2113 fn get_num_parameters(&self) -> usize {
2114 self.parameters.len()
2115 }
2116}
2117
2118impl ParameterizedQuantumCircuitLayer {
2119 fn apply_gate(&self, state: &Array1<Complex64>, gate: &PQCGate) -> Result<Array1<Complex64>> {
2121 match &gate.gate_type {
2122 PQCGateType::SingleQubit(rotation_gate) => {
2123 let angle = if let Some(param_idx) = gate.parameter_index {
2124 self.parameters[param_idx]
2125 } else {
2126 0.0
2127 };
2128 Self::apply_single_qubit_gate(state, gate.qubits[0], *rotation_gate, angle)
2129 }
2130 PQCGateType::TwoQubit(two_qubit_gate) => {
2131 Self::apply_two_qubit_gate(state, gate.qubits[0], gate.qubits[1], *two_qubit_gate)
2132 }
2133 }
2134 }
2135
2136 fn apply_single_qubit_gate(
2138 state: &Array1<Complex64>,
2139 qubit: usize,
2140 gate_type: RotationGate,
2141 angle: f64,
2142 ) -> Result<Array1<Complex64>> {
2143 let state_size = state.len();
2144 let mut new_state = Array1::zeros(state_size);
2145
2146 match gate_type {
2147 RotationGate::RX => {
2148 let cos_half = (angle / 2.0).cos();
2149 let sin_half = (angle / 2.0).sin();
2150
2151 for i in 0..state_size {
2152 if i & (1 << qubit) == 0 {
2153 let j = i | (1 << qubit);
2154 if j < state_size {
2155 new_state[i] = Complex64::new(cos_half, 0.0) * state[i]
2156 + Complex64::new(0.0, -sin_half) * state[j];
2157 new_state[j] = Complex64::new(0.0, -sin_half) * state[i]
2158 + Complex64::new(cos_half, 0.0) * state[j];
2159 }
2160 }
2161 }
2162 }
2163 RotationGate::RY => {
2164 let cos_half = (angle / 2.0).cos();
2165 let sin_half = (angle / 2.0).sin();
2166
2167 for i in 0..state_size {
2168 if i & (1 << qubit) == 0 {
2169 let j = i | (1 << qubit);
2170 if j < state_size {
2171 new_state[i] = Complex64::new(cos_half, 0.0) * state[i]
2172 - Complex64::new(sin_half, 0.0) * state[j];
2173 new_state[j] = Complex64::new(sin_half, 0.0) * state[i]
2174 + Complex64::new(cos_half, 0.0) * state[j];
2175 }
2176 }
2177 }
2178 }
2179 RotationGate::RZ => {
2180 let phase_0 = Complex64::from_polar(1.0, -angle / 2.0);
2181 let phase_1 = Complex64::from_polar(1.0, angle / 2.0);
2182
2183 for i in 0..state_size {
2184 if i & (1 << qubit) == 0 {
2185 new_state[i] = phase_0 * state[i];
2186 } else {
2187 new_state[i] = phase_1 * state[i];
2188 }
2189 }
2190 }
2191 _ => {
2192 return Err(SimulatorError::InvalidGate(
2193 "Gate type not implemented".to_string(),
2194 ))
2195 }
2196 }
2197
2198 Ok(new_state)
2199 }
2200
2201 fn apply_two_qubit_gate(
2203 state: &Array1<Complex64>,
2204 control: usize,
2205 target: usize,
2206 gate_type: TwoQubitGate,
2207 ) -> Result<Array1<Complex64>> {
2208 let state_size = state.len();
2209 let mut new_state = state.clone();
2210
2211 match gate_type {
2212 TwoQubitGate::CNOT => {
2213 for i in 0..state_size {
2214 if (i & (1 << control)) != 0 {
2215 let j = i ^ (1 << target);
2217 new_state[i] = state[j];
2218 }
2219 }
2220 }
2221 TwoQubitGate::CZ => {
2222 for i in 0..state_size {
2223 if (i & (1 << control)) != 0 && (i & (1 << target)) != 0 {
2224 new_state[i] = -state[i];
2226 }
2227 }
2228 }
2229 TwoQubitGate::SWAP => {
2230 for i in 0..state_size {
2231 let ctrl_bit = (i & (1 << control)) != 0;
2232 let targ_bit = (i & (1 << target)) != 0;
2233 if ctrl_bit != targ_bit {
2234 let j = i ^ (1 << control) ^ (1 << target);
2236 new_state[i] = state[j];
2237 }
2238 }
2239 }
2240 TwoQubitGate::CPhase => {
2241 for i in 0..state_size {
2242 if (i & (1 << control)) != 0 && (i & (1 << target)) != 0 {
2243 new_state[i] = -state[i];
2245 }
2246 }
2247 }
2248 }
2249
2250 Ok(new_state)
2251 }
2252}
2253
2254#[derive(Debug)]
2256pub struct QuantumConvolutionalLayer {
2257 num_qubits: usize,
2259 config: QMLLayerConfig,
2261 parameters: Array1<f64>,
2263 conv_structure: Vec<ConvolutionalFilter>,
2265}
2266
2267impl QuantumConvolutionalLayer {
2268 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
2270 let mut layer = Self {
2271 num_qubits,
2272 config: config.clone(),
2273 parameters: Array1::zeros(config.num_parameters),
2274 conv_structure: Vec::new(),
2275 };
2276
2277 layer.initialize_parameters();
2278 layer.build_convolutional_structure()?;
2279
2280 Ok(layer)
2281 }
2282
2283 fn initialize_parameters(&mut self) {
2285 let mut rng = thread_rng();
2286 for param in &mut self.parameters {
2287 *param = rng.gen_range(-PI..PI);
2288 }
2289 }
2290
2291 fn build_convolutional_structure(&mut self) -> Result<()> {
2293 let filter_size = 2; let stride = 1;
2296
2297 let mut param_idx = 0;
2298 for start in (0..=(self.num_qubits - filter_size)).step_by(stride) {
2299 if param_idx + 2 <= self.parameters.len() {
2300 self.conv_structure.push(ConvolutionalFilter {
2301 qubits: vec![start, start + 1],
2302 parameter_indices: vec![param_idx, param_idx + 1],
2303 });
2304 param_idx += 2;
2305 }
2306 }
2307
2308 Ok(())
2309 }
2310}
2311
2312impl QMLLayer for QuantumConvolutionalLayer {
2313 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2314 let mut state = input.clone();
2315
2316 for filter in &self.conv_structure {
2318 state = self.apply_convolutional_filter(&state, filter)?;
2319 }
2320
2321 Ok(state)
2322 }
2323
2324 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2325 Ok(gradient.clone())
2326 }
2327
2328 fn get_parameters(&self) -> Array1<f64> {
2329 self.parameters.clone()
2330 }
2331
2332 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2333 self.parameters = parameters.clone();
2334 }
2335
2336 fn get_depth(&self) -> usize {
2337 self.conv_structure.len()
2338 }
2339
2340 fn get_gate_count(&self) -> usize {
2341 self.conv_structure.len() * 4 }
2343
2344 fn get_num_parameters(&self) -> usize {
2345 self.parameters.len()
2346 }
2347}
2348
2349impl QuantumConvolutionalLayer {
2350 fn apply_convolutional_filter(
2352 &self,
2353 state: &Array1<Complex64>,
2354 filter: &ConvolutionalFilter,
2355 ) -> Result<Array1<Complex64>> {
2356 let mut new_state = state.clone();
2357
2358 let param1 = self.parameters[filter.parameter_indices[0]];
2360 let param2 = self.parameters[filter.parameter_indices[1]];
2361
2362 new_state = Self::apply_ry_to_state(&new_state, filter.qubits[0], param1)?;
2364 new_state = Self::apply_ry_to_state(&new_state, filter.qubits[1], param2)?;
2365 new_state = Self::apply_cnot_to_state(&new_state, filter.qubits[0], filter.qubits[1])?;
2366
2367 Ok(new_state)
2368 }
2369
2370 fn apply_ry_to_state(
2372 state: &Array1<Complex64>,
2373 qubit: usize,
2374 angle: f64,
2375 ) -> Result<Array1<Complex64>> {
2376 let state_size = state.len();
2377 let mut new_state = Array1::zeros(state_size);
2378
2379 let cos_half = (angle / 2.0).cos();
2380 let sin_half = (angle / 2.0).sin();
2381
2382 for i in 0..state_size {
2383 if i & (1 << qubit) == 0 {
2384 let j = i | (1 << qubit);
2385 if j < state_size {
2386 new_state[i] = Complex64::new(cos_half, 0.0) * state[i]
2387 - Complex64::new(sin_half, 0.0) * state[j];
2388 new_state[j] = Complex64::new(sin_half, 0.0) * state[i]
2389 + Complex64::new(cos_half, 0.0) * state[j];
2390 }
2391 }
2392 }
2393
2394 Ok(new_state)
2395 }
2396
2397 fn apply_cnot_to_state(
2399 state: &Array1<Complex64>,
2400 control: usize,
2401 target: usize,
2402 ) -> Result<Array1<Complex64>> {
2403 let state_size = state.len();
2404 let mut new_state = state.clone();
2405
2406 for i in 0..state_size {
2407 if (i & (1 << control)) != 0 {
2408 let j = i ^ (1 << target);
2409 new_state[i] = state[j];
2410 }
2411 }
2412
2413 Ok(new_state)
2414 }
2415}
2416
2417#[derive(Debug)]
2419pub struct QuantumDenseLayer {
2420 num_qubits: usize,
2422 config: QMLLayerConfig,
2424 parameters: Array1<f64>,
2426 dense_structure: Vec<DenseConnection>,
2428}
2429
2430impl QuantumDenseLayer {
2431 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
2433 let mut layer = Self {
2434 num_qubits,
2435 config: config.clone(),
2436 parameters: Array1::zeros(config.num_parameters),
2437 dense_structure: Vec::new(),
2438 };
2439
2440 layer.initialize_parameters();
2441 layer.build_dense_structure()?;
2442
2443 Ok(layer)
2444 }
2445
2446 fn initialize_parameters(&mut self) {
2448 let mut rng = thread_rng();
2449 for param in &mut self.parameters {
2450 *param = rng.gen_range(-PI..PI);
2451 }
2452 }
2453
2454 fn build_dense_structure(&mut self) -> Result<()> {
2456 let mut param_idx = 0;
2457
2458 for i in 0..self.num_qubits {
2460 for j in (i + 1)..self.num_qubits {
2461 if param_idx < self.parameters.len() {
2462 self.dense_structure.push(DenseConnection {
2463 qubit1: i,
2464 qubit2: j,
2465 parameter_index: param_idx,
2466 });
2467 param_idx += 1;
2468 }
2469 }
2470 }
2471
2472 Ok(())
2473 }
2474}
2475
2476impl QMLLayer for QuantumDenseLayer {
2477 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2478 let mut state = input.clone();
2479
2480 for connection in &self.dense_structure {
2482 state = self.apply_dense_connection(&state, connection)?;
2483 }
2484
2485 Ok(state)
2486 }
2487
2488 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2489 Ok(gradient.clone())
2490 }
2491
2492 fn get_parameters(&self) -> Array1<f64> {
2493 self.parameters.clone()
2494 }
2495
2496 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2497 self.parameters = parameters.clone();
2498 }
2499
2500 fn get_depth(&self) -> usize {
2501 1 }
2503
2504 fn get_gate_count(&self) -> usize {
2505 self.dense_structure.len() * 2 }
2507
2508 fn get_num_parameters(&self) -> usize {
2509 self.parameters.len()
2510 }
2511}
2512
2513impl QuantumDenseLayer {
2514 fn apply_dense_connection(
2516 &self,
2517 state: &Array1<Complex64>,
2518 connection: &DenseConnection,
2519 ) -> Result<Array1<Complex64>> {
2520 let angle = self.parameters[connection.parameter_index];
2521
2522 Self::apply_parameterized_two_qubit_gate(state, connection.qubit1, connection.qubit2, angle)
2524 }
2525
2526 fn apply_parameterized_two_qubit_gate(
2528 state: &Array1<Complex64>,
2529 qubit1: usize,
2530 qubit2: usize,
2531 angle: f64,
2532 ) -> Result<Array1<Complex64>> {
2533 let state_size = state.len();
2534 let mut new_state = state.clone();
2535
2536 let cos_val = angle.cos();
2538 let sin_val = angle.sin();
2539
2540 for i in 0..state_size {
2541 if (i & (1 << qubit1)) != 0 && (i & (1 << qubit2)) != 0 {
2542 let phase = Complex64::new(cos_val, sin_val);
2544 new_state[i] *= phase;
2545 }
2546 }
2547
2548 Ok(new_state)
2549 }
2550}
2551
2552#[derive(Debug)]
2554pub struct QuantumLSTMLayer {
2555 num_qubits: usize,
2557 config: QMLLayerConfig,
2559 parameters: Array1<f64>,
2561 lstm_gates: Vec<LSTMGate>,
2563 hidden_state: Option<Array1<Complex64>>,
2565 cell_state: Option<Array1<Complex64>>,
2567}
2568
2569impl QuantumLSTMLayer {
2570 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
2572 let mut layer = Self {
2573 num_qubits,
2574 config: config.clone(),
2575 parameters: Array1::zeros(config.num_parameters),
2576 lstm_gates: Vec::new(),
2577 hidden_state: None,
2578 cell_state: None,
2579 };
2580
2581 layer.initialize_parameters();
2582 layer.build_lstm_structure()?;
2583
2584 Ok(layer)
2585 }
2586
2587 fn initialize_parameters(&mut self) {
2589 let mut rng = thread_rng();
2590 for param in &mut self.parameters {
2591 *param = rng.gen_range(-PI..PI);
2592 }
2593 }
2594
2595 fn build_lstm_structure(&mut self) -> Result<()> {
2597 let params_per_gate = self.parameters.len() / 4; self.lstm_gates = vec![
2600 LSTMGate {
2601 gate_type: LSTMGateType::Forget,
2602 parameter_start: 0,
2603 parameter_count: params_per_gate,
2604 },
2605 LSTMGate {
2606 gate_type: LSTMGateType::Input,
2607 parameter_start: params_per_gate,
2608 parameter_count: params_per_gate,
2609 },
2610 LSTMGate {
2611 gate_type: LSTMGateType::Output,
2612 parameter_start: 2 * params_per_gate,
2613 parameter_count: params_per_gate,
2614 },
2615 LSTMGate {
2616 gate_type: LSTMGateType::Candidate,
2617 parameter_start: 3 * params_per_gate,
2618 parameter_count: params_per_gate,
2619 },
2620 ];
2621
2622 Ok(())
2623 }
2624}
2625
2626impl QMLLayer for QuantumLSTMLayer {
2627 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2628 if self.hidden_state.is_none() {
2630 let state_size = 1 << self.num_qubits;
2631 let mut hidden = Array1::zeros(state_size);
2632 let mut cell = Array1::zeros(state_size);
2633 hidden[0] = Complex64::new(1.0, 0.0);
2635 cell[0] = Complex64::new(1.0, 0.0);
2636 self.hidden_state = Some(hidden);
2637 self.cell_state = Some(cell);
2638 }
2639
2640 let mut current_state = input.clone();
2641
2642 for gate in &self.lstm_gates {
2644 current_state = self.apply_lstm_gate(¤t_state, gate)?;
2645 }
2646
2647 self.hidden_state = Some(current_state.clone());
2649
2650 Ok(current_state)
2651 }
2652
2653 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2654 Ok(gradient.clone())
2655 }
2656
2657 fn get_parameters(&self) -> Array1<f64> {
2658 self.parameters.clone()
2659 }
2660
2661 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2662 self.parameters = parameters.clone();
2663 }
2664
2665 fn get_depth(&self) -> usize {
2666 self.lstm_gates.len()
2667 }
2668
2669 fn get_gate_count(&self) -> usize {
2670 self.parameters.len() }
2672
2673 fn get_num_parameters(&self) -> usize {
2674 self.parameters.len()
2675 }
2676}
2677
2678impl QuantumLSTMLayer {
2679 fn apply_lstm_gate(
2681 &self,
2682 state: &Array1<Complex64>,
2683 gate: &LSTMGate,
2684 ) -> Result<Array1<Complex64>> {
2685 let mut new_state = state.clone();
2686
2687 for i in 0..gate.parameter_count {
2689 let param_idx = gate.parameter_start + i;
2690 if param_idx < self.parameters.len() {
2691 let angle = self.parameters[param_idx];
2692 let qubit = i % self.num_qubits;
2693
2694 new_state = Self::apply_rotation(&new_state, qubit, angle)?;
2696 }
2697 }
2698
2699 Ok(new_state)
2700 }
2701
2702 fn apply_rotation(
2704 state: &Array1<Complex64>,
2705 qubit: usize,
2706 angle: f64,
2707 ) -> Result<Array1<Complex64>> {
2708 let state_size = state.len();
2709 let mut new_state = Array1::zeros(state_size);
2710
2711 let cos_half = (angle / 2.0).cos();
2712 let sin_half = (angle / 2.0).sin();
2713
2714 for i in 0..state_size {
2715 if i & (1 << qubit) == 0 {
2716 let j = i | (1 << qubit);
2717 if j < state_size {
2718 new_state[i] = Complex64::new(cos_half, 0.0) * state[i]
2719 - Complex64::new(sin_half, 0.0) * state[j];
2720 new_state[j] = Complex64::new(sin_half, 0.0) * state[i]
2721 + Complex64::new(cos_half, 0.0) * state[j];
2722 }
2723 }
2724 }
2725
2726 Ok(new_state)
2727 }
2728
2729 #[must_use]
2731 pub fn get_lstm_gates(&self) -> &[LSTMGate] {
2732 &self.lstm_gates
2733 }
2734}
2735
2736#[derive(Debug)]
2738pub struct QuantumAttentionLayer {
2739 num_qubits: usize,
2741 config: QMLLayerConfig,
2743 parameters: Array1<f64>,
2745 attention_structure: Vec<AttentionHead>,
2747}
2748
2749impl QuantumAttentionLayer {
2750 pub fn new(num_qubits: usize, config: QMLLayerConfig) -> Result<Self> {
2752 let mut layer = Self {
2753 num_qubits,
2754 config: config.clone(),
2755 parameters: Array1::zeros(config.num_parameters),
2756 attention_structure: Vec::new(),
2757 };
2758
2759 layer.initialize_parameters();
2760 layer.build_attention_structure()?;
2761
2762 Ok(layer)
2763 }
2764
2765 fn initialize_parameters(&mut self) {
2767 let mut rng = thread_rng();
2768 for param in &mut self.parameters {
2769 *param = rng.gen_range(-PI..PI);
2770 }
2771 }
2772
2773 fn build_attention_structure(&mut self) -> Result<()> {
2775 let num_heads = 2; let params_per_head = self.parameters.len() / num_heads;
2777
2778 for head in 0..num_heads {
2779 self.attention_structure.push(AttentionHead {
2780 head_id: head,
2781 parameter_start: head * params_per_head,
2782 parameter_count: params_per_head,
2783 query_qubits: (0..self.num_qubits / 2).collect(),
2784 key_qubits: (self.num_qubits / 2..self.num_qubits).collect(),
2785 });
2786 }
2787
2788 Ok(())
2789 }
2790}
2791
2792impl QMLLayer for QuantumAttentionLayer {
2793 fn forward(&mut self, input: &Array1<Complex64>) -> Result<Array1<Complex64>> {
2794 let mut state = input.clone();
2795
2796 for head in &self.attention_structure {
2798 state = self.apply_attention_head(&state, head)?;
2799 }
2800
2801 Ok(state)
2802 }
2803
2804 fn backward(&mut self, gradient: &Array1<f64>) -> Result<Array1<f64>> {
2805 Ok(gradient.clone())
2806 }
2807
2808 fn get_parameters(&self) -> Array1<f64> {
2809 self.parameters.clone()
2810 }
2811
2812 fn set_parameters(&mut self, parameters: &Array1<f64>) {
2813 self.parameters = parameters.clone();
2814 }
2815
2816 fn get_depth(&self) -> usize {
2817 self.attention_structure.len()
2818 }
2819
2820 fn get_gate_count(&self) -> usize {
2821 self.parameters.len()
2822 }
2823
2824 fn get_num_parameters(&self) -> usize {
2825 self.parameters.len()
2826 }
2827}
2828
2829impl QuantumAttentionLayer {
2830 fn apply_attention_head(
2832 &self,
2833 state: &Array1<Complex64>,
2834 head: &AttentionHead,
2835 ) -> Result<Array1<Complex64>> {
2836 let mut new_state = state.clone();
2837
2838 for i in 0..head.parameter_count {
2840 let param_idx = head.parameter_start + i;
2841 if param_idx < self.parameters.len() {
2842 let angle = self.parameters[param_idx];
2843
2844 if i < head.query_qubits.len() && i < head.key_qubits.len() {
2846 let query_qubit = head.query_qubits[i];
2847 let key_qubit = head.key_qubits[i];
2848
2849 new_state =
2850 Self::apply_attention_gate(&new_state, query_qubit, key_qubit, angle)?;
2851 }
2852 }
2853 }
2854
2855 Ok(new_state)
2856 }
2857
2858 fn apply_attention_gate(
2860 state: &Array1<Complex64>,
2861 query_qubit: usize,
2862 key_qubit: usize,
2863 angle: f64,
2864 ) -> Result<Array1<Complex64>> {
2865 let state_size = state.len();
2866 let mut new_state = state.clone();
2867
2868 let cos_val = angle.cos();
2870 let sin_val = angle.sin();
2871
2872 for i in 0..state_size {
2873 if (i & (1 << query_qubit)) != 0 {
2874 let key_state = (i & (1 << key_qubit)) != 0;
2876 let attention_phase = if key_state {
2877 Complex64::new(cos_val, sin_val)
2878 } else {
2879 Complex64::new(cos_val, -sin_val)
2880 };
2881 new_state[i] *= attention_phase;
2882 }
2883 }
2884
2885 Ok(new_state)
2886 }
2887
2888 #[must_use]
2890 pub fn get_attention_structure(&self) -> &[AttentionHead] {
2891 &self.attention_structure
2892 }
2893}
2894
2895#[derive(Debug, Clone)]
2897pub struct QMLTrainingState {
2898 pub current_epoch: usize,
2900 pub current_learning_rate: f64,
2902 pub best_validation_loss: f64,
2904 pub patience_counter: usize,
2906 pub training_loss_history: Vec<f64>,
2908 pub validation_loss_history: Vec<f64>,
2910}
2911
2912impl Default for QMLTrainingState {
2913 fn default() -> Self {
2914 Self::new()
2915 }
2916}
2917
2918impl QMLTrainingState {
2919 #[must_use]
2921 pub const fn new() -> Self {
2922 Self {
2923 current_epoch: 0,
2924 current_learning_rate: 0.01,
2925 best_validation_loss: f64::INFINITY,
2926 patience_counter: 0,
2927 training_loss_history: Vec::new(),
2928 validation_loss_history: Vec::new(),
2929 }
2930 }
2931}
2932
2933#[derive(Debug, Clone)]
2935pub struct QMLTrainingResult {
2936 pub final_training_loss: f64,
2938 pub final_validation_loss: f64,
2940 pub best_validation_loss: f64,
2942 pub epochs_trained: usize,
2944 pub total_training_time: std::time::Duration,
2946 pub training_metrics: Vec<QMLEpochMetrics>,
2948 pub quantum_advantage_metrics: QuantumAdvantageMetrics,
2950}
2951
2952#[derive(Debug, Clone)]
2954pub struct QMLEpochMetrics {
2955 pub epoch: usize,
2957 pub training_loss: f64,
2959 pub validation_loss: f64,
2961 pub epoch_time: std::time::Duration,
2963 pub learning_rate: f64,
2965}
2966
2967#[derive(Debug, Clone, Serialize, Deserialize)]
2969pub struct QuantumAdvantageMetrics {
2970 pub quantum_volume: f64,
2972 pub classical_simulation_cost: f64,
2974 pub quantum_speedup_factor: f64,
2976 pub circuit_depth: usize,
2978 pub gate_count: usize,
2980 pub entanglement_measure: f64,
2982}
2983
2984#[derive(Debug, Clone)]
2986pub struct QMLStats {
2987 pub forward_passes: usize,
2989 pub backward_passes: usize,
2991 pub total_training_time: std::time::Duration,
2993 pub average_epoch_time: std::time::Duration,
2995 pub peak_memory_usage: usize,
2997 pub num_parameters: usize,
2999}
3000
3001impl Default for QMLStats {
3002 fn default() -> Self {
3003 Self::new()
3004 }
3005}
3006
3007impl QMLStats {
3008 #[must_use]
3010 pub const fn new() -> Self {
3011 Self {
3012 forward_passes: 0,
3013 backward_passes: 0,
3014 total_training_time: std::time::Duration::from_secs(0),
3015 average_epoch_time: std::time::Duration::from_secs(0),
3016 peak_memory_usage: 0,
3017 num_parameters: 0,
3018 }
3019 }
3020}
3021
3022#[derive(Debug, Clone)]
3024pub struct PQCGate {
3025 pub gate_type: PQCGateType,
3027 pub qubits: Vec<usize>,
3029 pub parameter_index: Option<usize>,
3031}
3032
3033#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3035pub enum PQCGateType {
3036 SingleQubit(RotationGate),
3038 TwoQubit(TwoQubitGate),
3040}
3041
3042#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3044pub enum TwoQubitGate {
3045 CNOT,
3047 CZ,
3049 SWAP,
3051 CPhase,
3053}
3054
3055#[derive(Debug, Clone)]
3057pub struct ConvolutionalFilter {
3058 pub qubits: Vec<usize>,
3060 pub parameter_indices: Vec<usize>,
3062}
3063
3064#[derive(Debug, Clone)]
3066pub struct DenseConnection {
3067 pub qubit1: usize,
3069 pub qubit2: usize,
3071 pub parameter_index: usize,
3073}
3074
3075#[derive(Debug, Clone)]
3077pub struct LSTMGate {
3078 pub gate_type: LSTMGateType,
3080 pub parameter_start: usize,
3082 pub parameter_count: usize,
3084}
3085
3086#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3088pub enum LSTMGateType {
3089 Forget,
3091 Input,
3093 Output,
3095 Candidate,
3097}
3098
3099#[derive(Debug, Clone)]
3101pub struct AttentionHead {
3102 pub head_id: usize,
3104 pub parameter_start: usize,
3106 pub parameter_count: usize,
3108 pub query_qubits: Vec<usize>,
3110 pub key_qubits: Vec<usize>,
3112}
3113
3114#[derive(Debug, Clone, Serialize, Deserialize)]
3116pub struct QMLBenchmarkResults {
3117 pub training_times: HashMap<String, std::time::Duration>,
3119 pub final_accuracies: HashMap<String, f64>,
3121 pub convergence_rates: HashMap<String, f64>,
3123 pub memory_usage: HashMap<String, usize>,
3125 pub quantum_advantage: HashMap<String, QuantumAdvantageMetrics>,
3127 pub parameter_counts: HashMap<String, usize>,
3129 pub circuit_depths: HashMap<String, usize>,
3131 pub gate_counts: HashMap<String, usize>,
3133}
3134
3135pub struct QMLUtils;
3137
3138impl QMLUtils {
3139 #[must_use]
3141 pub fn generate_synthetic_data(
3142 num_samples: usize,
3143 input_dim: usize,
3144 output_dim: usize,
3145 ) -> (Vec<Array1<f64>>, Vec<Array1<f64>>) {
3146 let mut rng = thread_rng();
3147 let mut inputs = Vec::new();
3148 let mut outputs = Vec::new();
3149
3150 for _ in 0..num_samples {
3151 let input: Array1<f64> = Array1::from_vec(
3152 (0..input_dim)
3153 .map(|_| rng.gen_range(-1.0_f64..1.0_f64))
3154 .collect(),
3155 );
3156
3157 let output = Array1::from_vec(
3159 (0..output_dim)
3160 .map(|i| {
3161 if i < input_dim {
3162 input[i].sin() } else {
3164 rng.gen_range(-1.0_f64..1.0_f64)
3165 }
3166 })
3167 .collect(),
3168 );
3169
3170 inputs.push(input);
3171 outputs.push(output);
3172 }
3173
3174 (inputs, outputs)
3175 }
3176
3177 #[must_use]
3179 pub fn train_test_split(
3180 inputs: Vec<Array1<f64>>,
3181 outputs: Vec<Array1<f64>>,
3182 test_ratio: f64,
3183 ) -> (
3184 Vec<(Array1<f64>, Array1<f64>)>,
3185 Vec<(Array1<f64>, Array1<f64>)>,
3186 ) {
3187 let total_samples = inputs.len();
3188 let test_samples = ((total_samples as f64) * test_ratio) as usize;
3189 let train_samples = total_samples - test_samples;
3190
3191 let mut combined: Vec<(Array1<f64>, Array1<f64>)> =
3192 inputs.into_iter().zip(outputs).collect();
3193
3194 let mut rng = thread_rng();
3196 for i in (1..combined.len()).rev() {
3197 let j = rng.gen_range(0..=i);
3198 combined.swap(i, j);
3199 }
3200
3201 let (train_data, test_data) = combined.split_at(train_samples);
3202 (train_data.to_vec(), test_data.to_vec())
3203 }
3204
3205 #[must_use]
3207 pub fn evaluate_accuracy(
3208 predictions: &[Array1<f64>],
3209 targets: &[Array1<f64>],
3210 threshold: f64,
3211 ) -> f64 {
3212 let mut correct = 0;
3213 let total = predictions.len();
3214
3215 for (pred, target) in predictions.iter().zip(targets.iter()) {
3216 let diff = pred - target;
3217 let mse = diff.iter().map(|x| x * x).sum::<f64>() / diff.len() as f64;
3218 if mse < threshold {
3219 correct += 1;
3220 }
3221 }
3222
3223 f64::from(correct) / total as f64
3224 }
3225
3226 #[must_use]
3228 pub fn compute_circuit_complexity(
3229 num_qubits: usize,
3230 depth: usize,
3231 gate_count: usize,
3232 ) -> HashMap<String, f64> {
3233 let mut metrics = HashMap::new();
3234
3235 let state_space_size = 2.0_f64.powi(num_qubits as i32);
3237 metrics.insert("state_space_size".to_string(), state_space_size);
3238
3239 let circuit_complexity = (depth * gate_count) as f64;
3241 metrics.insert("circuit_complexity".to_string(), circuit_complexity);
3242
3243 let classical_cost = state_space_size * gate_count as f64;
3245 metrics.insert("classical_simulation_cost".to_string(), classical_cost);
3246
3247 let quantum_advantage = classical_cost.log(circuit_complexity);
3249 metrics.insert("quantum_advantage_estimate".to_string(), quantum_advantage);
3250
3251 metrics
3252 }
3253}
3254
3255pub fn benchmark_quantum_ml_layers(config: &QMLConfig) -> Result<QMLBenchmarkResults> {
3257 let mut results = QMLBenchmarkResults {
3258 training_times: HashMap::new(),
3259 final_accuracies: HashMap::new(),
3260 convergence_rates: HashMap::new(),
3261 memory_usage: HashMap::new(),
3262 quantum_advantage: HashMap::new(),
3263 parameter_counts: HashMap::new(),
3264 circuit_depths: HashMap::new(),
3265 gate_counts: HashMap::new(),
3266 };
3267
3268 let (inputs, outputs) =
3270 QMLUtils::generate_synthetic_data(100, config.num_qubits, config.num_qubits);
3271 let (train_data, val_data) = QMLUtils::train_test_split(inputs, outputs, 0.2);
3272
3273 let architectures = vec![
3275 QMLArchitectureType::VariationalQuantumCircuit,
3276 QMLArchitectureType::QuantumConvolutionalNN,
3277 ];
3279
3280 for architecture in architectures {
3281 let arch_name = format!("{architecture:?}");
3282
3283 let mut arch_config = config.clone();
3285 arch_config.architecture_type = architecture;
3286
3287 let start_time = std::time::Instant::now();
3289 let mut framework = QuantumMLFramework::new(arch_config)?;
3290
3291 let training_result = framework.train(&train_data, Some(&val_data))?;
3292 let training_time = start_time.elapsed();
3293
3294 let final_accuracy = framework.evaluate(&val_data)?;
3296
3297 results
3299 .training_times
3300 .insert(arch_name.clone(), training_time);
3301 results
3302 .final_accuracies
3303 .insert(arch_name.clone(), 1.0 / (1.0 + final_accuracy)); results.convergence_rates.insert(
3305 arch_name.clone(),
3306 training_result.epochs_trained as f64 / config.training_config.epochs as f64,
3307 );
3308 results
3309 .memory_usage
3310 .insert(arch_name.clone(), framework.get_stats().peak_memory_usage);
3311 results
3312 .quantum_advantage
3313 .insert(arch_name.clone(), training_result.quantum_advantage_metrics);
3314 results.parameter_counts.insert(
3315 arch_name.clone(),
3316 framework
3317 .layers
3318 .iter()
3319 .map(|l| l.get_num_parameters())
3320 .sum(),
3321 );
3322 results.circuit_depths.insert(
3323 arch_name.clone(),
3324 framework.layers.iter().map(|l| l.get_depth()).sum(),
3325 );
3326 results.gate_counts.insert(
3327 arch_name.clone(),
3328 framework.layers.iter().map(|l| l.get_gate_count()).sum(),
3329 );
3330 }
3331
3332 Ok(results)
3333}